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 <drm/drm_print.h> 38 39 #include "i915_utils.h" 40 #include "intel_backlight.h" 41 #include "intel_display_core.h" 42 #include "intel_display_types.h" 43 #include "intel_dp.h" 44 #include "intel_dp_aux_backlight.h" 45 46 /* 47 * DP AUX registers for Intel's proprietary HDR backlight interface. We define 48 * them here since we'll likely be the only driver to ever use these. 49 */ 50 #define INTEL_EDP_HDR_TCON_CAP0 0x340 51 52 #define INTEL_EDP_HDR_TCON_CAP1 0x341 53 # define INTEL_EDP_HDR_TCON_2084_DECODE_CAP BIT(0) 54 # define INTEL_EDP_HDR_TCON_2020_GAMUT_CAP BIT(1) 55 # define INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP BIT(2) 56 # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP BIT(3) 57 # define INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP BIT(4) 58 # define INTEL_EDP_HDR_TCON_OPTIMIZATION_CAP BIT(5) 59 # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP BIT(6) 60 # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_CONVERSION_CAP BIT(7) 61 62 #define INTEL_EDP_HDR_TCON_CAP2 0x342 63 # define INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP BIT(0) 64 65 #define INTEL_EDP_HDR_TCON_CAP3 0x343 66 67 #define INTEL_EDP_HDR_GETSET_CTRL_PARAMS 0x344 68 # define INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE BIT(0) 69 # define INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE BIT(1) 70 # define INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE BIT(2) 71 # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE BIT(3) 72 # define INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE BIT(4) 73 # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_ENABLE BIT(5) 74 /* Bit 6 is reserved */ 75 # define INTEL_EDP_HDR_TCON_SDP_OVERRIDE_AUX BIT(7) 76 77 #define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346 78 #define INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE 0x34A 79 #define INTEL_EDP_SDR_LUMINANCE_LEVEL 0x352 80 #define INTEL_EDP_BRIGHTNESS_NITS_LSB 0x354 81 #define INTEL_EDP_BRIGHTNESS_NITS_MSB 0x355 82 #define INTEL_EDP_BRIGHTNESS_DELAY_FRAMES 0x356 83 #define INTEL_EDP_BRIGHTNESS_PER_FRAME_STEPS 0x357 84 85 #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_0 0x358 86 # define INTEL_EDP_TCON_USAGE_MASK GENMASK(0, 3) 87 # define INTEL_EDP_TCON_USAGE_UNKNOWN 0x0 88 # define INTEL_EDP_TCON_USAGE_DESKTOP 0x1 89 # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_MEDIA 0x2 90 # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_GAMING 0x3 91 # define INTEL_EDP_TCON_POWER_MASK BIT(4) 92 # define INTEL_EDP_TCON_POWER_DC (0 << 4) 93 # define INTEL_EDP_TCON_POWER_AC (1 << 4) 94 # define INTEL_EDP_TCON_OPTIMIZATION_STRENGTH_MASK GENMASK(5, 7) 95 96 #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359 97 98 enum intel_dp_aux_backlight_modparam { 99 INTEL_DP_AUX_BACKLIGHT_AUTO = -1, 100 INTEL_DP_AUX_BACKLIGHT_OFF = 0, 101 INTEL_DP_AUX_BACKLIGHT_ON = 1, 102 INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2, 103 INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3, 104 }; 105 106 static bool is_intel_tcon_cap(const u8 tcon_cap[4]) 107 { 108 return tcon_cap[0] >= 1; 109 } 110 111 /* Intel EDP backlight callbacks */ 112 static bool 113 intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector) 114 { 115 struct intel_display *display = to_intel_display(connector); 116 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 117 struct drm_dp_aux *aux = &intel_dp->aux; 118 struct intel_panel *panel = &connector->panel; 119 int ret; 120 u8 tcon_cap[4]; 121 122 intel_dp_wait_source_oui(intel_dp); 123 124 ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap)); 125 if (ret != sizeof(tcon_cap)) 126 return false; 127 128 drm_dbg_kms(display->drm, 129 "[CONNECTOR:%d:%s] Detected %s HDR backlight interface version %d\n", 130 connector->base.base.id, connector->base.name, 131 is_intel_tcon_cap(tcon_cap) ? "Intel" : "unsupported", tcon_cap[0]); 132 133 if (!is_intel_tcon_cap(tcon_cap)) 134 return false; 135 136 if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP)) 137 return false; 138 139 /* 140 * If we don't have HDR static metadata there is no way to 141 * runtime detect used range for nits based control. For now 142 * do not use Intel proprietary eDP backlight control if we 143 * don't have this data in panel EDID. In case we find panel 144 * which supports only nits based control, but doesn't provide 145 * HDR static metadata we need to start maintaining table of 146 * ranges for such panels. 147 */ 148 if (display->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL && 149 !(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type & 150 BIT(HDMI_STATIC_METADATA_TYPE1))) { 151 drm_info(display->drm, 152 "[CONNECTOR:%d:%s] 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", 153 connector->base.base.id, connector->base.name, 154 INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL); 155 return false; 156 } 157 158 panel->backlight.edp.intel_cap.sdr_uses_aux = 159 tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP; 160 panel->backlight.edp.intel_cap.supports_2084_decode = 161 tcon_cap[1] & INTEL_EDP_HDR_TCON_2084_DECODE_CAP; 162 panel->backlight.edp.intel_cap.supports_2020_gamut = 163 tcon_cap[1] & INTEL_EDP_HDR_TCON_2020_GAMUT_CAP; 164 panel->backlight.edp.intel_cap.supports_segmented_backlight = 165 tcon_cap[1] & INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP; 166 panel->backlight.edp.intel_cap.supports_sdp_colorimetry = 167 tcon_cap[1] & INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP; 168 panel->backlight.edp.intel_cap.supports_tone_mapping = 169 tcon_cap[1] & INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP; 170 171 return true; 172 } 173 174 static u32 175 intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe) 176 { 177 struct intel_display *display = to_intel_display(connector); 178 struct intel_panel *panel = &connector->panel; 179 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 180 u8 tmp; 181 u8 buf[2] = {}; 182 183 if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) { 184 drm_err(display->drm, 185 "[CONNECTOR:%d:%s] Failed to read current backlight mode from DPCD\n", 186 connector->base.base.id, connector->base.name); 187 return 0; 188 } 189 190 if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) { 191 if (!panel->backlight.edp.intel_cap.sdr_uses_aux) { 192 u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe); 193 194 return intel_backlight_level_from_pwm(connector, pwm_level); 195 } 196 197 /* Assume 100% brightness if backlight controls aren't enabled yet */ 198 return panel->backlight.max; 199 } 200 201 if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf, 202 sizeof(buf)) != sizeof(buf)) { 203 drm_err(display->drm, 204 "[CONNECTOR:%d:%s] Failed to read brightness from DPCD\n", 205 connector->base.base.id, connector->base.name); 206 return 0; 207 } 208 209 return (buf[1] << 8 | buf[0]); 210 } 211 212 static void 213 intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, u32 level) 214 { 215 struct intel_connector *connector = to_intel_connector(conn_state->connector); 216 struct drm_device *dev = connector->base.dev; 217 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 218 u8 buf[4] = {}; 219 220 buf[0] = level & 0xFF; 221 buf[1] = (level & 0xFF00) >> 8; 222 223 if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf, 224 sizeof(buf)) != sizeof(buf)) 225 drm_err(dev, "[CONNECTOR:%d:%s] Failed to write brightness level to DPCD\n", 226 connector->base.base.id, connector->base.name); 227 } 228 229 static bool 230 intel_dp_in_hdr_mode(const struct drm_connector_state *conn_state) 231 { 232 struct hdr_output_metadata *hdr_metadata; 233 234 if (!conn_state->hdr_output_metadata) 235 return false; 236 237 hdr_metadata = conn_state->hdr_output_metadata->data; 238 239 return hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084; 240 } 241 242 static void 243 intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32 level) 244 { 245 struct intel_connector *connector = to_intel_connector(conn_state->connector); 246 struct intel_panel *panel = &connector->panel; 247 248 if (intel_dp_in_hdr_mode(conn_state) || 249 panel->backlight.edp.intel_cap.sdr_uses_aux) { 250 intel_dp_aux_hdr_set_aux_backlight(conn_state, level); 251 } else { 252 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level); 253 254 intel_backlight_set_pwm_level(conn_state, pwm_level); 255 } 256 } 257 258 static void 259 intel_dp_aux_write_content_luminance(struct intel_connector *connector, 260 struct hdr_output_metadata *hdr_metadata) 261 { 262 struct intel_display *display = to_intel_display(connector); 263 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 264 int ret; 265 u8 buf[4]; 266 267 if (!intel_dp_has_gamut_metadata_dip(connector->encoder)) 268 return; 269 270 buf[0] = hdr_metadata->hdmi_metadata_type1.max_cll & 0xFF; 271 buf[1] = (hdr_metadata->hdmi_metadata_type1.max_cll & 0xFF00) >> 8; 272 buf[2] = hdr_metadata->hdmi_metadata_type1.max_fall & 0xFF; 273 buf[3] = (hdr_metadata->hdmi_metadata_type1.max_fall & 0xFF00) >> 8; 274 275 ret = drm_dp_dpcd_write(&intel_dp->aux, 276 INTEL_EDP_HDR_CONTENT_LUMINANCE, 277 buf, sizeof(buf)); 278 if (ret < 0) 279 drm_dbg_kms(display->drm, 280 "Content Luminance DPCD reg write failed, err:-%d\n", 281 ret); 282 } 283 284 static void 285 intel_dp_aux_fill_hdr_tcon_params(const struct drm_connector_state *conn_state, u8 *ctrl) 286 { 287 struct intel_connector *connector = to_intel_connector(conn_state->connector); 288 struct intel_panel *panel = &connector->panel; 289 struct intel_display *display = to_intel_display(connector); 290 291 /* 292 * According to spec segmented backlight needs to be set whenever panel is in 293 * HDR mode. 294 */ 295 if (intel_dp_in_hdr_mode(conn_state)) { 296 *ctrl |= INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE; 297 *ctrl |= INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE; 298 } 299 300 if (DISPLAY_VER(display) < 11) 301 *ctrl &= ~INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE; 302 303 if (panel->backlight.edp.intel_cap.supports_2020_gamut && 304 (conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_RGB || 305 conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_YCC || 306 conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_CYCC)) 307 *ctrl |= INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE; 308 309 if (panel->backlight.edp.intel_cap.supports_sdp_colorimetry && 310 intel_dp_has_gamut_metadata_dip(connector->encoder)) 311 *ctrl |= INTEL_EDP_HDR_TCON_SDP_OVERRIDE_AUX; 312 else 313 *ctrl &= ~INTEL_EDP_HDR_TCON_SDP_OVERRIDE_AUX; 314 } 315 316 static void 317 intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state, 318 const struct drm_connector_state *conn_state, u32 level) 319 { 320 struct intel_display *display = to_intel_display(crtc_state); 321 struct intel_connector *connector = to_intel_connector(conn_state->connector); 322 struct intel_panel *panel = &connector->panel; 323 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 324 struct hdr_output_metadata *hdr_metadata; 325 int ret; 326 u8 old_ctrl, ctrl; 327 328 intel_dp_wait_source_oui(intel_dp); 329 330 ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl); 331 if (ret != 1) { 332 drm_err(display->drm, 333 "[CONNECTOR:%d:%s] Failed to read current backlight control mode: %d\n", 334 connector->base.base.id, connector->base.name, ret); 335 return; 336 } 337 338 ctrl = old_ctrl; 339 if (intel_dp_in_hdr_mode(conn_state) || 340 panel->backlight.edp.intel_cap.sdr_uses_aux) { 341 ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE; 342 343 intel_dp_aux_hdr_set_aux_backlight(conn_state, level); 344 } else { 345 u32 pwm_level = intel_backlight_level_to_pwm(connector, level); 346 347 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level); 348 349 ctrl &= ~INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE; 350 } 351 352 intel_dp_aux_fill_hdr_tcon_params(conn_state, &ctrl); 353 354 if (ctrl != old_ctrl && 355 drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) != 1) 356 drm_err(display->drm, 357 "[CONNECTOR:%d:%s] Failed to configure DPCD brightness controls\n", 358 connector->base.base.id, connector->base.name); 359 360 if (intel_dp_in_hdr_mode(conn_state)) { 361 hdr_metadata = conn_state->hdr_output_metadata->data; 362 intel_dp_aux_write_content_luminance(connector, hdr_metadata); 363 } 364 } 365 366 static void 367 intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state, u32 level) 368 { 369 struct intel_connector *connector = to_intel_connector(conn_state->connector); 370 struct intel_panel *panel = &connector->panel; 371 372 /* Nothing to do for AUX based backlight controls */ 373 if (panel->backlight.edp.intel_cap.sdr_uses_aux) 374 return; 375 376 /* Note we want the actual pwm_level to be 0, regardless of pwm_min */ 377 panel->backlight.pwm_funcs->disable(conn_state, intel_backlight_invert_pwm_level(connector, 0)); 378 } 379 380 static const char *dpcd_vs_pwm_str(bool aux) 381 { 382 return aux ? "DPCD" : "PWM"; 383 } 384 385 static void 386 intel_dp_aux_write_panel_luminance_override(struct intel_connector *connector) 387 { 388 struct intel_display *display = to_intel_display(connector); 389 struct intel_panel *panel = &connector->panel; 390 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 391 int ret; 392 u8 buf[4] = {}; 393 394 buf[0] = panel->backlight.min & 0xFF; 395 buf[1] = (panel->backlight.min & 0xFF00) >> 8; 396 buf[2] = panel->backlight.max & 0xFF; 397 buf[3] = (panel->backlight.max & 0xFF00) >> 8; 398 399 ret = drm_dp_dpcd_write(&intel_dp->aux, 400 INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE, 401 buf, sizeof(buf)); 402 if (ret < 0) 403 drm_dbg_kms(display->drm, 404 "Panel Luminance DPCD reg write failed, err:-%d\n", 405 ret); 406 } 407 408 static int 409 intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pipe) 410 { 411 struct intel_display *display = to_intel_display(connector); 412 struct intel_panel *panel = &connector->panel; 413 struct drm_luminance_range_info *luminance_range = 414 &connector->base.display_info.luminance_range; 415 int ret; 416 417 drm_dbg_kms(display->drm, 418 "[CONNECTOR:%d:%s] SDR backlight is controlled through %s\n", 419 connector->base.base.id, connector->base.name, 420 dpcd_vs_pwm_str(panel->backlight.edp.intel_cap.sdr_uses_aux)); 421 422 if (!panel->backlight.edp.intel_cap.sdr_uses_aux) { 423 ret = panel->backlight.pwm_funcs->setup(connector, pipe); 424 if (ret < 0) { 425 drm_err(display->drm, 426 "[CONNECTOR:%d:%s] Failed to setup SDR backlight controls through PWM: %d\n", 427 connector->base.base.id, connector->base.name, ret); 428 return ret; 429 } 430 } 431 432 if (luminance_range->max_luminance) { 433 panel->backlight.max = luminance_range->max_luminance; 434 panel->backlight.min = luminance_range->min_luminance; 435 } else { 436 panel->backlight.max = 512; 437 panel->backlight.min = 0; 438 } 439 440 intel_dp_aux_write_panel_luminance_override(connector); 441 442 drm_dbg_kms(display->drm, 443 "[CONNECTOR:%d:%s] Using AUX HDR interface for backlight control (range %d..%d)\n", 444 connector->base.base.id, connector->base.name, 445 panel->backlight.min, panel->backlight.max); 446 447 panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe); 448 panel->backlight.enabled = panel->backlight.level != 0; 449 450 return 0; 451 } 452 453 /* VESA backlight callbacks */ 454 static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused) 455 { 456 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 457 struct intel_panel *panel = &connector->panel; 458 u8 buf[3]; 459 u32 val = 0; 460 int ret; 461 462 if (panel->backlight.edp.vesa.luminance_control_support) { 463 ret = drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, buf, 464 sizeof(buf)); 465 if (ret < 0) { 466 drm_err(intel_dp->aux.drm_dev, 467 "[CONNECTOR:%d:%s] Failed to read Luminance from DPCD\n", 468 connector->base.base.id, connector->base.name); 469 return 0; 470 } 471 472 val |= buf[0] | buf[1] << 8 | buf[2] << 16; 473 return val / 1000; 474 } 475 476 return connector->panel.backlight.level; 477 } 478 479 static int 480 intel_dp_aux_vesa_set_luminance(struct intel_connector *connector, u32 level) 481 { 482 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 483 u8 buf[3]; 484 int ret; 485 486 level = level * 1000; 487 level &= 0xffffff; 488 buf[0] = (level & 0x0000ff); 489 buf[1] = (level & 0x00ff00) >> 8; 490 buf[2] = (level & 0xff0000) >> 16; 491 492 ret = drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, 493 buf, sizeof(buf)); 494 if (ret != sizeof(buf)) { 495 drm_err(intel_dp->aux.drm_dev, 496 "%s: Failed to set VESA Aux Luminance: %d\n", 497 intel_dp->aux.name, ret); 498 return -EINVAL; 499 } else { 500 return 0; 501 } 502 } 503 504 static void 505 intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level) 506 { 507 struct intel_connector *connector = to_intel_connector(conn_state->connector); 508 struct intel_panel *panel = &connector->panel; 509 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 510 511 if (panel->backlight.edp.vesa.luminance_control_support) { 512 if (!intel_dp_aux_vesa_set_luminance(connector, level)) 513 return; 514 } 515 516 if (!panel->backlight.edp.vesa.info.aux_set) { 517 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level); 518 519 intel_backlight_set_pwm_level(conn_state, pwm_level); 520 } 521 522 drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); 523 } 524 525 static void 526 intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, 527 const struct drm_connector_state *conn_state, u32 level) 528 { 529 struct intel_connector *connector = to_intel_connector(conn_state->connector); 530 struct intel_panel *panel = &connector->panel; 531 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 532 int ret; 533 534 if (panel->backlight.edp.vesa.luminance_control_support) { 535 ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, 536 DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE); 537 538 if (ret == 1) 539 return; 540 541 if (!intel_dp_aux_vesa_set_luminance(connector, level)) 542 return; 543 } 544 545 if (!panel->backlight.edp.vesa.info.aux_enable) { 546 u32 pwm_level; 547 548 if (!panel->backlight.edp.vesa.info.aux_set) 549 pwm_level = intel_backlight_level_to_pwm(connector, level); 550 else 551 pwm_level = intel_backlight_invert_pwm_level(connector, 552 panel->backlight.pwm_level_max); 553 554 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level); 555 } 556 557 drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); 558 } 559 560 static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state *old_conn_state, 561 u32 level) 562 { 563 struct intel_connector *connector = to_intel_connector(old_conn_state->connector); 564 struct intel_panel *panel = &connector->panel; 565 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); 566 567 if (panel->backlight.edp.vesa.luminance_control_support) 568 return; 569 570 drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info); 571 572 if (!panel->backlight.edp.vesa.info.aux_enable) 573 panel->backlight.pwm_funcs->disable(old_conn_state, 574 intel_backlight_invert_pwm_level(connector, 0)); 575 } 576 577 static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe) 578 { 579 struct intel_display *display = to_intel_display(connector); 580 struct drm_luminance_range_info *luminance_range = 581 &connector->base.display_info.luminance_range; 582 struct intel_dp *intel_dp = intel_attached_dp(connector); 583 struct intel_panel *panel = &connector->panel; 584 u16 current_level; 585 u8 current_mode; 586 int ret; 587 588 if (panel->backlight.edp.vesa.luminance_control_support) { 589 if (luminance_range->max_luminance) { 590 panel->backlight.max = luminance_range->max_luminance; 591 panel->backlight.min = luminance_range->min_luminance; 592 } else { 593 panel->backlight.max = 512; 594 panel->backlight.min = 0; 595 } 596 panel->backlight.level = intel_dp_aux_vesa_get_backlight(connector, 0); 597 panel->backlight.enabled = panel->backlight.level != 0; 598 drm_dbg_kms(display->drm, 599 "[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n", 600 connector->base.base.id, connector->base.name); 601 } else { 602 ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, 603 panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, 604 ¤t_level, ¤t_mode); 605 if (ret < 0) 606 return ret; 607 608 drm_dbg_kms(display->drm, 609 "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n", 610 connector->base.base.id, connector->base.name, 611 dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable)); 612 drm_dbg_kms(display->drm, 613 "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n", 614 connector->base.base.id, connector->base.name, 615 dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set)); 616 617 if (!panel->backlight.edp.vesa.info.aux_set || 618 !panel->backlight.edp.vesa.info.aux_enable) { 619 ret = panel->backlight.pwm_funcs->setup(connector, pipe); 620 if (ret < 0) { 621 drm_err(display->drm, 622 "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n", 623 connector->base.base.id, connector->base.name, ret); 624 return ret; 625 } 626 } 627 628 if (panel->backlight.edp.vesa.info.aux_set) { 629 panel->backlight.max = panel->backlight.edp.vesa.info.max; 630 panel->backlight.min = 0; 631 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { 632 panel->backlight.level = current_level; 633 panel->backlight.enabled = panel->backlight.level != 0; 634 } else { 635 panel->backlight.level = panel->backlight.max; 636 panel->backlight.enabled = false; 637 } 638 } else { 639 panel->backlight.max = panel->backlight.pwm_level_max; 640 panel->backlight.min = panel->backlight.pwm_level_min; 641 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) { 642 panel->backlight.level = 643 panel->backlight.pwm_funcs->get(connector, pipe); 644 panel->backlight.enabled = panel->backlight.pwm_enabled; 645 } else { 646 panel->backlight.level = panel->backlight.max; 647 panel->backlight.enabled = false; 648 } 649 } 650 } 651 652 drm_dbg_kms(display->drm, 653 "[CONNECTOR:%d:%s] Using AUX VESA interface for backlight control\n", 654 connector->base.base.id, connector->base.name); 655 656 return 0; 657 } 658 659 static bool 660 intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) 661 { 662 struct intel_display *display = to_intel_display(connector); 663 struct intel_dp *intel_dp = intel_attached_dp(connector); 664 struct intel_panel *panel = &connector->panel; 665 666 if ((intel_dp->edp_dpcd[3] & DP_EDP_PANEL_LUMINANCE_CONTROL_CAPABLE)) { 667 drm_dbg_kms(display->drm, 668 "[CONNECTOR:%d:%s] AUX Luminance Based Backlight Control Supported!\n", 669 connector->base.base.id, connector->base.name); 670 panel->backlight.edp.vesa.luminance_control_support = true; 671 return true; 672 } 673 674 if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) { 675 drm_dbg_kms(display->drm, 676 "[CONNECTOR:%d:%s] AUX Backlight Control Supported!\n", 677 connector->base.base.id, connector->base.name); 678 return true; 679 } 680 return false; 681 } 682 683 static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = { 684 .setup = intel_dp_aux_hdr_setup_backlight, 685 .enable = intel_dp_aux_hdr_enable_backlight, 686 .disable = intel_dp_aux_hdr_disable_backlight, 687 .set = intel_dp_aux_hdr_set_backlight, 688 .get = intel_dp_aux_hdr_get_backlight, 689 }; 690 691 static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = { 692 .setup = intel_dp_aux_vesa_setup_backlight, 693 .enable = intel_dp_aux_vesa_enable_backlight, 694 .disable = intel_dp_aux_vesa_disable_backlight, 695 .set = intel_dp_aux_vesa_set_backlight, 696 .get = intel_dp_aux_vesa_get_backlight, 697 }; 698 699 int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) 700 { 701 struct intel_display *display = to_intel_display(connector); 702 struct intel_dp *intel_dp = intel_attached_dp(connector); 703 struct drm_device *dev = connector->base.dev; 704 struct intel_panel *panel = &connector->panel; 705 bool try_intel_interface = false, try_vesa_interface = false; 706 707 /* Check the VBT and user's module parameters to figure out which 708 * interfaces to probe 709 */ 710 switch (display->params.enable_dpcd_backlight) { 711 case INTEL_DP_AUX_BACKLIGHT_OFF: 712 return -ENODEV; 713 case INTEL_DP_AUX_BACKLIGHT_AUTO: 714 switch (panel->vbt.backlight.type) { 715 case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE: 716 try_vesa_interface = true; 717 break; 718 case INTEL_BACKLIGHT_DISPLAY_DDI: 719 try_intel_interface = true; 720 break; 721 default: 722 return -ENODEV; 723 } 724 break; 725 case INTEL_DP_AUX_BACKLIGHT_ON: 726 if (panel->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE) 727 try_intel_interface = true; 728 729 try_vesa_interface = true; 730 break; 731 case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA: 732 try_vesa_interface = true; 733 break; 734 case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL: 735 try_intel_interface = true; 736 break; 737 } 738 739 /* For eDP 1.5 and above we are supposed to use VESA interface for brightness control */ 740 if (intel_dp->edp_dpcd[0] >= DP_EDP_15) 741 try_vesa_interface = true; 742 743 /* 744 * Since Intel has their own backlight control interface, the majority of machines out there 745 * using DPCD backlight controls with Intel GPUs will be using this interface as opposed to 746 * the VESA interface. However, other GPUs (such as Nvidia's) will always use the VESA 747 * interface. This means that there's quite a number of panels out there that will advertise 748 * support for both interfaces, primarily systems with Intel/Nvidia hybrid GPU setups. 749 * 750 * There's a catch to this though: on many panels that advertise support for both 751 * interfaces, the VESA backlight interface will stop working once we've programmed the 752 * panel with Intel's OUI - which is also required for us to be able to detect Intel's 753 * backlight interface at all. This means that the only sensible way for us to detect both 754 * interfaces is to probe for Intel's first, and VESA's second. 755 */ 756 if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector) && 757 intel_dp->edp_dpcd[0] <= DP_EDP_14b) { 758 drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Using Intel proprietary eDP backlight controls\n", 759 connector->base.base.id, connector->base.name); 760 panel->backlight.funcs = &intel_dp_hdr_bl_funcs; 761 return 0; 762 } 763 764 if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) { 765 drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Using VESA eDP backlight controls\n", 766 connector->base.base.id, connector->base.name); 767 panel->backlight.funcs = &intel_dp_vesa_bl_funcs; 768 return 0; 769 } 770 771 return -ENODEV; 772 } 773