2 * Copyright © 2015 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 #include "intel_display_types.h"
26 #include "intel_dp_aux_backlight.h"
28 static void set_aux_backlight_enable(struct intel_dp
*intel_dp
, bool enable
)
30 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
33 /* Early return when display use other mechanism to enable backlight. */
34 if (!(intel_dp
->edp_dpcd
[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP
))
37 if (drm_dp_dpcd_readb(&intel_dp
->aux
, DP_EDP_DISPLAY_CONTROL_REGISTER
,
39 drm_dbg_kms(&i915
->drm
, "Failed to read DPCD register 0x%x\n",
40 DP_EDP_DISPLAY_CONTROL_REGISTER
);
44 reg_val
|= DP_EDP_BACKLIGHT_ENABLE
;
46 reg_val
&= ~(DP_EDP_BACKLIGHT_ENABLE
);
48 if (drm_dp_dpcd_writeb(&intel_dp
->aux
, DP_EDP_DISPLAY_CONTROL_REGISTER
,
50 drm_dbg_kms(&i915
->drm
, "Failed to %s aux backlight\n",
51 enable
? "enable" : "disable");
55 static bool intel_dp_aux_backlight_dpcd_mode(struct intel_connector
*connector
)
57 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
58 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
61 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
62 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
,
64 drm_dbg_kms(&i915
->drm
,
65 "Failed to read the DPCD register 0x%x\n",
66 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
);
70 return (mode_reg
& DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
) ==
71 DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
;
75 * Read the current backlight value from DPCD register(s) based
76 * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
78 static u32
intel_dp_aux_get_backlight(struct intel_connector
*connector
)
80 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
81 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
82 u8 read_val
[2] = { 0x0 };
86 * If we're not in DPCD control mode yet, the programmed brightness
87 * value is meaningless and we should assume max brightness
89 if (!intel_dp_aux_backlight_dpcd_mode(connector
))
90 return connector
->panel
.backlight
.max
;
92 if (drm_dp_dpcd_read(&intel_dp
->aux
, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
,
93 &read_val
, sizeof(read_val
)) < 0) {
94 drm_dbg_kms(&i915
->drm
, "Failed to read DPCD register 0x%x\n",
95 DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
);
99 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
)
100 level
= (read_val
[0] << 8 | read_val
[1]);
106 * Sends the current backlight level over the aux channel, checking if its using
107 * 8-bit or 16 bit value (MSB and LSB)
110 intel_dp_aux_set_backlight(const struct drm_connector_state
*conn_state
, u32 level
)
112 struct intel_connector
*connector
= to_intel_connector(conn_state
->connector
);
113 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
114 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
115 u8 vals
[2] = { 0x0 };
119 /* Write the MSB and/or LSB */
120 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
) {
121 vals
[0] = (level
& 0xFF00) >> 8;
122 vals
[1] = (level
& 0xFF);
124 if (drm_dp_dpcd_write(&intel_dp
->aux
, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
,
125 vals
, sizeof(vals
)) < 0) {
126 drm_dbg_kms(&i915
->drm
,
127 "Failed to write aux backlight level\n");
133 * Set PWM Frequency divider to match desired frequency in vbt.
134 * The PWM Frequency is calculated as 27Mhz / (F x P).
135 * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the
136 * EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h)
137 * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the
138 * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h)
140 static bool intel_dp_aux_set_pwm_freq(struct intel_connector
*connector
)
142 struct drm_i915_private
*dev_priv
= to_i915(connector
->base
.dev
);
143 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
144 const u8 pn
= connector
->panel
.backlight
.pwmgen_bit_count
;
145 int freq
, fxp
, f
, fxp_actual
, fxp_min
, fxp_max
;
147 freq
= dev_priv
->vbt
.backlight
.pwm_freq_hz
;
149 drm_dbg_kms(&dev_priv
->drm
,
150 "Use panel default backlight frequency\n");
154 fxp
= DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ
), freq
);
155 f
= clamp(DIV_ROUND_CLOSEST(fxp
, 1 << pn
), 1, 255);
156 fxp_actual
= f
<< pn
;
158 /* Ensure frequency is within 25% of desired value */
159 fxp_min
= DIV_ROUND_CLOSEST(fxp
* 3, 4);
160 fxp_max
= DIV_ROUND_CLOSEST(fxp
* 5, 4);
162 if (fxp_min
> fxp_actual
|| fxp_actual
> fxp_max
) {
163 drm_dbg_kms(&dev_priv
->drm
, "Actual frequency out of range\n");
167 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
168 DP_EDP_BACKLIGHT_FREQ_SET
, (u8
) f
) < 0) {
169 drm_dbg_kms(&dev_priv
->drm
,
170 "Failed to write aux backlight freq\n");
176 static void intel_dp_aux_enable_backlight(const struct intel_crtc_state
*crtc_state
,
177 const struct drm_connector_state
*conn_state
)
179 struct intel_connector
*connector
= to_intel_connector(conn_state
->connector
);
180 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
181 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
182 struct intel_panel
*panel
= &connector
->panel
;
183 u8 dpcd_buf
, new_dpcd_buf
, edp_backlight_mode
;
185 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
186 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
, &dpcd_buf
) != 1) {
187 drm_dbg_kms(&i915
->drm
, "Failed to read DPCD register 0x%x\n",
188 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
);
192 new_dpcd_buf
= dpcd_buf
;
193 edp_backlight_mode
= dpcd_buf
& DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
;
195 switch (edp_backlight_mode
) {
196 case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM
:
197 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET
:
198 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT
:
199 new_dpcd_buf
&= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
;
200 new_dpcd_buf
|= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
;
202 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
203 DP_EDP_PWMGEN_BIT_COUNT
,
204 panel
->backlight
.pwmgen_bit_count
) < 0)
205 drm_dbg_kms(&i915
->drm
,
206 "Failed to write aux pwmgen bit count\n");
210 /* Do nothing when it is already DPCD mode */
211 case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
:
216 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP
)
217 if (intel_dp_aux_set_pwm_freq(connector
))
218 new_dpcd_buf
|= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE
;
220 if (new_dpcd_buf
!= dpcd_buf
) {
221 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
222 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
, new_dpcd_buf
) < 0) {
223 drm_dbg_kms(&i915
->drm
,
224 "Failed to write aux backlight mode\n");
228 intel_dp_aux_set_backlight(conn_state
,
229 connector
->panel
.backlight
.level
);
230 set_aux_backlight_enable(intel_dp
, true);
233 static void intel_dp_aux_disable_backlight(const struct drm_connector_state
*old_conn_state
)
235 set_aux_backlight_enable(enc_to_intel_dp(to_intel_encoder(old_conn_state
->best_encoder
)),
239 static u32
intel_dp_aux_calc_max_backlight(struct intel_connector
*connector
)
241 struct drm_i915_private
*i915
= to_i915(connector
->base
.dev
);
242 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
243 struct intel_panel
*panel
= &connector
->panel
;
244 u32 max_backlight
= 0;
245 int freq
, fxp
, fxp_min
, fxp_max
, fxp_actual
, f
= 1;
246 u8 pn
, pn_min
, pn_max
;
248 if (drm_dp_dpcd_readb(&intel_dp
->aux
, DP_EDP_PWMGEN_BIT_COUNT
, &pn
) == 1) {
249 pn
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
250 max_backlight
= (1 << pn
) - 1;
253 /* Find desired value of (F x P)
254 * Note that, if F x P is out of supported range, the maximum value or
255 * minimum value will applied automatically. So no need to check that.
257 freq
= i915
->vbt
.backlight
.pwm_freq_hz
;
258 drm_dbg_kms(&i915
->drm
, "VBT defined backlight frequency %u Hz\n",
261 drm_dbg_kms(&i915
->drm
,
262 "Use panel default backlight frequency\n");
263 return max_backlight
;
266 fxp
= DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ
), freq
);
268 /* Use highest possible value of Pn for more granularity of brightness
269 * adjustment while satifying the conditions below.
270 * - Pn is in the range of Pn_min and Pn_max
271 * - F is in the range of 1 and 255
272 * - FxP is within 25% of desired value.
273 * Note: 25% is arbitrary value and may need some tweak.
275 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
276 DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN
, &pn_min
) != 1) {
277 drm_dbg_kms(&i915
->drm
,
278 "Failed to read pwmgen bit count cap min\n");
279 return max_backlight
;
281 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
282 DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX
, &pn_max
) != 1) {
283 drm_dbg_kms(&i915
->drm
,
284 "Failed to read pwmgen bit count cap max\n");
285 return max_backlight
;
287 pn_min
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
288 pn_max
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
290 fxp_min
= DIV_ROUND_CLOSEST(fxp
* 3, 4);
291 fxp_max
= DIV_ROUND_CLOSEST(fxp
* 5, 4);
292 if (fxp_min
< (1 << pn_min
) || (255 << pn_max
) < fxp_max
) {
293 drm_dbg_kms(&i915
->drm
,
294 "VBT defined backlight frequency out of range\n");
295 return max_backlight
;
298 for (pn
= pn_max
; pn
>= pn_min
; pn
--) {
299 f
= clamp(DIV_ROUND_CLOSEST(fxp
, 1 << pn
), 1, 255);
300 fxp_actual
= f
<< pn
;
301 if (fxp_min
<= fxp_actual
&& fxp_actual
<= fxp_max
)
305 drm_dbg_kms(&i915
->drm
, "Using eDP pwmgen bit count of %d\n", pn
);
306 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
307 DP_EDP_PWMGEN_BIT_COUNT
, pn
) < 0) {
308 drm_dbg_kms(&i915
->drm
,
309 "Failed to write aux pwmgen bit count\n");
310 return max_backlight
;
312 panel
->backlight
.pwmgen_bit_count
= pn
;
314 max_backlight
= (1 << pn
) - 1;
316 return max_backlight
;
319 static int intel_dp_aux_setup_backlight(struct intel_connector
*connector
,
322 struct intel_panel
*panel
= &connector
->panel
;
324 panel
->backlight
.max
= intel_dp_aux_calc_max_backlight(connector
);
325 if (!panel
->backlight
.max
)
328 panel
->backlight
.min
= 0;
329 panel
->backlight
.level
= intel_dp_aux_get_backlight(connector
);
330 panel
->backlight
.enabled
= intel_dp_aux_backlight_dpcd_mode(connector
) &&
331 panel
->backlight
.level
!= 0;
337 intel_dp_aux_display_control_capable(struct intel_connector
*connector
)
339 struct intel_dp
*intel_dp
= intel_attached_dp(connector
);
340 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
342 /* Check the eDP Display control capabilities registers to determine if
343 * the panel can support backlight control over the aux channel
345 if (intel_dp
->edp_dpcd
[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP
&&
346 (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP
)) {
347 drm_dbg_kms(&i915
->drm
, "AUX Backlight Control Supported!\n");
353 int intel_dp_aux_init_backlight_funcs(struct intel_connector
*intel_connector
)
355 struct intel_panel
*panel
= &intel_connector
->panel
;
356 struct intel_dp
*intel_dp
= enc_to_intel_dp(intel_connector
->encoder
);
357 struct drm_i915_private
*i915
= dp_to_i915(intel_dp
);
359 if (i915
->params
.enable_dpcd_backlight
== 0 ||
360 !intel_dp_aux_display_control_capable(intel_connector
))
364 * There are a lot of machines that don't advertise the backlight
365 * control interface to use properly in their VBIOS, :\
367 if (i915
->vbt
.backlight
.type
!=
368 INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE
&&
369 i915
->params
.enable_dpcd_backlight
!= 1 &&
370 !drm_dp_has_quirk(&intel_dp
->desc
, intel_dp
->edid_quirks
,
371 DP_QUIRK_FORCE_DPCD_BACKLIGHT
)) {
373 "Panel advertises DPCD backlight support, but "
374 "VBT disagrees. If your backlight controls "
375 "don't work try booting with "
376 "i915.enable_dpcd_backlight=1. If your machine "
377 "needs this, please file a _new_ bug report on "
378 "drm/i915, see " FDO_BUG_URL
" for details.\n");
382 panel
->backlight
.setup
= intel_dp_aux_setup_backlight
;
383 panel
->backlight
.enable
= intel_dp_aux_enable_backlight
;
384 panel
->backlight
.disable
= intel_dp_aux_disable_backlight
;
385 panel
->backlight
.set
= intel_dp_aux_set_backlight
;
386 panel
->backlight
.get
= intel_dp_aux_get_backlight
;