blob: 1cd0d557c28709e622fa9e85f96aef551cb0fa8b [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;
158 PCH_BLC_PWM_CTL2_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
159
160 ----------------------------------------------------------------------------
161
162 procedure Static_Init
163 with
164 Refined_Global =>
165 (Output => (Power_Cycle_Timer, Power_Up_Timer, Delays_US),
166 Input => (Time.State))
167 is
168 begin
169 Power_Cycle_Timer := Time.Now;
170 Power_Up_Timer := Power_Cycle_Timer;
171
172 Delays_US := Default_EDP_Delays_US;
173 end Static_Init;
174
175 ----------------------------------------------------------------------------
176
177 procedure Check_PP_Delays
178 (Delays : in out Panel_Power_Delays;
179 Override : in out Boolean) is
180 begin
181 for D in Delays_Enum loop
182 if Delays (D) = 0 then
183 Delays (D) := Default_EDP_Delays_US (D);
184 Override := True;
185 end if;
186 end loop;
187 end Check_PP_Delays;
188
189 procedure Setup_PP_Sequencer (Default_Delays : Boolean := False)
190 is
191 Power_Delay, Port_Select : Word32;
192
193 Override_Delays : Boolean := False;
194 begin
195 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
196
197 Static_Init;
198
199 if Default_Delays then
200 Override_Delays := True;
201 else
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200202 Registers.Read (Panel_PP_Regs.ON_DELAYS, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200203 Delays_US (Power_Up_Delay) := 100 * Natural
204 (Shift_Right (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_MASK, 16));
205 Delays_US (Power_Up_To_BL_On) := 100 * Natural
206 (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK);
207
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200208 Registers.Read (Panel_PP_Regs.OFF_DELAYS, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200209 Delays_US (Power_Down_Delay) := 100 * Natural
210 (Shift_Right (Power_Delay and PCH_PP_OFF_DELAYS_PWR_DOWN_MASK, 16));
211 Delays_US (BL_Off_To_Power_Down) := 100 * Natural
212 (Power_Delay and PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK);
213
Nico Huber3ea5d602020-01-06 17:57:59 +0100214 if Config.Has_PP_Divisor_Reg then
215 Registers.Read (Panel_PP_Regs.DIVISOR, Power_Delay);
216 else
217 Registers.Read (Panel_PP_Regs.CONTROL, Power_Delay);
218 Power_Delay := Shift_Right (Power_Delay, BXT_PP_CONTROL_PWR_CYC_DELAY_SHIFT);
219 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200220 if (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) > 1 then
221 Delays_US (Power_Cycle_Delay) := 100_000 * (Natural
222 (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) - 1);
223 end if;
224
225 Check_PP_Delays (Delays_US, Override_Delays);
226 end if;
227
228 if Override_Delays then
229 if Config.Has_PP_Port_Select then
Nico Huber8a6e7bd2020-01-07 16:36:38 +0100230 Port_Select :=
Nico Huber2bbd6e72020-01-07 18:22:59 +0100231 (case Config.Panel_Ports (Panel_1) is
Nico Huber8a6e7bd2020-01-07 16:36:38 +0100232 when LVDS => PCH_PP_ON_DELAYS_PORT_SELECT_LVDS,
233 when eDP => PCH_PP_ON_DELAYS_PORT_SELECT_DP_A,
234 when DP2 | HDMI2 => PCH_PP_ON_DELAYS_PORT_SELECT_DP_C,
235 when DP3 | HDMI3 => PCH_PP_ON_DELAYS_PORT_SELECT_DP_D,
236 when others => 0);
Nico Huber83693c82016-10-08 22:17:55 +0200237 else
238 Port_Select := 0;
239 end if;
240
241 -- Force power-up to backlight-on delay to 100us as recommended by PRM.
242 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200243 (Register => Panel_PP_Regs.ON_DELAYS,
Nico Huber83693c82016-10-08 22:17:55 +0200244 Mask_Unset => PCH_PP_ON_DELAYS_PORT_SELECT_MASK or
245 PCH_PP_ON_DELAYS_PWR_UP_MASK or
246 PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK,
247 Mask_Set => Port_Select or
248 PCH_PP_ON_DELAYS_PWR_UP (Delays_US (Power_Up_Delay))
249 or PCH_PP_ON_DELAYS_PWR_UP_BL_ON (100));
250
251 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200252 (Register => Panel_PP_Regs.OFF_DELAYS,
Nico Huber83693c82016-10-08 22:17:55 +0200253 Mask_Unset => PCH_PP_OFF_DELAYS_PWR_DOWN_MASK or
254 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK,
255 Mask_Set => PCH_PP_OFF_DELAYS_PWR_DOWN
256 (Delays_US (Power_Down_Delay)) or
257 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN
258 (Delays_US (BL_Off_To_Power_Down)));
259
Nico Huber3ea5d602020-01-06 17:57:59 +0100260 if Config.Has_PP_Divisor_Reg then
261 Registers.Unset_And_Set_Mask
262 (Register => Panel_PP_Regs.DIVISOR,
263 Mask_Unset => PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK,
264 Mask_Set => PCH_PP_DIVISOR_PWR_CYC_DELAY
265 (Delays_US (Power_Cycle_Delay)));
266 else
267 Registers.Unset_And_Set_Mask
268 (Register => Panel_PP_Regs.CONTROL,
269 Mask_Unset => BXT_PP_CONTROL_PWR_CYC_DELAY_MASK,
270 Mask_Set => BXT_PP_CONTROL_PWR_CYC_DELAY
271 (Delays_US (Power_Cycle_Delay)));
272 end if;
Nico Huber83693c82016-10-08 22:17:55 +0200273 end if;
274
275 if Config.Has_PP_Write_Protection then
276 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200277 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200278 Mask_Unset => PCH_PP_CONTROL_WRITE_PROTECT_MASK,
279 Mask_Set => PCH_PP_CONTROL_WRITE_PROTECT_KEY or
280 PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
281 else
282 Registers.Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200283 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200284 Mask => PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
285 end if;
286 end Setup_PP_Sequencer;
287
288 ----------------------------------------------------------------------------
289
Nico Huber2bbd6e72020-01-07 18:22:59 +0100290 procedure VDD_Override (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200291 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100292 if Panel not in Valid_Panels then
293 return;
294 end if;
295
Nico Huber83693c82016-10-08 22:17:55 +0200296 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
297
298 -- Yeah, We could do, what we are supposed to do here. But OTOH, we
299 -- are should wait for the full Power Up Delay, which we would have
300 -- to do later again. And just powering on the display seems to work
301 -- too. Also this function vanished on newer hardware.
Nico Huber2bbd6e72020-01-07 18:22:59 +0100302 On (Panel);
Nico Huber83693c82016-10-08 22:17:55 +0200303 end VDD_Override;
304
Nico Huber2bbd6e72020-01-07 18:22:59 +0100305 procedure On (Panel : Panel_Control; Wait : Boolean := True)
Nico Huber83693c82016-10-08 22:17:55 +0200306 is
307 Was_On : Boolean;
308 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100309 if Panel not in Valid_Panels then
310 return;
311 end if;
312
Nico Huber83693c82016-10-08 22:17:55 +0200313 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
314
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200315 Registers.Is_Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Nico Huber83693c82016-10-08 22:17:55 +0200316 if not Was_On then
317 Time.Delay_Until (Power_Cycle_Timer);
318 end if;
319
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200320 Registers.Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON);
Nico Huber83693c82016-10-08 22:17:55 +0200321 if not Was_On then
322 Power_Up_Timer := Time.US_From_Now (Delays_US (Power_Up_Delay));
323 end if;
324 if Wait then
Nico Huber2bbd6e72020-01-07 18:22:59 +0100325 Wait_On (Panel);
Nico Huber83693c82016-10-08 22:17:55 +0200326 end if;
327 end On;
328
Nico Huber2bbd6e72020-01-07 18:22:59 +0100329 procedure Wait_On (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200330 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100331 if Panel not in Valid_Panels then
332 return;
333 end if;
334
Nico Huber83693c82016-10-08 22:17:55 +0200335 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
336
337 Time.Delay_Until (Power_Up_Timer);
338 Registers.Wait_Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200339 (Register => Panel_PP_Regs.STATUS,
Nico Huber83693c82016-10-08 22:17:55 +0200340 Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
341 TOut_MS => 300);
342
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200343 Registers.Unset_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_VDD_OVERRIDE);
Nico Huber83693c82016-10-08 22:17:55 +0200344 end Wait_On;
345
Nico Huber2bbd6e72020-01-07 18:22:59 +0100346 procedure Off (Panel : Panel_Control)
Nico Huber83693c82016-10-08 22:17:55 +0200347 is
348 Was_On : Boolean;
349 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100350 if Panel not in Valid_Panels then
351 return;
352 end if;
353
Nico Huber83693c82016-10-08 22:17:55 +0200354 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
355
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200356 Registers.Is_Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Nico Huber83693c82016-10-08 22:17:55 +0200357 Registers.Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200358 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200359 Mask => PCH_PP_CONTROL_TARGET_ON or
360 PCH_PP_CONTROL_VDD_OVERRIDE);
361 if Was_On then
362 Time.U_Delay (Delays_US (Power_Down_Delay));
363 end if;
364 Registers.Wait_Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200365 (Register => Panel_PP_Regs.STATUS,
Nico Huber83693c82016-10-08 22:17:55 +0200366 Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
367 TOut_MS => 600);
368 if Was_On then
369 Power_Cycle_Timer := Time.US_From_Now (Delays_US (Power_Cycle_Delay));
370 end if;
371 end Off;
372
373 ----------------------------------------------------------------------------
374
Nico Huber2bbd6e72020-01-07 18:22:59 +0100375 procedure Backlight_On (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200376 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100377 if Panel not in Valid_Panels then
378 return;
379 end if;
380
Nico Huber83693c82016-10-08 22:17:55 +0200381 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
382
383 Registers.Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200384 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200385 Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
386 end Backlight_On;
387
Nico Huber2bbd6e72020-01-07 18:22:59 +0100388 procedure Backlight_Off (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200389 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100390 if Panel not in Valid_Panels then
391 return;
392 end if;
393
Nico Huber83693c82016-10-08 22:17:55 +0200394 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
395
396 Registers.Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200397 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200398 Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
399 end Backlight_Off;
400
Nico Huber2bbd6e72020-01-07 18:22:59 +0100401 procedure Set_Backlight (Panel : Panel_Control; Level : Word16) is
Nico Huber83693c82016-10-08 22:17:55 +0200402 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100403 if Panel not in Valid_Panels then
404 return;
405 end if;
406
Nico Huber83693c82016-10-08 22:17:55 +0200407 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
408
409 Registers.Unset_And_Set_Mask
410 (Register => Registers.BLC_PWM_CPU_CTL,
411 Mask_Unset => CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK,
412 Mask_Set => Word32 (Level));
413 end Set_Backlight;
414
Nico Huber2bbd6e72020-01-07 18:22:59 +0100415 procedure Get_Max_Backlight (Panel : Panel_Control; Level : out Word16)
Nico Huber83693c82016-10-08 22:17:55 +0200416 is
417 Reg : Word32;
418 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100419 if Panel not in Valid_Panels then
420 Level := 0;
421 return;
422 end if;
423
Nico Huber83693c82016-10-08 22:17:55 +0200424 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
425
426 Registers.Read (Registers.BLC_PWM_PCH_CTL2, Reg);
427 Level := Word16
428 (Shift_Right (Reg and PCH_BLC_PWM_CTL2_BL_MOD_FREQ_MASK, 16));
429 end Get_Max_Backlight;
430
431end HW.GFX.GMA.Panel;