gma g45: Add support for Intel GM965 (Crestline)

Add GM965 as a new CPU type under the G45 generation. GM965 shares
the GMCH display architecture with G45/GM45 (no PCH, same connector
registers) but differs in PLL limits, VCO/CDClk tables, and register
field encoding.

Key differences from G45/GM45:
 - PLL limits: Uses i9xx limits (VCO 1.4-2.8 GHz) instead of g4x
   limits. Add I9XX_LVDS_Limits; refactor Calculate_Clock_Parameters
   to take Limits as a parameter, with a new Select_Limits function.
 - VCO: Uses Crestline (CL) VCO tables with different frequencies
   and divisors than GM45's Cantiga (CTG) tables.
 - CDClk: GCFGC register decoding uses bits 12:8 minus 1 (3 possible
   divisor selections), unlike GM45's single bit 12.
 - No native DisplayPort (SDVO B/C only).
 - No HD Audio (G4X_AUD_VID_DID reads as 0).
 - Has integrated LVDS transmitter (mobile platform).
 - PCI IDs: 0x2a02 (I965_GM), 0x2a12 (I965_GME).

All implementation details cross-referenced against the Linux kernel
i915 driver (intel_dpll.c, intel_cdclk.c, intel_display_device.c).

Change-Id: I0d5d698cc1c2aa84778f0fc6c2752cb5ce4f1cb2
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.sourcearcade.org/c/libgfxinit/+/499
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: Nico Huber <nico.h@gmx.de>
diff --git a/common/hw-gfx-gma.adb b/common/hw-gfx-gma.adb
index d1fb7b1..7c336a2 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -506,35 +506,23 @@
    is
       use type HW.Word64;
 
-      function MMIO_GTT_Offset return Natural is
-        (if Config.Has_I945_GTT_BAR
-         then 0  -- i945: GTT is on separate BAR3, not within BAR0
-         elsif Config.Has_64bit_GTT
-         then Registers.MMIO_GTT_64_Offset
-         else Registers.MMIO_GTT_32_Offset);
       PCI_MMIO_Base, PCI_GTT_Base : Word64;
 
+      function Default_GTT_Base return Word64 is
+        (Config.Default_MMIO_Base + Word64 (Config.MMIO_GTT_Offset));
+
       Now : constant Time.T := Time.Now;
 
       procedure Check_Platform (Success : out Boolean)
       is
          Audio_VID_DID : Word32;
       begin
-         if Config.Gen_I945 then
-            -- i945 has no integrated audio DID to verify
+         if Config.Gen_I945 or Config.GMCH_GM965 then
+            -- i945 and GM965 have no integrated audio DID to verify.
             Success := True;
             return;
          end if;
-         case Config.Gen is
-            when I945 =>
-               Audio_VID_DID := 0;  -- unreachable due to early return
-            when G45 =>
-               Registers.Read (Registers.G4X_AUD_VID_DID, Audio_VID_DID);
-            when Ironlake =>
-               Registers.Read (Registers.PCH_AUD_VID_DID, Audio_VID_DID);
-            when Haswell .. Tigerlake =>
-               Registers.Read (Registers.AUD_VID_DID, Audio_VID_DID);
-         end case;
+         Registers.Read_AUD_VID_DID (Audio_VID_DID);
          Success :=
            ((Config.Gen_Broxton        and Audio_VID_DID = 16#8086_280a#) or
             (Config.CPU_Kabylake       and Audio_VID_DID = 16#8086_280b#) or
@@ -580,7 +568,7 @@
             Cursor      => Default_Cursor,
             Mode        => HW.GFX.Invalid_Mode));
       Config.Variable := Config.Initial_Settings;
-      Registers.Set_Register_Base (Config.Default_MMIO_Base);
+      Registers.Set_Register_Base (Config.Default_MMIO_Base, Default_GTT_Base);
       PLLs.Initialize;
 
       Dev.Initialize (Success);
@@ -593,8 +581,10 @@
                Dev.Map (PCI_MMIO_Base, PCI.Res0);
                Dev.Map (PCI_GTT_Base, PCI.Res3);
             else
-               Dev.Map (PCI_MMIO_Base, PCI.Res0, Length => MMIO_GTT_Offset);
-               Dev.Map (PCI_GTT_Base, PCI.Res0, Offset => MMIO_GTT_Offset);
+               Dev.Map
+                 (PCI_MMIO_Base, PCI.Res0, Length => Config.MMIO_GTT_Offset);
+               Dev.Map
+                 (PCI_GTT_Base, PCI.Res0, Offset => Config.MMIO_GTT_Offset);
             end if;
             if PCI_MMIO_Base /= 0 and PCI_GTT_Base /= 0 then
                Registers.Set_Register_Base (PCI_MMIO_Base, PCI_GTT_Base);
@@ -869,6 +859,11 @@
          -- from Gen4+.  Match the Linux driver and use the BAR size.
          Dev.Resource_Size (GTT_Size, PCI.Res3);
          Stolen_Size := Stolen_Size_Gen4 (GGC);
+      elsif Config.GMCH_GM965 then
+         -- GM965 has no GGMS field in GGC. The GTT is a fixed 512 KiB
+         -- region in the upper half of the 1 MiB GTTMMADR BAR.
+         GTT_Size    := 512 * 2 ** 10;
+         Stolen_Size := Stolen_Size_Gen4 (GGC);
       elsif Config.Gen_G45 or Config.CPU_Ironlake then
          GTT_Size    := GTT_Size_Gen4 (GGC);
          Stolen_Size := Stolen_Size_Gen4 (GGC);
@@ -901,6 +896,9 @@
       if Config.Has_I945_GTT_BAR then
          -- i945 GTT is on a separate BAR3; its size is the BAR size.
          Dev.Resource_Size (GTT_Size, PCI.Res3);
+      elsif Config.GMCH_GM965 then
+         -- GM965 has no GGMS field in GGC; its GTT is fixed at 512 KiB.
+         GTT_Size := 512 * 2 ** 10;
       else
          -- Gen4+: GTT size is encoded in the GGC register.
          declare