blob: ab2f1fa69c5b3f270bf3d1cdb309daa8de71300c [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2014-2016 secunet Security Networks AG
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
Nico Huber125a29e2016-10-18 00:23:54 +02006-- the Free Software Foundation; either version 2 of the License, or
7-- (at your option) any later version.
Nico Huber83693c82016-10-08 22:17:55 +02008--
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 GNAT.Source_Info;
16
17with HW.Time;
18with HW.Debug;
19with HW.GFX.GMA.Config;
20with HW.GFX.GMA.Registers;
21with HW.GFX.GMA.Power_And_Clocks_Haswell;
22
23use type HW.Word64;
24
25package body HW.GFX.GMA.Power_And_Clocks_Skylake is
26
27 type Power_Domain is (MISC_IO, PW1, PW2, DDI_AE, DDI_B, DDI_C, DDI_D);
28 subtype Power_Well is Power_Domain range PW1 .. PW2;
29 subtype Dynamic_Domain is Power_Domain range PW2 .. DDI_D;
30
31 NDE_RSTWRN_OPT_RST_PCH_Handshake_En : constant := 1 * 2 ** 4;
32
33 FUSE_STATUS_DOWNLOAD_STATUS : constant := 1 * 2 ** 31;
34 FUSE_STATUS_PG0_DIST_STATUS : constant := 1 * 2 ** 27;
35
36 type Power_Domain_Values is array (Power_Domain) of Word32;
37 PWR_WELL_CTL_POWER_REQUEST : constant Power_Domain_Values :=
38 (MISC_IO => 1 * 2 ** 1,
39 DDI_AE => 1 * 2 ** 3,
40 DDI_B => 1 * 2 ** 5,
41 DDI_C => 1 * 2 ** 7,
42 DDI_D => 1 * 2 ** 9,
43 PW1 => 1 * 2 ** 29,
44 PW2 => 1 * 2 ** 31);
45 PWR_WELL_CTL_POWER_STATE : constant Power_Domain_Values :=
46 (MISC_IO => 1 * 2 ** 0,
47 DDI_AE => 1 * 2 ** 2,
48 DDI_B => 1 * 2 ** 4,
49 DDI_C => 1 * 2 ** 6,
50 DDI_D => 1 * 2 ** 8,
51 PW1 => 1 * 2 ** 28,
52 PW2 => 1 * 2 ** 30);
53
54 type Power_Well_Values is array (Power_Well) of Word32;
55 FUSE_STATUS_PGx_DIST_STATUS : constant Power_Well_Values :=
56 (PW1 => 1 * 2 ** 26,
57 PW2 => 1 * 2 ** 25);
58
59 DBUF_CTL_DBUF_POWER_REQUEST : constant := 1 * 2 ** 31;
60 DBUF_CTL_DBUF_POWER_STATE : constant := 1 * 2 ** 30;
61
62 ----------------------------------------------------------------------------
63
64 DPLL_CTRL1_DPLL0_LINK_RATE_MASK : constant := 7 * 2 ** 1;
65 DPLL_CTRL1_DPLL0_LINK_RATE_2700MHZ : constant := 0 * 2 ** 1;
66 DPLL_CTRL1_DPLL0_LINK_RATE_1350MHZ : constant := 1 * 2 ** 1;
67 DPLL_CTRL1_DPLL0_LINK_RATE_810MHZ : constant := 2 * 2 ** 1;
68 DPLL_CTRL1_DPLL0_LINK_RATE_1620MHZ : constant := 3 * 2 ** 1;
69 DPLL_CTRL1_DPLL0_LINK_RATE_1080MHZ : constant := 4 * 2 ** 1;
70 DPLL_CTRL1_DPLL0_LINK_RATE_2160MHZ : constant := 5 * 2 ** 1;
71 DPLL_CTRL1_DPLL0_OVERRIDE : constant := 1 * 2 ** 0;
72
73 LCPLL1_CTL_PLL_ENABLE : constant := 1 * 2 ** 31;
74 LCPLL1_CTL_PLL_LOCK : constant := 1 * 2 ** 30;
75
76 ----------------------------------------------------------------------------
77
78 CDCLK_CTL_CD_FREQ_SELECT_MASK : constant := 3 * 2 ** 26;
79 CDCLK_CTL_CD_FREQ_SELECT_450MHZ : constant := 0 * 2 ** 26;
80 CDCLK_CTL_CD_FREQ_SELECT_540MHZ : constant := 1 * 2 ** 26;
81 CDCLK_CTL_CD_FREQ_SELECT_337_5MHZ : constant := 2 * 2 ** 26;
82 CDCLK_CTL_CD_FREQ_SELECT_675MHZ : constant := 3 * 2 ** 26;
83 CDCLK_CTL_CD_FREQ_DECIMAL_MASK : constant := 16#7ff#;
84
85 SKL_PCODE_CDCLK_CONTROL : constant := 7;
86 SKL_CDCLK_PREPARE_FOR_CHANGE : constant := 3;
87 SKL_CDCLK_READY_FOR_CHANGE : constant := 1;
88
89 GT_MAILBOX_READY : constant := 1 * 2 ** 31;
90
91 function CDCLK_CTL_CD_FREQ_DECIMAL
92 (Freq : Positive;
93 Plus_Half : Boolean)
94 return Word32 is
95 begin
96 return Word32 (2 * (Freq - 1)) or (if Plus_Half then 1 else 0);
97 end CDCLK_CTL_CD_FREQ_DECIMAL;
98
99 ----------------------------------------------------------------------------
100
101 procedure GT_Mailbox_Write (MBox : Word32; Value : Word64) is
102 begin
103 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
104
105 Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
106 Registers.Write
107 (Registers.GT_MAILBOX_DATA, Word32 (Value and 16#ffff_ffff#));
108 Registers.Write
109 (Registers.GT_MAILBOX_DATA_1, Word32 (Shift_Right (Value, 32)));
110 Registers.Write (Registers.GT_MAILBOX, GT_MAILBOX_READY or MBox);
111
112 Registers.Wait_Unset_Mask (Registers.GT_MAILBOX, GT_MAILBOX_READY);
113 end GT_Mailbox_Write;
114
115 ----------------------------------------------------------------------------
116
117 procedure PD_Off (PD : Power_Domain)
118 is
119 Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
120 begin
121 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
122
123 Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
124 Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
125 Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
126 Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
127 pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
128 pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
129
130 if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
131 PWR_WELL_CTL_POWER_REQUEST (PD)) /= 0
132 then
133 Registers.Wait_Set_Mask
134 (Register => Registers.PWR_WELL_CTL_DRIVER,
135 Mask => PWR_WELL_CTL_POWER_STATE (PD));
136 end if;
137
138 if (Ctl1 and PWR_WELL_CTL_POWER_REQUEST (PD)) /= 0 then
139 Registers.Unset_Mask
140 (Register => Registers.PWR_WELL_CTL_BIOS,
141 Mask => PWR_WELL_CTL_POWER_REQUEST (PD));
142 end if;
143
144 if (Ctl2 and PWR_WELL_CTL_POWER_REQUEST (PD)) /= 0 then
145 Registers.Unset_Mask
146 (Register => Registers.PWR_WELL_CTL_DRIVER,
147 Mask => PWR_WELL_CTL_POWER_REQUEST (PD));
148 end if;
149 end PD_Off;
150
151 procedure PD_On (PD : Power_Domain)
152 with
153 Pre => True
154 is
155 Ctl1, Ctl2, Ctl3, Ctl4 : Word32;
156 begin
157 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
158
159 Registers.Read (Registers.PWR_WELL_CTL_BIOS, Ctl1);
160 Registers.Read (Registers.PWR_WELL_CTL_DRIVER, Ctl2);
161 Registers.Read (Registers.PWR_WELL_CTL_KVMR, Ctl3);
162 Registers.Read (Registers.PWR_WELL_CTL_DEBUG, Ctl4);
163 pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL5)); -- Result for debugging only
164 pragma Debug (Registers.Posting_Read (Registers.PWR_WELL_CTL6)); -- Result for debugging only
165
166 if ((Ctl1 or Ctl2 or Ctl3 or Ctl4) and
167 PWR_WELL_CTL_POWER_REQUEST (PD)) = 0
168 then
169 Registers.Wait_Unset_Mask
170 (Register => Registers.PWR_WELL_CTL_DRIVER,
171 Mask => PWR_WELL_CTL_POWER_STATE (PD));
172 end if;
173
174 if (Ctl2 and PWR_WELL_CTL_POWER_REQUEST (PD)) = 0 then
175 Registers.Set_Mask
176 (Register => Registers.PWR_WELL_CTL_DRIVER,
177 Mask => PWR_WELL_CTL_POWER_REQUEST (PD));
178 Registers.Wait_Set_Mask
179 (Register => Registers.PWR_WELL_CTL_DRIVER,
180 Mask => PWR_WELL_CTL_POWER_STATE (PD));
181
182 if PD in Power_Well then
183 Registers.Wait_Set_Mask
184 (Register => Registers.FUSE_STATUS,
185 Mask => FUSE_STATUS_PGx_DIST_STATUS (PD));
186 end if;
187 end if;
188 end PD_On;
189
190 function Need_PD (PD : Dynamic_Domain; Configs : Configs_Type) return Boolean
191 is
192 begin
193 return (case PD is
194 when DDI_AE => Configs (Primary).Port = Internal or
195 Configs (Secondary).Port = Internal or
196 Configs (Tertiary).Port = Internal,
197 when DDI_B => Configs (Primary).Port = Digital1 or
198 Configs (Primary).Port = DP1 or
199 Configs (Secondary).Port = Digital1 or
200 Configs (Secondary).Port = DP1 or
201 Configs (Tertiary).Port = Digital1 or
202 Configs (Tertiary).Port = DP1,
203 when DDI_C => Configs (Primary).Port = Digital2 or
204 Configs (Primary).Port = DP2 or
205 Configs (Secondary).Port = Digital2 or
206 Configs (Secondary).Port = DP2 or
207 Configs (Tertiary).Port = Digital2 or
208 Configs (Tertiary).Port = DP2,
209 when DDI_D => Configs (Primary).Port = Digital3 or
210 Configs (Primary).Port = DP3 or
211 Configs (Secondary).Port = Digital3 or
212 Configs (Secondary).Port = DP3 or
213 Configs (Tertiary).Port = Digital3 or
214 Configs (Tertiary).Port = DP3,
215 when PW2 => (Configs (Primary).Port /= Disabled and
216 Configs (Primary).Port /= Internal) or
217 Configs (Secondary).Port /= Disabled or
218 Configs (Tertiary).Port /= Disabled);
219 end Need_PD;
220
221 ----------------------------------------------------------------------------
222
223 procedure Pre_All_Off is
224 begin
225 Power_And_Clocks_Haswell.PSR_Off;
226 end Pre_All_Off;
227
228 procedure Post_All_Off is
229 begin
230 for PD in reverse Dynamic_Domain loop
231 PD_Off (PD);
232 end loop;
233
234 Registers.Unset_Mask
235 (Register => Registers.DBUF_CTL,
236 Mask => DBUF_CTL_DBUF_POWER_REQUEST);
237 Registers.Wait_Unset_Mask
238 (Register => Registers.DBUF_CTL,
239 Mask => DBUF_CTL_DBUF_POWER_STATE);
240
241 Registers.Unset_Mask
242 (Register => Registers.LCPLL1_CTL,
243 Mask => LCPLL1_CTL_PLL_ENABLE);
244 Registers.Wait_Unset_Mask
245 (Register => Registers.LCPLL1_CTL,
246 Mask => LCPLL1_CTL_PLL_LOCK);
247
248 PD_Off (MISC_IO);
249 PD_Off (PW1);
250 end Post_All_Off;
251
252 procedure Initialize
253 is
254 CDClk_Change_Timeout : Time.T;
255 Timed_Out : Boolean;
256
257 MBox_Data0 : Word32;
258 begin
259 Registers.Set_Mask
260 (Register => Registers.NDE_RSTWRN_OPT,
261 Mask => NDE_RSTWRN_OPT_RST_PCH_Handshake_En);
262
263 Registers.Wait_Set_Mask
264 (Register => Registers.FUSE_STATUS,
265 Mask => FUSE_STATUS_PG0_DIST_STATUS);
266 PD_On (PW1);
267 PD_On (MISC_IO);
268
269 Registers.Write
270 (Register => Registers.CDCLK_CTL,
271 Value => CDCLK_CTL_CD_FREQ_SELECT_337_5MHZ or
272 CDCLK_CTL_CD_FREQ_DECIMAL (337, True));
273 -- TODO: Set to preferred eDP rate:
274 -- Registers.Unset_And_Set_Mask
275 -- (Register => Registers.DPLL_CTRL1,
276 -- Unset_Mask => DPLL_CTRL1_DPLL0_LINK_RATE_MASK,
277 -- Set_Mask => DPLL_CTRL1_DPLL0_LINK_RATE_...);
278 Registers.Set_Mask
279 (Register => Registers.LCPLL1_CTL,
280 Mask => LCPLL1_CTL_PLL_ENABLE);
281 Registers.Wait_Set_Mask
282 (Register => Registers.LCPLL1_CTL,
283 Mask => LCPLL1_CTL_PLL_LOCK);
284
285 CDClk_Change_Timeout := Time.MS_From_Now (3);
286 loop
287 GT_Mailbox_Write
288 (MBox => SKL_PCODE_CDCLK_CONTROL,
289 Value => SKL_CDCLK_PREPARE_FOR_CHANGE);
290 Timed_Out := Time.Timed_Out (CDClk_Change_Timeout);
291 Registers.Read (Registers.GT_MAILBOX_DATA, MBox_Data0);
292 if (MBox_Data0 and SKL_CDCLK_READY_FOR_CHANGE) =
293 SKL_CDCLK_READY_FOR_CHANGE
294 then
295 Timed_Out := False;
296 exit;
297 end if;
298 exit when Timed_Out;
299 end loop;
300
301 if not Timed_Out then
302 GT_Mailbox_Write
303 (MBox => SKL_PCODE_CDCLK_CONTROL,
304 Value => 16#0000_0000#); -- 0 - 337.5MHz
305 -- 1 - 450.0MHz
306 -- 2 - 540.0MHz
307 -- 3 - 675.0MHz
308 Registers.Set_Mask
309 (Register => Registers.DBUF_CTL,
310 Mask => DBUF_CTL_DBUF_POWER_REQUEST);
311 Registers.Wait_Set_Mask
312 (Register => Registers.DBUF_CTL,
313 Mask => DBUF_CTL_DBUF_POWER_STATE);
314 end if;
315 end Initialize;
316
317 procedure Power_Set_To (Configs : Configs_Type) is
318 begin
319 for PD in reverse Dynamic_Domain loop
320 if not Need_PD (PD, Configs) then
321 PD_Off (PD);
322 end if;
323 end loop;
324 for PD in Dynamic_Domain loop
325 if Need_PD (PD, Configs) then
326 PD_On (PD);
327 end if;
328 end loop;
329 end Power_Set_To;
330
331 procedure Power_Up (Old_Configs, New_Configs : Configs_Type) is
332 begin
333 for PD in Dynamic_Domain loop
334 if not Need_PD (PD, Old_Configs) and Need_PD (PD, New_Configs) then
335 PD_On (PD);
336 end if;
337 end loop;
338 end Power_Up;
339
340 procedure Power_Down (Old_Configs, Tmp_Configs, New_Configs : Configs_Type)
341 is
342 begin
343 for PD in reverse Dynamic_Domain loop
344 if (Need_PD (PD, Old_Configs) or Need_PD (PD, Tmp_Configs)) and
345 not Need_PD (PD, New_Configs)
346 then
347 PD_Off (PD);
348 end if;
349 end loop;
350 end Power_Down;
351
352end HW.GFX.GMA.Power_And_Clocks_Skylake;