blob: 359f580ab9e3728bf6eb37148adce86e3ecdf18a [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
79 PCH_PP_ON_DELAYS_PORT_SELECT_MASK : constant := 16#00_0003# * 2 ** 30;
80 PCH_PP_ON_DELAYS_PORT_SELECT_LVDS : constant := 16#00_0000# * 2 ** 30;
81 PCH_PP_ON_DELAYS_PORT_SELECT_DP_A : constant := 16#00_0001# * 2 ** 30;
82 PCH_PP_ON_DELAYS_PORT_SELECT_DP_C : constant := 16#00_0002# * 2 ** 30;
83 PCH_PP_ON_DELAYS_PORT_SELECT_DP_D : constant := 16#00_0003# * 2 ** 30;
84 PCH_PP_ON_DELAYS_PWR_UP_MASK : constant := 16#00_1fff# * 2 ** 16;
85 PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK : constant := 16#00_1fff# * 2 ** 0;
Arthur Heymanse87d0d12018-03-28 17:02:49 +020086
87 type PP_Regs is record
88 STATUS : Registers.Registers_Index;
89 CONTROL : Registers.Registers_Index;
90 ON_DELAYS : Registers.Registers_Index;
91 OFF_DELAYS : Registers.Registers_Index;
92 DIVISOR : Registers.Registers_Index;
93 end record;
94
95 Panel_PP_Regs : constant PP_Regs := (if Config.Has_PCH_Panel_Power then
96 (STATUS => Registers.PCH_PP_STATUS,
97 CONTROL => Registers.PCH_PP_CONTROL,
98 ON_DELAYS => Registers.PCH_PP_ON_DELAYS,
99 OFF_DELAYS => Registers.PCH_PP_OFF_DELAYS,
100 DIVISOR => Registers.PCH_PP_DIVISOR)
101 else
102 (STATUS => Registers.GMCH_PP_STATUS,
103 CONTROL => Registers.GMCH_PP_CONTROL,
104 ON_DELAYS => Registers.GMCH_PP_ON_DELAYS,
105 OFF_DELAYS => Registers.GMCH_PP_OFF_DELAYS,
106 DIVISOR => Registers.GMCH_PP_DIVISOR));
107
Nico Huber83693c82016-10-08 22:17:55 +0200108 function PCH_PP_ON_DELAYS_PWR_UP (US : Natural) return Word32 is
109 begin
110 return Shift_Left (Div_Round_Up32 (US, 100), 16);
111 end PCH_PP_ON_DELAYS_PWR_UP;
112 function PCH_PP_ON_DELAYS_PWR_UP_BL_ON (US : Natural) return Word32 is
113 begin
114 return Div_Round_Up32 (US, 100);
115 end PCH_PP_ON_DELAYS_PWR_UP_BL_ON;
116
117 PCH_PP_OFF_DELAYS_PWR_DOWN_MASK : constant := 16#1fff# * 2 ** 16;
118 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK : constant := 16#1fff# * 2 ** 0;
119 function PCH_PP_OFF_DELAYS_PWR_DOWN (US : Natural) return Word32 is
120 begin
121 return Shift_Left (Div_Round_Up32 (US, 100), 16);
122 end PCH_PP_OFF_DELAYS_PWR_DOWN;
123 function PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN (US : Natural) return Word32 is
124 begin
125 return Div_Round_Up32 (US, 100);
126 end PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN;
127
128 PCH_PP_DIVISOR_REF_DIVIDER_MASK : constant := 16#ff_ffff# * 2 ** 8;
129 PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK : constant := 16#00_001f# * 2 ** 0;
130 function PCH_PP_DIVISOR_PWR_CYC_DELAY (US : Natural) return Word32 is
131 begin
132 return Div_Round_Up32 (US, 100_000) + 1;
133 end PCH_PP_DIVISOR_PWR_CYC_DELAY;
134
135 CPU_BLC_PWM_CTL_ENABLE : constant := 16#00_0001# * 2 ** 31;
136 CPU_BLC_PWM_CTL_PIPE_SELECT_MASK : constant := 16#00_0003# * 2 ** 29;
137 CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_A : constant := 16#00_0000# * 2 ** 29;
138 CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_B : constant := 16#00_0001# * 2 ** 29;
139 CPU_BLC_PWM_CTL_PIPE_SELECT_PIPE_C : constant := 16#00_0002# * 2 ** 29;
140
141 CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
142
143 PCH_BLC_PWM_CTL1_ENABLE : constant := 16#00_0001# * 2 ** 31;
144 PCH_BLC_PWM_CTL1_BL_POLARITY_MASK : constant := 16#00_0001# * 2 ** 29;
145 PCH_BLC_PWM_CTL1_PHASE_IN_INTR_STAT : constant := 16#00_0001# * 2 ** 26;
146 PCH_BLC_PWM_CTL1_PHASE_IN_ENABLE : constant := 16#00_0001# * 2 ** 25;
147 PCH_BLC_PWM_CTL1_PHASE_IN_INTR_EN : constant := 16#00_0001# * 2 ** 24;
148 PCH_BLC_PWM_CTL1_PHASE_IN_TIME_BASE : constant := 16#00_00ff# * 2 ** 16;
149 PCH_BLC_PWM_CTL1_PHASE_IN_COUNT : constant := 16#00_00ff# * 2 ** 8;
150 PCH_BLC_PWM_CTL1_PHASE_IN_INCREMENT : constant := 16#00_00ff# * 2 ** 0;
151
152 PCH_BLC_PWM_CTL2_BL_MOD_FREQ_MASK : constant := 16#00_ffff# * 2 ** 16;
153 PCH_BLC_PWM_CTL2_BL_DUTY_CYC_MASK : constant := 16#00_ffff# * 2 ** 0;
154
155 ----------------------------------------------------------------------------
156
157 procedure Static_Init
158 with
159 Refined_Global =>
160 (Output => (Power_Cycle_Timer, Power_Up_Timer, Delays_US),
161 Input => (Time.State))
162 is
163 begin
164 Power_Cycle_Timer := Time.Now;
165 Power_Up_Timer := Power_Cycle_Timer;
166
167 Delays_US := Default_EDP_Delays_US;
168 end Static_Init;
169
170 ----------------------------------------------------------------------------
171
172 procedure Check_PP_Delays
173 (Delays : in out Panel_Power_Delays;
174 Override : in out Boolean) is
175 begin
176 for D in Delays_Enum loop
177 if Delays (D) = 0 then
178 Delays (D) := Default_EDP_Delays_US (D);
179 Override := True;
180 end if;
181 end loop;
182 end Check_PP_Delays;
183
184 procedure Setup_PP_Sequencer (Default_Delays : Boolean := False)
185 is
186 Power_Delay, Port_Select : Word32;
187
188 Override_Delays : Boolean := False;
189 begin
190 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
191
192 Static_Init;
193
194 if Default_Delays then
195 Override_Delays := True;
196 else
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200197 Registers.Read (Panel_PP_Regs.ON_DELAYS, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200198 Delays_US (Power_Up_Delay) := 100 * Natural
199 (Shift_Right (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_MASK, 16));
200 Delays_US (Power_Up_To_BL_On) := 100 * Natural
201 (Power_Delay and PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK);
202
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200203 Registers.Read (Panel_PP_Regs.OFF_DELAYS, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200204 Delays_US (Power_Down_Delay) := 100 * Natural
205 (Shift_Right (Power_Delay and PCH_PP_OFF_DELAYS_PWR_DOWN_MASK, 16));
206 Delays_US (BL_Off_To_Power_Down) := 100 * Natural
207 (Power_Delay and PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK);
208
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200209 Registers.Read (Panel_PP_Regs.DIVISOR, Power_Delay);
Nico Huber83693c82016-10-08 22:17:55 +0200210 if (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) > 1 then
211 Delays_US (Power_Cycle_Delay) := 100_000 * (Natural
212 (Power_Delay and PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK) - 1);
213 end if;
214
215 Check_PP_Delays (Delays_US, Override_Delays);
216 end if;
217
218 if Override_Delays then
219 if Config.Has_PP_Port_Select then
Nico Huber8a6e7bd2020-01-07 16:36:38 +0100220 Port_Select :=
Nico Huber2bbd6e72020-01-07 18:22:59 +0100221 (case Config.Panel_Ports (Panel_1) is
Nico Huber8a6e7bd2020-01-07 16:36:38 +0100222 when LVDS => PCH_PP_ON_DELAYS_PORT_SELECT_LVDS,
223 when eDP => PCH_PP_ON_DELAYS_PORT_SELECT_DP_A,
224 when DP2 | HDMI2 => PCH_PP_ON_DELAYS_PORT_SELECT_DP_C,
225 when DP3 | HDMI3 => PCH_PP_ON_DELAYS_PORT_SELECT_DP_D,
226 when others => 0);
Nico Huber83693c82016-10-08 22:17:55 +0200227 else
228 Port_Select := 0;
229 end if;
230
231 -- Force power-up to backlight-on delay to 100us as recommended by PRM.
232 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200233 (Register => Panel_PP_Regs.ON_DELAYS,
Nico Huber83693c82016-10-08 22:17:55 +0200234 Mask_Unset => PCH_PP_ON_DELAYS_PORT_SELECT_MASK or
235 PCH_PP_ON_DELAYS_PWR_UP_MASK or
236 PCH_PP_ON_DELAYS_PWR_UP_BL_ON_MASK,
237 Mask_Set => Port_Select or
238 PCH_PP_ON_DELAYS_PWR_UP (Delays_US (Power_Up_Delay))
239 or PCH_PP_ON_DELAYS_PWR_UP_BL_ON (100));
240
241 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200242 (Register => Panel_PP_Regs.OFF_DELAYS,
Nico Huber83693c82016-10-08 22:17:55 +0200243 Mask_Unset => PCH_PP_OFF_DELAYS_PWR_DOWN_MASK or
244 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN_MASK,
245 Mask_Set => PCH_PP_OFF_DELAYS_PWR_DOWN
246 (Delays_US (Power_Down_Delay)) or
247 PCH_PP_OFF_DELAYS_BL_OFF_PWR_DOWN
248 (Delays_US (BL_Off_To_Power_Down)));
249
250 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200251 (Register => Panel_PP_Regs.DIVISOR,
Nico Huber83693c82016-10-08 22:17:55 +0200252 Mask_Unset => PCH_PP_DIVISOR_PWR_CYC_DELAY_MASK,
253 Mask_Set => PCH_PP_DIVISOR_PWR_CYC_DELAY
254 (Delays_US (Power_Cycle_Delay)));
255 end if;
256
257 if Config.Has_PP_Write_Protection then
258 Registers.Unset_And_Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200259 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200260 Mask_Unset => PCH_PP_CONTROL_WRITE_PROTECT_MASK,
261 Mask_Set => PCH_PP_CONTROL_WRITE_PROTECT_KEY or
262 PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
263 else
264 Registers.Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200265 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200266 Mask => PCH_PP_CONTROL_POWER_DOWN_ON_RESET);
267 end if;
268 end Setup_PP_Sequencer;
269
270 ----------------------------------------------------------------------------
271
Nico Huber2bbd6e72020-01-07 18:22:59 +0100272 procedure VDD_Override (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200273 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100274 if Panel not in Valid_Panels then
275 return;
276 end if;
277
Nico Huber83693c82016-10-08 22:17:55 +0200278 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
279
280 -- Yeah, We could do, what we are supposed to do here. But OTOH, we
281 -- are should wait for the full Power Up Delay, which we would have
282 -- to do later again. And just powering on the display seems to work
283 -- too. Also this function vanished on newer hardware.
Nico Huber2bbd6e72020-01-07 18:22:59 +0100284 On (Panel);
Nico Huber83693c82016-10-08 22:17:55 +0200285 end VDD_Override;
286
Nico Huber2bbd6e72020-01-07 18:22:59 +0100287 procedure On (Panel : Panel_Control; Wait : Boolean := True)
Nico Huber83693c82016-10-08 22:17:55 +0200288 is
289 Was_On : Boolean;
290 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100291 if Panel not in Valid_Panels then
292 return;
293 end if;
294
Nico Huber83693c82016-10-08 22:17:55 +0200295 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
296
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200297 Registers.Is_Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Nico Huber83693c82016-10-08 22:17:55 +0200298 if not Was_On then
299 Time.Delay_Until (Power_Cycle_Timer);
300 end if;
301
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200302 Registers.Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON);
Nico Huber83693c82016-10-08 22:17:55 +0200303 if not Was_On then
304 Power_Up_Timer := Time.US_From_Now (Delays_US (Power_Up_Delay));
305 end if;
306 if Wait then
Nico Huber2bbd6e72020-01-07 18:22:59 +0100307 Wait_On (Panel);
Nico Huber83693c82016-10-08 22:17:55 +0200308 end if;
309 end On;
310
Nico Huber2bbd6e72020-01-07 18:22:59 +0100311 procedure Wait_On (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200312 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100313 if Panel not in Valid_Panels then
314 return;
315 end if;
316
Nico Huber83693c82016-10-08 22:17:55 +0200317 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
318
319 Time.Delay_Until (Power_Up_Timer);
320 Registers.Wait_Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200321 (Register => Panel_PP_Regs.STATUS,
Nico Huber83693c82016-10-08 22:17:55 +0200322 Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
323 TOut_MS => 300);
324
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200325 Registers.Unset_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_VDD_OVERRIDE);
Nico Huber83693c82016-10-08 22:17:55 +0200326 end Wait_On;
327
Nico Huber2bbd6e72020-01-07 18:22:59 +0100328 procedure Off (Panel : Panel_Control)
Nico Huber83693c82016-10-08 22:17:55 +0200329 is
330 Was_On : Boolean;
331 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100332 if Panel not in Valid_Panels then
333 return;
334 end if;
335
Nico Huber83693c82016-10-08 22:17:55 +0200336 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
337
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200338 Registers.Is_Set_Mask (Panel_PP_Regs.CONTROL, PCH_PP_CONTROL_TARGET_ON, Was_On);
Nico Huber83693c82016-10-08 22:17:55 +0200339 Registers.Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200340 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200341 Mask => PCH_PP_CONTROL_TARGET_ON or
342 PCH_PP_CONTROL_VDD_OVERRIDE);
343 if Was_On then
344 Time.U_Delay (Delays_US (Power_Down_Delay));
345 end if;
346 Registers.Wait_Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200347 (Register => Panel_PP_Regs.STATUS,
Nico Huber83693c82016-10-08 22:17:55 +0200348 Mask => PCH_PP_STATUS_PWR_SEQ_PROGRESS_MASK,
349 TOut_MS => 600);
350 if Was_On then
351 Power_Cycle_Timer := Time.US_From_Now (Delays_US (Power_Cycle_Delay));
352 end if;
353 end Off;
354
355 ----------------------------------------------------------------------------
356
Nico Huber2bbd6e72020-01-07 18:22:59 +0100357 procedure Backlight_On (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200358 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100359 if Panel not in Valid_Panels then
360 return;
361 end if;
362
Nico Huber83693c82016-10-08 22:17:55 +0200363 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
364
365 Registers.Set_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200366 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200367 Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
368 end Backlight_On;
369
Nico Huber2bbd6e72020-01-07 18:22:59 +0100370 procedure Backlight_Off (Panel : Panel_Control) is
Nico Huber83693c82016-10-08 22:17:55 +0200371 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100372 if Panel not in Valid_Panels then
373 return;
374 end if;
375
Nico Huber83693c82016-10-08 22:17:55 +0200376 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
377
378 Registers.Unset_Mask
Arthur Heymanse87d0d12018-03-28 17:02:49 +0200379 (Register => Panel_PP_Regs.CONTROL,
Nico Huber83693c82016-10-08 22:17:55 +0200380 Mask => PCH_PP_CONTROL_BACKLIGHT_ENABLE);
381 end Backlight_Off;
382
Nico Huber2bbd6e72020-01-07 18:22:59 +0100383 procedure Set_Backlight (Panel : Panel_Control; Level : Word16) is
Nico Huber83693c82016-10-08 22:17:55 +0200384 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100385 if Panel not in Valid_Panels then
386 return;
387 end if;
388
Nico Huber83693c82016-10-08 22:17:55 +0200389 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
390
391 Registers.Unset_And_Set_Mask
392 (Register => Registers.BLC_PWM_CPU_CTL,
393 Mask_Unset => CPU_BLC_PWM_DATA_BL_DUTY_CYC_MASK,
394 Mask_Set => Word32 (Level));
395 end Set_Backlight;
396
Nico Huber2bbd6e72020-01-07 18:22:59 +0100397 procedure Get_Max_Backlight (Panel : Panel_Control; Level : out Word16)
Nico Huber83693c82016-10-08 22:17:55 +0200398 is
399 Reg : Word32;
400 begin
Nico Huber2bbd6e72020-01-07 18:22:59 +0100401 if Panel not in Valid_Panels then
402 Level := 0;
403 return;
404 end if;
405
Nico Huber83693c82016-10-08 22:17:55 +0200406 pragma Debug (Debug.Put_Line (GNAT.Source_Info.Enclosing_Entity));
407
408 Registers.Read (Registers.BLC_PWM_PCH_CTL2, Reg);
409 Level := Word16
410 (Shift_Right (Reg and PCH_BLC_PWM_CTL2_BL_MOD_FREQ_MASK, 16));
411 end Get_Max_Backlight;
412
413end HW.GFX.GMA.Panel;