]>
Commit | Line | Data |
---|---|---|
e7156c83 YA |
1 | /* |
2 | * Copyright © 2015 Intel Corporation | |
3 | * | |
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: | |
10 | * | |
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 | |
13 | * Software. | |
14 | * | |
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 | |
21 | * IN THE SOFTWARE. | |
22 | * | |
23 | */ | |
24 | ||
4a8d7990 LP |
25 | /* |
26 | * Laptops with Intel GPUs which have panels that support controlling the | |
27 | * backlight through DP AUX can actually use two different interfaces: Intel's | |
28 | * proprietary DP AUX backlight interface, and the standard VESA backlight | |
29 | * interface. Unfortunately, at the time of writing this a lot of laptops will | |
30 | * advertise support for the standard VESA backlight interface when they | |
31 | * don't properly support it. However, on these systems the Intel backlight | |
32 | * interface generally does work properly. Additionally, these systems will | |
33 | * usually just indicate that they use PWM backlight controls in their VBIOS | |
34 | * for some reason. | |
35 | */ | |
36 | ||
1d455f8d | 37 | #include "intel_display_types.h" |
158fd774 | 38 | #include "intel_dp.h" |
81afa278 | 39 | #include "intel_dp_aux_backlight.h" |
4a8d7990 LP |
40 | #include "intel_panel.h" |
41 | ||
42 | /* TODO: | |
43 | * Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we | |
44 | * can make people's backlights work in the mean time | |
45 | */ | |
e7156c83 | 46 | |
021a3ac2 LP |
47 | /* |
48 | * DP AUX registers for Intel's proprietary HDR backlight interface. We define | |
49 | * them here since we'll likely be the only driver to ever use these. | |
50 | */ | |
51 | #define INTEL_EDP_HDR_TCON_CAP0 0x340 | |
52 | ||
53 | #define INTEL_EDP_HDR_TCON_CAP1 0x341 | |
54 | # define INTEL_EDP_HDR_TCON_2084_DECODE_CAP BIT(0) | |
55 | # define INTEL_EDP_HDR_TCON_2020_GAMUT_CAP BIT(1) | |
56 | # define INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP BIT(2) | |
57 | # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP BIT(3) | |
58 | # define INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP BIT(4) | |
59 | # define INTEL_EDP_HDR_TCON_OPTIMIZATION_CAP BIT(5) | |
60 | # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP BIT(6) | |
61 | # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_CONVERSION_CAP BIT(7) | |
62 | ||
63 | #define INTEL_EDP_HDR_TCON_CAP2 0x342 | |
64 | # define INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP BIT(0) | |
65 | ||
66 | #define INTEL_EDP_HDR_TCON_CAP3 0x343 | |
67 | ||
68 | #define INTEL_EDP_HDR_GETSET_CTRL_PARAMS 0x344 | |
69 | # define INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE BIT(0) | |
70 | # define INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE BIT(1) | |
71 | # define INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE BIT(2) /* Pre-TGL+ */ | |
72 | # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE BIT(3) | |
73 | # define INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE BIT(4) | |
74 | # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_ENABLE BIT(5) | |
75 | /* Bit 6 is reserved */ | |
76 | # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_ENABLE BIT(7) | |
77 | ||
78 | #define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346 /* Pre-TGL+ */ | |
79 | #define INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE 0x34A | |
80 | #define INTEL_EDP_SDR_LUMINANCE_LEVEL 0x352 | |
81 | #define INTEL_EDP_BRIGHTNESS_NITS_LSB 0x354 | |
82 | #define INTEL_EDP_BRIGHTNESS_NITS_MSB 0x355 | |
83 | #define INTEL_EDP_BRIGHTNESS_DELAY_FRAMES 0x356 | |
84 | #define INTEL_EDP_BRIGHTNESS_PER_FRAME_STEPS 0x357 | |
85 | ||
86 | #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_0 0x358 | |
87 | # define INTEL_EDP_TCON_USAGE_MASK GENMASK(0, 3) | |
88 | # define INTEL_EDP_TCON_USAGE_UNKNOWN 0x0 | |
89 | # define INTEL_EDP_TCON_USAGE_DESKTOP 0x1 | |
90 | # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_MEDIA 0x2 | |
91 | # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_GAMING 0x3 | |
92 | # define INTEL_EDP_TCON_POWER_MASK BIT(4) | |
93 | # define INTEL_EDP_TCON_POWER_DC (0 << 4) | |
94 | # define INTEL_EDP_TCON_POWER_AC (1 << 4) | |
95 | # define INTEL_EDP_TCON_OPTIMIZATION_STRENGTH_MASK GENMASK(5, 7) | |
96 | ||
97 | #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359 | |
98 | ||
bf7bdd3e JH |
99 | enum intel_dp_aux_backlight_modparam { |
100 | INTEL_DP_AUX_BACKLIGHT_AUTO = -1, | |
101 | INTEL_DP_AUX_BACKLIGHT_OFF = 0, | |
102 | INTEL_DP_AUX_BACKLIGHT_ON = 1, | |
103 | INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2, | |
104 | INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3, | |
105 | }; | |
106 | ||
4a8d7990 LP |
107 | /* Intel EDP backlight callbacks */ |
108 | static bool | |
109 | intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector) | |
110 | { | |
111 | struct drm_i915_private *i915 = to_i915(connector->base.dev); | |
112 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); | |
113 | struct drm_dp_aux *aux = &intel_dp->aux; | |
114 | struct intel_panel *panel = &connector->panel; | |
115 | int ret; | |
116 | u8 tcon_cap[4]; | |
117 | ||
158fd774 LP |
118 | intel_dp_wait_source_oui(intel_dp); |
119 | ||
4a8d7990 | 120 | ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap)); |
3faea993 | 121 | if (ret != sizeof(tcon_cap)) |
4a8d7990 LP |
122 | return false; |
123 | ||
124 | if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP)) | |
125 | return false; | |
126 | ||
127 | if (tcon_cap[0] >= 1) { | |
128 | drm_dbg_kms(&i915->drm, "Detected Intel HDR backlight interface version %d\n", | |
129 | tcon_cap[0]); | |
130 | } else { | |
131 | drm_dbg_kms(&i915->drm, "Detected unsupported HDR backlight interface version %d\n", | |
132 | tcon_cap[0]); | |
133 | return false; | |
134 | } | |
135 | ||
bf7bdd3e JH |
136 | /* |
137 | * If we don't have HDR static metadata there is no way to | |
138 | * runtime detect used range for nits based control. For now | |
139 | * do not use Intel proprietary eDP backlight control if we | |
140 | * don't have this data in panel EDID. In case we find panel | |
141 | * which supports only nits based control, but doesn't provide | |
142 | * HDR static metadata we need to start maintaining table of | |
143 | * ranges for such panels. | |
144 | */ | |
145 | if (i915->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL && | |
146 | !(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type & | |
147 | BIT(HDMI_STATIC_METADATA_TYPE1))) { | |
148 | drm_info(&i915->drm, | |
149 | "Panel is missing HDR static metadata. Possible support for Intel HDR backlight interface is not used. If your backlight controls don't work try booting with i915.enable_dpcd_backlight=%d. needs this, please file a _new_ bug report on drm/i915, see " FDO_BUG_URL " for details.\n", | |
150 | INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL); | |
151 | return false; | |
152 | } | |
153 | ||
4a8d7990 LP |
154 | panel->backlight.edp.intel.sdr_uses_aux = |
155 | tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP; | |
156 | ||
157 | return true; | |
158 | } | |
159 | ||
160 | static u32 | |
161 | intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe) | |
162 | { | |
163 | struct drm_i915_private *i915 = to_i915(connector->base.dev); | |
164 | struct intel_panel *panel = &connector->panel; | |
165 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); | |
166 | u8 tmp; | |
167 | u8 buf[2] = { 0 }; | |
168 | ||
3faea993 | 169 | if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) { |
4a8d7990 LP |
170 | drm_err(&i915->drm, "Failed to read current backlight mode from DPCD\n"); |
171 | return 0; | |
172 | } | |
173 | ||
174 | if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) { | |
175 | if (!panel->backlight.edp.intel.sdr_uses_aux) { | |
176 | u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe); | |
177 | ||
178 | return intel_panel_backlight_level_from_pwm(connector, pwm_level); | |
179 | } | |
180 | ||
181 | /* Assume 100% brightness if backlight controls aren't enabled yet */ | |
182 | return panel->backlight.max; | |
183 | } | |
184 | ||
3faea993 LP |
185 | if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf, |
186 | sizeof(buf)) != sizeof(buf)) { | |
4a8d7990 LP |
187 | drm_err(&i915->drm, "Failed to read brightness from DPCD\n"); |
188 | return 0; | |
189 | } | |
190 | ||
191 | return (buf[1] << 8 | buf[0]); | |
192 | } | |
193 | ||
194 | static void | |
195 | intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, u32 level) | |
196 | { | |
197 | struct intel_connector *connector = to_intel_connector(conn_state->connector); | |
198 | struct drm_device *dev = connector->base.dev; | |
199 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); | |
200 | u8 buf[4] = { 0 }; | |
201 | ||
202 | buf[0] = level & 0xFF; | |
203 | buf[1] = (level & 0xFF00) >> 8; | |
204 | ||
3faea993 LP |
205 | if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf, |
206 | sizeof(buf)) != sizeof(buf)) | |
4a8d7990 LP |
207 | drm_err(dev, "Failed to write brightness level to DPCD\n"); |
208 | } | |
209 | ||
210 | static void | |
211 | intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32 level) | |
212 | { | |
213 | struct intel_connector *connector = to_intel_connector(conn_state->connector); | |
214 | struct intel_panel *panel = &connector->panel; | |
215 | ||
216 | if (panel->backlight.edp.intel.sdr_uses_aux) { | |
217 | intel_dp_aux_hdr_set_aux_backlight(conn_state, level); | |
218 | } else { | |
219 | const u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level); | |
220 | ||
221 | intel_panel_set_pwm_level(conn_state, pwm_level); | |
222 | } | |
223 | } | |
224 | ||
225 | static void | |
226 | intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state, | |
227 | const struct drm_connector_state *conn_state, u32 level) | |
228 | { | |
229 | struct intel_connector *connector = to_intel_connector(conn_state->connector); | |
230 | struct intel_panel *panel = &connector->panel; | |
231 | struct drm_i915_private *i915 = to_i915(connector->base.dev); | |
232 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); | |
233 | int ret; | |
234 | u8 old_ctrl, ctrl; | |
235 | ||
158fd774 LP |
236 | intel_dp_wait_source_oui(intel_dp); |
237 | ||
4a8d7990 | 238 | ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl); |
3faea993 | 239 | if (ret != 1) { |
4a8d7990 LP |
240 | drm_err(&i915->drm, "Failed to read current backlight control mode: %d\n", ret); |
241 | return; | |
242 | } | |
243 | ||
244 | ctrl = old_ctrl; | |
245 | if (panel->backlight.edp.intel.sdr_uses_aux) { | |
246 | ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE; | |
247 | intel_dp_aux_hdr_set_aux_backlight(conn_state, level); | |
248 | } else { | |
249 | u32 pwm_level = intel_panel_backlight_level_to_pwm(connector, level); | |
250 | ||
251 | panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level); | |
252 | ||
253 | ctrl &= ~INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE; | |
254 | } | |
255 | ||
256 | if (ctrl != old_ctrl) | |
3faea993 | 257 | if (drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) != 1) |
4a8d7990 LP |
258 | drm_err(&i915->drm, "Failed to configure DPCD brightness controls\n"); |
259 | } | |
260 | ||
261 | static void | |
262 | intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state, u32 level) | |
263 | { | |
264 | struct intel_connector *connector = to_intel_connector(conn_state->connector); | |
265 | struct intel_panel *panel = &connector->panel; | |
266 | ||
267 | /* Nothing to do for AUX based backlight controls */ | |
268 | if (panel->backlight.edp.intel.sdr_uses_aux) | |
269 | return; | |
270 | ||
271 | /* Note we want the actual pwm_level to be 0, regardless of pwm_min */ | |
272 | panel->backlight.pwm_funcs->disable(conn_state, intel_panel_invert_pwm_level(connector, 0)); | |
273 | } | |
274 | ||
275 | static int | |
276 | intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pipe) | |
277 | { | |
278 | struct drm_i915_private *i915 = to_i915(connector->base.dev); | |
279 | struct intel_panel *panel = &connector->panel; | |
280 | int ret; | |
281 | ||
282 | if (panel->backlight.edp.intel.sdr_uses_aux) { | |
283 | drm_dbg_kms(&i915->drm, "SDR backlight is controlled through DPCD\n"); | |
284 | } else { | |
285 | drm_dbg_kms(&i915->drm, "SDR backlight is controlled through PWM\n"); | |
286 | ||
287 | ret = panel->backlight.pwm_funcs->setup(connector, pipe); | |
288 | if (ret < 0) { | |
289 | drm_err(&i915->drm, | |
290 | "Failed to setup SDR backlight controls through PWM: %d\n", ret); | |
291 | return ret; | |
292 | } | |
293 | } | |
294 | ||
295 | panel->backlight.max = 512; | |
296 | panel->backlight.min = 0; | |
297 | panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe); | |
298 | panel->backlight.enabled = panel->backlight.level != 0; | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
021a3ac2 | 303 | /* VESA backlight callbacks */ |
31b10c1a | 304 | static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused) |
4ade8f31 | 305 | { |
867cf9cd | 306 | return connector->panel.backlight.level; |
e7156c83 YA |
307 | } |
308 | ||
e7156c83 | 309 | static void |
867cf9cd | 310 | intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level) |
e7156c83 | 311 | { |
7d025e08 | 312 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
867cf9cd LP |
313 | struct intel_panel *panel = &connector->panel; |
314 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); | |
ade673bb | 315 | |
867cf9cd | 316 | drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); |
ade673bb LP |
317 | } |
318 | ||
8fd1806d LP |
319 | static void |
320 | intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, | |
321 | const struct drm_connector_state *conn_state, u32 level) | |
e7156c83 | 322 | { |
7d025e08 | 323 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
fde7266f | 324 | struct intel_panel *panel = &connector->panel; |
867cf9cd | 325 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); |
c03e53b0 | 326 | |
867cf9cd | 327 | drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); |
e7156c83 YA |
328 | } |
329 | ||
8fd1806d LP |
330 | static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state *old_conn_state, |
331 | u32 level) | |
e7156c83 | 332 | { |
867cf9cd | 333 | struct intel_connector *connector = to_intel_connector(old_conn_state->connector); |
fde7266f | 334 | struct intel_panel *panel = &connector->panel; |
867cf9cd | 335 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); |
fde7266f | 336 | |
867cf9cd | 337 | drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info); |
fde7266f LP |
338 | } |
339 | ||
867cf9cd | 340 | static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe) |
e7156c83 | 341 | { |
3b51c2bb | 342 | struct intel_dp *intel_dp = intel_attached_dp(connector); |
e7156c83 | 343 | struct intel_panel *panel = &connector->panel; |
867cf9cd LP |
344 | struct drm_i915_private *i915 = dp_to_i915(intel_dp); |
345 | u16 current_level; | |
346 | u8 current_mode; | |
347 | int ret; | |
e7156c83 | 348 | |
867cf9cd LP |
349 | ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, |
350 | i915->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, | |
351 | ¤t_level, ¤t_mode); | |
352 | if (ret < 0) | |
353 | return ret; | |
e7156c83 | 354 | |
867cf9cd | 355 | panel->backlight.max = panel->backlight.edp.vesa.info.max; |
e7156c83 | 356 | panel->backlight.min = 0; |
867cf9cd LP |
357 | if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { |
358 | panel->backlight.level = current_level; | |
359 | panel->backlight.enabled = panel->backlight.level != 0; | |
360 | } else { | |
361 | panel->backlight.level = panel->backlight.max; | |
362 | panel->backlight.enabled = false; | |
363 | } | |
e7156c83 YA |
364 | |
365 | return 0; | |
366 | } | |
367 | ||
368 | static bool | |
8fd1806d | 369 | intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) |
e7156c83 | 370 | { |
490eda58 | 371 | struct intel_dp *intel_dp = intel_attached_dp(connector); |
eba9836f | 372 | struct drm_i915_private *i915 = dp_to_i915(intel_dp); |
e7156c83 | 373 | |
867cf9cd | 374 | /* TODO: We currently only support AUX only backlight configurations, not backlights which |
fe7d52bc LP |
375 | * require a mix of PWM and AUX controls to work. In the mean time, these machines typically |
376 | * work just fine using normal PWM controls anyway. | |
e7156c83 | 377 | */ |
867cf9cd LP |
378 | if ((intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) && |
379 | drm_edp_backlight_supported(intel_dp->edp_dpcd)) { | |
eba9836f | 380 | drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n"); |
e7156c83 YA |
381 | return true; |
382 | } | |
383 | return false; | |
384 | } | |
385 | ||
4a8d7990 LP |
386 | static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = { |
387 | .setup = intel_dp_aux_hdr_setup_backlight, | |
388 | .enable = intel_dp_aux_hdr_enable_backlight, | |
389 | .disable = intel_dp_aux_hdr_disable_backlight, | |
390 | .set = intel_dp_aux_hdr_set_backlight, | |
391 | .get = intel_dp_aux_hdr_get_backlight, | |
392 | }; | |
393 | ||
8fd1806d LP |
394 | static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = { |
395 | .setup = intel_dp_aux_vesa_setup_backlight, | |
396 | .enable = intel_dp_aux_vesa_enable_backlight, | |
397 | .disable = intel_dp_aux_vesa_disable_backlight, | |
398 | .set = intel_dp_aux_vesa_set_backlight, | |
399 | .get = intel_dp_aux_vesa_get_backlight, | |
1494a1de DA |
400 | }; |
401 | ||
4a8d7990 | 402 | int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) |
e7156c83 | 403 | { |
4a8d7990 LP |
404 | struct drm_device *dev = connector->base.dev; |
405 | struct intel_panel *panel = &connector->panel; | |
406 | struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); | |
eba9836f | 407 | struct drm_i915_private *i915 = dp_to_i915(intel_dp); |
2227816e | 408 | bool try_intel_interface = false, try_vesa_interface = false; |
e7156c83 | 409 | |
2227816e LP |
410 | /* Check the VBT and user's module parameters to figure out which |
411 | * interfaces to probe | |
412 | */ | |
413 | switch (i915->params.enable_dpcd_backlight) { | |
414 | case INTEL_DP_AUX_BACKLIGHT_OFF: | |
e7156c83 | 415 | return -ENODEV; |
2227816e LP |
416 | case INTEL_DP_AUX_BACKLIGHT_AUTO: |
417 | switch (i915->vbt.backlight.type) { | |
418 | case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE: | |
419 | try_vesa_interface = true; | |
420 | break; | |
421 | case INTEL_BACKLIGHT_DISPLAY_DDI: | |
422 | try_intel_interface = true; | |
2227816e LP |
423 | break; |
424 | default: | |
425 | return -ENODEV; | |
426 | } | |
427 | break; | |
428 | case INTEL_DP_AUX_BACKLIGHT_ON: | |
429 | if (i915->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE) | |
430 | try_intel_interface = true; | |
431 | ||
432 | try_vesa_interface = true; | |
433 | break; | |
434 | case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA: | |
435 | try_vesa_interface = true; | |
436 | break; | |
437 | case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL: | |
438 | try_intel_interface = true; | |
439 | break; | |
440 | } | |
e7156c83 | 441 | |
17f5d579 | 442 | /* |
4a8d7990 LP |
443 | * A lot of eDP panels in the wild will report supporting both the |
444 | * Intel proprietary backlight control interface, and the VESA | |
445 | * backlight control interface. Many of these panels are liars though, | |
446 | * and will only work with the Intel interface. So, always probe for | |
447 | * that first. | |
17f5d579 | 448 | */ |
2227816e | 449 | if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) { |
4a8d7990 LP |
450 | drm_dbg_kms(dev, "Using Intel proprietary eDP backlight controls\n"); |
451 | panel->backlight.funcs = &intel_dp_hdr_bl_funcs; | |
452 | return 0; | |
17f5d579 | 453 | } |
e7156c83 | 454 | |
2227816e | 455 | if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) { |
4a8d7990 LP |
456 | drm_dbg_kms(dev, "Using VESA eDP backlight controls\n"); |
457 | panel->backlight.funcs = &intel_dp_vesa_bl_funcs; | |
458 | return 0; | |
459 | } | |
e7156c83 | 460 | |
4a8d7990 | 461 | return -ENODEV; |
e7156c83 | 462 | } |