1b35a56d4Sjsg // SPDX-License-Identifier: MIT
2b35a56d4Sjsg /*
3b35a56d4Sjsg * Copyright © 2021 Intel Corporation
4b35a56d4Sjsg */
5b35a56d4Sjsg
61bb76ff1Sjsg #include <linux/backlight.h>
7b35a56d4Sjsg #include <linux/kernel.h>
8b35a56d4Sjsg #include <linux/pwm.h>
91bb76ff1Sjsg #include <linux/string_helpers.h>
101bb76ff1Sjsg
111bb76ff1Sjsg #include <acpi/video.h>
12b35a56d4Sjsg
13f005ef32Sjsg #include "i915_reg.h"
14b35a56d4Sjsg #include "intel_backlight.h"
151bb76ff1Sjsg #include "intel_backlight_regs.h"
16b35a56d4Sjsg #include "intel_connector.h"
17b35a56d4Sjsg #include "intel_de.h"
18b35a56d4Sjsg #include "intel_display_types.h"
19b35a56d4Sjsg #include "intel_dp_aux_backlight.h"
20b35a56d4Sjsg #include "intel_dsi_dcs_backlight.h"
21b35a56d4Sjsg #include "intel_panel.h"
221bb76ff1Sjsg #include "intel_pci_config.h"
231bb76ff1Sjsg #include "intel_pps.h"
241bb76ff1Sjsg #include "intel_quirks.h"
25b35a56d4Sjsg
26b35a56d4Sjsg /**
27b35a56d4Sjsg * scale - scale values from one range to another
28b35a56d4Sjsg * @source_val: value in range [@source_min..@source_max]
29b35a56d4Sjsg * @source_min: minimum legal value for @source_val
30b35a56d4Sjsg * @source_max: maximum legal value for @source_val
31b35a56d4Sjsg * @target_min: corresponding target value for @source_min
32b35a56d4Sjsg * @target_max: corresponding target value for @source_max
33b35a56d4Sjsg *
34b35a56d4Sjsg * Return @source_val in range [@source_min..@source_max] scaled to range
35b35a56d4Sjsg * [@target_min..@target_max].
36b35a56d4Sjsg */
scale(u32 source_val,u32 source_min,u32 source_max,u32 target_min,u32 target_max)37b35a56d4Sjsg static u32 scale(u32 source_val,
38b35a56d4Sjsg u32 source_min, u32 source_max,
39b35a56d4Sjsg u32 target_min, u32 target_max)
40b35a56d4Sjsg {
41b35a56d4Sjsg u64 target_val;
42b35a56d4Sjsg
43b35a56d4Sjsg WARN_ON(source_min > source_max);
44b35a56d4Sjsg WARN_ON(target_min > target_max);
45b35a56d4Sjsg
46b35a56d4Sjsg /* defensive */
47b35a56d4Sjsg source_val = clamp(source_val, source_min, source_max);
48b35a56d4Sjsg
49b35a56d4Sjsg /* avoid overflows */
50b35a56d4Sjsg target_val = mul_u32_u32(source_val - source_min,
51b35a56d4Sjsg target_max - target_min);
52b35a56d4Sjsg target_val = DIV_ROUND_CLOSEST_ULL(target_val, source_max - source_min);
53b35a56d4Sjsg target_val += target_min;
54b35a56d4Sjsg
55b35a56d4Sjsg return target_val;
56b35a56d4Sjsg }
57b35a56d4Sjsg
58b35a56d4Sjsg /*
59b35a56d4Sjsg * Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
60b35a56d4Sjsg * to [hw_min..hw_max].
61b35a56d4Sjsg */
clamp_user_to_hw(struct intel_connector * connector,u32 user_level,u32 user_max)62b35a56d4Sjsg static u32 clamp_user_to_hw(struct intel_connector *connector,
63b35a56d4Sjsg u32 user_level, u32 user_max)
64b35a56d4Sjsg {
65b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
66b35a56d4Sjsg u32 hw_level;
67b35a56d4Sjsg
68b35a56d4Sjsg hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
69b35a56d4Sjsg hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
70b35a56d4Sjsg
71b35a56d4Sjsg return hw_level;
72b35a56d4Sjsg }
73b35a56d4Sjsg
74b35a56d4Sjsg /* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
scale_hw_to_user(struct intel_connector * connector,u32 hw_level,u32 user_max)75b35a56d4Sjsg static u32 scale_hw_to_user(struct intel_connector *connector,
76b35a56d4Sjsg u32 hw_level, u32 user_max)
77b35a56d4Sjsg {
78b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
79b35a56d4Sjsg
80b35a56d4Sjsg return scale(hw_level, panel->backlight.min, panel->backlight.max,
81b35a56d4Sjsg 0, user_max);
82b35a56d4Sjsg }
83b35a56d4Sjsg
intel_backlight_invert_pwm_level(struct intel_connector * connector,u32 val)841bb76ff1Sjsg u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 val)
85b35a56d4Sjsg {
86f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
87b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
88b35a56d4Sjsg
89f005ef32Sjsg drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
90b35a56d4Sjsg
91f005ef32Sjsg if (i915->params.invert_brightness < 0)
92b35a56d4Sjsg return val;
93b35a56d4Sjsg
94f005ef32Sjsg if (i915->params.invert_brightness > 0 ||
95f005ef32Sjsg intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)) {
96b35a56d4Sjsg return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min;
97b35a56d4Sjsg }
98b35a56d4Sjsg
99b35a56d4Sjsg return val;
100b35a56d4Sjsg }
101b35a56d4Sjsg
intel_backlight_set_pwm_level(const struct drm_connector_state * conn_state,u32 val)1021bb76ff1Sjsg void intel_backlight_set_pwm_level(const struct drm_connector_state *conn_state, u32 val)
103b35a56d4Sjsg {
104b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
105b35a56d4Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
106b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
107b35a56d4Sjsg
108f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] set backlight PWM = %d\n",
109f005ef32Sjsg connector->base.base.id, connector->base.name, val);
110b35a56d4Sjsg panel->backlight.pwm_funcs->set(conn_state, val);
111b35a56d4Sjsg }
112b35a56d4Sjsg
intel_backlight_level_to_pwm(struct intel_connector * connector,u32 val)1131bb76ff1Sjsg u32 intel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
114b35a56d4Sjsg {
115f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
116b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
117b35a56d4Sjsg
118f005ef32Sjsg drm_WARN_ON_ONCE(&i915->drm,
119b35a56d4Sjsg panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
120b35a56d4Sjsg
121b35a56d4Sjsg val = scale(val, panel->backlight.min, panel->backlight.max,
122b35a56d4Sjsg panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
123b35a56d4Sjsg
1241bb76ff1Sjsg return intel_backlight_invert_pwm_level(connector, val);
125b35a56d4Sjsg }
126b35a56d4Sjsg
intel_backlight_level_from_pwm(struct intel_connector * connector,u32 val)1271bb76ff1Sjsg u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
128b35a56d4Sjsg {
129f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
130b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
131b35a56d4Sjsg
132f005ef32Sjsg drm_WARN_ON_ONCE(&i915->drm,
133b35a56d4Sjsg panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
134b35a56d4Sjsg
135f005ef32Sjsg if (i915->params.invert_brightness > 0 ||
136f005ef32Sjsg (i915->params.invert_brightness == 0 && intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)))
137b35a56d4Sjsg val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);
138b35a56d4Sjsg
139b35a56d4Sjsg return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
140b35a56d4Sjsg panel->backlight.min, panel->backlight.max);
141b35a56d4Sjsg }
142b35a56d4Sjsg
lpt_get_backlight(struct intel_connector * connector,enum pipe unused)143b35a56d4Sjsg static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused)
144b35a56d4Sjsg {
145f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
146b35a56d4Sjsg
147f005ef32Sjsg return intel_de_read(i915, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
148b35a56d4Sjsg }
149b35a56d4Sjsg
pch_get_backlight(struct intel_connector * connector,enum pipe unused)150b35a56d4Sjsg static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused)
151b35a56d4Sjsg {
152f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
153b35a56d4Sjsg
154f005ef32Sjsg return intel_de_read(i915, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
155b35a56d4Sjsg }
156b35a56d4Sjsg
i9xx_get_backlight(struct intel_connector * connector,enum pipe unused)157b35a56d4Sjsg static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused)
158b35a56d4Sjsg {
159f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
160b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
161b35a56d4Sjsg u32 val;
162b35a56d4Sjsg
163f005ef32Sjsg val = intel_de_read(i915, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
164f005ef32Sjsg if (DISPLAY_VER(i915) < 4)
165b35a56d4Sjsg val >>= 1;
166b35a56d4Sjsg
167b35a56d4Sjsg if (panel->backlight.combination_mode) {
168b35a56d4Sjsg u8 lbpc;
169b35a56d4Sjsg
170f005ef32Sjsg pci_read_config_byte(i915->drm.pdev, LBPC, &lbpc);
171b35a56d4Sjsg val *= lbpc;
172b35a56d4Sjsg }
173b35a56d4Sjsg
174b35a56d4Sjsg return val;
175b35a56d4Sjsg }
176b35a56d4Sjsg
vlv_get_backlight(struct intel_connector * connector,enum pipe pipe)177b35a56d4Sjsg static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe)
178b35a56d4Sjsg {
179f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
180b35a56d4Sjsg
181f005ef32Sjsg if (drm_WARN_ON(&i915->drm, pipe != PIPE_A && pipe != PIPE_B))
182b35a56d4Sjsg return 0;
183b35a56d4Sjsg
184f005ef32Sjsg return intel_de_read(i915, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
185b35a56d4Sjsg }
186b35a56d4Sjsg
bxt_get_backlight(struct intel_connector * connector,enum pipe unused)187b35a56d4Sjsg static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused)
188b35a56d4Sjsg {
189f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
190b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
191b35a56d4Sjsg
192f005ef32Sjsg return intel_de_read(i915, BXT_BLC_PWM_DUTY(panel->backlight.controller));
193b35a56d4Sjsg }
194b35a56d4Sjsg
ext_pwm_get_backlight(struct intel_connector * connector,enum pipe unused)195b35a56d4Sjsg static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused)
196b35a56d4Sjsg {
197b35a56d4Sjsg STUB();
198b35a56d4Sjsg return 0;
199b35a56d4Sjsg #ifdef notyet
200b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
201b35a56d4Sjsg struct pwm_state state;
202b35a56d4Sjsg
203b35a56d4Sjsg pwm_get_state(panel->backlight.pwm, &state);
204b35a56d4Sjsg return pwm_get_relative_duty_cycle(&state, 100);
205b35a56d4Sjsg #endif
206b35a56d4Sjsg }
207b35a56d4Sjsg
lpt_set_backlight(const struct drm_connector_state * conn_state,u32 level)208b35a56d4Sjsg static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
209b35a56d4Sjsg {
210b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
211f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
212f005ef32Sjsg u32 val;
213b35a56d4Sjsg
214f005ef32Sjsg val = intel_de_read(i915, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
215f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL2, val | level);
216b35a56d4Sjsg }
217b35a56d4Sjsg
pch_set_backlight(const struct drm_connector_state * conn_state,u32 level)218b35a56d4Sjsg static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level)
219b35a56d4Sjsg {
220b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
221f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
222b35a56d4Sjsg u32 tmp;
223b35a56d4Sjsg
224f005ef32Sjsg tmp = intel_de_read(i915, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
225f005ef32Sjsg intel_de_write(i915, BLC_PWM_CPU_CTL, tmp | level);
226b35a56d4Sjsg }
227b35a56d4Sjsg
i9xx_set_backlight(const struct drm_connector_state * conn_state,u32 level)228b35a56d4Sjsg static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level)
229b35a56d4Sjsg {
230b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
231f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
232b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
233b35a56d4Sjsg u32 tmp, mask;
234b35a56d4Sjsg
235f005ef32Sjsg drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
236b35a56d4Sjsg
237b35a56d4Sjsg if (panel->backlight.combination_mode) {
238b35a56d4Sjsg u8 lbpc;
239b35a56d4Sjsg
240b35a56d4Sjsg lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1;
241b35a56d4Sjsg level /= lbpc;
242f005ef32Sjsg pci_write_config_byte(i915->drm.pdev, LBPC, lbpc);
243b35a56d4Sjsg }
244b35a56d4Sjsg
245f005ef32Sjsg if (DISPLAY_VER(i915) == 4) {
246b35a56d4Sjsg mask = BACKLIGHT_DUTY_CYCLE_MASK;
247b35a56d4Sjsg } else {
248b35a56d4Sjsg level <<= 1;
249b35a56d4Sjsg mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
250b35a56d4Sjsg }
251b35a56d4Sjsg
252f005ef32Sjsg tmp = intel_de_read(i915, BLC_PWM_CTL) & ~mask;
253f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL, tmp | level);
254b35a56d4Sjsg }
255b35a56d4Sjsg
vlv_set_backlight(const struct drm_connector_state * conn_state,u32 level)256b35a56d4Sjsg static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level)
257b35a56d4Sjsg {
258b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
259f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
260b35a56d4Sjsg enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
261b35a56d4Sjsg u32 tmp;
262b35a56d4Sjsg
263f005ef32Sjsg tmp = intel_de_read(i915, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
264f005ef32Sjsg intel_de_write(i915, VLV_BLC_PWM_CTL(pipe), tmp | level);
265b35a56d4Sjsg }
266b35a56d4Sjsg
bxt_set_backlight(const struct drm_connector_state * conn_state,u32 level)267b35a56d4Sjsg static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
268b35a56d4Sjsg {
269b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
270f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
271b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
272b35a56d4Sjsg
273f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
274b35a56d4Sjsg }
275b35a56d4Sjsg
ext_pwm_set_backlight(const struct drm_connector_state * conn_state,u32 level)276b35a56d4Sjsg static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
277b35a56d4Sjsg {
278b35a56d4Sjsg STUB();
279b35a56d4Sjsg #ifdef notyet
280b35a56d4Sjsg struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
281b35a56d4Sjsg
282b35a56d4Sjsg pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
283*2e4fb78aSjsg pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
284b35a56d4Sjsg #endif
285b35a56d4Sjsg }
286b35a56d4Sjsg
287b35a56d4Sjsg static void
intel_panel_actually_set_backlight(const struct drm_connector_state * conn_state,u32 level)288b35a56d4Sjsg intel_panel_actually_set_backlight(const struct drm_connector_state *conn_state, u32 level)
289b35a56d4Sjsg {
290b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
291b35a56d4Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
292b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
293b35a56d4Sjsg
294f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] set backlight level = %d\n",
295f005ef32Sjsg connector->base.base.id, connector->base.name, level);
296b35a56d4Sjsg
297b35a56d4Sjsg panel->backlight.funcs->set(conn_state, level);
298b35a56d4Sjsg }
299b35a56d4Sjsg
300b35a56d4Sjsg /* set backlight brightness to level in range [0..max], assuming hw min is
301b35a56d4Sjsg * respected.
302b35a56d4Sjsg */
intel_backlight_set_acpi(const struct drm_connector_state * conn_state,u32 user_level,u32 user_max)3031bb76ff1Sjsg void intel_backlight_set_acpi(const struct drm_connector_state *conn_state,
304b35a56d4Sjsg u32 user_level, u32 user_max)
305b35a56d4Sjsg {
306b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
307f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
308b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
309b35a56d4Sjsg u32 hw_level;
310b35a56d4Sjsg
311b35a56d4Sjsg /*
312b35a56d4Sjsg * Lack of crtc may occur during driver init because
313b35a56d4Sjsg * connection_mutex isn't held across the entire backlight
314b35a56d4Sjsg * setup + modeset readout, and the BIOS can issue the
315b35a56d4Sjsg * requests at any time.
316b35a56d4Sjsg */
317b35a56d4Sjsg if (!panel->backlight.present || !conn_state->crtc)
318b35a56d4Sjsg return;
319b35a56d4Sjsg
320f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
321b35a56d4Sjsg
322f005ef32Sjsg drm_WARN_ON(&i915->drm, panel->backlight.max == 0);
323b35a56d4Sjsg
324b35a56d4Sjsg hw_level = clamp_user_to_hw(connector, user_level, user_max);
325b35a56d4Sjsg panel->backlight.level = hw_level;
326b35a56d4Sjsg
327b35a56d4Sjsg if (panel->backlight.device)
328b35a56d4Sjsg panel->backlight.device->props.brightness =
329b35a56d4Sjsg scale_hw_to_user(connector,
330b35a56d4Sjsg panel->backlight.level,
331b35a56d4Sjsg panel->backlight.device->props.max_brightness);
332b35a56d4Sjsg
333b35a56d4Sjsg if (panel->backlight.enabled)
334b35a56d4Sjsg intel_panel_actually_set_backlight(conn_state, hw_level);
335b35a56d4Sjsg
336f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
337b35a56d4Sjsg }
338b35a56d4Sjsg
lpt_disable_backlight(const struct drm_connector_state * old_conn_state,u32 level)339b35a56d4Sjsg static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
340b35a56d4Sjsg {
341b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
342f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
343b35a56d4Sjsg u32 tmp;
344b35a56d4Sjsg
3451bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, level);
346b35a56d4Sjsg
347b35a56d4Sjsg /*
348b35a56d4Sjsg * Although we don't support or enable CPU PWM with LPT/SPT based
349b35a56d4Sjsg * systems, it may have been enabled prior to loading the
350b35a56d4Sjsg * driver. Disable to avoid warnings on LCPLL disable.
351b35a56d4Sjsg *
352b35a56d4Sjsg * This needs rework if we need to add support for CPU PWM on PCH split
353b35a56d4Sjsg * platforms.
354b35a56d4Sjsg */
355f005ef32Sjsg tmp = intel_de_read(i915, BLC_PWM_CPU_CTL2);
356b35a56d4Sjsg if (tmp & BLM_PWM_ENABLE) {
357f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] CPU backlight was enabled, disabling\n",
358f005ef32Sjsg connector->base.base.id, connector->base.name);
359f005ef32Sjsg intel_de_write(i915, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
360b35a56d4Sjsg }
361b35a56d4Sjsg
362f005ef32Sjsg intel_de_rmw(i915, BLC_PWM_PCH_CTL1, BLM_PCH_PWM_ENABLE, 0);
363b35a56d4Sjsg }
364b35a56d4Sjsg
pch_disable_backlight(const struct drm_connector_state * old_conn_state,u32 val)365b35a56d4Sjsg static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
366b35a56d4Sjsg {
367b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
368f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
369b35a56d4Sjsg
3701bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, val);
371b35a56d4Sjsg
372f005ef32Sjsg intel_de_rmw(i915, BLC_PWM_CPU_CTL2, BLM_PWM_ENABLE, 0);
373b35a56d4Sjsg
374f005ef32Sjsg intel_de_rmw(i915, BLC_PWM_PCH_CTL1, BLM_PCH_PWM_ENABLE, 0);
375b35a56d4Sjsg }
376b35a56d4Sjsg
i9xx_disable_backlight(const struct drm_connector_state * old_conn_state,u32 val)377b35a56d4Sjsg static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
378b35a56d4Sjsg {
3791bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, val);
380b35a56d4Sjsg }
381b35a56d4Sjsg
i965_disable_backlight(const struct drm_connector_state * old_conn_state,u32 val)382b35a56d4Sjsg static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
383b35a56d4Sjsg {
384f005ef32Sjsg struct drm_i915_private *i915 = to_i915(old_conn_state->connector->dev);
385b35a56d4Sjsg
3861bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, val);
387b35a56d4Sjsg
388f005ef32Sjsg intel_de_rmw(i915, BLC_PWM_CTL2, BLM_PWM_ENABLE, 0);
389b35a56d4Sjsg }
390b35a56d4Sjsg
vlv_disable_backlight(const struct drm_connector_state * old_conn_state,u32 val)391b35a56d4Sjsg static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
392b35a56d4Sjsg {
393b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
394f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
395b35a56d4Sjsg enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
396b35a56d4Sjsg
3971bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, val);
398b35a56d4Sjsg
399f005ef32Sjsg intel_de_rmw(i915, VLV_BLC_PWM_CTL2(pipe), BLM_PWM_ENABLE, 0);
400b35a56d4Sjsg }
401b35a56d4Sjsg
bxt_disable_backlight(const struct drm_connector_state * old_conn_state,u32 val)402b35a56d4Sjsg static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
403b35a56d4Sjsg {
404b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
405f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
406b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
407b35a56d4Sjsg
4081bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, val);
409b35a56d4Sjsg
410f005ef32Sjsg intel_de_rmw(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
411f005ef32Sjsg BXT_BLC_PWM_ENABLE, 0);
412b35a56d4Sjsg
413f005ef32Sjsg if (panel->backlight.controller == 1)
414f005ef32Sjsg intel_de_rmw(i915, UTIL_PIN_CTL, UTIL_PIN_ENABLE, 0);
415b35a56d4Sjsg }
416b35a56d4Sjsg
cnp_disable_backlight(const struct drm_connector_state * old_conn_state,u32 val)417b35a56d4Sjsg static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
418b35a56d4Sjsg {
419b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
420f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
421b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
422b35a56d4Sjsg
4231bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, val);
424b35a56d4Sjsg
425f005ef32Sjsg intel_de_rmw(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
426f005ef32Sjsg BXT_BLC_PWM_ENABLE, 0);
427b35a56d4Sjsg }
428b35a56d4Sjsg
ext_pwm_disable_backlight(const struct drm_connector_state * old_conn_state,u32 level)429b35a56d4Sjsg static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
430b35a56d4Sjsg {
431b35a56d4Sjsg STUB();
432b35a56d4Sjsg #ifdef notyet
433b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
434b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
435b35a56d4Sjsg
4361bb76ff1Sjsg intel_backlight_set_pwm_level(old_conn_state, level);
4371bb76ff1Sjsg
438b35a56d4Sjsg panel->backlight.pwm_state.enabled = false;
439*2e4fb78aSjsg pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
440b35a56d4Sjsg #endif
441b35a56d4Sjsg }
442b35a56d4Sjsg
intel_backlight_disable(const struct drm_connector_state * old_conn_state)4431bb76ff1Sjsg void intel_backlight_disable(const struct drm_connector_state *old_conn_state)
444b35a56d4Sjsg {
445b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
446f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
447b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
448b35a56d4Sjsg
449b35a56d4Sjsg if (!panel->backlight.present)
450b35a56d4Sjsg return;
451b35a56d4Sjsg
452b35a56d4Sjsg /*
453b35a56d4Sjsg * Do not disable backlight on the vga_switcheroo path. When switching
454b35a56d4Sjsg * away from i915, the other client may depend on i915 to handle the
455b35a56d4Sjsg * backlight. This will leave the backlight on unnecessarily when
456b35a56d4Sjsg * another client is not activated.
457b35a56d4Sjsg */
458f005ef32Sjsg if (i915->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
459f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Skipping backlight disable on vga switch\n",
460f005ef32Sjsg connector->base.base.id, connector->base.name);
461b35a56d4Sjsg return;
462b35a56d4Sjsg }
463b35a56d4Sjsg
464f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
465b35a56d4Sjsg
466b35a56d4Sjsg if (panel->backlight.device)
467b35a56d4Sjsg panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
468b35a56d4Sjsg panel->backlight.enabled = false;
469b35a56d4Sjsg panel->backlight.funcs->disable(old_conn_state, 0);
470b35a56d4Sjsg
471f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
472b35a56d4Sjsg }
473b35a56d4Sjsg
lpt_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)474b35a56d4Sjsg static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
475b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
476b35a56d4Sjsg {
477b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
478f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
479b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
480f005ef32Sjsg u32 pch_ctl1, pch_ctl2;
481b35a56d4Sjsg
482f005ef32Sjsg pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
483b35a56d4Sjsg if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
484f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] PCH backlight already enabled\n",
485f005ef32Sjsg connector->base.base.id, connector->base.name);
486b35a56d4Sjsg pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
487f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
488b35a56d4Sjsg }
489b35a56d4Sjsg
490f005ef32Sjsg if (HAS_PCH_LPT(i915))
491f005ef32Sjsg intel_de_rmw(i915, SOUTH_CHICKEN2, LPT_PWM_GRANULARITY,
492f005ef32Sjsg panel->backlight.alternate_pwm_increment ?
493f005ef32Sjsg LPT_PWM_GRANULARITY : 0);
494b35a56d4Sjsg else
495f005ef32Sjsg intel_de_rmw(i915, SOUTH_CHICKEN1, SPT_PWM_GRANULARITY,
496f005ef32Sjsg panel->backlight.alternate_pwm_increment ?
497f005ef32Sjsg SPT_PWM_GRANULARITY : 0);
498b35a56d4Sjsg
499b35a56d4Sjsg pch_ctl2 = panel->backlight.pwm_level_max << 16;
500f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL2, pch_ctl2);
501b35a56d4Sjsg
502b35a56d4Sjsg pch_ctl1 = 0;
503b35a56d4Sjsg if (panel->backlight.active_low_pwm)
504b35a56d4Sjsg pch_ctl1 |= BLM_PCH_POLARITY;
505b35a56d4Sjsg
506b35a56d4Sjsg /* After LPT, override is the default. */
507f005ef32Sjsg if (HAS_PCH_LPT(i915))
508b35a56d4Sjsg pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
509b35a56d4Sjsg
510f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
511f005ef32Sjsg intel_de_posting_read(i915, BLC_PWM_PCH_CTL1);
512f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
513b35a56d4Sjsg
514b35a56d4Sjsg /* This won't stick until the above enable. */
5151bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
516b35a56d4Sjsg }
517b35a56d4Sjsg
pch_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)518b35a56d4Sjsg static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
519b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
520b35a56d4Sjsg {
521b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
522f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
523b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
524b35a56d4Sjsg enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
525b35a56d4Sjsg u32 cpu_ctl2, pch_ctl1, pch_ctl2;
526b35a56d4Sjsg
527f005ef32Sjsg cpu_ctl2 = intel_de_read(i915, BLC_PWM_CPU_CTL2);
528b35a56d4Sjsg if (cpu_ctl2 & BLM_PWM_ENABLE) {
529f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] CPU backlight already enabled\n",
530f005ef32Sjsg connector->base.base.id, connector->base.name);
531b35a56d4Sjsg cpu_ctl2 &= ~BLM_PWM_ENABLE;
532f005ef32Sjsg intel_de_write(i915, BLC_PWM_CPU_CTL2, cpu_ctl2);
533b35a56d4Sjsg }
534b35a56d4Sjsg
535f005ef32Sjsg pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
536b35a56d4Sjsg if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
537f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] PCH backlight already enabled\n",
538f005ef32Sjsg connector->base.base.id, connector->base.name);
539b35a56d4Sjsg pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
540f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
541b35a56d4Sjsg }
542b35a56d4Sjsg
543b35a56d4Sjsg if (cpu_transcoder == TRANSCODER_EDP)
544b35a56d4Sjsg cpu_ctl2 = BLM_TRANSCODER_EDP;
545b35a56d4Sjsg else
546b35a56d4Sjsg cpu_ctl2 = BLM_PIPE(cpu_transcoder);
547f005ef32Sjsg intel_de_write(i915, BLC_PWM_CPU_CTL2, cpu_ctl2);
548f005ef32Sjsg intel_de_posting_read(i915, BLC_PWM_CPU_CTL2);
549f005ef32Sjsg intel_de_write(i915, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
550b35a56d4Sjsg
551b35a56d4Sjsg /* This won't stick until the above enable. */
5521bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
553b35a56d4Sjsg
554b35a56d4Sjsg pch_ctl2 = panel->backlight.pwm_level_max << 16;
555f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL2, pch_ctl2);
556b35a56d4Sjsg
557b35a56d4Sjsg pch_ctl1 = 0;
558b35a56d4Sjsg if (panel->backlight.active_low_pwm)
559b35a56d4Sjsg pch_ctl1 |= BLM_PCH_POLARITY;
560b35a56d4Sjsg
561f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
562f005ef32Sjsg intel_de_posting_read(i915, BLC_PWM_PCH_CTL1);
563f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
564b35a56d4Sjsg }
565b35a56d4Sjsg
i9xx_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)566b35a56d4Sjsg static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
567b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
568b35a56d4Sjsg {
569b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
570f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
571b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
572b35a56d4Sjsg u32 ctl, freq;
573b35a56d4Sjsg
574f005ef32Sjsg ctl = intel_de_read(i915, BLC_PWM_CTL);
575b35a56d4Sjsg if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
576f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] backlight already enabled\n",
577f005ef32Sjsg connector->base.base.id, connector->base.name);
578f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL, 0);
579b35a56d4Sjsg }
580b35a56d4Sjsg
581b35a56d4Sjsg freq = panel->backlight.pwm_level_max;
582b35a56d4Sjsg if (panel->backlight.combination_mode)
583b35a56d4Sjsg freq /= 0xff;
584b35a56d4Sjsg
585b35a56d4Sjsg ctl = freq << 17;
586b35a56d4Sjsg if (panel->backlight.combination_mode)
587b35a56d4Sjsg ctl |= BLM_LEGACY_MODE;
588f005ef32Sjsg if (IS_PINEVIEW(i915) && panel->backlight.active_low_pwm)
589b35a56d4Sjsg ctl |= BLM_POLARITY_PNV;
590b35a56d4Sjsg
591f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL, ctl);
592f005ef32Sjsg intel_de_posting_read(i915, BLC_PWM_CTL);
593b35a56d4Sjsg
594b35a56d4Sjsg /* XXX: combine this into above write? */
5951bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
596b35a56d4Sjsg
597b35a56d4Sjsg /*
598b35a56d4Sjsg * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is
599b35a56d4Sjsg * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
600b35a56d4Sjsg * that has backlight.
601b35a56d4Sjsg */
602f005ef32Sjsg if (DISPLAY_VER(i915) == 2)
603f005ef32Sjsg intel_de_write(i915, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
604b35a56d4Sjsg }
605b35a56d4Sjsg
i965_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)606b35a56d4Sjsg static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
607b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
608b35a56d4Sjsg {
609b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
610f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
611b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
612b35a56d4Sjsg enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
613b35a56d4Sjsg u32 ctl, ctl2, freq;
614b35a56d4Sjsg
615f005ef32Sjsg ctl2 = intel_de_read(i915, BLC_PWM_CTL2);
616b35a56d4Sjsg if (ctl2 & BLM_PWM_ENABLE) {
617f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] backlight already enabled\n",
618f005ef32Sjsg connector->base.base.id, connector->base.name);
619b35a56d4Sjsg ctl2 &= ~BLM_PWM_ENABLE;
620f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL2, ctl2);
621b35a56d4Sjsg }
622b35a56d4Sjsg
623b35a56d4Sjsg freq = panel->backlight.pwm_level_max;
624b35a56d4Sjsg if (panel->backlight.combination_mode)
625b35a56d4Sjsg freq /= 0xff;
626b35a56d4Sjsg
627b35a56d4Sjsg ctl = freq << 16;
628f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL, ctl);
629b35a56d4Sjsg
630b35a56d4Sjsg ctl2 = BLM_PIPE(pipe);
631b35a56d4Sjsg if (panel->backlight.combination_mode)
632b35a56d4Sjsg ctl2 |= BLM_COMBINATION_MODE;
633b35a56d4Sjsg if (panel->backlight.active_low_pwm)
634b35a56d4Sjsg ctl2 |= BLM_POLARITY_I965;
635f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL2, ctl2);
636f005ef32Sjsg intel_de_posting_read(i915, BLC_PWM_CTL2);
637f005ef32Sjsg intel_de_write(i915, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
638b35a56d4Sjsg
6391bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
640b35a56d4Sjsg }
641b35a56d4Sjsg
vlv_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)642b35a56d4Sjsg static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
643b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
644b35a56d4Sjsg {
645b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
646f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
647b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
648b35a56d4Sjsg enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
649b35a56d4Sjsg u32 ctl, ctl2;
650b35a56d4Sjsg
651f005ef32Sjsg ctl2 = intel_de_read(i915, VLV_BLC_PWM_CTL2(pipe));
652b35a56d4Sjsg if (ctl2 & BLM_PWM_ENABLE) {
653f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] backlight already enabled\n",
654f005ef32Sjsg connector->base.base.id, connector->base.name);
655b35a56d4Sjsg ctl2 &= ~BLM_PWM_ENABLE;
656f005ef32Sjsg intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), ctl2);
657b35a56d4Sjsg }
658b35a56d4Sjsg
659b35a56d4Sjsg ctl = panel->backlight.pwm_level_max << 16;
660f005ef32Sjsg intel_de_write(i915, VLV_BLC_PWM_CTL(pipe), ctl);
661b35a56d4Sjsg
662b35a56d4Sjsg /* XXX: combine this into above write? */
6631bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
664b35a56d4Sjsg
665b35a56d4Sjsg ctl2 = 0;
666b35a56d4Sjsg if (panel->backlight.active_low_pwm)
667b35a56d4Sjsg ctl2 |= BLM_POLARITY_I965;
668f005ef32Sjsg intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), ctl2);
669f005ef32Sjsg intel_de_posting_read(i915, VLV_BLC_PWM_CTL2(pipe));
670f005ef32Sjsg intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
671b35a56d4Sjsg }
672b35a56d4Sjsg
bxt_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)673b35a56d4Sjsg static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
674b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
675b35a56d4Sjsg {
676b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
677f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
678b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
679b35a56d4Sjsg enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
680b35a56d4Sjsg u32 pwm_ctl, val;
681b35a56d4Sjsg
682b35a56d4Sjsg /* Controller 1 uses the utility pin. */
683b35a56d4Sjsg if (panel->backlight.controller == 1) {
684f005ef32Sjsg val = intel_de_read(i915, UTIL_PIN_CTL);
685b35a56d4Sjsg if (val & UTIL_PIN_ENABLE) {
686f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] utility pin already enabled\n",
687f005ef32Sjsg connector->base.base.id, connector->base.name);
688b35a56d4Sjsg val &= ~UTIL_PIN_ENABLE;
689f005ef32Sjsg intel_de_write(i915, UTIL_PIN_CTL, val);
690b35a56d4Sjsg }
691b35a56d4Sjsg
692b35a56d4Sjsg val = 0;
693b35a56d4Sjsg if (panel->backlight.util_pin_active_low)
694b35a56d4Sjsg val |= UTIL_PIN_POLARITY;
695f005ef32Sjsg intel_de_write(i915, UTIL_PIN_CTL,
696b35a56d4Sjsg val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
697b35a56d4Sjsg }
698b35a56d4Sjsg
699f005ef32Sjsg pwm_ctl = intel_de_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
700b35a56d4Sjsg if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
701f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] backlight already enabled\n",
702f005ef32Sjsg connector->base.base.id, connector->base.name);
703b35a56d4Sjsg pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
704f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
705b35a56d4Sjsg pwm_ctl);
706b35a56d4Sjsg }
707b35a56d4Sjsg
708f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller),
709b35a56d4Sjsg panel->backlight.pwm_level_max);
710b35a56d4Sjsg
7111bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
712b35a56d4Sjsg
713b35a56d4Sjsg pwm_ctl = 0;
714b35a56d4Sjsg if (panel->backlight.active_low_pwm)
715b35a56d4Sjsg pwm_ctl |= BXT_BLC_PWM_POLARITY;
716b35a56d4Sjsg
717f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
718f005ef32Sjsg intel_de_posting_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
719f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
720b35a56d4Sjsg pwm_ctl | BXT_BLC_PWM_ENABLE);
721b35a56d4Sjsg }
722b35a56d4Sjsg
cnp_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)723b35a56d4Sjsg static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
724b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
725b35a56d4Sjsg {
726b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
727f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
728b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
729b35a56d4Sjsg u32 pwm_ctl;
730b35a56d4Sjsg
731f005ef32Sjsg pwm_ctl = intel_de_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
732b35a56d4Sjsg if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
733f005ef32Sjsg drm_dbg_kms(&i915->drm, "backlight already enabled\n");
734b35a56d4Sjsg pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
735f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
736b35a56d4Sjsg pwm_ctl);
737b35a56d4Sjsg }
738b35a56d4Sjsg
739f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller),
740b35a56d4Sjsg panel->backlight.pwm_level_max);
741b35a56d4Sjsg
7421bb76ff1Sjsg intel_backlight_set_pwm_level(conn_state, level);
743b35a56d4Sjsg
744b35a56d4Sjsg pwm_ctl = 0;
745b35a56d4Sjsg if (panel->backlight.active_low_pwm)
746b35a56d4Sjsg pwm_ctl |= BXT_BLC_PWM_POLARITY;
747b35a56d4Sjsg
748f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
749f005ef32Sjsg intel_de_posting_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
750f005ef32Sjsg intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
751b35a56d4Sjsg pwm_ctl | BXT_BLC_PWM_ENABLE);
752b35a56d4Sjsg }
753b35a56d4Sjsg
ext_pwm_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)754b35a56d4Sjsg static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
755b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
756b35a56d4Sjsg {
757b35a56d4Sjsg STUB();
758b35a56d4Sjsg #ifdef notyet
759b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
760b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
761b35a56d4Sjsg
762b35a56d4Sjsg pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
763b35a56d4Sjsg panel->backlight.pwm_state.enabled = true;
764*2e4fb78aSjsg pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
765b35a56d4Sjsg #endif
766b35a56d4Sjsg }
767b35a56d4Sjsg
__intel_backlight_enable(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)7681bb76ff1Sjsg static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state,
769b35a56d4Sjsg const struct drm_connector_state *conn_state)
770b35a56d4Sjsg {
771b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
772b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
773b35a56d4Sjsg
774b35a56d4Sjsg WARN_ON(panel->backlight.max == 0);
775b35a56d4Sjsg
776b35a56d4Sjsg if (panel->backlight.level <= panel->backlight.min) {
777b35a56d4Sjsg panel->backlight.level = panel->backlight.max;
778b35a56d4Sjsg if (panel->backlight.device)
779b35a56d4Sjsg panel->backlight.device->props.brightness =
780b35a56d4Sjsg scale_hw_to_user(connector,
781b35a56d4Sjsg panel->backlight.level,
782b35a56d4Sjsg panel->backlight.device->props.max_brightness);
783b35a56d4Sjsg }
784b35a56d4Sjsg
785b35a56d4Sjsg panel->backlight.funcs->enable(crtc_state, conn_state, panel->backlight.level);
786b35a56d4Sjsg panel->backlight.enabled = true;
787b35a56d4Sjsg if (panel->backlight.device)
788b35a56d4Sjsg panel->backlight.device->props.power = FB_BLANK_UNBLANK;
789b35a56d4Sjsg }
790b35a56d4Sjsg
intel_backlight_enable(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)7911bb76ff1Sjsg void intel_backlight_enable(const struct intel_crtc_state *crtc_state,
792b35a56d4Sjsg const struct drm_connector_state *conn_state)
793b35a56d4Sjsg {
794b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
795f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
796b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
797b35a56d4Sjsg enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
798b35a56d4Sjsg
799b35a56d4Sjsg if (!panel->backlight.present)
800b35a56d4Sjsg return;
801b35a56d4Sjsg
802f005ef32Sjsg drm_dbg_kms(&i915->drm, "pipe %c\n", pipe_name(pipe));
803b35a56d4Sjsg
804f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
805b35a56d4Sjsg
8061bb76ff1Sjsg __intel_backlight_enable(crtc_state, conn_state);
807b35a56d4Sjsg
808f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
809b35a56d4Sjsg }
810b35a56d4Sjsg
811b35a56d4Sjsg #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
intel_panel_get_backlight(struct intel_connector * connector)812b35a56d4Sjsg static u32 intel_panel_get_backlight(struct intel_connector *connector)
813b35a56d4Sjsg {
814f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
815b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
816b35a56d4Sjsg u32 val = 0;
817b35a56d4Sjsg
818f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
819b35a56d4Sjsg
820b35a56d4Sjsg if (panel->backlight.enabled)
821b35a56d4Sjsg val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector));
822b35a56d4Sjsg
823f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
824b35a56d4Sjsg
825f005ef32Sjsg drm_dbg_kms(&i915->drm, "get backlight PWM = %d\n", val);
826b35a56d4Sjsg return val;
827b35a56d4Sjsg }
828b35a56d4Sjsg
829b35a56d4Sjsg /* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
scale_user_to_hw(struct intel_connector * connector,u32 user_level,u32 user_max)830b35a56d4Sjsg static u32 scale_user_to_hw(struct intel_connector *connector,
831b35a56d4Sjsg u32 user_level, u32 user_max)
832b35a56d4Sjsg {
833b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
834b35a56d4Sjsg
835b35a56d4Sjsg return scale(user_level, 0, user_max,
836b35a56d4Sjsg panel->backlight.min, panel->backlight.max);
837b35a56d4Sjsg }
838b35a56d4Sjsg
839b35a56d4Sjsg /* set backlight brightness to level in range [0..max], scaling wrt hw min */
intel_panel_set_backlight(const struct drm_connector_state * conn_state,u32 user_level,u32 user_max)840b35a56d4Sjsg static void intel_panel_set_backlight(const struct drm_connector_state *conn_state,
841b35a56d4Sjsg u32 user_level, u32 user_max)
842b35a56d4Sjsg {
843b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
844f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
845b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
846b35a56d4Sjsg u32 hw_level;
847b35a56d4Sjsg
848b35a56d4Sjsg if (!panel->backlight.present)
849b35a56d4Sjsg return;
850b35a56d4Sjsg
851f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
852b35a56d4Sjsg
853f005ef32Sjsg drm_WARN_ON(&i915->drm, panel->backlight.max == 0);
854b35a56d4Sjsg
855b35a56d4Sjsg hw_level = scale_user_to_hw(connector, user_level, user_max);
856b35a56d4Sjsg panel->backlight.level = hw_level;
857b35a56d4Sjsg
858b35a56d4Sjsg if (panel->backlight.enabled)
859b35a56d4Sjsg intel_panel_actually_set_backlight(conn_state, hw_level);
860b35a56d4Sjsg
861f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
862b35a56d4Sjsg }
863b35a56d4Sjsg
intel_backlight_device_update_status(struct backlight_device * bd)864b35a56d4Sjsg static int intel_backlight_device_update_status(struct backlight_device *bd)
865b35a56d4Sjsg {
866b35a56d4Sjsg struct intel_connector *connector = bl_get_data(bd);
867f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
868b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
869b35a56d4Sjsg
870f005ef32Sjsg drm_modeset_lock(&i915->drm.mode_config.connection_mutex, NULL);
871f005ef32Sjsg
872f005ef32Sjsg drm_dbg_kms(&i915->drm, "updating intel_backlight, brightness=%d/%d\n",
873b35a56d4Sjsg bd->props.brightness, bd->props.max_brightness);
874b35a56d4Sjsg intel_panel_set_backlight(connector->base.state, bd->props.brightness,
875b35a56d4Sjsg bd->props.max_brightness);
876b35a56d4Sjsg
877b35a56d4Sjsg /*
878b35a56d4Sjsg * Allow flipping bl_power as a sub-state of enabled. Sadly the
879b35a56d4Sjsg * backlight class device does not make it easy to differentiate
880b35a56d4Sjsg * between callbacks for brightness and bl_power, so our backlight_power
881b35a56d4Sjsg * callback needs to take this into account.
882b35a56d4Sjsg */
883b35a56d4Sjsg if (panel->backlight.enabled) {
884b35a56d4Sjsg if (panel->backlight.power) {
885b35a56d4Sjsg bool enable = bd->props.power == FB_BLANK_UNBLANK &&
886b35a56d4Sjsg bd->props.brightness != 0;
887b35a56d4Sjsg panel->backlight.power(connector, enable);
888b35a56d4Sjsg }
889b35a56d4Sjsg } else {
890b35a56d4Sjsg bd->props.power = FB_BLANK_POWERDOWN;
891b35a56d4Sjsg }
892b35a56d4Sjsg
893f005ef32Sjsg drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
894f005ef32Sjsg
895b35a56d4Sjsg return 0;
896b35a56d4Sjsg }
897b35a56d4Sjsg
intel_backlight_device_get_brightness(struct backlight_device * bd)898b35a56d4Sjsg static int intel_backlight_device_get_brightness(struct backlight_device *bd)
899b35a56d4Sjsg {
900b35a56d4Sjsg struct intel_connector *connector = bl_get_data(bd);
901f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
902b35a56d4Sjsg intel_wakeref_t wakeref;
903b35a56d4Sjsg int ret = 0;
904b35a56d4Sjsg
905f005ef32Sjsg with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
906b35a56d4Sjsg u32 hw_level;
907b35a56d4Sjsg
908f005ef32Sjsg drm_modeset_lock(&i915->drm.mode_config.connection_mutex, NULL);
909b35a56d4Sjsg
910b35a56d4Sjsg hw_level = intel_panel_get_backlight(connector);
911b35a56d4Sjsg ret = scale_hw_to_user(connector,
912b35a56d4Sjsg hw_level, bd->props.max_brightness);
913b35a56d4Sjsg
914f005ef32Sjsg drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
915b35a56d4Sjsg }
916b35a56d4Sjsg
917b35a56d4Sjsg return ret;
918b35a56d4Sjsg }
919b35a56d4Sjsg
920b35a56d4Sjsg static const struct backlight_ops intel_backlight_device_ops = {
921b35a56d4Sjsg .update_status = intel_backlight_device_update_status,
922b35a56d4Sjsg .get_brightness = intel_backlight_device_get_brightness,
923b35a56d4Sjsg };
924b35a56d4Sjsg
intel_backlight_device_register(struct intel_connector * connector)925b35a56d4Sjsg int intel_backlight_device_register(struct intel_connector *connector)
926b35a56d4Sjsg {
927b35a56d4Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
928b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
929b35a56d4Sjsg struct backlight_properties props;
930b35a56d4Sjsg struct backlight_device *bd;
931b35a56d4Sjsg const char *name;
932b35a56d4Sjsg int ret = 0;
933b35a56d4Sjsg
934b35a56d4Sjsg if (WARN_ON(panel->backlight.device))
935b35a56d4Sjsg return -ENODEV;
936b35a56d4Sjsg
937b35a56d4Sjsg if (!panel->backlight.present)
938b35a56d4Sjsg return 0;
939b35a56d4Sjsg
940b35a56d4Sjsg WARN_ON(panel->backlight.max == 0);
941b35a56d4Sjsg
9421bb76ff1Sjsg if (!acpi_video_backlight_use_native()) {
9431bb76ff1Sjsg drm_info(&i915->drm, "Skipping intel_backlight registration\n");
9441bb76ff1Sjsg return 0;
9451bb76ff1Sjsg }
9461bb76ff1Sjsg
947b35a56d4Sjsg memset(&props, 0, sizeof(props));
948b35a56d4Sjsg props.type = BACKLIGHT_RAW;
949b35a56d4Sjsg
950b35a56d4Sjsg /*
951b35a56d4Sjsg * Note: Everything should work even if the backlight device max
952b35a56d4Sjsg * presented to the userspace is arbitrarily chosen.
953b35a56d4Sjsg */
954b35a56d4Sjsg props.max_brightness = panel->backlight.max;
955b35a56d4Sjsg props.brightness = scale_hw_to_user(connector,
956b35a56d4Sjsg panel->backlight.level,
957b35a56d4Sjsg props.max_brightness);
958b35a56d4Sjsg
959b35a56d4Sjsg if (panel->backlight.enabled)
960b35a56d4Sjsg props.power = FB_BLANK_UNBLANK;
961b35a56d4Sjsg else
962b35a56d4Sjsg props.power = FB_BLANK_POWERDOWN;
963b35a56d4Sjsg
964b35a56d4Sjsg name = kstrdup("intel_backlight", GFP_KERNEL);
965b35a56d4Sjsg if (!name)
966b35a56d4Sjsg return -ENOMEM;
967b35a56d4Sjsg
968a939c9caSjsg bd = backlight_device_get_by_name(name);
969a939c9caSjsg if (bd) {
970a939c9caSjsg #ifdef __linux__
971a939c9caSjsg put_device(&bd->dev);
972a939c9caSjsg #endif
973b35a56d4Sjsg /*
974b35a56d4Sjsg * Using the same name independent of the drm device or connector
975b35a56d4Sjsg * prevents registration of multiple backlight devices in the
976b35a56d4Sjsg * driver. However, we need to use the default name for backward
977b35a56d4Sjsg * compatibility. Use unique names for subsequent backlight devices as a
978b35a56d4Sjsg * fallback when the default name already exists.
979b35a56d4Sjsg */
980b35a56d4Sjsg kfree(name);
981b35a56d4Sjsg name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
982b35a56d4Sjsg i915->drm.primary->index, connector->base.name);
983b35a56d4Sjsg if (!name)
984b35a56d4Sjsg return -ENOMEM;
985a939c9caSjsg }
986b35a56d4Sjsg bd = backlight_device_register(name, connector->base.kdev, connector,
987b35a56d4Sjsg &intel_backlight_device_ops, &props);
988b35a56d4Sjsg
989b35a56d4Sjsg if (IS_ERR(bd)) {
990b35a56d4Sjsg drm_err(&i915->drm,
991b35a56d4Sjsg "[CONNECTOR:%d:%s] backlight device %s register failed: %ld\n",
992b35a56d4Sjsg connector->base.base.id, connector->base.name, name, PTR_ERR(bd));
993b35a56d4Sjsg ret = PTR_ERR(bd);
994b35a56d4Sjsg goto out;
995b35a56d4Sjsg }
996b35a56d4Sjsg
997b35a56d4Sjsg panel->backlight.device = bd;
998b35a56d4Sjsg
999b35a56d4Sjsg drm_dbg_kms(&i915->drm,
1000b35a56d4Sjsg "[CONNECTOR:%d:%s] backlight device %s registered\n",
1001b35a56d4Sjsg connector->base.base.id, connector->base.name, name);
1002b35a56d4Sjsg
1003b35a56d4Sjsg out:
1004b35a56d4Sjsg kfree(name);
1005b35a56d4Sjsg
1006b35a56d4Sjsg return ret;
1007b35a56d4Sjsg }
1008b35a56d4Sjsg
intel_backlight_device_unregister(struct intel_connector * connector)1009b35a56d4Sjsg void intel_backlight_device_unregister(struct intel_connector *connector)
1010b35a56d4Sjsg {
1011b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1012b35a56d4Sjsg
1013b35a56d4Sjsg if (panel->backlight.device) {
1014b35a56d4Sjsg backlight_device_unregister(panel->backlight.device);
1015b35a56d4Sjsg panel->backlight.device = NULL;
1016b35a56d4Sjsg }
1017b35a56d4Sjsg }
1018b35a56d4Sjsg #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
1019b35a56d4Sjsg
1020b35a56d4Sjsg /*
1021b35a56d4Sjsg * CNP: PWM clock frequency is 19.2 MHz or 24 MHz.
1022b35a56d4Sjsg * PWM increment = 1
1023b35a56d4Sjsg */
cnp_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1024b35a56d4Sjsg static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1025b35a56d4Sjsg {
1026f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1027b35a56d4Sjsg
1028f005ef32Sjsg return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(i915)->rawclk_freq),
1029b35a56d4Sjsg pwm_freq_hz);
1030b35a56d4Sjsg }
1031b35a56d4Sjsg
1032b35a56d4Sjsg /*
1033b35a56d4Sjsg * BXT: PWM clock frequency = 19.2 MHz.
1034b35a56d4Sjsg */
bxt_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1035b35a56d4Sjsg static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1036b35a56d4Sjsg {
1037b35a56d4Sjsg return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz);
1038b35a56d4Sjsg }
1039b35a56d4Sjsg
1040b35a56d4Sjsg /*
1041b35a56d4Sjsg * SPT: This value represents the period of the PWM stream in clock periods
1042b35a56d4Sjsg * multiplied by 16 (default increment) or 128 (alternate increment selected in
1043b35a56d4Sjsg * SCHICKEN_1 bit 0). PWM clock is 24 MHz.
1044b35a56d4Sjsg */
spt_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1045b35a56d4Sjsg static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1046b35a56d4Sjsg {
1047b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1048b35a56d4Sjsg u32 mul;
1049b35a56d4Sjsg
1050b35a56d4Sjsg if (panel->backlight.alternate_pwm_increment)
1051b35a56d4Sjsg mul = 128;
1052b35a56d4Sjsg else
1053b35a56d4Sjsg mul = 16;
1054b35a56d4Sjsg
1055b35a56d4Sjsg return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul);
1056b35a56d4Sjsg }
1057b35a56d4Sjsg
1058b35a56d4Sjsg /*
1059b35a56d4Sjsg * LPT: This value represents the period of the PWM stream in clock periods
1060b35a56d4Sjsg * multiplied by 128 (default increment) or 16 (alternate increment, selected in
1061b35a56d4Sjsg * LPT SOUTH_CHICKEN2 register bit 5).
1062b35a56d4Sjsg */
lpt_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1063b35a56d4Sjsg static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1064b35a56d4Sjsg {
1065f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1066b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1067b35a56d4Sjsg u32 mul, clock;
1068b35a56d4Sjsg
1069b35a56d4Sjsg if (panel->backlight.alternate_pwm_increment)
1070b35a56d4Sjsg mul = 16;
1071b35a56d4Sjsg else
1072b35a56d4Sjsg mul = 128;
1073b35a56d4Sjsg
1074f005ef32Sjsg if (HAS_PCH_LPT_H(i915))
1075b35a56d4Sjsg clock = MHz(135); /* LPT:H */
1076b35a56d4Sjsg else
1077b35a56d4Sjsg clock = MHz(24); /* LPT:LP */
1078b35a56d4Sjsg
1079b35a56d4Sjsg return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
1080b35a56d4Sjsg }
1081b35a56d4Sjsg
1082b35a56d4Sjsg /*
1083b35a56d4Sjsg * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH
1084b35a56d4Sjsg * display raw clocks multiplied by 128.
1085b35a56d4Sjsg */
pch_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1086b35a56d4Sjsg static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1087b35a56d4Sjsg {
1088f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1089b35a56d4Sjsg
1090f005ef32Sjsg return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(i915)->rawclk_freq),
1091b35a56d4Sjsg pwm_freq_hz * 128);
1092b35a56d4Sjsg }
1093b35a56d4Sjsg
1094b35a56d4Sjsg /*
1095b35a56d4Sjsg * Gen2: This field determines the number of time base events (display core
1096b35a56d4Sjsg * clock frequency/32) in total for a complete cycle of modulated backlight
1097b35a56d4Sjsg * control.
1098b35a56d4Sjsg *
1099b35a56d4Sjsg * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock)
1100b35a56d4Sjsg * divided by 32.
1101b35a56d4Sjsg */
i9xx_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1102b35a56d4Sjsg static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1103b35a56d4Sjsg {
1104f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1105b35a56d4Sjsg int clock;
1106b35a56d4Sjsg
1107f005ef32Sjsg if (IS_PINEVIEW(i915))
1108f005ef32Sjsg clock = KHz(RUNTIME_INFO(i915)->rawclk_freq);
1109b35a56d4Sjsg else
1110f005ef32Sjsg clock = KHz(i915->display.cdclk.hw.cdclk);
1111b35a56d4Sjsg
1112b35a56d4Sjsg return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
1113b35a56d4Sjsg }
1114b35a56d4Sjsg
1115b35a56d4Sjsg /*
1116b35a56d4Sjsg * Gen4: This value represents the period of the PWM stream in display core
1117b35a56d4Sjsg * clocks ([DevCTG] HRAW clocks) multiplied by 128.
1118b35a56d4Sjsg *
1119b35a56d4Sjsg */
i965_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1120b35a56d4Sjsg static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1121b35a56d4Sjsg {
1122f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1123b35a56d4Sjsg int clock;
1124b35a56d4Sjsg
1125f005ef32Sjsg if (IS_G4X(i915))
1126f005ef32Sjsg clock = KHz(RUNTIME_INFO(i915)->rawclk_freq);
1127b35a56d4Sjsg else
1128f005ef32Sjsg clock = KHz(i915->display.cdclk.hw.cdclk);
1129b35a56d4Sjsg
1130b35a56d4Sjsg return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
1131b35a56d4Sjsg }
1132b35a56d4Sjsg
1133b35a56d4Sjsg /*
1134b35a56d4Sjsg * VLV: This value represents the period of the PWM stream in display core
1135b35a56d4Sjsg * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks
1136b35a56d4Sjsg * multiplied by 16. CHV uses a 19.2MHz S0IX clock.
1137b35a56d4Sjsg */
vlv_hz_to_pwm(struct intel_connector * connector,u32 pwm_freq_hz)1138b35a56d4Sjsg static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
1139b35a56d4Sjsg {
1140f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1141b35a56d4Sjsg int mul, clock;
1142b35a56d4Sjsg
1143f005ef32Sjsg if ((intel_de_read(i915, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
1144f005ef32Sjsg if (IS_CHERRYVIEW(i915))
1145b35a56d4Sjsg clock = KHz(19200);
1146b35a56d4Sjsg else
1147b35a56d4Sjsg clock = MHz(25);
1148b35a56d4Sjsg mul = 16;
1149b35a56d4Sjsg } else {
1150f005ef32Sjsg clock = KHz(RUNTIME_INFO(i915)->rawclk_freq);
1151b35a56d4Sjsg mul = 128;
1152b35a56d4Sjsg }
1153b35a56d4Sjsg
1154b35a56d4Sjsg return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
1155b35a56d4Sjsg }
1156b35a56d4Sjsg
get_vbt_pwm_freq(struct intel_connector * connector)11571bb76ff1Sjsg static u16 get_vbt_pwm_freq(struct intel_connector *connector)
1158b35a56d4Sjsg {
1159f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
11601bb76ff1Sjsg u16 pwm_freq_hz = connector->panel.vbt.backlight.pwm_freq_hz;
1161b35a56d4Sjsg
1162b35a56d4Sjsg if (pwm_freq_hz) {
1163f005ef32Sjsg drm_dbg_kms(&i915->drm,
1164b35a56d4Sjsg "VBT defined backlight frequency %u Hz\n",
1165b35a56d4Sjsg pwm_freq_hz);
1166b35a56d4Sjsg } else {
1167b35a56d4Sjsg pwm_freq_hz = 200;
1168f005ef32Sjsg drm_dbg_kms(&i915->drm,
1169b35a56d4Sjsg "default backlight frequency %u Hz\n",
1170b35a56d4Sjsg pwm_freq_hz);
1171b35a56d4Sjsg }
1172b35a56d4Sjsg
1173b35a56d4Sjsg return pwm_freq_hz;
1174b35a56d4Sjsg }
1175b35a56d4Sjsg
get_backlight_max_vbt(struct intel_connector * connector)1176b35a56d4Sjsg static u32 get_backlight_max_vbt(struct intel_connector *connector)
1177b35a56d4Sjsg {
1178f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1179b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
11801bb76ff1Sjsg u16 pwm_freq_hz = get_vbt_pwm_freq(connector);
1181b35a56d4Sjsg u32 pwm;
1182b35a56d4Sjsg
1183b35a56d4Sjsg if (!panel->backlight.pwm_funcs->hz_to_pwm) {
1184f005ef32Sjsg drm_dbg_kms(&i915->drm,
1185b35a56d4Sjsg "backlight frequency conversion not supported\n");
1186b35a56d4Sjsg return 0;
1187b35a56d4Sjsg }
1188b35a56d4Sjsg
1189b35a56d4Sjsg pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz);
1190b35a56d4Sjsg if (!pwm) {
1191f005ef32Sjsg drm_dbg_kms(&i915->drm,
1192b35a56d4Sjsg "backlight frequency conversion failed\n");
1193b35a56d4Sjsg return 0;
1194b35a56d4Sjsg }
1195b35a56d4Sjsg
1196b35a56d4Sjsg return pwm;
1197b35a56d4Sjsg }
1198b35a56d4Sjsg
1199b35a56d4Sjsg /*
1200b35a56d4Sjsg * Note: The setup hooks can't assume pipe is set!
1201b35a56d4Sjsg */
get_backlight_min_vbt(struct intel_connector * connector)1202b35a56d4Sjsg static u32 get_backlight_min_vbt(struct intel_connector *connector)
1203b35a56d4Sjsg {
1204f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1205b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1206b35a56d4Sjsg int min;
1207b35a56d4Sjsg
1208f005ef32Sjsg drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
1209b35a56d4Sjsg
1210b35a56d4Sjsg /*
1211b35a56d4Sjsg * XXX: If the vbt value is 255, it makes min equal to max, which leads
1212b35a56d4Sjsg * to problems. There are such machines out there. Either our
1213b35a56d4Sjsg * interpretation is wrong or the vbt has bogus data. Or both. Safeguard
1214b35a56d4Sjsg * against this by letting the minimum be at most (arbitrarily chosen)
1215b35a56d4Sjsg * 25% of the max.
1216b35a56d4Sjsg */
12171bb76ff1Sjsg min = clamp_t(int, connector->panel.vbt.backlight.min_brightness, 0, 64);
12181bb76ff1Sjsg if (min != connector->panel.vbt.backlight.min_brightness) {
1219f005ef32Sjsg drm_dbg_kms(&i915->drm,
1220b35a56d4Sjsg "clamping VBT min backlight %d/255 to %d/255\n",
12211bb76ff1Sjsg connector->panel.vbt.backlight.min_brightness, min);
1222b35a56d4Sjsg }
1223b35a56d4Sjsg
1224b35a56d4Sjsg /* vbt value is a coefficient in range [0..255] */
1225b35a56d4Sjsg return scale(min, 0, 255, 0, panel->backlight.pwm_level_max);
1226b35a56d4Sjsg }
1227b35a56d4Sjsg
lpt_setup_backlight(struct intel_connector * connector,enum pipe unused)1228b35a56d4Sjsg static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
1229b35a56d4Sjsg {
1230f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1231b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1232b35a56d4Sjsg u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
1233b35a56d4Sjsg bool alt, cpu_mode;
1234b35a56d4Sjsg
1235f005ef32Sjsg if (HAS_PCH_LPT(i915))
1236f005ef32Sjsg alt = intel_de_read(i915, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
1237b35a56d4Sjsg else
1238f005ef32Sjsg alt = intel_de_read(i915, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
1239b35a56d4Sjsg panel->backlight.alternate_pwm_increment = alt;
1240b35a56d4Sjsg
1241f005ef32Sjsg pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
1242b35a56d4Sjsg panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
1243b35a56d4Sjsg
1244f005ef32Sjsg pch_ctl2 = intel_de_read(i915, BLC_PWM_PCH_CTL2);
1245b35a56d4Sjsg panel->backlight.pwm_level_max = pch_ctl2 >> 16;
1246b35a56d4Sjsg
1247f005ef32Sjsg cpu_ctl2 = intel_de_read(i915, BLC_PWM_CPU_CTL2);
1248b35a56d4Sjsg
1249b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1250b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1251b35a56d4Sjsg
1252b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1253b35a56d4Sjsg return -ENODEV;
1254b35a56d4Sjsg
1255b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1256b35a56d4Sjsg
1257b35a56d4Sjsg panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
1258b35a56d4Sjsg
1259f005ef32Sjsg cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(i915) &&
1260b35a56d4Sjsg !(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
1261b35a56d4Sjsg (cpu_ctl2 & BLM_PWM_ENABLE);
1262b35a56d4Sjsg
1263b35a56d4Sjsg if (cpu_mode) {
1264b35a56d4Sjsg val = pch_get_backlight(connector, unused);
1265b35a56d4Sjsg
1266f005ef32Sjsg drm_dbg_kms(&i915->drm,
1267b35a56d4Sjsg "CPU backlight register was enabled, switching to PCH override\n");
1268b35a56d4Sjsg
1269b35a56d4Sjsg /* Write converted CPU PWM value to PCH override register */
1270b35a56d4Sjsg lpt_set_backlight(connector->base.state, val);
1271f005ef32Sjsg intel_de_write(i915, BLC_PWM_PCH_CTL1,
1272b35a56d4Sjsg pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
1273b35a56d4Sjsg
1274f005ef32Sjsg intel_de_write(i915, BLC_PWM_CPU_CTL2,
1275b35a56d4Sjsg cpu_ctl2 & ~BLM_PWM_ENABLE);
1276b35a56d4Sjsg }
1277b35a56d4Sjsg
1278f005ef32Sjsg drm_dbg_kms(&i915->drm,
1279f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PCH PWM for backlight control\n",
1280f005ef32Sjsg connector->base.base.id, connector->base.name);
1281f005ef32Sjsg
1282b35a56d4Sjsg return 0;
1283b35a56d4Sjsg }
1284b35a56d4Sjsg
pch_setup_backlight(struct intel_connector * connector,enum pipe unused)1285b35a56d4Sjsg static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
1286b35a56d4Sjsg {
1287f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1288b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1289b35a56d4Sjsg u32 cpu_ctl2, pch_ctl1, pch_ctl2;
1290b35a56d4Sjsg
1291f005ef32Sjsg pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
1292b35a56d4Sjsg panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
1293b35a56d4Sjsg
1294f005ef32Sjsg pch_ctl2 = intel_de_read(i915, BLC_PWM_PCH_CTL2);
1295b35a56d4Sjsg panel->backlight.pwm_level_max = pch_ctl2 >> 16;
1296b35a56d4Sjsg
1297b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1298b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1299b35a56d4Sjsg
1300b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1301b35a56d4Sjsg return -ENODEV;
1302b35a56d4Sjsg
1303b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1304b35a56d4Sjsg
1305f005ef32Sjsg cpu_ctl2 = intel_de_read(i915, BLC_PWM_CPU_CTL2);
1306b35a56d4Sjsg panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
1307b35a56d4Sjsg (pch_ctl1 & BLM_PCH_PWM_ENABLE);
1308b35a56d4Sjsg
1309f005ef32Sjsg drm_dbg_kms(&i915->drm,
1310f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PCH PWM for backlight control\n",
1311f005ef32Sjsg connector->base.base.id, connector->base.name);
1312f005ef32Sjsg
1313b35a56d4Sjsg return 0;
1314b35a56d4Sjsg }
1315b35a56d4Sjsg
i9xx_setup_backlight(struct intel_connector * connector,enum pipe unused)1316b35a56d4Sjsg static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
1317b35a56d4Sjsg {
1318f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1319b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1320b35a56d4Sjsg u32 ctl, val;
1321b35a56d4Sjsg
1322f005ef32Sjsg ctl = intel_de_read(i915, BLC_PWM_CTL);
1323b35a56d4Sjsg
1324f005ef32Sjsg if (DISPLAY_VER(i915) == 2 || IS_I915GM(i915) || IS_I945GM(i915))
1325b35a56d4Sjsg panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
1326b35a56d4Sjsg
1327f005ef32Sjsg if (IS_PINEVIEW(i915))
1328b35a56d4Sjsg panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
1329b35a56d4Sjsg
1330b35a56d4Sjsg panel->backlight.pwm_level_max = ctl >> 17;
1331b35a56d4Sjsg
1332b35a56d4Sjsg if (!panel->backlight.pwm_level_max) {
1333b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1334b35a56d4Sjsg panel->backlight.pwm_level_max >>= 1;
1335b35a56d4Sjsg }
1336b35a56d4Sjsg
1337b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1338b35a56d4Sjsg return -ENODEV;
1339b35a56d4Sjsg
1340b35a56d4Sjsg if (panel->backlight.combination_mode)
1341b35a56d4Sjsg panel->backlight.pwm_level_max *= 0xff;
1342b35a56d4Sjsg
1343b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1344b35a56d4Sjsg
1345b35a56d4Sjsg val = i9xx_get_backlight(connector, unused);
13461bb76ff1Sjsg val = intel_backlight_invert_pwm_level(connector, val);
1347b35a56d4Sjsg val = clamp(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
1348b35a56d4Sjsg
1349b35a56d4Sjsg panel->backlight.pwm_enabled = val != 0;
1350b35a56d4Sjsg
1351f005ef32Sjsg drm_dbg_kms(&i915->drm,
1352f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PWM for backlight control\n",
1353f005ef32Sjsg connector->base.base.id, connector->base.name);
1354f005ef32Sjsg
1355b35a56d4Sjsg return 0;
1356b35a56d4Sjsg }
1357b35a56d4Sjsg
i965_setup_backlight(struct intel_connector * connector,enum pipe unused)1358b35a56d4Sjsg static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
1359b35a56d4Sjsg {
1360f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1361b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1362b35a56d4Sjsg u32 ctl, ctl2;
1363b35a56d4Sjsg
1364f005ef32Sjsg ctl2 = intel_de_read(i915, BLC_PWM_CTL2);
1365b35a56d4Sjsg panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
1366b35a56d4Sjsg panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
1367b35a56d4Sjsg
1368f005ef32Sjsg ctl = intel_de_read(i915, BLC_PWM_CTL);
1369b35a56d4Sjsg panel->backlight.pwm_level_max = ctl >> 16;
1370b35a56d4Sjsg
1371b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1372b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1373b35a56d4Sjsg
1374b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1375b35a56d4Sjsg return -ENODEV;
1376b35a56d4Sjsg
1377b35a56d4Sjsg if (panel->backlight.combination_mode)
1378b35a56d4Sjsg panel->backlight.pwm_level_max *= 0xff;
1379b35a56d4Sjsg
1380b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1381b35a56d4Sjsg
1382b35a56d4Sjsg panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
1383b35a56d4Sjsg
1384f005ef32Sjsg drm_dbg_kms(&i915->drm,
1385f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PWM for backlight control\n",
1386f005ef32Sjsg connector->base.base.id, connector->base.name);
1387f005ef32Sjsg
1388b35a56d4Sjsg return 0;
1389b35a56d4Sjsg }
1390b35a56d4Sjsg
vlv_setup_backlight(struct intel_connector * connector,enum pipe pipe)1391b35a56d4Sjsg static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
1392b35a56d4Sjsg {
1393f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1394b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1395b35a56d4Sjsg u32 ctl, ctl2;
1396b35a56d4Sjsg
1397f005ef32Sjsg if (drm_WARN_ON(&i915->drm, pipe != PIPE_A && pipe != PIPE_B))
1398b35a56d4Sjsg return -ENODEV;
1399b35a56d4Sjsg
1400f005ef32Sjsg ctl2 = intel_de_read(i915, VLV_BLC_PWM_CTL2(pipe));
1401b35a56d4Sjsg panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
1402b35a56d4Sjsg
1403f005ef32Sjsg ctl = intel_de_read(i915, VLV_BLC_PWM_CTL(pipe));
1404b35a56d4Sjsg panel->backlight.pwm_level_max = ctl >> 16;
1405b35a56d4Sjsg
1406b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1407b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1408b35a56d4Sjsg
1409b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1410b35a56d4Sjsg return -ENODEV;
1411b35a56d4Sjsg
1412b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1413b35a56d4Sjsg
1414b35a56d4Sjsg panel->backlight.pwm_enabled = ctl2 & BLM_PWM_ENABLE;
1415b35a56d4Sjsg
1416f005ef32Sjsg drm_dbg_kms(&i915->drm,
1417f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PWM for backlight control (on pipe %c)\n",
1418f005ef32Sjsg connector->base.base.id, connector->base.name, pipe_name(pipe));
1419f005ef32Sjsg
1420b35a56d4Sjsg return 0;
1421b35a56d4Sjsg }
1422b35a56d4Sjsg
1423b35a56d4Sjsg static int
bxt_setup_backlight(struct intel_connector * connector,enum pipe unused)1424b35a56d4Sjsg bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
1425b35a56d4Sjsg {
1426f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1427b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1428b35a56d4Sjsg u32 pwm_ctl, val;
1429b35a56d4Sjsg
14301bb76ff1Sjsg panel->backlight.controller = connector->panel.vbt.backlight.controller;
1431b35a56d4Sjsg
1432f005ef32Sjsg pwm_ctl = intel_de_read(i915,
1433b35a56d4Sjsg BXT_BLC_PWM_CTL(panel->backlight.controller));
1434b35a56d4Sjsg
1435b35a56d4Sjsg /* Controller 1 uses the utility pin. */
1436b35a56d4Sjsg if (panel->backlight.controller == 1) {
1437f005ef32Sjsg val = intel_de_read(i915, UTIL_PIN_CTL);
1438b35a56d4Sjsg panel->backlight.util_pin_active_low =
1439b35a56d4Sjsg val & UTIL_PIN_POLARITY;
1440b35a56d4Sjsg }
1441b35a56d4Sjsg
1442b35a56d4Sjsg panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
1443b35a56d4Sjsg panel->backlight.pwm_level_max =
1444f005ef32Sjsg intel_de_read(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller));
1445b35a56d4Sjsg
1446b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1447b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1448b35a56d4Sjsg
1449b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1450b35a56d4Sjsg return -ENODEV;
1451b35a56d4Sjsg
1452b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1453b35a56d4Sjsg
1454b35a56d4Sjsg panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
1455b35a56d4Sjsg
1456f005ef32Sjsg drm_dbg_kms(&i915->drm,
1457f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PWM for backlight control (controller=%d)\n",
1458f005ef32Sjsg connector->base.base.id, connector->base.name,
1459f005ef32Sjsg panel->backlight.controller);
1460f005ef32Sjsg
1461b35a56d4Sjsg return 0;
1462b35a56d4Sjsg }
1463b35a56d4Sjsg
cnp_num_backlight_controllers(struct drm_i915_private * i915)1464f005ef32Sjsg static int cnp_num_backlight_controllers(struct drm_i915_private *i915)
1465f005ef32Sjsg {
1466f005ef32Sjsg if (INTEL_PCH_TYPE(i915) >= PCH_DG1)
1467f005ef32Sjsg return 1;
1468f005ef32Sjsg
1469f005ef32Sjsg if (INTEL_PCH_TYPE(i915) >= PCH_ICP)
1470f005ef32Sjsg return 2;
1471f005ef32Sjsg
1472f005ef32Sjsg return 1;
1473f005ef32Sjsg }
1474f005ef32Sjsg
cnp_backlight_controller_is_valid(struct drm_i915_private * i915,int controller)1475f005ef32Sjsg static bool cnp_backlight_controller_is_valid(struct drm_i915_private *i915, int controller)
1476f005ef32Sjsg {
1477f005ef32Sjsg if (controller < 0 || controller >= cnp_num_backlight_controllers(i915))
1478f005ef32Sjsg return false;
1479f005ef32Sjsg
1480f005ef32Sjsg if (controller == 1 &&
1481f005ef32Sjsg INTEL_PCH_TYPE(i915) >= PCH_ICP &&
1482f005ef32Sjsg INTEL_PCH_TYPE(i915) < PCH_MTP)
1483f005ef32Sjsg return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT;
1484f005ef32Sjsg
1485f005ef32Sjsg return true;
1486f005ef32Sjsg }
1487f005ef32Sjsg
1488b35a56d4Sjsg static int
cnp_setup_backlight(struct intel_connector * connector,enum pipe unused)1489b35a56d4Sjsg cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
1490b35a56d4Sjsg {
1491f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1492b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1493b35a56d4Sjsg u32 pwm_ctl;
1494b35a56d4Sjsg
1495b35a56d4Sjsg /*
1496b35a56d4Sjsg * CNP has the BXT implementation of backlight, but with only one
1497f005ef32Sjsg * controller. ICP+ can have two controllers, depending on pin muxing.
1498b35a56d4Sjsg */
1499f005ef32Sjsg panel->backlight.controller = connector->panel.vbt.backlight.controller;
1500f005ef32Sjsg if (!cnp_backlight_controller_is_valid(i915, panel->backlight.controller)) {
1501f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Invalid backlight controller %d, assuming 0\n",
1502f005ef32Sjsg connector->base.base.id, connector->base.name,
1503f005ef32Sjsg panel->backlight.controller);
1504b35a56d4Sjsg panel->backlight.controller = 0;
1505f005ef32Sjsg }
1506b35a56d4Sjsg
1507f005ef32Sjsg pwm_ctl = intel_de_read(i915,
1508b35a56d4Sjsg BXT_BLC_PWM_CTL(panel->backlight.controller));
1509b35a56d4Sjsg
1510b35a56d4Sjsg panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
1511b35a56d4Sjsg panel->backlight.pwm_level_max =
1512f005ef32Sjsg intel_de_read(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller));
1513b35a56d4Sjsg
1514b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1515b35a56d4Sjsg panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
1516b35a56d4Sjsg
1517b35a56d4Sjsg if (!panel->backlight.pwm_level_max)
1518b35a56d4Sjsg return -ENODEV;
1519b35a56d4Sjsg
1520b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1521b35a56d4Sjsg
1522b35a56d4Sjsg panel->backlight.pwm_enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
1523b35a56d4Sjsg
1524f005ef32Sjsg drm_dbg_kms(&i915->drm,
1525f005ef32Sjsg "[CONNECTOR:%d:%s] Using native PCH PWM for backlight control (controller=%d)\n",
1526f005ef32Sjsg connector->base.base.id, connector->base.name,
1527f005ef32Sjsg panel->backlight.controller);
1528f005ef32Sjsg
1529b35a56d4Sjsg return 0;
1530b35a56d4Sjsg }
1531b35a56d4Sjsg
ext_pwm_setup_backlight(struct intel_connector * connector,enum pipe pipe)1532b35a56d4Sjsg static int ext_pwm_setup_backlight(struct intel_connector *connector,
1533b35a56d4Sjsg enum pipe pipe)
1534b35a56d4Sjsg {
1535f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1536b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1537b35a56d4Sjsg const char *desc;
1538b35a56d4Sjsg u32 level;
1539b35a56d4Sjsg
1540b35a56d4Sjsg /* Get the right PWM chip for DSI backlight according to VBT */
15411bb76ff1Sjsg if (connector->panel.vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
1542f005ef32Sjsg panel->backlight.pwm = pwm_get(i915->drm.dev, "pwm_pmic_backlight");
1543b35a56d4Sjsg desc = "PMIC";
1544b35a56d4Sjsg } else {
1545f005ef32Sjsg panel->backlight.pwm = pwm_get(i915->drm.dev, "pwm_soc_backlight");
1546b35a56d4Sjsg desc = "SoC";
1547b35a56d4Sjsg }
1548b35a56d4Sjsg
1549b35a56d4Sjsg if (IS_ERR(panel->backlight.pwm)) {
1550f005ef32Sjsg drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to get the %s PWM chip\n",
1551f005ef32Sjsg connector->base.base.id, connector->base.name, desc);
1552b35a56d4Sjsg panel->backlight.pwm = NULL;
1553b35a56d4Sjsg return -ENODEV;
1554b35a56d4Sjsg }
1555b35a56d4Sjsg
1556b35a56d4Sjsg panel->backlight.pwm_level_max = 100; /* 100% */
1557b35a56d4Sjsg panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
1558b35a56d4Sjsg
1559b35a56d4Sjsg #ifdef notyet
1560b35a56d4Sjsg if (pwm_is_enabled(panel->backlight.pwm)) {
1561b35a56d4Sjsg /* PWM is already enabled, use existing settings */
1562b35a56d4Sjsg pwm_get_state(panel->backlight.pwm, &panel->backlight.pwm_state);
1563b35a56d4Sjsg
1564b35a56d4Sjsg level = pwm_get_relative_duty_cycle(&panel->backlight.pwm_state,
1565b35a56d4Sjsg 100);
15661bb76ff1Sjsg level = intel_backlight_invert_pwm_level(connector, level);
1567b35a56d4Sjsg panel->backlight.pwm_enabled = true;
1568b35a56d4Sjsg
1569f005ef32Sjsg drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] PWM already enabled at freq %ld, VBT freq %d, level %d\n",
1570f005ef32Sjsg connector->base.base.id, connector->base.name,
1571b35a56d4Sjsg NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
15721bb76ff1Sjsg get_vbt_pwm_freq(connector), level);
1573b35a56d4Sjsg } else {
1574b35a56d4Sjsg /* Set period from VBT frequency, leave other settings at 0. */
1575b35a56d4Sjsg panel->backlight.pwm_state.period =
15761bb76ff1Sjsg NSEC_PER_SEC / get_vbt_pwm_freq(connector);
1577b35a56d4Sjsg }
1578b35a56d4Sjsg #else
1579b35a56d4Sjsg STUB();
1580b35a56d4Sjsg #endif
1581b35a56d4Sjsg
1582f005ef32Sjsg drm_dbg_kms(&i915->drm,
1583f005ef32Sjsg "[CONNECTOR:%d:%s] Using %s PWM for backlight control\n",
1584f005ef32Sjsg connector->base.base.id, connector->base.name, desc);
1585f005ef32Sjsg
1586b35a56d4Sjsg return 0;
1587b35a56d4Sjsg }
1588b35a56d4Sjsg
intel_pwm_set_backlight(const struct drm_connector_state * conn_state,u32 level)1589b35a56d4Sjsg static void intel_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
1590b35a56d4Sjsg {
1591b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
1592b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1593b35a56d4Sjsg
1594b35a56d4Sjsg panel->backlight.pwm_funcs->set(conn_state,
15951bb76ff1Sjsg intel_backlight_invert_pwm_level(connector, level));
1596b35a56d4Sjsg }
1597b35a56d4Sjsg
intel_pwm_get_backlight(struct intel_connector * connector,enum pipe pipe)1598b35a56d4Sjsg static u32 intel_pwm_get_backlight(struct intel_connector *connector, enum pipe pipe)
1599b35a56d4Sjsg {
1600b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1601b35a56d4Sjsg
16021bb76ff1Sjsg return intel_backlight_invert_pwm_level(connector,
1603b35a56d4Sjsg panel->backlight.pwm_funcs->get(connector, pipe));
1604b35a56d4Sjsg }
1605b35a56d4Sjsg
intel_pwm_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)1606b35a56d4Sjsg static void intel_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
1607b35a56d4Sjsg const struct drm_connector_state *conn_state, u32 level)
1608b35a56d4Sjsg {
1609b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
1610b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1611b35a56d4Sjsg
1612b35a56d4Sjsg panel->backlight.pwm_funcs->enable(crtc_state, conn_state,
16131bb76ff1Sjsg intel_backlight_invert_pwm_level(connector, level));
1614b35a56d4Sjsg }
1615b35a56d4Sjsg
intel_pwm_disable_backlight(const struct drm_connector_state * conn_state,u32 level)1616b35a56d4Sjsg static void intel_pwm_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
1617b35a56d4Sjsg {
1618b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
1619b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1620b35a56d4Sjsg
1621b35a56d4Sjsg panel->backlight.pwm_funcs->disable(conn_state,
16221bb76ff1Sjsg intel_backlight_invert_pwm_level(connector, level));
1623b35a56d4Sjsg }
1624b35a56d4Sjsg
intel_pwm_setup_backlight(struct intel_connector * connector,enum pipe pipe)1625b35a56d4Sjsg static int intel_pwm_setup_backlight(struct intel_connector *connector, enum pipe pipe)
1626b35a56d4Sjsg {
1627b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1628f005ef32Sjsg int ret;
1629b35a56d4Sjsg
1630f005ef32Sjsg ret = panel->backlight.pwm_funcs->setup(connector, pipe);
1631b35a56d4Sjsg if (ret < 0)
1632b35a56d4Sjsg return ret;
1633b35a56d4Sjsg
1634b35a56d4Sjsg panel->backlight.min = panel->backlight.pwm_level_min;
1635b35a56d4Sjsg panel->backlight.max = panel->backlight.pwm_level_max;
1636b35a56d4Sjsg panel->backlight.level = intel_pwm_get_backlight(connector, pipe);
1637b35a56d4Sjsg panel->backlight.enabled = panel->backlight.pwm_enabled;
1638b35a56d4Sjsg
1639b35a56d4Sjsg return 0;
1640b35a56d4Sjsg }
1641b35a56d4Sjsg
intel_backlight_update(struct intel_atomic_state * state,struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)16421bb76ff1Sjsg void intel_backlight_update(struct intel_atomic_state *state,
1643b35a56d4Sjsg struct intel_encoder *encoder,
1644b35a56d4Sjsg const struct intel_crtc_state *crtc_state,
1645b35a56d4Sjsg const struct drm_connector_state *conn_state)
1646b35a56d4Sjsg {
1647b35a56d4Sjsg struct intel_connector *connector = to_intel_connector(conn_state->connector);
1648f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1649b35a56d4Sjsg struct intel_panel *panel = &connector->panel;
1650b35a56d4Sjsg
1651b35a56d4Sjsg if (!panel->backlight.present)
1652b35a56d4Sjsg return;
1653b35a56d4Sjsg
1654f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
1655b35a56d4Sjsg if (!panel->backlight.enabled)
16561bb76ff1Sjsg __intel_backlight_enable(crtc_state, conn_state);
1657b35a56d4Sjsg
1658f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
1659b35a56d4Sjsg }
1660b35a56d4Sjsg
intel_backlight_setup(struct intel_connector * connector,enum pipe pipe)16611bb76ff1Sjsg int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
1662b35a56d4Sjsg {
1663f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
16641bb76ff1Sjsg struct intel_panel *panel = &connector->panel;
1665b35a56d4Sjsg int ret;
1666b35a56d4Sjsg
16671bb76ff1Sjsg if (!connector->panel.vbt.backlight.present) {
1668f005ef32Sjsg if (intel_has_quirk(i915, QUIRK_BACKLIGHT_PRESENT)) {
1669f005ef32Sjsg drm_dbg_kms(&i915->drm,
1670f005ef32Sjsg "[CONNECTOR:%d:%s] no backlight present per VBT, but present per quirk\n",
1671f005ef32Sjsg connector->base.base.id, connector->base.name);
1672b35a56d4Sjsg } else {
1673f005ef32Sjsg drm_dbg_kms(&i915->drm,
1674f005ef32Sjsg "[CONNECTOR:%d:%s] no backlight present per VBT\n",
1675f005ef32Sjsg connector->base.base.id, connector->base.name);
1676b35a56d4Sjsg return 0;
1677b35a56d4Sjsg }
1678b35a56d4Sjsg }
1679b35a56d4Sjsg
1680b35a56d4Sjsg /* ensure intel_panel has been initialized first */
1681f005ef32Sjsg if (drm_WARN_ON(&i915->drm, !panel->backlight.funcs))
1682b35a56d4Sjsg return -ENODEV;
1683b35a56d4Sjsg
1684b35a56d4Sjsg /* set level and max in panel struct */
1685f005ef32Sjsg mutex_lock(&i915->display.backlight.lock);
16861bb76ff1Sjsg ret = panel->backlight.funcs->setup(connector, pipe);
1687f005ef32Sjsg mutex_unlock(&i915->display.backlight.lock);
1688b35a56d4Sjsg
1689b35a56d4Sjsg if (ret) {
1690f005ef32Sjsg drm_dbg_kms(&i915->drm,
1691f005ef32Sjsg "[CONNECTOR:%d:%s] failed to setup backlight\n",
1692f005ef32Sjsg connector->base.base.id, connector->base.name);
1693b35a56d4Sjsg return ret;
1694b35a56d4Sjsg }
1695b35a56d4Sjsg
1696b35a56d4Sjsg panel->backlight.present = true;
1697b35a56d4Sjsg
1698f005ef32Sjsg drm_dbg_kms(&i915->drm,
1699f005ef32Sjsg "[CONNECTOR:%d:%s] backlight initialized, %s, brightness %u/%u\n",
1700f005ef32Sjsg connector->base.base.id, connector->base.name,
17011bb76ff1Sjsg str_enabled_disabled(panel->backlight.enabled),
1702b35a56d4Sjsg panel->backlight.level, panel->backlight.max);
1703b35a56d4Sjsg
1704b35a56d4Sjsg return 0;
1705b35a56d4Sjsg }
1706b35a56d4Sjsg
intel_backlight_destroy(struct intel_panel * panel)17071bb76ff1Sjsg void intel_backlight_destroy(struct intel_panel *panel)
1708b35a56d4Sjsg {
1709b35a56d4Sjsg /* dispose of the pwm */
1710b35a56d4Sjsg if (panel->backlight.pwm)
1711b35a56d4Sjsg pwm_put(panel->backlight.pwm);
1712b35a56d4Sjsg
1713b35a56d4Sjsg panel->backlight.present = false;
1714b35a56d4Sjsg }
1715b35a56d4Sjsg
1716b35a56d4Sjsg static const struct intel_panel_bl_funcs bxt_pwm_funcs = {
1717b35a56d4Sjsg .setup = bxt_setup_backlight,
1718b35a56d4Sjsg .enable = bxt_enable_backlight,
1719b35a56d4Sjsg .disable = bxt_disable_backlight,
1720b35a56d4Sjsg .set = bxt_set_backlight,
1721b35a56d4Sjsg .get = bxt_get_backlight,
1722b35a56d4Sjsg .hz_to_pwm = bxt_hz_to_pwm,
1723b35a56d4Sjsg };
1724b35a56d4Sjsg
1725b35a56d4Sjsg static const struct intel_panel_bl_funcs cnp_pwm_funcs = {
1726b35a56d4Sjsg .setup = cnp_setup_backlight,
1727b35a56d4Sjsg .enable = cnp_enable_backlight,
1728b35a56d4Sjsg .disable = cnp_disable_backlight,
1729b35a56d4Sjsg .set = bxt_set_backlight,
1730b35a56d4Sjsg .get = bxt_get_backlight,
1731b35a56d4Sjsg .hz_to_pwm = cnp_hz_to_pwm,
1732b35a56d4Sjsg };
1733b35a56d4Sjsg
1734b35a56d4Sjsg static const struct intel_panel_bl_funcs lpt_pwm_funcs = {
1735b35a56d4Sjsg .setup = lpt_setup_backlight,
1736b35a56d4Sjsg .enable = lpt_enable_backlight,
1737b35a56d4Sjsg .disable = lpt_disable_backlight,
1738b35a56d4Sjsg .set = lpt_set_backlight,
1739b35a56d4Sjsg .get = lpt_get_backlight,
1740b35a56d4Sjsg .hz_to_pwm = lpt_hz_to_pwm,
1741b35a56d4Sjsg };
1742b35a56d4Sjsg
1743b35a56d4Sjsg static const struct intel_panel_bl_funcs spt_pwm_funcs = {
1744b35a56d4Sjsg .setup = lpt_setup_backlight,
1745b35a56d4Sjsg .enable = lpt_enable_backlight,
1746b35a56d4Sjsg .disable = lpt_disable_backlight,
1747b35a56d4Sjsg .set = lpt_set_backlight,
1748b35a56d4Sjsg .get = lpt_get_backlight,
1749b35a56d4Sjsg .hz_to_pwm = spt_hz_to_pwm,
1750b35a56d4Sjsg };
1751b35a56d4Sjsg
1752b35a56d4Sjsg static const struct intel_panel_bl_funcs pch_pwm_funcs = {
1753b35a56d4Sjsg .setup = pch_setup_backlight,
1754b35a56d4Sjsg .enable = pch_enable_backlight,
1755b35a56d4Sjsg .disable = pch_disable_backlight,
1756b35a56d4Sjsg .set = pch_set_backlight,
1757b35a56d4Sjsg .get = pch_get_backlight,
1758b35a56d4Sjsg .hz_to_pwm = pch_hz_to_pwm,
1759b35a56d4Sjsg };
1760b35a56d4Sjsg
1761b35a56d4Sjsg static const struct intel_panel_bl_funcs ext_pwm_funcs = {
1762b35a56d4Sjsg .setup = ext_pwm_setup_backlight,
1763b35a56d4Sjsg .enable = ext_pwm_enable_backlight,
1764b35a56d4Sjsg .disable = ext_pwm_disable_backlight,
1765b35a56d4Sjsg .set = ext_pwm_set_backlight,
1766b35a56d4Sjsg .get = ext_pwm_get_backlight,
1767b35a56d4Sjsg };
1768b35a56d4Sjsg
1769b35a56d4Sjsg static const struct intel_panel_bl_funcs vlv_pwm_funcs = {
1770b35a56d4Sjsg .setup = vlv_setup_backlight,
1771b35a56d4Sjsg .enable = vlv_enable_backlight,
1772b35a56d4Sjsg .disable = vlv_disable_backlight,
1773b35a56d4Sjsg .set = vlv_set_backlight,
1774b35a56d4Sjsg .get = vlv_get_backlight,
1775b35a56d4Sjsg .hz_to_pwm = vlv_hz_to_pwm,
1776b35a56d4Sjsg };
1777b35a56d4Sjsg
1778b35a56d4Sjsg static const struct intel_panel_bl_funcs i965_pwm_funcs = {
1779b35a56d4Sjsg .setup = i965_setup_backlight,
1780b35a56d4Sjsg .enable = i965_enable_backlight,
1781b35a56d4Sjsg .disable = i965_disable_backlight,
1782b35a56d4Sjsg .set = i9xx_set_backlight,
1783b35a56d4Sjsg .get = i9xx_get_backlight,
1784b35a56d4Sjsg .hz_to_pwm = i965_hz_to_pwm,
1785b35a56d4Sjsg };
1786b35a56d4Sjsg
1787b35a56d4Sjsg static const struct intel_panel_bl_funcs i9xx_pwm_funcs = {
1788b35a56d4Sjsg .setup = i9xx_setup_backlight,
1789b35a56d4Sjsg .enable = i9xx_enable_backlight,
1790b35a56d4Sjsg .disable = i9xx_disable_backlight,
1791b35a56d4Sjsg .set = i9xx_set_backlight,
1792b35a56d4Sjsg .get = i9xx_get_backlight,
1793b35a56d4Sjsg .hz_to_pwm = i9xx_hz_to_pwm,
1794b35a56d4Sjsg };
1795b35a56d4Sjsg
1796b35a56d4Sjsg static const struct intel_panel_bl_funcs pwm_bl_funcs = {
1797b35a56d4Sjsg .setup = intel_pwm_setup_backlight,
1798b35a56d4Sjsg .enable = intel_pwm_enable_backlight,
1799b35a56d4Sjsg .disable = intel_pwm_disable_backlight,
1800b35a56d4Sjsg .set = intel_pwm_set_backlight,
1801b35a56d4Sjsg .get = intel_pwm_get_backlight,
1802b35a56d4Sjsg };
1803b35a56d4Sjsg
1804b35a56d4Sjsg /* Set up chip specific backlight functions */
intel_backlight_init_funcs(struct intel_panel * panel)18051bb76ff1Sjsg void intel_backlight_init_funcs(struct intel_panel *panel)
1806b35a56d4Sjsg {
1807b35a56d4Sjsg struct intel_connector *connector =
1808b35a56d4Sjsg container_of(panel, struct intel_connector, panel);
1809f005ef32Sjsg struct drm_i915_private *i915 = to_i915(connector->base.dev);
1810b35a56d4Sjsg
1811b35a56d4Sjsg if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
1812b35a56d4Sjsg intel_dsi_dcs_init_backlight_funcs(connector) == 0)
1813b35a56d4Sjsg return;
1814b35a56d4Sjsg
1815f005ef32Sjsg if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) {
1816b35a56d4Sjsg panel->backlight.pwm_funcs = &bxt_pwm_funcs;
1817f005ef32Sjsg } else if (INTEL_PCH_TYPE(i915) >= PCH_CNP) {
1818b35a56d4Sjsg panel->backlight.pwm_funcs = &cnp_pwm_funcs;
1819f005ef32Sjsg } else if (INTEL_PCH_TYPE(i915) >= PCH_LPT) {
1820f005ef32Sjsg if (HAS_PCH_LPT(i915))
1821b35a56d4Sjsg panel->backlight.pwm_funcs = &lpt_pwm_funcs;
1822b35a56d4Sjsg else
1823b35a56d4Sjsg panel->backlight.pwm_funcs = &spt_pwm_funcs;
1824f005ef32Sjsg } else if (HAS_PCH_SPLIT(i915)) {
1825b35a56d4Sjsg panel->backlight.pwm_funcs = &pch_pwm_funcs;
1826f005ef32Sjsg } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
1827b35a56d4Sjsg if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
1828b35a56d4Sjsg panel->backlight.pwm_funcs = &ext_pwm_funcs;
1829b35a56d4Sjsg } else {
1830b35a56d4Sjsg panel->backlight.pwm_funcs = &vlv_pwm_funcs;
1831b35a56d4Sjsg }
1832f005ef32Sjsg } else if (DISPLAY_VER(i915) == 4) {
1833b35a56d4Sjsg panel->backlight.pwm_funcs = &i965_pwm_funcs;
1834b35a56d4Sjsg } else {
1835b35a56d4Sjsg panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
1836b35a56d4Sjsg }
1837b35a56d4Sjsg
18381bb76ff1Sjsg if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) {
18391bb76ff1Sjsg if (intel_dp_aux_init_backlight_funcs(connector) == 0)
1840b35a56d4Sjsg return;
1841b35a56d4Sjsg
1842f005ef32Sjsg if (!intel_has_quirk(i915, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
18431bb76ff1Sjsg connector->panel.backlight.power = intel_pps_backlight_power;
18441bb76ff1Sjsg }
18451bb76ff1Sjsg
1846b35a56d4Sjsg /* We're using a standard PWM backlight interface */
1847b35a56d4Sjsg panel->backlight.funcs = &pwm_bl_funcs;
1848b35a56d4Sjsg }
1849