0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include "i915_drv.h"
0038 #include "intel_backlight.h"
0039 #include "intel_display_types.h"
0040 #include "intel_dp.h"
0041 #include "intel_dp_aux_backlight.h"
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 #define INTEL_EDP_HDR_TCON_CAP0 0x340
0053
0054 #define INTEL_EDP_HDR_TCON_CAP1 0x341
0055 # define INTEL_EDP_HDR_TCON_2084_DECODE_CAP BIT(0)
0056 # define INTEL_EDP_HDR_TCON_2020_GAMUT_CAP BIT(1)
0057 # define INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP BIT(2)
0058 # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP BIT(3)
0059 # define INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP BIT(4)
0060 # define INTEL_EDP_HDR_TCON_OPTIMIZATION_CAP BIT(5)
0061 # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP BIT(6)
0062 # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_CONVERSION_CAP BIT(7)
0063
0064 #define INTEL_EDP_HDR_TCON_CAP2 0x342
0065 # define INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP BIT(0)
0066
0067 #define INTEL_EDP_HDR_TCON_CAP3 0x343
0068
0069 #define INTEL_EDP_HDR_GETSET_CTRL_PARAMS 0x344
0070 # define INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE BIT(0)
0071 # define INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE BIT(1)
0072 # define INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE BIT(2)
0073 # define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE BIT(3)
0074 # define INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE BIT(4)
0075 # define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_ENABLE BIT(5)
0076
0077 # define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_ENABLE BIT(7)
0078
0079 #define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346
0080 #define INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE 0x34A
0081 #define INTEL_EDP_SDR_LUMINANCE_LEVEL 0x352
0082 #define INTEL_EDP_BRIGHTNESS_NITS_LSB 0x354
0083 #define INTEL_EDP_BRIGHTNESS_NITS_MSB 0x355
0084 #define INTEL_EDP_BRIGHTNESS_DELAY_FRAMES 0x356
0085 #define INTEL_EDP_BRIGHTNESS_PER_FRAME_STEPS 0x357
0086
0087 #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_0 0x358
0088 # define INTEL_EDP_TCON_USAGE_MASK GENMASK(0, 3)
0089 # define INTEL_EDP_TCON_USAGE_UNKNOWN 0x0
0090 # define INTEL_EDP_TCON_USAGE_DESKTOP 0x1
0091 # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_MEDIA 0x2
0092 # define INTEL_EDP_TCON_USAGE_FULL_SCREEN_GAMING 0x3
0093 # define INTEL_EDP_TCON_POWER_MASK BIT(4)
0094 # define INTEL_EDP_TCON_POWER_DC (0 << 4)
0095 # define INTEL_EDP_TCON_POWER_AC (1 << 4)
0096 # define INTEL_EDP_TCON_OPTIMIZATION_STRENGTH_MASK GENMASK(5, 7)
0097
0098 #define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359
0099
0100 enum intel_dp_aux_backlight_modparam {
0101 INTEL_DP_AUX_BACKLIGHT_AUTO = -1,
0102 INTEL_DP_AUX_BACKLIGHT_OFF = 0,
0103 INTEL_DP_AUX_BACKLIGHT_ON = 1,
0104 INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2,
0105 INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3,
0106 };
0107
0108
0109 static bool
0110 intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
0111 {
0112 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0113 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0114 struct drm_dp_aux *aux = &intel_dp->aux;
0115 struct intel_panel *panel = &connector->panel;
0116 int ret;
0117 u8 tcon_cap[4];
0118
0119 intel_dp_wait_source_oui(intel_dp);
0120
0121 ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap));
0122 if (ret != sizeof(tcon_cap))
0123 return false;
0124
0125 if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP))
0126 return false;
0127
0128 if (tcon_cap[0] >= 1) {
0129 drm_dbg_kms(&i915->drm, "Detected Intel HDR backlight interface version %d\n",
0130 tcon_cap[0]);
0131 } else {
0132 drm_dbg_kms(&i915->drm, "Detected unsupported HDR backlight interface version %d\n",
0133 tcon_cap[0]);
0134 return false;
0135 }
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 if (i915->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL &&
0147 !(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type &
0148 BIT(HDMI_STATIC_METADATA_TYPE1))) {
0149 drm_info(&i915->drm,
0150 "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",
0151 INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL);
0152 return false;
0153 }
0154
0155 panel->backlight.edp.intel.sdr_uses_aux =
0156 tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP;
0157
0158 return true;
0159 }
0160
0161 static u32
0162 intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe)
0163 {
0164 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0165 struct intel_panel *panel = &connector->panel;
0166 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0167 u8 tmp;
0168 u8 buf[2] = { 0 };
0169
0170 if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) {
0171 drm_err(&i915->drm, "Failed to read current backlight mode from DPCD\n");
0172 return 0;
0173 }
0174
0175 if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) {
0176 if (!panel->backlight.edp.intel.sdr_uses_aux) {
0177 u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe);
0178
0179 return intel_backlight_level_from_pwm(connector, pwm_level);
0180 }
0181
0182
0183 return panel->backlight.max;
0184 }
0185
0186 if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
0187 sizeof(buf)) != sizeof(buf)) {
0188 drm_err(&i915->drm, "Failed to read brightness from DPCD\n");
0189 return 0;
0190 }
0191
0192 return (buf[1] << 8 | buf[0]);
0193 }
0194
0195 static void
0196 intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, u32 level)
0197 {
0198 struct intel_connector *connector = to_intel_connector(conn_state->connector);
0199 struct drm_device *dev = connector->base.dev;
0200 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0201 u8 buf[4] = { 0 };
0202
0203 buf[0] = level & 0xFF;
0204 buf[1] = (level & 0xFF00) >> 8;
0205
0206 if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
0207 sizeof(buf)) != sizeof(buf))
0208 drm_err(dev, "Failed to write brightness level to DPCD\n");
0209 }
0210
0211 static void
0212 intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32 level)
0213 {
0214 struct intel_connector *connector = to_intel_connector(conn_state->connector);
0215 struct intel_panel *panel = &connector->panel;
0216
0217 if (panel->backlight.edp.intel.sdr_uses_aux) {
0218 intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
0219 } else {
0220 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
0221
0222 intel_backlight_set_pwm_level(conn_state, pwm_level);
0223 }
0224 }
0225
0226 static void
0227 intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
0228 const struct drm_connector_state *conn_state, u32 level)
0229 {
0230 struct intel_connector *connector = to_intel_connector(conn_state->connector);
0231 struct intel_panel *panel = &connector->panel;
0232 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0233 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0234 int ret;
0235 u8 old_ctrl, ctrl;
0236
0237 intel_dp_wait_source_oui(intel_dp);
0238
0239 ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
0240 if (ret != 1) {
0241 drm_err(&i915->drm, "Failed to read current backlight control mode: %d\n", ret);
0242 return;
0243 }
0244
0245 ctrl = old_ctrl;
0246 if (panel->backlight.edp.intel.sdr_uses_aux) {
0247 ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
0248 intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
0249 } else {
0250 u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
0251
0252 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
0253
0254 ctrl &= ~INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
0255 }
0256
0257 if (ctrl != old_ctrl)
0258 if (drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) != 1)
0259 drm_err(&i915->drm, "Failed to configure DPCD brightness controls\n");
0260 }
0261
0262 static void
0263 intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
0264 {
0265 struct intel_connector *connector = to_intel_connector(conn_state->connector);
0266 struct intel_panel *panel = &connector->panel;
0267
0268
0269 if (panel->backlight.edp.intel.sdr_uses_aux)
0270 return;
0271
0272
0273 panel->backlight.pwm_funcs->disable(conn_state, intel_backlight_invert_pwm_level(connector, 0));
0274 }
0275
0276 static int
0277 intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pipe)
0278 {
0279 struct drm_i915_private *i915 = to_i915(connector->base.dev);
0280 struct intel_panel *panel = &connector->panel;
0281 int ret;
0282
0283 if (panel->backlight.edp.intel.sdr_uses_aux) {
0284 drm_dbg_kms(&i915->drm, "SDR backlight is controlled through DPCD\n");
0285 } else {
0286 drm_dbg_kms(&i915->drm, "SDR backlight is controlled through PWM\n");
0287
0288 ret = panel->backlight.pwm_funcs->setup(connector, pipe);
0289 if (ret < 0) {
0290 drm_err(&i915->drm,
0291 "Failed to setup SDR backlight controls through PWM: %d\n", ret);
0292 return ret;
0293 }
0294 }
0295
0296 panel->backlight.max = 512;
0297 panel->backlight.min = 0;
0298 panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe);
0299 panel->backlight.enabled = panel->backlight.level != 0;
0300
0301 return 0;
0302 }
0303
0304
0305 static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused)
0306 {
0307 return connector->panel.backlight.level;
0308 }
0309
0310 static void
0311 intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
0312 {
0313 struct intel_connector *connector = to_intel_connector(conn_state->connector);
0314 struct intel_panel *panel = &connector->panel;
0315 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0316
0317 if (!panel->backlight.edp.vesa.info.aux_set) {
0318 const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
0319
0320 intel_backlight_set_pwm_level(conn_state, pwm_level);
0321 }
0322
0323 drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level);
0324 }
0325
0326 static void
0327 intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state,
0328 const struct drm_connector_state *conn_state, u32 level)
0329 {
0330 struct intel_connector *connector = to_intel_connector(conn_state->connector);
0331 struct intel_panel *panel = &connector->panel;
0332 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0333
0334 if (!panel->backlight.edp.vesa.info.aux_enable) {
0335 u32 pwm_level;
0336
0337 if (!panel->backlight.edp.vesa.info.aux_set)
0338 pwm_level = intel_backlight_level_to_pwm(connector, level);
0339 else
0340 pwm_level = intel_backlight_invert_pwm_level(connector,
0341 panel->backlight.pwm_level_max);
0342
0343 panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level);
0344 }
0345
0346 drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level);
0347 }
0348
0349 static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state *old_conn_state,
0350 u32 level)
0351 {
0352 struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
0353 struct intel_panel *panel = &connector->panel;
0354 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0355
0356 drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info);
0357
0358 if (!panel->backlight.edp.vesa.info.aux_enable)
0359 panel->backlight.pwm_funcs->disable(old_conn_state,
0360 intel_backlight_invert_pwm_level(connector, 0));
0361 }
0362
0363 static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe)
0364 {
0365 struct intel_dp *intel_dp = intel_attached_dp(connector);
0366 struct intel_panel *panel = &connector->panel;
0367 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0368 u16 current_level;
0369 u8 current_mode;
0370 int ret;
0371
0372 ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
0373 panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
0374 ¤t_level, ¤t_mode);
0375 if (ret < 0)
0376 return ret;
0377
0378 if (!panel->backlight.edp.vesa.info.aux_set || !panel->backlight.edp.vesa.info.aux_enable) {
0379 ret = panel->backlight.pwm_funcs->setup(connector, pipe);
0380 if (ret < 0) {
0381 drm_err(&i915->drm,
0382 "Failed to setup PWM backlight controls for eDP backlight: %d\n",
0383 ret);
0384 return ret;
0385 }
0386 }
0387
0388 if (panel->backlight.edp.vesa.info.aux_set) {
0389 panel->backlight.max = panel->backlight.edp.vesa.info.max;
0390 panel->backlight.min = 0;
0391 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) {
0392 panel->backlight.level = current_level;
0393 panel->backlight.enabled = panel->backlight.level != 0;
0394 } else {
0395 panel->backlight.level = panel->backlight.max;
0396 panel->backlight.enabled = false;
0397 }
0398 } else {
0399 panel->backlight.max = panel->backlight.pwm_level_max;
0400 panel->backlight.min = panel->backlight.pwm_level_min;
0401 if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) {
0402 panel->backlight.level = panel->backlight.pwm_funcs->get(connector, pipe);
0403 panel->backlight.enabled = panel->backlight.pwm_enabled;
0404 } else {
0405 panel->backlight.level = panel->backlight.max;
0406 panel->backlight.enabled = false;
0407 }
0408 }
0409
0410 return 0;
0411 }
0412
0413 static bool
0414 intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
0415 {
0416 struct intel_dp *intel_dp = intel_attached_dp(connector);
0417 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0418
0419 if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) {
0420 drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n");
0421 return true;
0422 }
0423 return false;
0424 }
0425
0426 static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = {
0427 .setup = intel_dp_aux_hdr_setup_backlight,
0428 .enable = intel_dp_aux_hdr_enable_backlight,
0429 .disable = intel_dp_aux_hdr_disable_backlight,
0430 .set = intel_dp_aux_hdr_set_backlight,
0431 .get = intel_dp_aux_hdr_get_backlight,
0432 };
0433
0434 static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
0435 .setup = intel_dp_aux_vesa_setup_backlight,
0436 .enable = intel_dp_aux_vesa_enable_backlight,
0437 .disable = intel_dp_aux_vesa_disable_backlight,
0438 .set = intel_dp_aux_vesa_set_backlight,
0439 .get = intel_dp_aux_vesa_get_backlight,
0440 };
0441
0442 int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
0443 {
0444 struct drm_device *dev = connector->base.dev;
0445 struct intel_panel *panel = &connector->panel;
0446 struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
0447 struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0448 bool try_intel_interface = false, try_vesa_interface = false;
0449
0450
0451
0452
0453 switch (i915->params.enable_dpcd_backlight) {
0454 case INTEL_DP_AUX_BACKLIGHT_OFF:
0455 return -ENODEV;
0456 case INTEL_DP_AUX_BACKLIGHT_AUTO:
0457 switch (panel->vbt.backlight.type) {
0458 case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE:
0459 try_vesa_interface = true;
0460 break;
0461 case INTEL_BACKLIGHT_DISPLAY_DDI:
0462 try_intel_interface = true;
0463 break;
0464 default:
0465 return -ENODEV;
0466 }
0467 break;
0468 case INTEL_DP_AUX_BACKLIGHT_ON:
0469 if (panel->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE)
0470 try_intel_interface = true;
0471
0472 try_vesa_interface = true;
0473 break;
0474 case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA:
0475 try_vesa_interface = true;
0476 break;
0477 case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL:
0478 try_intel_interface = true;
0479 break;
0480 }
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495 if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) {
0496 drm_dbg_kms(dev, "Using Intel proprietary eDP backlight controls\n");
0497 panel->backlight.funcs = &intel_dp_hdr_bl_funcs;
0498 return 0;
0499 }
0500
0501 if (try_vesa_interface && intel_dp_aux_supports_vesa_backlight(connector)) {
0502 drm_dbg_kms(dev, "Using VESA eDP backlight controls\n");
0503 panel->backlight.funcs = &intel_dp_vesa_bl_funcs;
0504 return 0;
0505 }
0506
0507 return -ENODEV;
0508 }