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
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
37 #include "i915_drv.h"
38 #include "intel_backlight.h"
39 #include "intel_display_types.h"
40 #include "intel_dp.h"
41 #include "intel_dp_aux_backlight.h"
42
43 /* TODO:
44 * Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we
45 * can make people's backlights work in the mean time
46 */
47
48 /*
49 * DP AUX registers for Intel's proprietary HDR backlight interface. We define
50 * them here since we'll likely be the only driver to ever use these.
51 */
52 #define INTEL_EDP_HDR_TCON_CAP0 0x340
53
54 #define INTEL_EDP_HDR_TCON_CAP1 0x341
55 # define INTEL_EDP_HDR_TCON_2084_DECODE_CAP BIT(0)
56 # define INTEL_EDP_HDR_TCON_2020_GAMUT_CAP BIT(1)
57 # define INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP BIT(2)
58 # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP BIT(3)
59 # define INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP BIT(4)
60 # define INTEL_EDP_HDR_TCON_OPTIMIZATION_CAP BIT(5)
61 # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP BIT(6)
62 # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_CONVERSION_CAP BIT(7)
63
64 #define INTEL_EDP_HDR_TCON_CAP2 0x342
65 # define INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP BIT(0)
66
67 #define INTEL_EDP_HDR_TCON_CAP3 0x343
68
69 #define INTEL_EDP_HDR_GETSET_CTRL_PARAMS 0x344
70 # define INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE BIT(0)
71 # define INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE BIT(1)
72 # define INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE BIT(2) /* Pre-TGL+ */
73 # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE BIT(3)
74 # define INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE BIT(4)
75 # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_ENABLE BIT(5)
76 /* Bit 6 is reserved */
77 # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_ENABLE BIT(7)
78
79 #define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346 /* Pre-TGL+ */
80 #define INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE 0x34A
81 #define INTEL_EDP_SDR_LUMINANCE_LEVEL 0x352
82 #define INTEL_EDP_BRIGHTNESS_NITS_LSB 0x354
83 #define INTEL_EDP_BRIGHTNESS_NITS_MSB 0x355
84 #define INTEL_EDP_BRIGHTNESS_DELAY_FRAMES 0x356
85 #define INTEL_EDP_BRIGHTNESS_PER_FRAME_STEPS 0x357
86
87 #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_0 0x358
88 # define INTEL_EDP_TCON_USAGE_MASK GENMASK(0, 3)
89 # define INTEL_EDP_TCON_USAGE_UNKNOWN 0x0
90 # define INTEL_EDP_TCON_USAGE_DESKTOP 0x1
91 # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_MEDIA 0x2
92 # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_GAMING 0x3
93 # define INTEL_EDP_TCON_POWER_MASK BIT(4)
94 # define INTEL_EDP_TCON_POWER_DC (0 << 4)
95 # define INTEL_EDP_TCON_POWER_AC (1 << 4)
96 # define INTEL_EDP_TCON_OPTIMIZATION_STRENGTH_MASK GENMASK(5, 7)
97
98 #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359
99
100 enum intel_dp_aux_backlight_modparam {
101 INTEL_DP_AUX_BACKLIGHT_AUTO = -1,
102 INTEL_DP_AUX_BACKLIGHT_OFF = 0,
103 INTEL_DP_AUX_BACKLIGHT_ON = 1,
104 INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2,
105 INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3,
106 };
107
108 /* Intel EDP backlight callbacks */
109 static bool
intel_dp_aux_supports_hdr_backlight(struct intel_connector * connector)110 intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
111 {
112 struct drm_i915_private *i915 = to_i915(connector->base.dev);
113 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
114 struct drm_dp_aux *aux = &intel_dp->aux;
115 struct intel_panel *panel = &connector->panel;
116 int ret;
117 u8 tcon_cap[4];
118
119 intel_dp_wait_source_oui(intel_dp);
120
121 ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap));
122 if (ret != sizeof(tcon_cap))
123 return false;
124
125 if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP))
126 return false;
127
128 if (tcon_cap[0] >= 1) {
129 drm_dbg_kms(&i915->drm, "Detected Intel HDR backlight interface version %d\n",
130 tcon_cap[0]);
131 } else {
132 drm_dbg_kms(&i915->drm, "Detected unsupported HDR backlight interface version %d\n",
133 tcon_cap[0]);
134 return false;
135 }
136
137 /*
138 * If we don't have HDR static metadata there is no way to
139 * runtime detect used range for nits based control. For now
140 * do not use Intel proprietary eDP backlight control if we
141 * don't have this data in panel EDID. In case we find panel
142 * which supports only nits based control, but doesn't provide
143 * HDR static metadata we need to start maintaining table of
144 * ranges for such panels.
145 */
146 if (i915->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL &&
147 !(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type &
148 BIT(HDMI_STATIC_METADATA_TYPE1))) {
149 drm_info(&i915->drm,
150 "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",
151 INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL);
152 return false;
153 }
154
155 panel->backlight.edp.intel.sdr_uses_aux =
156 tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP;
157
158 return true;
159 }
160
161 static u32
intel_dp_aux_hdr_get_backlight(struct intel_connector * connector,enum pipe pipe)162 intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe)
163 {
164 struct drm_i915_private *i915 = to_i915(connector->base.dev);
165 struct intel_panel *panel = &connector->panel;
166 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
167 u8 tmp;
168 u8 buf[2] = { 0 };
169
170 if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) {
171 drm_err(&i915->drm, "Failed to read current backlight mode from DPCD\n");
172 return 0;
173 }
174
175 if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) {
176 if (!panel->backlight.edp.intel.sdr_uses_aux) {
177 u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe);
178
179 return intel_backlight_level_from_pwm(connector, pwm_level);
180 }
181
182 /* Assume 100% brightness if backlight controls aren't enabled yet */
183 return panel->backlight.max;
184 }
185
186 if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
187 sizeof(buf)) != sizeof(buf)) {
188 drm_err(&i915->drm, "Failed to read brightness from DPCD\n");
189 return 0;
190 }
191
192 return (buf[1] << 8 | buf[0]);
193 }
194
195 static void
intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state * conn_state,u32 level)196 intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, u32 level)
197 {
198 struct intel_connector *connector = to_intel_connector(conn_state->connector);
199 struct drm_device *dev = connector->base.dev;
200 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
201 u8 buf[4] = { 0 };
202
203 buf[0] = level & 0xFF;
204 buf[1] = (level & 0xFF00) >> 8;
205
206 if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
207 sizeof(buf)) != sizeof(buf))
208 drm_err(dev, "Failed to write brightness level to DPCD\n");
209 }
210
211 static void
intel_dp_aux_hdr_set_backlight(const struct drm_connector_state * conn_state,u32 level)212 intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32 level)
213 {
214 struct intel_connector *connector = to_intel_connector(conn_state->connector);
215 struct intel_panel *panel = &connector->panel;
216
217 if (panel->backlight.edp.intel.sdr_uses_aux) {
218 intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
219 } else {
220 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
221
222 intel_backlight_set_pwm_level(conn_state, pwm_level);
223 }
224 }
225
226 static void
intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)227 intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
228 const struct drm_connector_state *conn_state, u32 level)
229 {
230 struct intel_connector *connector = to_intel_connector(conn_state->connector);
231 struct intel_panel *panel = &connector->panel;
232 struct drm_i915_private *i915 = to_i915(connector->base.dev);
233 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
234 int ret;
235 u8 old_ctrl, ctrl;
236
237 intel_dp_wait_source_oui(intel_dp);
238
239 ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
240 if (ret != 1) {
241 drm_err(&i915->drm, "Failed to read current backlight control mode: %d\n", ret);
242 return;
243 }
244
245 ctrl = old_ctrl;
246 if (panel->backlight.edp.intel.sdr_uses_aux) {
247 ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
248 intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
249 } else {
250 u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
251
252 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
253
254 ctrl &= ~INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
255 }
256
257 if (ctrl != old_ctrl)
258 if (drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) != 1)
259 drm_err(&i915->drm, "Failed to configure DPCD brightness controls\n");
260 }
261
262 static void
intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state * conn_state,u32 level)263 intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
264 {
265 struct intel_connector *connector = to_intel_connector(conn_state->connector);
266 struct intel_panel *panel = &connector->panel;
267
268 /* Nothing to do for AUX based backlight controls */
269 if (panel->backlight.edp.intel.sdr_uses_aux)
270 return;
271
272 /* Note we want the actual pwm_level to be 0, regardless of pwm_min */
273 panel->backlight.pwm_funcs->disable(conn_state, intel_backlight_invert_pwm_level(connector, 0));
274 }
275
276 static int
intel_dp_aux_hdr_setup_backlight(struct intel_connector * connector,enum pipe pipe)277 intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pipe)
278 {
279 struct drm_i915_private *i915 = to_i915(connector->base.dev);
280 struct intel_panel *panel = &connector->panel;
281 struct drm_luminance_range_info *luminance_range =
282 &connector->base.display_info.luminance_range;
283 int ret;
284
285 if (panel->backlight.edp.intel.sdr_uses_aux) {
286 drm_dbg_kms(&i915->drm, "SDR backlight is controlled through DPCD\n");
287 } else {
288 drm_dbg_kms(&i915->drm, "SDR backlight is controlled through PWM\n");
289
290 ret = panel->backlight.pwm_funcs->setup(connector, pipe);
291 if (ret < 0) {
292 drm_err(&i915->drm,
293 "Failed to setup SDR backlight controls through PWM: %d\n", ret);
294 return ret;
295 }
296 }
297
298 if (luminance_range->max_luminance) {
299 panel->backlight.max = luminance_range->max_luminance;
300 panel->backlight.min = luminance_range->min_luminance;
301 } else {
302 panel->backlight.max = 512;
303 panel->backlight.min = 0;
304 }
305
306 drm_dbg_kms(&i915->drm, "Using backlight range %d..%d\n", panel->backlight.min,
307 panel->backlight.max);
308
309 panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe);
310 panel->backlight.enabled = panel->backlight.level != 0;
311
312 return 0;
313 }
314
315 /* VESA backlight callbacks */
intel_dp_aux_vesa_get_backlight(struct intel_connector * connector,enum pipe unused)316 static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused)
317 {
318 return connector->panel.backlight.level;
319 }
320
321 static void
intel_dp_aux_vesa_set_backlight(const struct drm_connector_state * conn_state,u32 level)322 intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
323 {
324 struct intel_connector *connector = to_intel_connector(conn_state->connector);
325 struct intel_panel *panel = &connector->panel;
326 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
327
328 if (!panel->backlight.edp.vesa.info.aux_set) {
329 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
330
331 intel_backlight_set_pwm_level(conn_state, pwm_level);
332 }
333
334 drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level);
335 }
336
337 static void
intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)338 intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
339 const struct drm_connector_state *conn_state, u32 level)
340 {
341 struct intel_connector *connector = to_intel_connector(conn_state->connector);
342 struct intel_panel *panel = &connector->panel;
343 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
344
345 if (!panel->backlight.edp.vesa.info.aux_enable) {
346 u32 pwm_level;
347
348 if (!panel->backlight.edp.vesa.info.aux_set)
349 pwm_level = intel_backlight_level_to_pwm(connector, level);
350 else
351 pwm_level = intel_backlight_invert_pwm_level(connector,
352 panel->backlight.pwm_level_max);
353
354 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
355 }
356
357 drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level);
358 }
359
intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state * old_conn_state,u32 level)360 static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state *old_conn_state,
361 u32 level)
362 {
363 struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
364 struct intel_panel *panel = &connector->panel;
365 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
366
367 drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info);
368
369 if (!panel->backlight.edp.vesa.info.aux_enable)
370 panel->backlight.pwm_funcs->disable(old_conn_state,
371 intel_backlight_invert_pwm_level(connector, 0));
372 }
373
intel_dp_aux_vesa_setup_backlight(struct intel_connector * connector,enum pipe pipe)374 static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe)
375 {
376 struct intel_dp *intel_dp = intel_attached_dp(connector);
377 struct intel_panel *panel = &connector->panel;
378 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
379 u16 current_level;
380 u8 current_mode;
381 int ret;
382
383 ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
384 panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
385 ¤t_level, ¤t_mode);
386 if (ret < 0)
387 return ret;
388
389 if (!panel->backlight.edp.vesa.info.aux_set || !panel->backlight.edp.vesa.info.aux_enable) {
390 ret = panel->backlight.pwm_funcs->setup(connector, pipe);
391 if (ret < 0) {
392 drm_err(&i915->drm,
393 "Failed to setup PWM backlight controls for eDP backlight: %d\n",
394 ret);
395 return ret;
396 }
397 }
398
399 if (panel->backlight.edp.vesa.info.aux_set) {
400 panel->backlight.max = panel->backlight.edp.vesa.info.max;
401 panel->backlight.min = 0;
402 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
403 panel->backlight.level = current_level;
404 panel->backlight.enabled = panel->backlight.level != 0;
405 } else {
406 panel->backlight.level = panel->backlight.max;
407 panel->backlight.enabled = false;
408 }
409 } else {
410 panel->backlight.max = panel->backlight.pwm_level_max;
411 panel->backlight.min = panel->backlight.pwm_level_min;
412 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
413 panel->backlight.level = panel->backlight.pwm_funcs->get(connector, pipe);
414 panel->backlight.enabled = panel->backlight.pwm_enabled;
415 } else {
416 panel->backlight.level = panel->backlight.max;
417 panel->backlight.enabled = false;
418 }
419 }
420
421 return 0;
422 }
423
424 static bool
intel_dp_aux_supports_vesa_backlight(struct intel_connector * connector)425 intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
426 {
427 struct intel_dp *intel_dp = intel_attached_dp(connector);
428 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
429
430 if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) {
431 drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
432 return true;
433 }
434 return false;
435 }
436
437 static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = {
438 .setup = intel_dp_aux_hdr_setup_backlight,
439 .enable = intel_dp_aux_hdr_enable_backlight,
440 .disable = intel_dp_aux_hdr_disable_backlight,
441 .set = intel_dp_aux_hdr_set_backlight,
442 .get = intel_dp_aux_hdr_get_backlight,
443 };
444
445 static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
446 .setup = intel_dp_aux_vesa_setup_backlight,
447 .enable = intel_dp_aux_vesa_enable_backlight,
448 .disable = intel_dp_aux_vesa_disable_backlight,
449 .set = intel_dp_aux_vesa_set_backlight,
450 .get = intel_dp_aux_vesa_get_backlight,
451 };
452
intel_dp_aux_init_backlight_funcs(struct intel_connector * connector)453 int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
454 {
455 struct drm_device *dev = connector->base.dev;
456 struct intel_panel *panel = &connector->panel;
457 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
458 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
459 bool try_intel_interface = false, try_vesa_interface = false;
460
461 /* Check the VBT and user's module parameters to figure out which
462 * interfaces to probe
463 */
464 switch (i915->params.enable_dpcd_backlight) {
465 case INTEL_DP_AUX_BACKLIGHT_OFF:
466 return -ENODEV;
467 case INTEL_DP_AUX_BACKLIGHT_AUTO:
468 switch (panel->vbt.backlight.type) {
469 case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE:
470 try_vesa_interface = true;
471 break;
472 case INTEL_BACKLIGHT_DISPLAY_DDI:
473 try_intel_interface = true;
474 break;
475 default:
476 return -ENODEV;
477 }
478 break;
479 case INTEL_DP_AUX_BACKLIGHT_ON:
480 if (panel->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE)
481 try_intel_interface = true;
482
483 try_vesa_interface = true;
484 break;
485 case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA:
486 try_vesa_interface = true;
487 break;
488 case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL:
489 try_intel_interface = true;
490 break;
491 }
492
493 /*
494 * Since Intel has their own backlight control interface, the majority of machines out there
495 * using DPCD backlight controls with Intel GPUs will be using this interface as opposed to
496 * the VESA interface. However, other GPUs (such as Nvidia's) will always use the VESA
497 * interface. This means that there's quite a number of panels out there that will advertise
498 * support for both interfaces, primarily systems with Intel/Nvidia hybrid GPU setups.
499 *
500 * There's a catch to this though: on many panels that advertise support for both
501 * interfaces, the VESA backlight interface will stop working once we've programmed the
502 * panel with Intel's OUI - which is also required for us to be able to detect Intel's
503 * backlight interface at all. This means that the only sensible way for us to detect both
504 * interfaces is to probe for Intel's first, and VESA's second.
505 */
506 if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) {
507 drm_dbg_kms(dev, "Using Intel proprietary eDP backlight controls\n");
508 panel->backlight.funcs = &intel_dp_hdr_bl_funcs;
509 return 0;
510 }
511
512 if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) {
513 drm_dbg_kms(dev, "Using VESA eDP backlight controls\n");
514 panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
515 return 0;
516 }
517
518 return -ENODEV;
519 }
520