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/g45/hw-gfx-gma-plls.adb b/common/g45/hw-gfx-gma-plls.adb
index 5db76d6..fcc08ad 100644
--- a/common/g45/hw-gfx-gma-plls.adb
+++ b/common/g45/hw-gfx-gma-plls.adb
@@ -140,6 +140,18 @@
       P2_Fast      =>   5,           P2_Slow   =>  10,
       P2_Threshold =>   165_000_000,
       VCO_Lower    => 1_750_000_000, VCO_Upper => 3_500_000_000);
+   -- I9XX limits are used by GM965 (Crestline) and older non-G4x chips.
+   I9XX_LVDS_Limits : constant Limits_Type := Limits_Type'
+     (N_Lower      =>   3,           N_Upper   =>   8,
+      M_Lower      =>  70,           M_Upper   => 120,
+      M1_Lower     =>  10,           M1_Upper  =>  20,
+      M2_Lower     =>   5,           M2_Upper  =>   9,
+      P_Lower      =>   7,           P_Upper   =>  98,
+      P1_Lower     =>   1,           P1_Upper  =>   8,
+      P2_Fast      =>   7,           P2_Slow   =>  14,
+      P2_Threshold => 112_000_000,
+      VCO_Lower    => 1_400_000_000, VCO_Upper => 2_800_000_000);
+   -- The All_Other/I9XX_SDVO limits match Linux' intel_limits_i9xx_sdvo.
    All_Other_Limits : constant Limits_Type := Limits_Type'
      (N_Lower      =>   3,           N_Upper   =>   8,
       M_Lower      =>  70,           M_Upper   => 120,
@@ -279,9 +291,9 @@
    end Verify_Parameters;
 
    procedure Calculate_Clock_Parameters
-     (Display         : in     Display_Type;
-      Target_Dotclock : in     Clock_Range;
+     (Target_Dotclock : in     Clock_Range;
       Reference_Clock : in     Clock_Range;
+      Limits          : in     Limits_Type;
       Best_Clock      :    out Clock_Type;
       Valid           :    out Boolean)
    with
@@ -289,17 +301,6 @@
      Pre => True,
      Post => True
    is
-      Limits : constant Limits_Type :=
-      (case Display is
-          when LVDS   =>
-             (if Target_Dotclock >= Config.LVDS_Dual_Threshold then
-                LVDS_Dual_Limits
-              else
-                LVDS_Single_Limits),
-          when HDMI   => HDMI_Analog_Limits,
-          when VGA    => HDMI_Analog_Limits,
-          when others => All_Other_Limits); --TODO add SDVO type, needs other limits
-
       P2               : P2_Range;
       Best_Delta       : Int64 := Int64'Last;
       Current_Delta    : Int64;
@@ -420,6 +421,34 @@
                      Shift_Left (Encoded_P1, DPLL_P1_DIVIDER_SHIFT));
    end Program_DPLL;
 
+   function Select_Limits
+     (Display         : Display_Type;
+      Target_Dotclock : Clock_Range)
+      return Limits_Type
+   is
+   begin
+      if Config.GMCH_GM965 then
+         -- i9xx PLL limits for GM965 (Crestline)
+         case Display is
+            when LVDS   => return I9XX_LVDS_Limits;
+            when others => return All_Other_Limits;
+         end case;
+      else
+         -- G4x PLL limits for G45/GM45
+         case Display is
+            when LVDS   =>
+               if Target_Dotclock >= Config.LVDS_Dual_Threshold then
+                  return LVDS_Dual_Limits;
+               else
+                  return LVDS_Single_Limits;
+               end if;
+            when HDMI   => return HDMI_Analog_Limits;
+            when VGA    => return HDMI_Analog_Limits;
+            when others => return All_Other_Limits;
+         end case;
+      end if;
+   end Select_Limits;
+
    procedure On
      (PLL      : in     T;
       Port_Cfg : in     Port_Config;
@@ -459,10 +488,10 @@
             end case;
          elsif Target_Clock <= 340_000_000 then
             Calculate_Clock_Parameters
-              (Display           => Port_Cfg.Display,
-               Target_Dotclock   => Target_Clock,
+              (Target_Dotclock   => Target_Clock,
                -- should be, but doesn't has to be always the same:
                Reference_Clock   => 96_000_000,
+               Limits            => Select_Limits (Port_Cfg.Display, Target_Clock),
                Best_Clock        => Clk,
                Valid             => Success);
          else
diff --git a/common/g45/hw-gfx-gma-port_detect.adb b/common/g45/hw-gfx-gma-port_detect.adb
index 45ed2dd..6fdb527 100644
--- a/common/g45/hw-gfx-gma-port_detect.adb
+++ b/common/g45/hw-gfx-gma-port_detect.adb
@@ -74,25 +74,27 @@
 
    begin
       Config.Valid_Port (Analog) := True;
-      Config.Valid_Port (LVDS)   := Config.GMCH_GM45;
-      for HDMI_Port in GMCH_HDMI_Port loop
-         Registers.Is_Set_Mask
-           (Register => GMCH_HDMI (HDMI_Port),
-            Mask     => PORT_DETECTED,
-            Result   => Detected);
-         Config.Valid_Port (To_HDMI_Port (HDMI_Port)) := Detected;
-         hotplug_mask_set := hotplug_mask_set or
-           (if Detected then HDMI_PORT_HOTPLUG_EN (HDMI_Port) else 0);
-      end loop;
-      for DP_Port in GMCH_DP_Port loop
-         Registers.Is_Set_Mask
-           (Register => GMCH_DP (DP_Port),
-            Mask     => PORT_DETECTED,
-            Result   => Detected);
-         Config.Valid_Port (To_DP_Port (DP_Port)) := Detected;
-         hotplug_mask_set := hotplug_mask_set or
-           (if Detected then DP_PORT_HOTPLUG_EN (DP_Port) else 0);
-      end loop;
+      Config.Valid_Port (LVDS)   := Config.GMCH_GM45 or Config.GMCH_GM965;
+      if not Config.GMCH_GM965 then
+         for HDMI_Port in GMCH_HDMI_Port loop
+            Registers.Is_Set_Mask
+              (Register => GMCH_HDMI (HDMI_Port),
+               Mask     => PORT_DETECTED,
+               Result   => Detected);
+            Config.Valid_Port (To_HDMI_Port (HDMI_Port)) := Detected;
+            hotplug_mask_set := hotplug_mask_set or
+              (if Detected then HDMI_PORT_HOTPLUG_EN (HDMI_Port) else 0);
+         end loop;
+         for DP_Port in GMCH_DP_Port loop
+            Registers.Is_Set_Mask
+              (Register => GMCH_DP (DP_Port),
+               Mask     => PORT_DETECTED,
+               Result   => Detected);
+            Config.Valid_Port (To_DP_Port (DP_Port)) := Detected;
+            hotplug_mask_set := hotplug_mask_set or
+              (if Detected then DP_PORT_HOTPLUG_EN (DP_Port) else 0);
+         end loop;
+      end if;
       Registers.Write
         (Register => Registers.PORT_HOTPLUG_EN,
          Value => hotplug_mask_set);
diff --git a/common/g45/hw-gfx-gma-power_and_clocks.adb b/common/g45/hw-gfx-gma-power_and_clocks.adb
index c0bb683..e082a6d 100644
--- a/common/g45/hw-gfx-gma-power_and_clocks.adb
+++ b/common/g45/hw-gfx-gma-power_and_clocks.adb
@@ -46,10 +46,32 @@
         (0 => GM45_3200, 1 => GM45_4000, 2 => GM45_5333, 4 => GM45_2667,
          others => (others => 1));
 
+      -- Crestline (GM965) VCO divisor tables from Linux' i965gm_get_cdclk
+      CL_3200 : constant Div_Array := (16, 10,  8, others => 1);
+      CL_4000 : constant Div_Array := (20, 12, 10, others => 1);
+      CL_5333 : constant Div_Array := (24, 16, 14, others => 1);
+      CL_Divs : constant array (Natural range 0 .. 7) of Div_Array :=
+        (0 => CL_3200, 1 => CL_4000, 2 => CL_5333,
+         others => (others => 1));
+
       HPLLVCO : Word32;
       VCO_Sel : Natural range 0 .. 7;
    begin
-      if Config.Has_GMCH_Mobile_VCO then
+      if Config.GMCH_GM965 then
+         Registers.Read (Registers.GMCH_HPLLVCO_MOBILE, HPLLVCO);
+         VCO_Sel := Natural (HPLLVCO and 7);
+         VCO :=
+           (case VCO_Sel is
+               when 0 => 3_200_000_000,
+               when 1 => 4_000_000_000,
+               when 2 => 5_333_333_333,
+               when 3 => 6_400_000_000,
+               when 4 => 3_333_333_333,
+               when 5 => 3_566_666_667,
+               when 6 => 4_266_666_667,
+               when others => 0);
+         Divisors := CL_Divs (VCO_Sel);
+      elsif Config.Has_GMCH_Mobile_VCO then
          Registers.Read (Registers.GMCH_HPLLVCO_MOBILE, HPLLVCO);
          VCO_Sel := Natural (HPLLVCO and 7);
          VCO :=
@@ -91,7 +113,14 @@
       if PCI_Usable then
          Get_VCO (VCO, Divisors);
          PCI_Read16 (GCFGC, 16#f0#);
-         if Config.Has_GMCH_Mobile_VCO then
+         if Config.GMCH_GM965 then
+            -- Linux i965gm_get_cdclk: cdclk_sel = ((tmp >> 8) & 0x1f) - 1
+            if (Shift_Right (GCFGC, 8) and 16#1f#) in 1 .. 3 then
+               CDClk_Sel := Natural (Shift_Right (GCFGC, 8) and 16#1f#) - 1;
+            else
+               CDClk_Sel := Div_Array'Last;
+            end if;
+         elsif Config.Has_GMCH_Mobile_VCO then
             CDClk_Sel := Natural (Shift_Right (GCFGC, 12) and 1);
          else
             CDClk_Sel := Natural (Shift_Right (GCFGC, 4) and 7);
@@ -102,7 +131,9 @@
       if Tmp_Clk in Config.CDClk_Range then
          CDClk := Tmp_Clk;
       else
-         if Config.Has_GMCH_Mobile_VCO then
+         if Config.GMCH_GM965 then
+            CDClk := 4_000_000_000 / 20;  -- 200 MHz
+         elsif Config.Has_GMCH_Mobile_VCO then
             CDClk := 5_333_333_333 / 24;
          else
             CDClk := 5_333_333_333 / 28;
diff --git a/common/hw-gfx-gma-config.ads.template b/common/hw-gfx-gma-config.ads.template
index 93e7ca4..a041e2c 100644
--- a/common/hw-gfx-gma-config.ads.template
+++ b/common/hw-gfx-gma-config.ads.template
@@ -19,7 +19,7 @@
    CPU_First : constant CPU_Type :=
      (case Gen is
          when I945      => I945G,
-         when G45       => G45,
+         when G45       => GM965,
          when Ironlake  => Ironlake,
          when Haswell   => Haswell,
          when Broxton   => Broxton,
@@ -159,6 +159,7 @@
    Tigerlake_On      : <genbool> := Gen >= Tigerlake;
 
    GMCH_I945GM       : <i945bool> := Gen_I945 and then CPU = I945GM;
+   GMCH_GM965        : <g45bool> := Gen_G45 and then CPU = GM965;
    GMCH_GM45         : <g45bool> := Gen_G45 and then CPU = GM45;
    CPU_Ironlake      : <ilkbool> := Gen_Ironlake and then CPU = Ironlake;
    CPU_Sandybridge   : <ilkbool> := Gen_Ironlake and then CPU = Sandybridge;
@@ -268,7 +269,7 @@
 
    ---------- Clocks: -----------
    Has_GMCH_RawClk               : <genbool> := Up_To_G45;
-   Has_GMCH_Mobile_VCO           : <g45bool> := GMCH_GM45;
+   Has_GMCH_Mobile_VCO           : <g45bool> := GMCH_GM45 or GMCH_GM965;
 
    ---------- I945-specific: ----
    Has_I945_GTT_BAR              : <genbool> := Gen_I945;
@@ -454,6 +455,19 @@
 
    GMA_Base_Is_64bit : constant Boolean := Config.Tigerlake_On;
 
+   AUD_VID_DID_Offset : <ilkhswvar> Natural :=
+     (if    Gen_G45       then 16#06_2020#
+      elsif Gen_Ironlake  then 16#0e_5020#
+      else                     16#06_5020#);
+
+   -- Default 32-bit GTT offset for static MMIO instantiation.
+   Default_MMIO_GTT_32_Offset : constant Natural :=
+     (if Has_I945_GTT_BAR then 16#00_0000# else 16#20_0000#);
+   MMIO_GTT_32_Offset : <g45var> Natural :=
+     (if GMCH_GM965 then 16#0008_0000# else Default_MMIO_GTT_32_Offset);
+   MMIO_GTT_64_Offset : constant Natural := 16#80_0000#;
+   MMIO_GTT_Offset : <g45hswvar> Natural :=
+     (if Has_64bit_GTT then MMIO_GTT_64_Offset else MMIO_GTT_32_Offset);
    GTT_PTE_Size : <hswvar> Natural := (if Has_64bit_GTT then 8 else 4);
 
    Fence_Base : <i945ilkvar> Natural :=
@@ -607,6 +621,7 @@
       return Boolean is
      (case CPU is
          when I945G        => Device_Id = 16#2772#,
+         when GM965        => (Device_Id and 16#ffef#) = 16#2a02#,
          when I945GM       => Device_Id = 16#27a2# or Device_Id = 16#27ae#,
          when G45          => (Device_Id and 16#ff02#) = 16#2e02#,
          when GM45         => (Device_Id and 16#fffe#) = 16#2a42#,
diff --git a/common/hw-gfx-gma-pipe_setup.adb b/common/hw-gfx-gma-pipe_setup.adb
index cb5369e..8975778 100644
--- a/common/hw-gfx-gma-pipe_setup.adb
+++ b/common/hw-gfx-gma-pipe_setup.adb
@@ -310,7 +310,8 @@
          end if;
 
          if Config.Has_DSP_Linoff and then FB.Tiling = Linear then
-            pragma Assert_And_Cut (True);
+            pragma Assert_And_Cut
+              (FB.Start_Y * FB.Stride + FB.Start_X in Pixel_Type);
             declare
                Linear_Offset : constant Pixel_Type :=
                   FB.Start_Y * FB.Stride + FB.Start_X;
diff --git a/common/hw-gfx-gma-registers.adb b/common/hw-gfx-gma-registers.adb
index eb12b0d..a59a4f7 100644
--- a/common/hw-gfx-gma-registers.adb
+++ b/common/hw-gfx-gma-registers.adb
@@ -45,13 +45,19 @@
 
    ----------------------------------------------------------------------------
 
+   MMIO_GTT_32_Size : constant := 16#20_0000#;
+   -- Limit Broadwell+ to 4MiB to have a stable
+   -- interface (i.e. same number of entries):
+   MMIO_GTT_64_Size : constant := 16#40_0000#;
+
    type GTT_PTE_32 is mod 2 ** 32;
    type GTT_Registers_32 is array (GTT_Range) of GTT_PTE_32
    with
       Volatile_Components,
       Size => MMIO_GTT_32_Size * 8;
    package GTT_32 is new MMIO_Range
-     (Base_Addr   => Config.Default_MMIO_Base + MMIO_GTT_32_Offset,
+     (Base_Addr   =>
+        Config.Default_MMIO_Base + Word64 (Config.Default_MMIO_GTT_32_Offset),
       Element_T   => GTT_PTE_32,
       Index_T     => GTT_Range,
       Array_T     => GTT_Registers_32);
@@ -62,7 +68,7 @@
       Volatile_Components,
       Size => MMIO_GTT_64_Size * 8;
    package GTT_64 is new MMIO_Range
-     (Base_Addr   => Config.Default_MMIO_Base + MMIO_GTT_64_Offset,
+     (Base_Addr   => Config.Default_MMIO_Base + Word64 (Config.MMIO_GTT_64_Offset),
       Element_T   => GTT_PTE_64,
       Index_T     => GTT_Range,
       Array_T     => GTT_Registers_64);
@@ -347,6 +353,14 @@
       pragma Debug (Verbose, Debug.Put_Line (Registers_Index'Image (Register)));
    end Read;
 
+   procedure Read_AUD_VID_DID (Value : out Word32)
+   is
+   begin
+      Regs.Read
+        (Value,
+         Registers_Range (Config.AUD_VID_DID_Offset / Register_Width));
+   end Read_AUD_VID_DID;
+
    ----------------------------------------------------------------------------
 
    -- Read a specific register to post a previous write
@@ -566,8 +580,9 @@
    begin
       Regs.Set_Base_Address (Base);
       if GTT_Base = 0 then
-         GTT_32.Set_Base_Address (Base + MMIO_GTT_32_Offset);
-         GTT_64.Set_Base_Address (Base + MMIO_GTT_64_Offset);
+         GTT_32.Set_Base_Address
+           (Base + Word64 (Config.Default_MMIO_GTT_32_Offset));
+         GTT_64.Set_Base_Address (Base + Word64 (Config.MMIO_GTT_64_Offset));
       else
          GTT_32.Set_Base_Address (GTT_Base);
          GTT_64.Set_Base_Address (GTT_Base);
diff --git a/common/hw-gfx-gma-registers.ads b/common/hw-gfx-gma-registers.ads
index 404dda3..c9454c9 100644
--- a/common/hw-gfx-gma-registers.ads
+++ b/common/hw-gfx-gma-registers.ads
@@ -24,14 +24,6 @@
    Initializes => Address_State
 is
 
-   MMIO_GTT_32_Size     : constant := 16#20_0000#;
-   MMIO_GTT_32_Offset   : constant := 16#20_0000#;
-
-   -- Limit Broadwell+ to 4MiB to have a stable
-   -- interface (i.e. same number of entries):
-   MMIO_GTT_64_Size     : constant := 16#40_0000#;
-   MMIO_GTT_64_Offset   : constant := 16#80_0000#;
-
    type Registers_Invalid_Index is
      (Invalid_Register, -- Allow a placeholder when access is not acceptable
 
@@ -2320,6 +2312,13 @@
       Post    => True;
    pragma Warnings (GNATprove, On, "unused variable ""Verbose""");
 
+   procedure Read_AUD_VID_DID (Value : out Word32)
+   with
+      Global  => (In_Out => Register_State),
+      Depends => ((Value, Register_State) => Register_State),
+      Pre     => True,
+      Post    => True;
+
    procedure Write
       (Register : Registers_Index;
        Value    : Word32)
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
diff --git a/common/hw-gfx-gma.ads b/common/hw-gfx-gma.ads
index 3777b45..69cc41b 100644
--- a/common/hw-gfx-gma.ads
+++ b/common/hw-gfx-gma.ads
@@ -40,6 +40,7 @@
    type CPU_Type is
      (I945G,
       I945GM,
+      GM965,
       G45,
       GM45,
       Ironlake,