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_drv.h"
27 static void set_aux_backlight_enable(struct intel_dp
*intel_dp
, bool enable
)
31 /* Early return when display use other mechanism to enable backlight. */
32 if (!(intel_dp
->edp_dpcd
[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP
))
35 if (drm_dp_dpcd_readb(&intel_dp
->aux
, DP_EDP_DISPLAY_CONTROL_REGISTER
,
37 DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
38 DP_EDP_DISPLAY_CONTROL_REGISTER
);
42 reg_val
|= DP_EDP_BACKLIGHT_ENABLE
;
44 reg_val
&= ~(DP_EDP_BACKLIGHT_ENABLE
);
46 if (drm_dp_dpcd_writeb(&intel_dp
->aux
, DP_EDP_DISPLAY_CONTROL_REGISTER
,
48 DRM_DEBUG_KMS("Failed to %s aux backlight\n",
49 enable
? "enable" : "disable");
54 * Read the current backlight value from DPCD register(s) based
55 * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported
57 static uint32_t intel_dp_aux_get_backlight(struct intel_connector
*connector
)
59 struct intel_dp
*intel_dp
= enc_to_intel_dp(&connector
->encoder
->base
);
60 uint8_t read_val
[2] = { 0x0 };
63 if (drm_dp_dpcd_read(&intel_dp
->aux
, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
,
64 &read_val
, sizeof(read_val
)) < 0) {
65 DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
66 DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
);
70 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
)
71 level
= (read_val
[0] << 8 | read_val
[1]);
77 * Sends the current backlight level over the aux channel, checking if its using
78 * 8-bit or 16 bit value (MSB and LSB)
81 intel_dp_aux_set_backlight(const struct drm_connector_state
*conn_state
, u32 level
)
83 struct intel_connector
*connector
= to_intel_connector(conn_state
->connector
);
84 struct intel_dp
*intel_dp
= enc_to_intel_dp(&connector
->encoder
->base
);
85 uint8_t vals
[2] = { 0x0 };
89 /* Write the MSB and/or LSB */
90 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
) {
91 vals
[0] = (level
& 0xFF00) >> 8;
92 vals
[1] = (level
& 0xFF);
94 if (drm_dp_dpcd_write(&intel_dp
->aux
, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB
,
95 vals
, sizeof(vals
)) < 0) {
96 DRM_DEBUG_KMS("Failed to write aux backlight level\n");
102 * Set PWM Frequency divider to match desired frequency in vbt.
103 * The PWM Frequency is calculated as 27Mhz / (F x P).
104 * - Where F = PWM Frequency Pre-Divider value programmed by field 7:0 of the
105 * EDP_BACKLIGHT_FREQ_SET register (DPCD Address 00728h)
106 * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the
107 * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h)
109 static bool intel_dp_aux_set_pwm_freq(struct intel_connector
*connector
)
111 struct drm_i915_private
*dev_priv
= to_i915(connector
->base
.dev
);
112 struct intel_dp
*intel_dp
= enc_to_intel_dp(&connector
->encoder
->base
);
113 int freq
, fxp
, fxp_min
, fxp_max
, fxp_actual
, f
= 1;
114 u8 pn
, pn_min
, pn_max
;
116 /* Find desired value of (F x P)
117 * Note that, if F x P is out of supported range, the maximum value or
118 * minimum value will applied automatically. So no need to check that.
120 freq
= dev_priv
->vbt
.backlight
.pwm_freq_hz
;
121 DRM_DEBUG_KMS("VBT defined backlight frequency %u Hz\n", freq
);
123 DRM_DEBUG_KMS("Use panel default backlight frequency\n");
127 fxp
= DIV_ROUND_CLOSEST(KHz(DP_EDP_BACKLIGHT_FREQ_BASE_KHZ
), freq
);
129 /* Use highest possible value of Pn for more granularity of brightness
130 * adjustment while satifying the conditions below.
131 * - Pn is in the range of Pn_min and Pn_max
132 * - F is in the range of 1 and 255
133 * - FxP is within 25% of desired value.
134 * Note: 25% is arbitrary value and may need some tweak.
136 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
137 DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN
, &pn_min
) != 1) {
138 DRM_DEBUG_KMS("Failed to read pwmgen bit count cap min\n");
141 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
142 DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX
, &pn_max
) != 1) {
143 DRM_DEBUG_KMS("Failed to read pwmgen bit count cap max\n");
146 pn_min
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
147 pn_max
&= DP_EDP_PWMGEN_BIT_COUNT_MASK
;
149 fxp_min
= DIV_ROUND_CLOSEST(fxp
* 3, 4);
150 fxp_max
= DIV_ROUND_CLOSEST(fxp
* 5, 4);
151 if (fxp_min
< (1 << pn_min
) || (255 << pn_max
) < fxp_max
) {
152 DRM_DEBUG_KMS("VBT defined backlight frequency out of range\n");
156 for (pn
= pn_max
; pn
>= pn_min
; pn
--) {
157 f
= clamp(DIV_ROUND_CLOSEST(fxp
, 1 << pn
), 1, 255);
158 fxp_actual
= f
<< pn
;
159 if (fxp_min
<= fxp_actual
&& fxp_actual
<= fxp_max
)
163 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
164 DP_EDP_PWMGEN_BIT_COUNT
, pn
) < 0) {
165 DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n");
168 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
169 DP_EDP_BACKLIGHT_FREQ_SET
, (u8
) f
) < 0) {
170 DRM_DEBUG_KMS("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
= enc_to_intel_dp(&connector
->encoder
->base
);
181 uint8_t dpcd_buf
, new_dpcd_buf
, edp_backlight_mode
;
183 if (drm_dp_dpcd_readb(&intel_dp
->aux
,
184 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
, &dpcd_buf
) != 1) {
185 DRM_DEBUG_KMS("Failed to read DPCD register 0x%x\n",
186 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
);
190 new_dpcd_buf
= dpcd_buf
;
191 edp_backlight_mode
= dpcd_buf
& DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
;
193 switch (edp_backlight_mode
) {
194 case DP_EDP_BACKLIGHT_CONTROL_MODE_PWM
:
195 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET
:
196 case DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT
:
197 new_dpcd_buf
&= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK
;
198 new_dpcd_buf
|= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
;
201 /* Do nothing when it is already DPCD mode */
202 case DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD
:
207 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP
)
208 if (intel_dp_aux_set_pwm_freq(connector
))
209 new_dpcd_buf
|= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE
;
211 if (new_dpcd_buf
!= dpcd_buf
) {
212 if (drm_dp_dpcd_writeb(&intel_dp
->aux
,
213 DP_EDP_BACKLIGHT_MODE_SET_REGISTER
, new_dpcd_buf
) < 0) {
214 DRM_DEBUG_KMS("Failed to write aux backlight mode\n");
218 set_aux_backlight_enable(intel_dp
, true);
219 intel_dp_aux_set_backlight(conn_state
, connector
->panel
.backlight
.level
);
222 static void intel_dp_aux_disable_backlight(const struct drm_connector_state
*old_conn_state
)
224 set_aux_backlight_enable(enc_to_intel_dp(old_conn_state
->best_encoder
), false);
227 static int intel_dp_aux_setup_backlight(struct intel_connector
*connector
,
230 struct intel_dp
*intel_dp
= enc_to_intel_dp(&connector
->encoder
->base
);
231 struct intel_panel
*panel
= &connector
->panel
;
233 if (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT
)
234 panel
->backlight
.max
= 0xFFFF;
236 panel
->backlight
.max
= 0xFF;
238 panel
->backlight
.min
= 0;
239 panel
->backlight
.level
= intel_dp_aux_get_backlight(connector
);
241 panel
->backlight
.enabled
= panel
->backlight
.level
!= 0;
247 intel_dp_aux_display_control_capable(struct intel_connector
*connector
)
249 struct intel_dp
*intel_dp
= enc_to_intel_dp(&connector
->encoder
->base
);
251 /* Check the eDP Display control capabilities registers to determine if
252 * the panel can support backlight control over the aux channel
254 if (intel_dp
->edp_dpcd
[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP
&&
255 (intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP
) &&
256 !(intel_dp
->edp_dpcd
[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP
)) {
257 DRM_DEBUG_KMS("AUX Backlight Control Supported!\n");
263 int intel_dp_aux_init_backlight_funcs(struct intel_connector
*intel_connector
)
265 struct intel_panel
*panel
= &intel_connector
->panel
;
267 if (!i915_modparams
.enable_dpcd_backlight
)
270 if (!intel_dp_aux_display_control_capable(intel_connector
))
273 panel
->backlight
.setup
= intel_dp_aux_setup_backlight
;
274 panel
->backlight
.enable
= intel_dp_aux_enable_backlight
;
275 panel
->backlight
.disable
= intel_dp_aux_disable_backlight
;
276 panel
->backlight
.set
= intel_dp_aux_set_backlight
;
277 panel
->backlight
.get
= intel_dp_aux_get_backlight
;