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 int ret;
282
283 if (panel->backlight.edp.intel.sdr_uses_aux) {
284 drm_dbg_kms(&i915->drm, "SDR backlight is controlled through DPCD\n");
285 } else {
286 drm_dbg_kms(&i915->drm, "SDR backlight is controlled through PWM\n");
287
288 ret = panel->backlight.pwm_funcs->setup(connector, pipe);
289 if (ret < 0) {
290 drm_err(&i915->drm,
291 "Failed to setup SDR backlight controls through PWM: %d\n", ret);
292 return ret;
293 }
294 }
295
296 panel->backlight.max = 512;
297 panel->backlight.min = 0;
298 panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe);
299 panel->backlight.enabled = panel->backlight.level != 0;
300
301 return 0;
302 }
303
304 /* VESA backlight callbacks */
intel_dp_aux_vesa_get_backlight(struct intel_connector * connector,enum pipe unused)305 static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused)
306 {
307 return connector->panel.backlight.level;
308 }
309
310 static void
intel_dp_aux_vesa_set_backlight(const struct drm_connector_state * conn_state,u32 level)311 intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
312 {
313 struct intel_connector *connector = to_intel_connector(conn_state->connector);
314 struct intel_panel *panel = &connector->panel;
315 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
316
317 if (!panel->backlight.edp.vesa.info.aux_set) {
318 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
319
320 intel_backlight_set_pwm_level(conn_state, pwm_level);
321 }
322
323 drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level);
324 }
325
326 static void
intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state,u32 level)327 intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
328 const struct drm_connector_state *conn_state, u32 level)
329 {
330 struct intel_connector *connector = to_intel_connector(conn_state->connector);
331 struct intel_panel *panel = &connector->panel;
332 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
333
334 if (!panel->backlight.edp.vesa.info.aux_enable) {
335 u32 pwm_level;
336
337 if (!panel->backlight.edp.vesa.info.aux_set)
338 pwm_level = intel_backlight_level_to_pwm(connector, level);
339 else
340 pwm_level = intel_backlight_invert_pwm_level(connector,
341 panel->backlight.pwm_level_max);
342
343 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
344 }
345
346 drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level);
347 }
348
intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state * old_conn_state,u32 level)349 static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state *old_conn_state,
350 u32 level)
351 {
352 struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
353 struct intel_panel *panel = &connector->panel;
354 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
355
356 drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info);
357
358 if (!panel->backlight.edp.vesa.info.aux_enable)
359 panel->backlight.pwm_funcs->disable(old_conn_state,
360 intel_backlight_invert_pwm_level(connector, 0));
361 }
362
intel_dp_aux_vesa_setup_backlight(struct intel_connector * connector,enum pipe pipe)363 static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe)
364 {
365 struct intel_dp *intel_dp = intel_attached_dp(connector);
366 struct intel_panel *panel = &connector->panel;
367 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
368 u16 current_level;
369 u8 current_mode;
370 int ret;
371
372 ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
373 i915->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
374 ¤t_level, ¤t_mode);
375 if (ret < 0)
376 return ret;
377
378 if (!panel->backlight.edp.vesa.info.aux_set || !panel->backlight.edp.vesa.info.aux_enable) {
379 ret = panel->backlight.pwm_funcs->setup(connector, pipe);
380 if (ret < 0) {
381 drm_err(&i915->drm,
382 "Failed to setup PWM backlight controls for eDP backlight: %d\n",
383 ret);
384 return ret;
385 }
386 }
387
388 if (panel->backlight.edp.vesa.info.aux_set) {
389 panel->backlight.max = panel->backlight.edp.vesa.info.max;
390 panel->backlight.min = 0;
391 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
392 panel->backlight.level = current_level;
393 panel->backlight.enabled = panel->backlight.level != 0;
394 } else {
395 panel->backlight.level = panel->backlight.max;
396 panel->backlight.enabled = false;
397 }
398 } else {
399 panel->backlight.max = panel->backlight.pwm_level_max;
400 panel->backlight.min = panel->backlight.pwm_level_min;
401 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
402 panel->backlight.level = panel->backlight.pwm_funcs->get(connector, pipe);
403 panel->backlight.enabled = panel->backlight.pwm_enabled;
404 } else {
405 panel->backlight.level = panel->backlight.max;
406 panel->backlight.enabled = false;
407 }
408 }
409
410 return 0;
411 }
412
413 static bool
intel_dp_aux_supports_vesa_backlight(struct intel_connector * connector)414 intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
415 {
416 struct intel_dp *intel_dp = intel_attached_dp(connector);
417 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
418
419 if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) {
420 drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
421 return true;
422 }
423 return false;
424 }
425
426 static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = {
427 .setup = intel_dp_aux_hdr_setup_backlight,
428 .enable = intel_dp_aux_hdr_enable_backlight,
429 .disable = intel_dp_aux_hdr_disable_backlight,
430 .set = intel_dp_aux_hdr_set_backlight,
431 .get = intel_dp_aux_hdr_get_backlight,
432 };
433
434 static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
435 .setup = intel_dp_aux_vesa_setup_backlight,
436 .enable = intel_dp_aux_vesa_enable_backlight,
437 .disable = intel_dp_aux_vesa_disable_backlight,
438 .set = intel_dp_aux_vesa_set_backlight,
439 .get = intel_dp_aux_vesa_get_backlight,
440 };
441
intel_dp_aux_init_backlight_funcs(struct intel_connector * connector)442 int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
443 {
444 struct drm_device *dev = connector->base.dev;
445 struct intel_panel *panel = &connector->panel;
446 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
447 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
448 bool try_intel_interface = false, try_vesa_interface = false;
449
450 /* Check the VBT and user's module parameters to figure out which
451 * interfaces to probe
452 */
453 switch (i915->params.enable_dpcd_backlight) {
454 case INTEL_DP_AUX_BACKLIGHT_OFF:
455 return -ENODEV;
456 case INTEL_DP_AUX_BACKLIGHT_AUTO:
457 switch (i915->vbt.backlight.type) {
458 case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE:
459 try_vesa_interface = true;
460 break;
461 case INTEL_BACKLIGHT_DISPLAY_DDI:
462 try_intel_interface = true;
463 break;
464 default:
465 return -ENODEV;
466 }
467 break;
468 case INTEL_DP_AUX_BACKLIGHT_ON:
469 if (i915->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE)
470 try_intel_interface = true;
471
472 try_vesa_interface = true;
473 break;
474 case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA:
475 try_vesa_interface = true;
476 break;
477 case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL:
478 try_intel_interface = true;
479 break;
480 }
481
482 /*
483 * Since Intel has their own backlight control interface, the majority of machines out there
484 * using DPCD backlight controls with Intel GPUs will be using this interface as opposed to
485 * the VESA interface. However, other GPUs (such as Nvidia's) will always use the VESA
486 * interface. This means that there's quite a number of panels out there that will advertise
487 * support for both interfaces, primarily systems with Intel/Nvidia hybrid GPU setups.
488 *
489 * There's a catch to this though: on many panels that advertise support for both
490 * interfaces, the VESA backlight interface will stop working once we've programmed the
491 * panel with Intel's OUI - which is also required for us to be able to detect Intel's
492 * backlight interface at all. This means that the only sensible way for us to detect both
493 * interfaces is to probe for Intel's first, and VESA's second.
494 */
495 if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) {
496 drm_dbg_kms(dev, "Using Intel proprietary eDP backlight controls\n");
497 panel->backlight.funcs = &intel_dp_hdr_bl_funcs;
498 return 0;
499 }
500
501 if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) {
502 drm_dbg_kms(dev, "Using VESA eDP backlight controls\n");
503 panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
504 return 0;
505 }
506
507 return -ENODEV;
508 }
509