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
)
32 /* Early return when display use other mechanism to enable backlight. */
33 if (!(intel_dp
->edp_dpcd
[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP
))
36 if (drm_dp_dpcd_readb(&intel_dp
->aux
, DP_EDP_DISPLAY_CONTROL_REGISTER
,
38 DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
39 DP_EDP_DISPLAY_CONTROL_REGISTER
);
43 reg_val
|= DP_EDP_BACKLIGHT_ENABLE
;
45 reg_val
&= ~(DP_EDP_BACKLIGHT_ENABLE
);
47 if (drm_dp_dpcd_writeb(&intel_dp
->aux
, DP_EDP_DISPLAY_CONTROL_REGISTER
,
49 DRM_DEBUG_KMS("Failed to %s aux backlight\n",
50 enable
? "enable" : "disable");
55 * Read the current backlight value from DPCD register(s) based
56 * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
58 static u32
intel_dp_aux_get_backlight(struct intel_connector
*connector
)
60 struct intel_dp
*intel_dp
= enc_to_intel_dp(connector
->encoder
);
61 u8 read_val
[2] = { 0x0 };
64 if (drm_dp_dpcd_read(&intel_dp
->aux
, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
,
65 &read_val
, sizeof(read_val
)) < 0) {
66 DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
67 DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
);
71 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
)
72 level
= (read_val
[0] << 8 | read_val
[1]);
78 * Sends the current backlight level over the aux channel, checking if its using
79 * 8-bit or 16 bit value (MSB and LSB)
82 intel_dp_aux_set_backlight(const struct drm_connector_state
*conn_state
, u32 level
)
84 struct intel_connector
*connector
= to_intel_connector(conn_state
->connector
);
85 struct intel_dp
*intel_dp
= enc_to_intel_dp(connector
->encoder
);
90 /* Write the MSB and/or LSB */
91 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
) {
92 vals
[0] = (level
& 0xFF00) >> 8;
93 vals
[1] = (level
& 0xFF);
95 if (drm_dp_dpcd_write(&intel_dp
->aux
, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
,
96 vals
, sizeof(vals
)) < 0) {
97 DRM_DEBUG_KMS("Failed to write aux backlight level\n");
103 * Set PWM Frequency divider to match desired frequency in vbt.
104 * The PWM Frequency is calculated as 27Mhz / (F x P).
105 * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the
106 * EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h)
107 * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the
108 * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h)
110 static bool intel_dp_aux_set_pwm_freq(struct intel_connector
*connector
)
112 struct drm_i915_private
*dev_priv
= to_i915(connector
->base
.dev
);
113 struct intel_dp
*intel_dp
= enc_to_intel_dp(connector
->encoder
);
114 int freq
, fxp
, fxp_min
, fxp_max
, fxp_actual
, f
= 1;
115 u8 pn
, pn_min
, pn_max
;
117 /* Find desired value of (F x P)
118 * Note that, if F x P is out of supported range, the maximum value or
119 * minimum value will applied automatically. So no need to check that.
121 freq
= dev_priv
->vbt
.backlight
.pwm_freq_hz
;
122 DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq
);
124 DRM_DEBUG_KMS("Use panel default backlight frequency\n");
128 fxp
= DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ
), freq
);
130 /* Use highest possible value of Pn for more granularity of brightness
131 * adjustment while satifying the conditions below.
132 * - Pn is in the range of Pn_min and Pn_max
133 * - F is in the range of 1 and 255
134 * - FxP is within 25% of desired value.
135 * Note: 25% is arbitrary value and may need some tweak.
137 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
138 DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN
, &pn_min
) != 1) {
139 DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n");
142 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
143 DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX
, &pn_max
) != 1) {
144 DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n");
147 pn_min
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
148 pn_max
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
150 fxp_min
= DIV_ROUND_CLOSEST(fxp
* 3, 4);
151 fxp_max
= DIV_ROUND_CLOSEST(fxp
* 5, 4);
152 if (fxp_min
< (1 << pn_min
) || (255 << pn_max
) < fxp_max
) {
153 DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n");
157 for (pn
= pn_max
; pn
>= pn_min
; pn
--) {
158 f
= clamp(DIV_ROUND_CLOSEST(fxp
, 1 << pn
), 1, 255);
159 fxp_actual
= f
<< pn
;
160 if (fxp_min
<= fxp_actual
&& fxp_actual
<= fxp_max
)
164 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
165 DP_EDP_PWMGEN_BIT_COUNT
, pn
) < 0) {
166 DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
169 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
170 DP_EDP_BACKLIGHT_FREQ_SET
, (u8
) f
) < 0) {
171 DRM_DEBUG_KMS("Failed to write aux backlight freq\n");
177 static void intel_dp_aux_enable_backlight(const struct intel_crtc_state
*crtc_state
,
178 const struct drm_connector_state
*conn_state
)
180 struct intel_connector
*connector
= to_intel_connector(conn_state
->connector
);
181 struct intel_dp
*intel_dp
= enc_to_intel_dp(connector
->encoder
);
182 u8 dpcd_buf
, new_dpcd_buf
, edp_backlight_mode
;
184 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
185 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
, &dpcd_buf
) != 1) {
186 DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
187 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
);
191 new_dpcd_buf
= dpcd_buf
;
192 edp_backlight_mode
= dpcd_buf
& DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
;
194 switch (edp_backlight_mode
) {
195 case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM
:
196 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET
:
197 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT
:
198 new_dpcd_buf
&= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
;
199 new_dpcd_buf
|= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
;
202 /* Do nothing when it is already DPCD mode */
203 case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
:
208 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP
)
209 if (intel_dp_aux_set_pwm_freq(connector
))
210 new_dpcd_buf
|= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE
;
212 if (new_dpcd_buf
!= dpcd_buf
) {
213 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
214 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
, new_dpcd_buf
) < 0) {
215 DRM_DEBUG_KMS("Failed to write aux backlight mode\n");
219 set_aux_backlight_enable(intel_dp
, true);
220 intel_dp_aux_set_backlight(conn_state
, connector
->panel
.backlight
.level
);
223 static void intel_dp_aux_disable_backlight(const struct drm_connector_state
*old_conn_state
)
225 set_aux_backlight_enable(enc_to_intel_dp(to_intel_encoder(old_conn_state
->best_encoder
)),
229 static int intel_dp_aux_setup_backlight(struct intel_connector
*connector
,
232 struct intel_dp
*intel_dp
= enc_to_intel_dp(connector
->encoder
);
233 struct intel_panel
*panel
= &connector
->panel
;
235 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
)
236 panel
->backlight
.max
= 0xFFFF;
238 panel
->backlight
.max
= 0xFF;
240 panel
->backlight
.min
= 0;
241 panel
->backlight
.level
= intel_dp_aux_get_backlight(connector
);
243 panel
->backlight
.enabled
= panel
->backlight
.level
!= 0;
249 intel_dp_aux_display_control_capable(struct intel_connector
*connector
)
251 struct intel_dp
*intel_dp
= enc_to_intel_dp(connector
->encoder
);
253 /* Check the eDP Display control capabilities registers to determine if
254 * the panel can support backlight control over the aux channel
256 if (intel_dp
->edp_dpcd
[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP
&&
257 (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP
) &&
258 !(intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP
)) {
259 DRM_DEBUG_KMS("AUX Backlight Control Supported!\n");
265 int intel_dp_aux_init_backlight_funcs(struct intel_connector
*intel_connector
)
267 struct intel_panel
*panel
= &intel_connector
->panel
;
268 struct drm_i915_private
*dev_priv
= to_i915(intel_connector
->base
.dev
);
270 if (i915_modparams
.enable_dpcd_backlight
== 0 ||
271 (i915_modparams
.enable_dpcd_backlight
== -1 &&
272 dev_priv
->vbt
.backlight
.type
!= INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE
))
275 if (!intel_dp_aux_display_control_capable(intel_connector
))
278 panel
->backlight
.setup
= intel_dp_aux_setup_backlight
;
279 panel
->backlight
.enable
= intel_dp_aux_enable_backlight
;
280 panel
->backlight
.disable
= intel_dp_aux_disable_backlight
;
281 panel
->backlight
.set
= intel_dp_aux_set_backlight
;
282 panel
->backlight
.get
= intel_dp_aux_get_backlight
;