blob: 6bc4555f0c77e5df9b958709a8fb454aef17b7a2 [file] [log] [blame]
Arthur Heymans960e2392026-03-03 19:45:24 +01001--
2-- Copyright (C) 2026 Arthur Heymans <arthur@aheymans.xyz>
3--
4-- This program is free software; you can redistribute it and/or modify
5-- it under the terms of the GNU General Public License as published by
6-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
8--
9-- This program is distributed in the hope that it will be useful,
10-- but WITHOUT ANY WARRANTY; without even the implied warranty of
11-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12-- GNU General Public License for more details.
13--
14
15with HW.GFX.GMA.Config;
16with HW.GFX.GMA.Registers;
17
18package body HW.GFX.GMA.Power_And_Clocks is
19
20 CLKCFG_FSB_MASK : constant := 7 * 2 ** 0;
21 -- hrawclk = FSB / 4. The CLKCFG FSB bits encode different FSB speeds
22 -- depending on whether the platform is mobile or desktop (ALT encoding):
23 -- mobile: 0=FSB400, 1=FSB533, 2=FSB800, 3=FSB667, 6=FSB1067, 7=FSB1333
24 -- desktop: 0=FSB1067, 1=FSB533, 2=FSB800, 3=FSB667, 4=FSB1333,
25 -- 5=FSB400, 6=FSB1600
26 HRAWCLK_100 : constant Frequency_Type := 100_000_000; -- FSB 400
27 HRAWCLK_133 : constant Frequency_Type := 133_333_333; -- FSB 533
28 HRAWCLK_167 : constant Frequency_Type := 166_666_666; -- FSB 667
29 HRAWCLK_200 : constant Frequency_Type := 200_000_000; -- FSB 800
30 HRAWCLK_267 : constant Frequency_Type := 266_666_667; -- FSB 1067
31 HRAWCLK_333 : constant Frequency_Type := 333_333_333; -- FSB 1333
32 HRAWCLK_400 : constant Frequency_Type := 400_000_000; -- FSB 1600 (desktop)
33
Arthur Heymans6dc78432026-06-18 09:34:50 +020034 -- i945/Pineview CDClk values (from Linux kernel intel_cdclk.c):
Arthur Heymans960e2392026-03-03 19:45:24 +010035 --
36 -- i945G (desktop): fixed 400 MHz CDClk
37 --
38 -- i945GM (mobile): read from GCFGC PCI register (0xF0)
39 -- GC_LOW_FREQUENCY_ENABLE (bit 7) => 133 MHz
40 -- GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) => 200 MHz (default)
41 -- GC_DISPLAY_CLOCK_333_320_MHZ (4 << 4) => 320 MHz
Arthur Heymans6dc78432026-06-18 09:34:50 +020042 --
43 -- Pineview: read from GCFGC PCI register (0xF0)
44 -- GC_DISPLAY_CLOCK_267_MHZ_PNV (0 << 4) => 267 MHz
45 -- GC_DISPLAY_CLOCK_333_MHZ_PNV (1 << 4) => 333 MHz
46 -- GC_DISPLAY_CLOCK_444_MHZ_PNV (2 << 4) => 444 MHz
47 -- GC_DISPLAY_CLOCK_200_MHZ_PNV (5 << 4) => 200 MHz
48 -- GC_DISPLAY_CLOCK_133_MHZ_PNV (6 << 4) => 133 MHz
49 -- GC_DISPLAY_CLOCK_167_MHZ_PNV (7 << 4) => 167 MHz
Arthur Heymans960e2392026-03-03 19:45:24 +010050
51 procedure Get_CDClk (CDClk : out Config.CDClk_Range)
52 is
53 use type HW.Word16;
54
55 GC_LOW_FREQUENCY_ENABLE : constant Word16 := 1 * 2 ** 7;
56 GC_DISPLAY_CLOCK_MASK : constant Word16 := 7 * 2 ** 4;
57 GC_DISPLAY_CLOCK_320_MHZ : constant Word16 := 4 * 2 ** 4;
Arthur Heymans6dc78432026-06-18 09:34:50 +020058 GC_DISPLAY_CLOCK_267_MHZ_PNV : constant Word16 := 0 * 2 ** 4;
59 GC_DISPLAY_CLOCK_333_MHZ_PNV : constant Word16 := 1 * 2 ** 4;
60 GC_DISPLAY_CLOCK_444_MHZ_PNV : constant Word16 := 2 * 2 ** 4;
61 GC_DISPLAY_CLOCK_200_MHZ_PNV : constant Word16 := 5 * 2 ** 4;
62 GC_DISPLAY_CLOCK_133_MHZ_PNV : constant Word16 := 6 * 2 ** 4;
63 GC_DISPLAY_CLOCK_167_MHZ_PNV : constant Word16 := 7 * 2 ** 4;
Arthur Heymans960e2392026-03-03 19:45:24 +010064
65 GCFGC : Word16;
Arthur Heymans960e2392026-03-03 19:45:24 +010066 begin
Arthur Heymans6dc78432026-06-18 09:34:50 +020067 if Config.CPU_Any_Pineview then
68 PCI_Read16 (GCFGC, 16#f0#);
69 CDClk :=
70 (case GCFGC and GC_DISPLAY_CLOCK_MASK is
71 when GC_DISPLAY_CLOCK_267_MHZ_PNV => 266_666_667,
72 when GC_DISPLAY_CLOCK_333_MHZ_PNV => 333_333_333,
73 when GC_DISPLAY_CLOCK_444_MHZ_PNV => 444_444_444,
74 when GC_DISPLAY_CLOCK_200_MHZ_PNV => 200_000_000,
75 when GC_DISPLAY_CLOCK_167_MHZ_PNV => 166_666_667,
76 when others => 133_333_333);
77 elsif Config.GMCH_I945GM then
Nico Huber4ba49112020-06-10 16:31:36 +020078 PCI_Read16 (GCFGC, 16#f0#);
79 if (GCFGC and GC_LOW_FREQUENCY_ENABLE) /= 0 then
80 CDClk := 133_333_333;
81 elsif (GCFGC and GC_DISPLAY_CLOCK_MASK) = GC_DISPLAY_CLOCK_320_MHZ then
82 CDClk := 320_000_000;
83 else
84 CDClk := 200_000_000;
Arthur Heymans960e2392026-03-03 19:45:24 +010085 end if;
86 else
87 -- i945G desktop: fixed 400 MHz
Nico Huber4ba49112020-06-10 16:31:36 +020088 CDClk := 400_000_000;
Arthur Heymans960e2392026-03-03 19:45:24 +010089 end if;
90 end Get_CDClk;
91
92 -- hrawclk = FSB / 4. The CLKCFG FSB encoding differs between
Arthur Heymans6dc78432026-06-18 09:34:50 +020093 -- mobile/Pineview and desktop (i945G), see CLKCFG_FSB_MASK comment above.
Arthur Heymans960e2392026-03-03 19:45:24 +010094 procedure Get_Raw_Clock (Raw_Clock : out Frequency_Type)
95 is
96 CLK_CFG : Word32;
97 type Freq_Sel is new Natural range 0 .. 7;
98 begin
99 Registers.Read
100 (Register => Registers.GMCH_CLKCFG,
101 Value => CLK_CFG);
Arthur Heymans6dc78432026-06-18 09:34:50 +0200102 if Config.GMCH_Gen3_Mobile or Config.CPU_Any_Pineview then
Arthur Heymans960e2392026-03-03 19:45:24 +0100103 Raw_Clock := (case Freq_Sel (CLK_CFG and CLKCFG_FSB_MASK) is
104 when 0 => HRAWCLK_100, -- FSB 400
105 when 1 => HRAWCLK_133, -- FSB 533
106 when 2 => HRAWCLK_200, -- FSB 800
107 when 3 => HRAWCLK_167, -- FSB 667
108 when 6 => HRAWCLK_267, -- FSB 1067
109 when 7 => HRAWCLK_333, -- FSB 1333
110 when others => HRAWCLK_133);
111 else
112 Raw_Clock := (case Freq_Sel (CLK_CFG and CLKCFG_FSB_MASK) is
113 when 0 => HRAWCLK_267, -- FSB 1067
114 when 1 => HRAWCLK_133, -- FSB 533
115 when 2 => HRAWCLK_200, -- FSB 800
116 when 3 => HRAWCLK_167, -- FSB 667
117 when 4 => HRAWCLK_333, -- FSB 1333
118 when 5 => HRAWCLK_100, -- FSB 400
119 when 6 => HRAWCLK_400, -- FSB 1600
120 when others => HRAWCLK_133);
121 end if;
122 end Get_Raw_Clock;
123
124 procedure Initialize
125 is
126 CDClk : Config.CDClk_Range;
127 Raw_Clk : Frequency_Type;
128 begin
129 Get_CDClk (CDClk);
130 Config.CDClk := CDClk;
131 Config.Max_CDClk := CDClk;
132
133 Get_Raw_Clock (Raw_Clk);
134 Config.Raw_Clock := Raw_Clk;
135 end Initialize;
136
137 procedure Limit_Dotclocks
138 (Configs : in out Pipe_Configs;
139 CDClk_Switch : out Boolean)
140 is
141 begin
142 Config_Helpers.Limit_Dotclocks (Configs, Config.CDClk * 90 / 100);
143 CDClk_Switch := False;
144 end Limit_Dotclocks;
145
Nico Huber41e86742024-07-17 17:10:28 +0200146 procedure Power_Up (Port : Active_Port_Type; Success : out Boolean) is
147 begin
148 Success := True;
149 end Power_Up;
150
Arthur Heymans960e2392026-03-03 19:45:24 +0100151end HW.GFX.GMA.Power_And_Clocks;