xref: /openbsd-src/sys/dev/pci/drm/i915/display/intel_backlight.c (revision 2e4fb78a2a7ee85037db13f8fc231c50b15cc442)
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