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.adb b/common/hw-gfx-gma.adb
index c3073d3..92c6f5e 100644
--- a/common/hw-gfx-gma.adb
+++ b/common/hw-gfx-gma.adb
@@ -496,7 +496,9 @@
use type HW.Word64;
function MMIO_GTT_Offset return Natural is
- (if Config.Has_64bit_GTT
+ (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;
@@ -507,7 +509,14 @@
is
Audio_VID_DID : Word32;
begin
+ if Config.Gen_I945 then
+ -- i945 has 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 =>
@@ -568,14 +577,20 @@
if Success then
Check_Platform_PCI (Success);
if Success then
- Dev.Map (PCI_MMIO_Base, PCI.Res0, Length => MMIO_GTT_Offset);
- Dev.Map (PCI_GTT_Base, PCI.Res0, Offset => MMIO_GTT_Offset);
+ if Config.Has_I945_GTT_BAR then
+ -- i945: MMIO is on BAR0, GTT is on separate BAR3
+ 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);
+ end if;
if PCI_MMIO_Base /= 0 and PCI_GTT_Base /= 0 then
Registers.Set_Register_Base (PCI_MMIO_Base, PCI_GTT_Base);
PCI_Usable := True;
else
pragma Debug (Debug.Put_Line
- ("ERROR: Couldn't map resoure0."));
+ ("ERROR: Couldn't map resource0."));
Success := Config.Default_MMIO_Base_Set;
end if;
end if;
@@ -828,11 +843,17 @@
Pre => Is_Initialized
is
GGC_Reg : constant PCI.Index :=
- (if Config.Gen_G45 or Config.CPU_Ironlake then 16#52# else 16#50#);
+ (if Config.Gen_I945 or Config.Gen_G45 or Config.CPU_Ironlake
+ then 16#52# else 16#50#);
GGC : Word16;
begin
Dev.Read16 (GGC, GGC_Reg);
- if Config.Gen_G45 or Config.CPU_Ironlake then
+ if Config.Gen_I945 then
+ -- i945 GTT is on a separate BAR3; GGC GGMS encoding differs
+ -- 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.Gen_G45 or Config.CPU_Ironlake then
GTT_Size := GTT_Size_Gen4 (GGC);
Stolen_Size := Stolen_Size_Gen4 (GGC);
elsif Config.CPU_Sandybridge or Config.CPU_Ivybridge or Config.CPU_Haswell
@@ -848,6 +869,46 @@
end if;
end Decode_Stolen;
+ procedure GTT_Entry_Count (Count : out Natural)
+ is
+ GTT_Size : Natural;
+
+ procedure Fake_Config_State_Access
+ with
+ Global => (Input => Config.Variable),
+ Annotate => (GNATprove, Intentional, "unused global",
+ "Used to have a common contract across platforms.");
+ procedure Fake_Config_State_Access is null;
+ begin
+ Fake_Config_State_Access;
+
+ 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);
+ else
+ -- Gen4+: GTT size is encoded in the GGC register.
+ declare
+ GGC_Reg : constant PCI.Index :=
+ (if Config.Gen_G45 or Config.CPU_Ironlake
+ then 16#52# else 16#50#);
+ GGC : Word16;
+ begin
+ Dev.Read16 (GGC, GGC_Reg);
+ if Config.Gen_G45 or Config.CPU_Ironlake then
+ GTT_Size := GTT_Size_Gen4 (GGC);
+ elsif Config.CPU_Sandybridge or
+ Config.CPU_Ivybridge or
+ Config.CPU_Haswell
+ then
+ GTT_Size := GTT_Size_Gen6 (GGC);
+ else
+ GTT_Size := GTT_Size_Gen8 (GGC);
+ end if;
+ end;
+ end if;
+ Count := Natural'Min (GTT_Size / Config.GTT_PTE_Size, GTT_Range'Last + 1);
+ end GTT_Entry_Count;
+
-- Additional runtime validation that FB fits stolen memory and aperture.
procedure Validate_FB (FB : Framebuffer_Type; Valid : out Boolean)
with