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-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;