gma: Add Intel i945 (Gen3) graphics init support
Add i945G (desktop) and i945GM (mobile) generation support, modeled
after the existing G45 generation code with hardware-specific
adaptations based on the Linux i915 DRM driver and coreboot.
Key hardware differences from G45 (Gen4):
- GTT on separate PCI BAR3 (not within BAR0)
- Simple 32-bit GTT PTEs (addr[31:12] | valid[0])
- No DSPSURF register (uses DSPADDR/DSPLINOFF instead)
- Gen3 fence registers: 32-bit at split 0x2000/0x3000 addresses
- Different PLL limits (VCO 1400-2800 MHz, 96 MHz refclk)
- SDVO multiplier in DPLL register bits[7:4]
- LVDS restricted to Pipe B (pre-i965 requirement)
- CDClk: fixed 400 MHz (desktop) or GCFGC-based (mobile)
- No HDMI/DP, only VGA, LVDS, and SDVO outputs
- PCI IDs: 0x2772 (I945G), 0x27a2/0x27ae (I945GM)
TESTED with thinkpad x60: LVDS & VGA works with a linear framebuffer.
Change-Id: Ib67b3d0ee5e06df427869dce4db926ba57a80fd8
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.sourcearcade.org/c/libgfxinit/+/476
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: Nico Huber <nico.h@gmx.de>
diff --git a/common/hw-gfx-gma-registers.adb b/common/hw-gfx-gma-registers.adb
index 3f0d7ae..eb12b0d 100644
--- a/common/hw-gfx-gma-registers.adb
+++ b/common/hw-gfx-gma-registers.adb
@@ -75,20 +75,57 @@
FENCE_PAGE_SHIFT : constant := 12;
FENCE_PAGE_MASK : constant := 16#ffff_f000#;
- FENCE_TILE_WALK_YMAJOR : constant := 1 * 2 ** 1;
FENCE_VALID : constant := 1 * 2 ** 0;
+ -- Gen4+ (i965/G45+): 64-bit fence pairs at Fence_Base + i*8
+ FENCE_TILE_WALK_YMAJOR : constant := 1 * 2 ** 1;
+
function Fence_Lower_Idx (Fence : Fence_Range) return Registers_Range is
(Registers_Range (Config.Fence_Base / Register_Width + 2 * Fence));
function Fence_Upper_Idx (Fence : Fence_Range) return Registers_Range is
(Fence_Lower_Idx (Fence) + 1);
+ -- Gen3 (i915/i945): 32-bit fences, split layout:
+ -- Fences 0-7: 0x2000 + i*4
+ -- Fences 8-15: 0x3000 + (i-8)*4
+ -- FENCE_REG(i) = 0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4
+ GEN3_FENCE_TILING_Y_SHIFT : constant := 12;
+ GEN3_FENCE_SIZE_SHIFT : constant := 8;
+ GEN3_FENCE_PITCH_SHIFT : constant := 4;
+
+ function Gen3_Fence_Idx (Fence : Fence_Range) return Registers_Range is
+ (Registers_Range
+ ((16#2000# + (Fence / 8) * 16#1000# + (Fence mod 8) * 4) /
+ Register_Width));
+
+ -- Compute floor(log2(n)) for n >= 1 (fence size/pitch encoding).
+ function Floor_Log2 (N : Word32) return Natural
+ with
+ Pre => N >= 1
+ is
+ Result : Natural := 0;
+ Val : Word32 := N;
+ begin
+ for I in 0 .. 31 loop
+ exit when Val <= 1;
+ Val := Shift_Right (Val, 1);
+ Result := I + 1;
+ end loop;
+ return Result;
+ end Floor_Log2;
+
procedure Clear_Fences
is
begin
- for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
- Regs.Write (Fence_Lower_Idx (Fence), 0);
- end loop;
+ if Config.Has_Gen3_Fences then
+ for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
+ Regs.Write (Gen3_Fence_Idx (Fence), 0);
+ end loop;
+ else
+ for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
+ Regs.Write (Fence_Lower_Idx (Fence), 0);
+ end loop;
+ end if;
end Clear_Fences;
procedure Add_Fence
@@ -111,42 +148,106 @@
pragma Debug (Debug.Put_Line (" tiles per row."));
Success := False;
- for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
- Regs.Read (Reg32, Fence_Lower_Idx (Fence));
- if (Reg32 and FENCE_VALID) = 0 then
- Regs.Write
- (Index => Fence_Lower_Idx (Fence),
- Value => Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT) or
- (if Y_Tiles then FENCE_TILE_WALK_YMAJOR else 0) or
- FENCE_VALID);
- Regs.Write
- (Index => Fence_Upper_Idx (Fence),
- Value => Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT) or
- Word32 (Pitch) * (if Y_Tiles then 1 else 4) - 1);
- Success := True;
- exit;
- end if;
- end loop;
+
+ if Config.Has_Gen3_Fences then
+ -- Gen3 i945: single 32-bit fence register per fence
+ -- Format: start[31:20] | tiling_y[12] | size_bits[11:8] |
+ -- pitch_log2[7:4] | valid[0]
+ -- stride: Y-tiled /128, X-tiled /512 (i945 has 128-byte Y tiling)
+ -- size_bits: log2(size_in_pages / 256) = log2(size_in_MB)
+ for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
+ Regs.Read (Reg32, Gen3_Fence_Idx (Fence));
+ if (Reg32 and FENCE_VALID) = 0 then
+ declare
+ Start_Addr : constant Word32 :=
+ Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT);
+ Size_Pages : constant Word32 :=
+ Word32 (Last_Page - First_Page + 1);
+ -- Size in MB (pages / 256, since page = 4KB, 256*4KB = 1MB)
+ Size_MB : constant Word32 := Size_Pages / 256;
+ -- Pitch in tiles (X: 512B tiles, Y: 128B tiles for i945)
+ Stride : constant Word32 :=
+ Word32 (Pitch) / (if Y_Tiles then 128 else 512);
+ Size_Bits : constant Word32 :=
+ (if Size_MB >= 1
+ then Word32 (Floor_Log2 (Size_MB))
+ else 0);
+ begin
+ Regs.Write
+ (Index => Gen3_Fence_Idx (Fence),
+ Value => Start_Addr or
+ (if Y_Tiles
+ then Shift_Left (1, GEN3_FENCE_TILING_Y_SHIFT)
+ else 0) or
+ Shift_Left (Size_Bits, GEN3_FENCE_SIZE_SHIFT) or
+ Shift_Left
+ ((if Stride >= 1
+ then Word32 (Floor_Log2 (Stride))
+ else 0),
+ GEN3_FENCE_PITCH_SHIFT) or
+ FENCE_VALID);
+ end;
+ Success := True;
+ exit;
+ end if;
+ end loop;
+ else
+ -- Gen4+ (i965/G45+): 64-bit fence register pairs
+ for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
+ Regs.Read (Reg32, Fence_Lower_Idx (Fence));
+ if (Reg32 and FENCE_VALID) = 0 then
+ Regs.Write
+ (Index => Fence_Lower_Idx (Fence),
+ Value => Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT) or
+ (if Y_Tiles then FENCE_TILE_WALK_YMAJOR else 0) or
+ FENCE_VALID);
+ Regs.Write
+ (Index => Fence_Upper_Idx (Fence),
+ Value => Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT) or
+ Word32 (Pitch) * (if Y_Tiles then 1 else 4) - 1);
+ Success := True;
+ exit;
+ end if;
+ end loop;
+ end if;
end Add_Fence;
procedure Remove_Fence (First_Page, Last_Page : GTT_Range)
is
Page_Lower : constant Word32 :=
Shift_Left (Word32 (First_Page), FENCE_PAGE_SHIFT);
- Page_Upper : constant Word32 :=
- Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT);
- Fence_Upper, Fence_Lower : Word32;
+ Reg32 : Word32;
begin
- for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
- Regs.Read (Fence_Lower, Fence_Lower_Idx (Fence));
- Regs.Read (Fence_Upper, Fence_Upper_Idx (Fence));
- if (Fence_Lower and FENCE_PAGE_MASK) = Page_Lower and
- (Fence_Upper and FENCE_PAGE_MASK) = Page_Upper
- then
- Regs.Write (Fence_Lower_Idx (Fence), 0);
- exit;
- end if;
- end loop;
+ if Config.Has_Gen3_Fences then
+ -- Gen3: match start address in single 32-bit register
+ for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
+ Regs.Read (Reg32, Gen3_Fence_Idx (Fence));
+ if (Reg32 and FENCE_VALID) /= 0 and
+ (Reg32 and 16#fff0_0000#) = (Page_Lower and 16#fff0_0000#)
+ then
+ Regs.Write (Gen3_Fence_Idx (Fence), 0);
+ exit;
+ end if;
+ end loop;
+ else
+ -- Gen4+: match start in lower, end in upper register
+ declare
+ Page_Upper : constant Word32 :=
+ Shift_Left (Word32 (Last_Page), FENCE_PAGE_SHIFT);
+ Fence_Upper, Fence_Lower : Word32;
+ begin
+ for Fence in Fence_Range range 0 .. Config.Fence_Count - 1 loop
+ Regs.Read (Fence_Lower, Fence_Lower_Idx (Fence));
+ Regs.Read (Fence_Upper, Fence_Upper_Idx (Fence));
+ if (Fence_Lower and FENCE_PAGE_MASK) = Page_Lower and
+ (Fence_Upper and FENCE_PAGE_MASK) = Page_Upper
+ then
+ Regs.Write (Fence_Lower_Idx (Fence), 0);
+ exit;
+ end if;
+ end loop;
+ end;
+ end if;
end Remove_Fence;
----------------------------------------------------------------------------
@@ -157,7 +258,13 @@
Valid : Boolean)
is
begin
- if not Config.Has_64bit_GTT then
+ if Config.Has_I945_Simple_GTT_PTE then
+ -- i945: simple 32-bit PTE, no high address bits
+ GTT_32.Write
+ (Index => GTT_Page,
+ Value => GTT_PTE_32 (Device_Address and 16#ffff_f000#) or
+ Boolean'Pos (Valid));
+ elsif not Config.Has_64bit_GTT then
GTT_32.Write
(Index => GTT_Page,
Value => GTT_PTE_32 (Device_Address and 16#ffff_f000#) or
@@ -178,7 +285,15 @@
GTT_Page : in GTT_Range)
is
begin
- if not Config.Has_64bit_GTT then
+ if Config.Has_I945_Simple_GTT_PTE then
+ declare
+ PTE : GTT_PTE_32;
+ begin
+ GTT_32.Read (PTE, GTT_Page);
+ Valid := (PTE and GTT_PTE_Valid) /= 0;
+ Device_Address := GTT_Address_Type (PTE and 16#ffff_f000#);
+ end;
+ elsif not Config.Has_64bit_GTT then
declare
PTE : GTT_PTE_32;
begin