blob: 3d6b3421eafb833c3edf72b5440019aa1d54873a [file] [log] [blame]
Nico Huber83693c82016-10-08 22:17:55 +02001--
2-- Copyright (C) 2015-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 HW.GFX.GMA.Config;
16
17with HW.Debug;
18with GNAT.Source_Info;
19
20package body HW.GFX.GMA.Panel
21with
22 Refined_State =>
23 (Panel_State =>
24 (Delays_US, Power_Cycle_Timer, Power_Up_Timer))
25is
26 type Delays_Enum is
27 (Power_Up_Delay,
28 Power_Up_To_BL_On,
29 Power_Down_Delay,
30 BL_Off_To_Power_Down,
31 Power_Cycle_Delay);
32
33 type Panel_Power_Delays is array (Delays_Enum) of Natural;
34 Default_EDP_Delays_US : constant Panel_Power_Delays := Panel_Power_Delays'
35 (Power_Up_Delay => 210_000,
36 Power_Up_To_BL_On => 50_000,
37 Power_Down_Delay => 500_000,
38 BL_Off_To_Power_Down => 50_000,
39 Power_Cycle_Delay => 510_000);
40
41 Delays_US : Panel_Power_Delays;
42
43 ----------------------------------------------------------------------------
44
45 -- And here the mess starts: We have this pretty hardware power sequencer
46 -- that should ensure the panel's timing constraints are satisfied. But
47 -- (at least on some generations) it doesn't do it's job. On Haswell, it
48 -- seems to ignore the Power_Cycle_Delay, so we ensure the delay in soft-
49 -- ware. On at least Ivy Bridge and Broadwell Power_Up_Delay is ignored.
50 --
51 -- If we ever do all delays in software, there are two ways: Either confi-
52 -- gure the hardware to zero delays or wait for both the software timeout
53 -- and the hardware power sequencer. The latter option would be less error
54 -- prone, as the hardware might just don't work as expected.
55
56 Power_Cycle_Timer : Time.T;
57 Power_Up_Timer : Time.T;
58
59 ----------------------------------------------------------------------------
60
Nico Huber57bebc72018-06-04 14:42:13 +020061 function Div_Round_Up32 (Num : Natural; Denom : Positive) return Word32 is
62 ((Word32 (Num) + Word32 (Denom) - 1) / Word32 (Denom));
Nico Huber83693c82016-10-08 22:17:55 +020063
64 PCH_PP_STATUS_ENABLED : constant := 16#00_0001# * 2 ** 31;
65 PCH_PP_STATUS_REQUIRE_ASSET : constant := 16#00_0001# * 2 ** 30;
66 PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK : constant := 16#00_0003# * 2 ** 28;
67 PCH_PP_STATUS_PWR_SEQ_PROGRESS_NONE : constant := 16#00_0000# * 2 ** 28;
68 PCH_PP_STATUS_PWR_SEQ_PROGRESS_UP : constant := 16#00_0001# * 2 ** 28;
69 PCH_PP_STATUS_PWR_SEQ_PROGRESS_DOWN : constant := 16#00_0002# * 2 ** 28;
70 PCH_PP_STATUS_PWR_CYC_DELAY_ACTIVE : constant := 16#00_0001# * 2 ** 27;
71
72 PCH_PP_CONTROL_WRITE_PROTECT_MASK : constant := 16#00_ffff# * 2 ** 16;
73 PCH_PP_CONTROL_WRITE_PROTECT_KEY : constant := 16#00_abcd# * 2 ** 16;
74 PCH_PP_CONTROL_VDD_OVERRIDE : constant := 16#00_0001# * 2 ** 3;
75 PCH_PP_CONTROL_BACKLIGHT_ENABLE : constant := 16#00_0001# * 2 ** 2;
76 PCH_PP_CONTROL_POWER_DOWN_ON_RESET : constant := 16#00_0001# * 2 ** 1;
77 PCH_PP_CONTROL_TARGET_ON : constant := 16#00_0001# * 2 ** 0;
78
Nico Huber3ea5d602020-01-06 17:57:59 +010079 BXT_PP_CONTROL_PWR_CYC_DELAY_SHIFT : constant := 4;
80 BXT_PP_CONTROL_PWR_CYC_DELAY_MASK : constant := 16#00_001f# * 2 ** 4;
81 function BXT_PP_CONTROL_PWR_CYC_DELAY (US : Natural) return Word32 is
82 (Shift_Left (Div_Round_Up32 (US, 100_000) + 1, BXT_PP_CONTROL_PWR_CYC_DELAY_SHIFT));
83
Nico Huber83693c82016-10-08 22:17:55 +020084 PCH_PP_ON_DELAYS_PORT_SELECT_MASK : constant := 16#00_0003# * 2 ** 30;
85 PCH_PP_ON_DELAYS_PORT_SELECT_LVDS : constant := 16#00_0000# * 2 ** 30;
86 PCH_PP_ON_DELAYS_PORT_SELECT_DP_A : constant := 16#00_0001# * 2 ** 30;
87 PCH_PP_ON_DELAYS_PORT_SELECT_DP_C : constant := 16#00_0002# * 2 ** 30;
88 PCH_PP_ON_DELAYS_PORT_SELECT_DP_D : constant := 16#00_0003# * 2 ** 30;
89 PCH_PP_ON_DELAYS_PWR_UP_MASK : constant := 16#00_1fff# * 2 ** 16;
90 PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK : constant := 16#00_1fff# * 2 ** 0;
Arthur Heymanse87d0d12018-03-28 17:02:49 +020091
92 type PP_Regs is record
93 STATUS : Registers.Registers_Index;
94 CONTROL : Registers.Registers_Index;
95 ON_DELAYS : Registers.Registers_Index;
96 OFF_DELAYS : Registers.Registers_Index;
97 DIVISOR : Registers.Registers_Index;
98 end record;
99
100 Panel_PP_Regs : constant PP_Regs := (if Config.Has_PCH_Panel_Power then
101 (STATUS => Registers.PCH_PP_STATUS,
102 CONTROL => Registers.PCH_PP_CONTROL,
103 ON_DELAYS => Registers.PCH_PP_ON_DELAYS,
104 OFF_DELAYS => Registers.PCH_PP_OFF_DELAYS,
105 DIVISOR => Registers.PCH_PP_DIVISOR)
106 else
107 (STATUS => Registers.GMCH_PP_STATUS,
108 CONTROL => Registers.GMCH_PP_CONTROL,
109 ON_DELAYS => Registers.GMCH_PP_ON_DELAYS,
110 OFF_DELAYS => Registers.GMCH_PP_OFF_DELAYS,
111 DIVISOR => Registers.GMCH_PP_DIVISOR));
112
Nico Huber83693c82016-10-08 22:17:55 +0200113 function PCH_PP_ON_DELAYS_PWR_UP (US : Natural) return Word32 is
114 begin
115 return Shift_Left (Div_Round_Up32 (US, 100), 16);
116 end PCH_PP_ON_DELAYS_PWR_UP;
117 function PCH_PP_ON_DELAYS_PWR_UP_BL_ON (US : Natural) return Word32 is
118 begin
119 return Div_Round_Up32 (US, 100);
120 end PCH_PP_ON_DELAYS_PWR_UP_BL_ON;
121
122 PCH_PP_OFF_DELAYS_PWR_DOWN_MASK : constant := 16#1fff# * 2 ** 16;
123 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK : constant := 16#1fff# * 2 ** 0;
124 function PCH_PP_OFF_DELAYS_PWR_DOWN (US : Natural) return Word32 is
125 begin
126 return Shift_Left (Div_Round_Up32 (US, 100), 16);
127 end PCH_PP_OFF_DELAYS_PWR_DOWN;
128 function PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN (US : Natural) return Word32 is
129 begin
130 return Div_Round_Up32 (US, 100);
131 end PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN;
132
133 PCH_PP_DIVISOR_REF_DIVIDER_MASK : constant := 16#ff_ffff# * 2 ** 8;
134 PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK : constant := 16#00_001f# * 2 ** 0;
135 function PCH_PP_DIVISOR_PWR_CYC_DELAY (US : Natural) return Word32 is
136 begin
137 return Div_Round_Up32 (US, 100_000) + 1;
138 end PCH_PP_DIVISOR_PWR_CYC_DELAY;
139
140 CPU_BLC_PWM_CTL_ENABLE : constant := 16#00_0001# * 2 ** 31;
141 CPU_BLC_PWM_CTL_PIPE_SELECT_MASK : constant := 16#00_0003# * 2 ** 29;
142 CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_A : constant := 16#00_0000# * 2 ** 29;
143 CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_B : constant := 16#00_0001# * 2 ** 29;
144 CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_C : constant := 16#00_0002# * 2 ** 29;
145
146 CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
147
148 PCH_BLC_PWM_CTL1_ENABLE : constant := 16#00_0001# * 2 ** 31;
149 PCH_BLC_PWM_CTL1_BL_POLARITY_MASK : constant := 16#00_0001# * 2 ** 29;
150 PCH_BLC_PWM_CTL1_PHASE_IN_INTR_STAT : constant := 16#00_0001# * 2 ** 26;
151 PCH_BLC_PWM_CTL1_PHASE_IN_ENABLE : constant := 16#00_0001# * 2 ** 25;
152 PCH_BLC_PWM_CTL1_PHASE_IN_INTR_EN : constant := 16#00_0001# * 2 ** 24;
153 PCH_BLC_PWM_CTL1_PHASE_IN_TIME_BASE : constant := 16#00_00ff# * 2 ** 16;
154 PCH_BLC_PWM_CTL1_PHASE_IN_COUNT : constant := 16#00_00ff# * 2 ** 8;
155 PCH_BLC_PWM_CTL1_PHASE_IN_INCREMENT : constant := 16#00_00ff# * 2 ** 0;
156
157 PCH_BLC_PWM_CTL2_BL_MOD_FREQ_MASK : constant := 16#00_ffff# * 2 ** 16;
Nico Huber1f63d512020-01-08 14:10:40 +0100158 PCH_BLC_PWM_CTL2_BL_MOD_FREQ_SHIFT : constant := 16;
Nico Huber83693c82016-10-08 22:17:55 +0200159 PCH_BLC_PWM_CTL2_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
160
Nico Huber1f63d512020-01-08 14:10:40 +0100161 BXT_BLC_PWM_CTL_ENABLE : constant := 16#00_0001# * 2 ** 31;
162
Nico Huber83693c82016-10-08 22:17:55 +0200163 ----------------------------------------------------------------------------
164
165 procedure Static_Init
166 with
167 Refined_Global =>
168 (Output => (Power_Cycle_Timer, Power_Up_Timer, Delays_US),
169 Input => (Time.State))
170 is
171 begin
172 Power_Cycle_Timer := Time.Now;
173 Power_Up_Timer := Power_Cycle_Timer;
174
175 Delays_US := Default_EDP_Delays_US;
176 end Static_Init;
177
178 ----------------------------------------------------------------------------
179
180 procedure Check_PP_Delays
181 (Delays : in out Panel_Power_Delays;
182 Override : in out Boolean) is
183 begin
184 for D in Delays_Enum loop
185 if Delays (D) = 0 then
186 Delays (D) := Default_EDP_Delays_US (D);
187 Override := True;
188 end if;
189 end loop;
190 end Check_PP_Delays;
191
192 procedure Setup_PP_Sequencer (Default_Delays : Boolean := False)
193 is
194 Power_Delay, Port_Select : Word32;
195
196 Override_Delays : Boolean := False;
197 begin
198 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
199
200 Static_Init;
201
202 if Default_Delays then
203 Override_Delays := True;
204 else
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200205 Registers.Read (Panel_PP_Regs.ON_DELAYS, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200206 Delays_US (Power_Up_Delay) := 100 * Natural
207 (Shift_Right (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_MASK, 16));
208 Delays_US (Power_Up_To_BL_On) := 100 * Natural
209 (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK);
210
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200211 Registers.Read (Panel_PP_Regs.OFF_DELAYS, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200212 Delays_US (Power_Down_Delay) := 100 * Natural
213 (Shift_Right (Power_Delay and PCH_PP_OFF_DELAYS_PWR_DOWN_MASK, 16));
214 Delays_US (BL_Off_To_Power_Down) := 100 * Natural
215 (Power_Delay and PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK);
216
Nico Huber3ea5d602020-01-06 17:57:59 +0100217 if Config.Has_PP_Divisor_Reg then
218 Registers.Read (Panel_PP_Regs.DIVISOR, Power_Delay);
219 else
220 Registers.Read (Panel_PP_Regs.CONTROL, Power_Delay);
221 Power_Delay := Shift_Right (Power_Delay, BXT_PP_CONTROL_PWR_CYC_DELAY_SHIFT);
222 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200223 if (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) > 1 then
224 Delays_US (Power_Cycle_Delay) := 100_000 * (Natural
225 (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) - 1);
226 end if;
227
228 Check_PP_Delays (Delays_US, Override_Delays);
229 end if;
230
231 if Override_Delays then
232 if Config.Has_PP_Port_Select then
Nico Huber8a6e7bd2020-01-07 16:36:38 +0100233 Port_Select :=
Nico Huber2bbd6e72020-01-07 18:22:59 +0100234 (case Config.Panel_Ports (Panel_1) is
Nico Huber8a6e7bd2020-01-07 16:36:38 +0100235 when LVDS => PCH_PP_ON_DELAYS_PORT_SELECT_LVDS,
236 when eDP => PCH_PP_ON_DELAYS_PORT_SELECT_DP_A,
237 when DP2 | HDMI2 => PCH_PP_ON_DELAYS_PORT_SELECT_DP_C,
238 when DP3 | HDMI3 => PCH_PP_ON_DELAYS_PORT_SELECT_DP_D,
239 when others => 0);
Nico Huber83693c82016-10-08 22:17:55 +0200240 else
241 Port_Select := 0;
242 end if;
243
244 -- Force power-up to backlight-on delay to 100us as recommended by PRM.
245 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200246 (Register => Panel_PP_Regs.ON_DELAYS,
Nico Huber83693c82016-10-08 22:17:55 +0200247 Mask_Unset => PCH_PP_ON_DELAYS_PORT_SELECT_MASK or
248 PCH_PP_ON_DELAYS_PWR_UP_MASK or
249 PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK,
250 Mask_Set => Port_Select or
251 PCH_PP_ON_DELAYS_PWR_UP (Delays_US (Power_Up_Delay))
252 or PCH_PP_ON_DELAYS_PWR_UP_BL_ON (100));
253
254 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200255 (Register => Panel_PP_Regs.OFF_DELAYS,
Nico Huber83693c82016-10-08 22:17:55 +0200256 Mask_Unset => PCH_PP_OFF_DELAYS_PWR_DOWN_MASK or
257 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK,
258 Mask_Set => PCH_PP_OFF_DELAYS_PWR_DOWN
259 (Delays_US (Power_Down_Delay)) or
260 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN
261 (Delays_US (BL_Off_To_Power_Down)));
262
Nico Huber3ea5d602020-01-06 17:57:59 +0100263 if Config.Has_PP_Divisor_Reg then
264 Registers.Unset_And_Set_Mask
265 (Register => Panel_PP_Regs.DIVISOR,
266 Mask_Unset => PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK,
267 Mask_Set => PCH_PP_DIVISOR_PWR_CYC_DELAY
268 (Delays_US (Power_Cycle_Delay)));
269 else
270 Registers.Unset_And_Set_Mask
271 (Register => Panel_PP_Regs.CONTROL,
272 Mask_Unset => BXT_PP_CONTROL_PWR_CYC_DELAY_MASK,
273 Mask_Set => BXT_PP_CONTROL_PWR_CYC_DELAY
274 (Delays_US (Power_Cycle_Delay)));
275 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200276 end if;
277
278 if Config.Has_PP_Write_Protection then
279 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200280 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200281 Mask_Unset => PCH_PP_CONTROL_WRITE_PROTECT_MASK,
282 Mask_Set => PCH_PP_CONTROL_WRITE_PROTECT_KEY or
283 PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
284 else
285 Registers.Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200286 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200287 Mask => PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
288 end if;
289 end Setup_PP_Sequencer;
290
291 ----------------------------------------------------------------------------
292
Nico Huber2bbd6e72020-01-07 18:22:59 +0100293 procedure VDD_Override (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200294 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100295 if Panel not in Valid_Panels then
296 return;
297 end if;
298
Nico Huber83693c82016-10-08 22:17:55 +0200299 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
300
301 -- Yeah, We could do, what we are supposed to do here. But OTOH, we
302 -- are should wait for the full Power Up Delay, which we would have
303 -- to do later again. And just powering on the display seems to work
304 -- too. Also this function vanished on newer hardware.
Nico Huber2bbd6e72020-01-07 18:22:59 +0100305 On (Panel);
Nico Huber83693c82016-10-08 22:17:55 +0200306 end VDD_Override;
307
Nico Huber2bbd6e72020-01-07 18:22:59 +0100308 procedure On (Panel : Panel_Control; Wait : Boolean := True)
Nico Huber83693c82016-10-08 22:17:55 +0200309 is
310 Was_On : Boolean;
311 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100312 if Panel not in Valid_Panels then
313 return;
314 end if;
315
Nico Huber83693c82016-10-08 22:17:55 +0200316 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
317
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200318 Registers.Is_Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Nico Huber83693c82016-10-08 22:17:55 +0200319 if not Was_On then
320 Time.Delay_Until (Power_Cycle_Timer);
321 end if;
322
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200323 Registers.Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON);
Nico Huber83693c82016-10-08 22:17:55 +0200324 if not Was_On then
325 Power_Up_Timer := Time.US_From_Now (Delays_US (Power_Up_Delay));
326 end if;
327 if Wait then
Nico Huber2bbd6e72020-01-07 18:22:59 +0100328 Wait_On (Panel);
Nico Huber83693c82016-10-08 22:17:55 +0200329 end if;
330 end On;
331
Nico Huber2bbd6e72020-01-07 18:22:59 +0100332 procedure Wait_On (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200333 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100334 if Panel not in Valid_Panels then
335 return;
336 end if;
337
Nico Huber83693c82016-10-08 22:17:55 +0200338 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
339
340 Time.Delay_Until (Power_Up_Timer);
341 Registers.Wait_Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200342 (Register => Panel_PP_Regs.STATUS,
Nico Huber83693c82016-10-08 22:17:55 +0200343 Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
344 TOut_MS => 300);
345
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200346 Registers.Unset_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_VDD_OVERRIDE);
Nico Huber83693c82016-10-08 22:17:55 +0200347 end Wait_On;
348
Nico Huber2bbd6e72020-01-07 18:22:59 +0100349 procedure Off (Panel : Panel_Control)
Nico Huber83693c82016-10-08 22:17:55 +0200350 is
351 Was_On : Boolean;
352 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100353 if Panel not in Valid_Panels then
354 return;
355 end if;
356
Nico Huber83693c82016-10-08 22:17:55 +0200357 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
358
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200359 Registers.Is_Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Nico Huber83693c82016-10-08 22:17:55 +0200360 Registers.Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200361 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200362 Mask => PCH_PP_CONTROL_TARGET_ON or
363 PCH_PP_CONTROL_VDD_OVERRIDE);
364 if Was_On then
365 Time.U_Delay (Delays_US (Power_Down_Delay));
366 end if;
367 Registers.Wait_Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200368 (Register => Panel_PP_Regs.STATUS,
Nico Huber83693c82016-10-08 22:17:55 +0200369 Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
370 TOut_MS => 600);
371 if Was_On then
372 Power_Cycle_Timer := Time.US_From_Now (Delays_US (Power_Cycle_Delay));
373 end if;
374 end Off;
375
376 ----------------------------------------------------------------------------
377
Nico Huber2bbd6e72020-01-07 18:22:59 +0100378 procedure Backlight_On (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200379 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100380 if Panel not in Valid_Panels then
381 return;
382 end if;
383
Nico Huber83693c82016-10-08 22:17:55 +0200384 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
385
Nico Huber1f63d512020-01-08 14:10:40 +0100386 if Config.Has_New_Backlight_Control then
387 Registers.Set_Mask
388 (Register => Registers.BXT_BLC_PWM_CTL_1,
389 Mask => BXT_BLC_PWM_CTL_ENABLE);
390 else
391 Registers.Set_Mask
392 (Register => Panel_PP_Regs.CONTROL,
393 Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
394 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200395 end Backlight_On;
396
Nico Huber2bbd6e72020-01-07 18:22:59 +0100397 procedure Backlight_Off (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200398 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100399 if Panel not in Valid_Panels then
400 return;
401 end if;
402
Nico Huber83693c82016-10-08 22:17:55 +0200403 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
404
Nico Huber1f63d512020-01-08 14:10:40 +0100405 if Config.Has_New_Backlight_Control then
406 Registers.Unset_Mask
407 (Register => Registers.BXT_BLC_PWM_CTL_1,
408 Mask => BXT_BLC_PWM_CTL_ENABLE);
409 else
410 Registers.Unset_Mask
411 (Register => Panel_PP_Regs.CONTROL,
412 Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
413 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200414 end Backlight_Off;
415
Nico Huber1f63d512020-01-08 14:10:40 +0100416 procedure Set_Backlight (Panel : Panel_Control; Level : Word32) is
Nico Huber83693c82016-10-08 22:17:55 +0200417 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100418 if Panel not in Valid_Panels then
419 return;
420 end if;
421
Nico Huber83693c82016-10-08 22:17:55 +0200422 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
423
Nico Huber1f63d512020-01-08 14:10:40 +0100424 if Config.Has_New_Backlight_Control then
425 Registers.Write (Registers.BXT_BLC_PWM_DUTY_1, Level);
426 else
427 Registers.Unset_And_Set_Mask
428 (Register => Registers.BLC_PWM_CPU_CTL,
429 Mask_Unset => CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK,
430 Mask_Set => Level);
431 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200432 end Set_Backlight;
433
Nico Huber1f63d512020-01-08 14:10:40 +0100434 procedure Get_Max_Backlight (Panel : Panel_Control; Level : out Word32) is
Nico Huber83693c82016-10-08 22:17:55 +0200435 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100436 if Panel not in Valid_Panels then
437 Level := 0;
438 return;
439 end if;
440
Nico Huber83693c82016-10-08 22:17:55 +0200441 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
442
Nico Huber1f63d512020-01-08 14:10:40 +0100443 if Config.Has_New_Backlight_Control then
444 Registers.Read (Registers.BXT_BLC_PWM_FREQ_1, Level);
445 else
446 Registers.Read (Registers.BLC_PWM_PCH_CTL2, Level);
447 Level := Shift_Right (Level, PCH_BLC_PWM_CTL2_BL_MOD_FREQ_SHIFT);
448 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200449 end Get_Max_Backlight;
450
451end HW.GFX.GMA.Panel;