diff options
Diffstat (limited to '0002-WIP-drm-i915-Enable-Intel-s-HDR-backlight-interface-.patch')
-rw-r--r-- | 0002-WIP-drm-i915-Enable-Intel-s-HDR-backlight-interface-.patch | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/0002-WIP-drm-i915-Enable-Intel-s-HDR-backlight-interface-.patch b/0002-WIP-drm-i915-Enable-Intel-s-HDR-backlight-interface-.patch new file mode 100644 index 000000000000..748b75270b5f --- /dev/null +++ b/0002-WIP-drm-i915-Enable-Intel-s-HDR-backlight-interface-.patch @@ -0,0 +1,583 @@ +From 904a2b4014ea38c67b6bd19de12c27a2d5f7a6b1 Mon Sep 17 00:00:00 2001 +From: Lyude Paul <lyude@redhat.com> +Date: Mon, 29 Jun 2020 15:01:49 -0400 +Subject: [PATCH 2/2] WIP: drm/i915: Enable Intel's HDR backlight interface + (only SDR for now) + +So-recently a bunch of laptops on the market have started using DPCD +backlight controls instead of the traditional DDI backlight controls. +Originally we thought we had this handled by adding VESA backlight +control support to i915, but the story ended up being a lot more +complicated then that. + +Simply put-there's two main backlight interfaces Intel can see in the +wild. Intel's proprietary HDR backlight interface, and the standard VESA +backlight interface. Note that many panels have been observed to report +support for both backlight interfaces, but testing has shown far more +panels work with the Intel HDR backlight interface at the moment. +Additionally, the VBT appears to be capable of reporting support for the +VESA backlight interface but not the Intel HDR interface which needs to +be probed by setting the right magic OUI. + +For the time being we've been using EDIDs to maintain a list of quirks +for panels that safely do support the VESA backlight interface. Adding +support for Intel's HDR backlight interface in addition however, should +finally allow us to auto-detect eDP backlight controls properly so long +as we probe like so: + +* If the panel's VBT reports VESA backlight support, assume it really + does support it +* If the panel's VBT reports DDI backlight controls: + * First probe for Intel's HDR backlight interface + * If that fails, probe for VESA's backlight interface + * If that fails, assume no DPCD backlight control +* If the panel's VBT reports any other backlight type: just assume it + doesn't have DPCD backlight controls + +Note as well that in order for us to make Intel's HDR backlight +interface appear, we need to start programming the appropriate source +OUI on the eDP panel as early as possible in the probing process. Note +that this technically could be done at any time before setting up +backlight controls, but this way allows us to avoid re-writing it +multiple times in case we need to use other source-OUI enabled features +in the future. + +Finally, we also make sure to document the registers for this backlight +interface since eventually, we want to actually implement the full +interface instead of keeping it in SDR mode. + +Signed-off-by: Lyude Paul <lyude@redhat.com> +--- + .../drm/i915/display/intel_display_types.h | 9 +- + drivers/gpu/drm/i915/display/intel_dp.c | 15 + + .../drm/i915/display/intel_dp_aux_backlight.c | 334 +++++++++++++++--- + drivers/gpu/drm/i915/i915_params.c | 2 +- + 4 files changed, 308 insertions(+), 52 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h +index 5e00e611f077..b89e67e271ed 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_types.h ++++ b/drivers/gpu/drm/i915/display/intel_display_types.h +@@ -219,7 +219,14 @@ struct intel_panel { + struct pwm_device *pwm; + + /* DPCD backlight */ +- u8 pwmgen_bit_count; ++ union { ++ struct { ++ u8 pwmgen_bit_count; ++ } vesa; ++ struct { ++ ++ } intel; ++ } edp; + + struct backlight_device *device; + +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index 9231a0ef6270..5a66cf5caefe 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -3201,7 +3201,10 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, + /* If the sink supports it, try to set the power state appropriately */ + void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) + { ++ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); ++ struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); + int ret, i; ++ u8 edp_oui[] = { 0x00, 0xaa, 0x01 }; + + /* Should have a valid DPCD by this point */ + if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) +@@ -3216,6 +3219,16 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) + } else { + struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp); + ++ /* Write the source OUI as early as possible */ ++ if (intel_dp_is_edp(intel_dp)) { ++ ret = drm_dp_dpcd_write(&intel_dp->aux, ++ DP_SOURCE_OUI, edp_oui, ++ sizeof(edp_oui)); ++ if (ret < 0) ++ drm_err(&dev_priv->drm, ++ "Failed to write eDP source OUI\n"); ++ } ++ + /* + * When turning on, we need to retry for 1ms to give the sink + * time to wake up. +@@ -4408,6 +4421,8 @@ static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp) + } + } + ++ ++ + static void + intel_edp_init_source_oui(struct intel_dp *intel_dp) + { +diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +index dbfa6895795b..9d43003760fd 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +@@ -22,10 +22,196 @@ + * + */ + ++/* XXX: maybe make this kernel docs */ ++/* ++ * Laptops with Intel GPUs which have panels that support controlling the ++ * backlight through DP AUX can actually use two different interfaces: Intel's ++ * proprietary DP AUX backlight interface, and the standard VESA backlight ++ * interface. Unfortunately, at the time of writing this a lot of laptops will ++ * advertise support for the standard VESA backlight interface when they ++ * don't properly support it. However, on these systems the Intel backlight ++ * interface generally does work properly. Additionally, these systems will ++ * usually just indicate that they use PWM backlight controls in their VBIOS ++ * for some reason. ++ */ ++ + #include "intel_display_types.h" + #include "intel_dp_aux_backlight.h" + +-static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) ++/* ++ * DP AUX registers for Intel's proprietary HDR backlight interface. We define ++ * them here since we'll likely be the only driver to ever use these. ++ */ ++#define INTEL_EDP_HDR_TCON_CAP0 0x340 ++ ++#define INTEL_EDP_HDR_TCON_CAP1 0x341 ++# define INTEL_EDP_HDR_TCON_2084_DECODE_CAP BIT(0) ++# define INTEL_EDP_HDR_TCON_2020_GAMUT_CAP BIT(1) ++# define INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP BIT(2) ++# define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP BIT(3) ++# define INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP BIT(4) ++# define INTEL_EDP_HDR_TCON_OPTIMIZATION_CAP BIT(5) ++# define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP BIT(6) ++# define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_CONVERSION_CAP BIT(7) ++ ++#define INTEL_EDP_HDR_TCON_CAP2 0x342 ++# define INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP BIT(0) ++ ++#define INTEL_EDP_HDR_TCON_CAP3 0x343 ++ ++#define INTEL_EDP_HDR_GETSET_CTRL_PARAMS 0x344 ++# define INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE BIT(0) ++# define INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE BIT(1) ++# define INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE BIT(2) /* Pre-TGL+ */ ++# define INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE BIT(3) ++# define INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE BIT(4) ++# define INTEL_EDP_HDR_TCON_SRGB_TO_PANEL_GAMUT_ENABLE BIT(5) ++/* Bit 6 is reserved */ ++# define INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_ENABLE BIT(7) ++ ++#define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346 /* Pre-TGL+ */ ++#define INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE 0x34A ++#define INTEL_EDP_SDR_LUMINANCE_LEVEL 0x352 ++#define INTEL_EDP_BRIGHTNESS_NITS_LSB 0x354 ++#define INTEL_EDP_BRIGHTNESS_NITS_MSB 0x355 ++#define INTEL_EDP_BRIGHTNESS_DELAY_FRAMES 0x356 ++#define INTEL_EDP_BRIGHTNESS_PER_FRAME_STEPS 0x357 ++ ++#define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_0 0x358 ++# define INTEL_EDP_TCON_USAGE_MASK GENMASK(0, 3) ++# define INTEL_EDP_TCON_USAGE_UNKNOWN 0x0 ++# define INTEL_EDP_TCON_USAGE_DESKTOP 0x1 ++# define INTEL_EDP_TCON_USAGE_FULL_SCREEN_MEDIA 0x2 ++# define INTEL_EDP_TCON_USAGE_FULL_SCREEN_GAMING 0x3 ++# define INTEL_EDP_TCON_POWER_MASK BIT(4) ++# define INTEL_EDP_TCON_POWER_DC (0 << 4) ++# define INTEL_EDP_TCON_POWER_AC (1 << 4) ++# define INTEL_EDP_TCON_OPTIMIZATION_STRENGTH_MASK GENMASK(5, 7) ++ ++#define INTEL_EDP_BRIGHTNESS_OPTIMIZATION_1 0x359 ++ ++/* Intel EDP backlight callbacks */ ++static bool ++intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector) ++{ ++ struct drm_device *dev = connector->base.dev; ++ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); ++ struct drm_dp_aux *aux = &intel_dp->aux; ++ int ret; ++ u8 tcon_cap[4]; ++ ++ ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, ++ tcon_cap, sizeof(tcon_cap)); ++ if (ret < 0) ++ return false; ++ ++ if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP)) ++ return false; ++ ++ /* TODO: Add support for AUX backlight controls in HDR mode */ ++ if (!(tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP)) { ++ DRM_DEV_DEBUG_KMS(dev->dev, ++ "Panel only supports AUX backlight controls for HDR mode, this isn't implemented yet\n"); ++ return false; ++ } ++ ++ return true; ++} ++ ++static u32 ++intel_dp_aux_hdr_get_backlight(struct intel_connector *connector) ++{ ++ struct drm_device *dev = connector->base.dev; ++ struct intel_panel *panel = &connector->panel; ++ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); ++ u8 tmp; ++ u8 buf[2] = { 0 }; ++ ++ if (drm_dp_dpcd_readb(&intel_dp->aux, ++ INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) < 0) ++ DRM_DEV_DEBUG_KMS(dev->dev, ++ "Failed to read current backlight mode from DPCD\n"); ++ ++ /* Assume 100% brightness if backlight controls aren't enabled over ++ * AUX yet ++ */ ++ if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) ++ return panel->backlight.max; ++ ++ if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, ++ buf, sizeof(buf)) < 0) { ++ DRM_DEV_DEBUG_KMS(dev->dev, ++ "Failed to read brightness from DPCD\n"); ++ return 0; ++ } ++ ++ return (buf[1] << 8 | buf[0]); ++} ++ ++static void ++intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, ++ u32 level) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct drm_device *dev = connector->base.dev; ++ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); ++ uint8_t buf[4] = { 0 }; ++ ++ buf[0] = level & 0xFF; ++ buf[1] = (level & 0xFF00) >> 8; ++ ++ if (drm_dp_dpcd_write(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, ++ buf, 4) < 0) ++ DRM_DEV_DEBUG_KMS(dev->dev, ++ "Failed to write brightness level to DPCD\n"); ++} ++ ++static void ++intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state) ++{ ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); ++ struct intel_panel *panel = &connector->panel; ++ struct drm_device *dev = connector->base.dev; ++ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); ++ ++ /* FIXME: figure out if we really need to clear the register ++ * beforehand, ideally we want to avoid turning the backlight off when ++ * it's not needed ++ */ ++ if (drm_dp_dpcd_writeb(&intel_dp->aux, ++ INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ++ INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE) < 0) ++ drm_err(dev, "Failed to enable AUX brightness control\n"); ++ ++ intel_dp_aux_hdr_set_backlight(conn_state, panel->backlight.level); ++ /* FIXME: do we need to write the brightness level before or after we ++ * enable the relevant brightness modes? ++ */ ++} ++ ++static void ++intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *old_conn_state) ++{ ++ /* no-op */ ++} ++ ++static int ++intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, ++ enum pipe pipe) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ panel->backlight.max = 512; ++ panel->backlight.min = 0; ++ panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector); ++ panel->backlight.enabled = panel->backlight.level != 0; ++ ++ return 0; ++} ++ ++/* VESA backlight callbacks */ ++static void set_vesa_backlight_enable(struct intel_dp *intel_dp, bool enable) + { + u8 reg_val = 0; + +@@ -55,7 +241,7 @@ static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) + * Read the current backlight value from DPCD register(s) based + * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported + */ +-static u32 intel_dp_aux_get_backlight(struct intel_connector *connector) ++static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector) + { + struct intel_dp *intel_dp = intel_attached_dp(connector); + u8 read_val[2] = { 0x0 }; +@@ -96,7 +282,7 @@ static u32 intel_dp_aux_get_backlight(struct intel_connector *connector) + * 8-bit or 16 bit value (MSB and LSB) + */ + static void +-intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 level) ++intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level) + { + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); +@@ -124,11 +310,11 @@ intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 lev + * - Where P = 2^Pn, where Pn is the value programmed by field 4:0 of the + * EDP_PWMGEN_BIT_COUNT register (DPCD Address 00724h) + */ +-static bool intel_dp_aux_set_pwm_freq(struct intel_connector *connector) ++static bool intel_dp_aux_vesa_set_pwm_freq(struct intel_connector *connector) + { + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_dp *intel_dp = intel_attached_dp(connector); +- const u8 pn = connector->panel.backlight.pwmgen_bit_count; ++ const u8 pn = connector->panel.backlight.edp.vesa.pwmgen_bit_count; + int freq, fxp, f, fxp_actual, fxp_min, fxp_max; + + freq = dev_priv->vbt.backlight.pwm_freq_hz; +@@ -158,13 +344,14 @@ static bool intel_dp_aux_set_pwm_freq(struct intel_connector *connector) + return true; + } + +-static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_state, +- const struct drm_connector_state *conn_state) ++static void intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, ++ const struct drm_connector_state *conn_state) + { + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_panel *panel = &connector->panel; + u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode; ++ u8 pwmgen_bit_count = panel->backlight.edp.vesa.pwmgen_bit_count; + + if (drm_dp_dpcd_readb(&intel_dp->aux, + DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) { +@@ -185,7 +372,7 @@ static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_st + + if (drm_dp_dpcd_writeb(&intel_dp->aux, + DP_EDP_PWMGEN_BIT_COUNT, +- panel->backlight.pwmgen_bit_count) < 0) ++ pwmgen_bit_count) < 0) + DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n"); + + break; +@@ -197,7 +384,7 @@ static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_st + } + + if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP) +- if (intel_dp_aux_set_pwm_freq(connector)) ++ if (intel_dp_aux_vesa_set_pwm_freq(connector)) + new_dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE; + + if (new_dpcd_buf != dpcd_buf) { +@@ -207,18 +394,18 @@ static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_st + } + } + +- intel_dp_aux_set_backlight(conn_state, +- connector->panel.backlight.level); +- set_aux_backlight_enable(intel_dp, true); ++ intel_dp_aux_vesa_set_backlight(conn_state, ++ connector->panel.backlight.level); ++ set_vesa_backlight_enable(intel_dp, true); + } + +-static void intel_dp_aux_disable_backlight(const struct drm_connector_state *old_conn_state) ++static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state *old_conn_state) + { +- set_aux_backlight_enable(enc_to_intel_dp(to_intel_encoder(old_conn_state->best_encoder)), +- false); ++ set_vesa_backlight_enable(enc_to_intel_dp(to_intel_encoder(old_conn_state->best_encoder)), ++ false); + } + +-static u32 intel_dp_aux_calc_max_backlight(struct intel_connector *connector) ++static u32 intel_dp_aux_vesa_calc_max_backlight(struct intel_connector *connector) + { + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_dp *intel_dp = intel_attached_dp(connector); +@@ -285,31 +472,31 @@ static u32 intel_dp_aux_calc_max_backlight(struct intel_connector *connector) + DRM_DEBUG_KMS("Failed to write aux pwmgen bit count\n"); + return max_backlight; + } +- panel->backlight.pwmgen_bit_count = pn; ++ panel->backlight.edp.vesa.pwmgen_bit_count = pn; + + max_backlight = (1 << pn) - 1; + + return max_backlight; + } + +-static int intel_dp_aux_setup_backlight(struct intel_connector *connector, +- enum pipe pipe) ++static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, ++ enum pipe pipe) + { + struct intel_panel *panel = &connector->panel; + +- panel->backlight.max = intel_dp_aux_calc_max_backlight(connector); ++ panel->backlight.max = intel_dp_aux_vesa_calc_max_backlight(connector); + if (!panel->backlight.max) + return -ENODEV; + + panel->backlight.min = 0; +- panel->backlight.level = intel_dp_aux_get_backlight(connector); ++ panel->backlight.level = intel_dp_aux_vesa_get_backlight(connector); + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; + } + + static bool +-intel_dp_aux_display_control_capable(struct intel_connector *connector) ++intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) + { + struct intel_dp *intel_dp = intel_attached_dp(connector); + +@@ -325,41 +512,88 @@ intel_dp_aux_display_control_capable(struct intel_connector *connector) + return false; + } + +-int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector) ++enum intel_dp_aux_backlight_modparam { ++ INTEL_DP_AUX_BACKLIGHT_AUTO = -1, ++ INTEL_DP_AUX_BACKLIGHT_OFF = 0, ++ INTEL_DP_AUX_BACKLIGHT_ON = 1, ++ INTEL_DP_AUX_BACKLIGHT_FORCE_VESA = 2, ++ INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL = 3, ++}; ++ ++int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) + { +- struct intel_panel *panel = &intel_connector->panel; +- struct intel_dp *intel_dp = enc_to_intel_dp(intel_connector->encoder); +- struct drm_device *dev = intel_connector->base.dev; +- struct drm_i915_private *dev_priv = to_i915(dev); ++ struct drm_device *dev = connector->base.dev; ++ struct intel_panel *panel = &connector->panel; ++ struct drm_i915_private *i915 = to_i915(dev); ++ bool try_intel_interface = false, try_vesa_interface = false; + +- if (i915_modparams.enable_dpcd_backlight == 0 || +- !intel_dp_aux_display_control_capable(intel_connector)) ++ /* Check the VBT and user's module parameters to figure out which ++ * interfaces to probe ++ */ ++ switch (i915_modparams.enable_dpcd_backlight) { ++ case INTEL_DP_AUX_BACKLIGHT_OFF: + return -ENODEV; ++ case INTEL_DP_AUX_BACKLIGHT_AUTO: ++ switch (i915->vbt.backlight.type) { ++ case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE: ++ try_vesa_interface = true; ++ break; ++ case INTEL_BACKLIGHT_DISPLAY_DDI: ++ try_intel_interface = true; ++ try_vesa_interface = true; ++ break; ++ default: ++ return -ENODEV; ++ } ++ break; ++ case INTEL_DP_AUX_BACKLIGHT_ON: ++ if (i915->vbt.backlight.type != ++ INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE) ++ try_intel_interface = true; ++ ++ try_vesa_interface = true; ++ break; ++ case INTEL_DP_AUX_BACKLIGHT_FORCE_VESA: ++ try_vesa_interface = true; ++ break; ++ case INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL: ++ try_intel_interface = true; ++ break; ++ } + + /* +- * There are a lot of machines that don't advertise the backlight +- * control interface to use properly in their VBIOS, :\ ++ * A lot of eDP panels in the wild will report supporting both the ++ * Intel proprietary backlight control interface, and the VESA ++ * backlight control interface. Many of these panels are liars though, ++ * and will only work with the Intel interface. So, always probe for ++ * that first. + */ +- if (dev_priv->vbt.backlight.type != +- INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE && +- i915_modparams.enable_dpcd_backlight != 1 && +- !drm_dp_has_quirk(&intel_dp->desc, intel_dp->edid_quirks, +- DP_QUIRK_FORCE_DPCD_BACKLIGHT)) { +- DRM_DEV_INFO(dev->dev, +- "Panel advertises DPCD backlight support, but " +- "VBT disagrees. If your backlight controls " +- "don't work try booting with " +- "i915.enable_dpcd_backlight=1. If your machine " +- "needs this, please file a _new_ bug report on " +- "drm/i915, see " FDO_BUG_URL " for details.\n"); +- return -ENODEV; ++ if (try_intel_interface && ++ intel_dp_aux_supports_hdr_backlight(connector)) { ++ DRM_DEV_DEBUG_DRIVER(dev->dev, ++ "Using Intel proprietary eDP backlight controls\n"); ++ ++ panel->backlight.setup = intel_dp_aux_hdr_setup_backlight; ++ panel->backlight.enable = intel_dp_aux_hdr_enable_backlight; ++ panel->backlight.disable = intel_dp_aux_hdr_disable_backlight; ++ panel->backlight.set = intel_dp_aux_hdr_set_backlight; ++ panel->backlight.get = intel_dp_aux_hdr_get_backlight; ++ ++ return 0; + } + +- panel->backlight.setup = intel_dp_aux_setup_backlight; +- panel->backlight.enable = intel_dp_aux_enable_backlight; +- panel->backlight.disable = intel_dp_aux_disable_backlight; +- panel->backlight.set = intel_dp_aux_set_backlight; +- panel->backlight.get = intel_dp_aux_get_backlight; ++ if (try_vesa_interface && ++ intel_dp_aux_supports_vesa_backlight(connector)) { ++ DRM_DEV_DEBUG_DRIVER(dev->dev, ++ "Using VESA eDP backlight controls\n"); ++ panel->backlight.setup = intel_dp_aux_vesa_setup_backlight; ++ panel->backlight.enable = intel_dp_aux_vesa_enable_backlight; ++ panel->backlight.disable = intel_dp_aux_vesa_disable_backlight; ++ panel->backlight.set = intel_dp_aux_vesa_set_backlight; ++ panel->backlight.get = intel_dp_aux_vesa_get_backlight; + +- return 0; ++ return 0; ++ } ++ ++ return -ENODEV; + } +diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c +index add00ec1f787..a1f939988240 100644 +--- a/drivers/gpu/drm/i915/i915_params.c ++++ b/drivers/gpu/drm/i915/i915_params.c +@@ -165,7 +165,7 @@ i915_param_named_unsafe(inject_probe_failure, uint, 0400, + + i915_param_named(enable_dpcd_backlight, int, 0600, + "Enable support for DPCD backlight control" +- "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enabled)"); ++ "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); + + #if IS_ENABLED(CONFIG_DRM_I915_GVT) + i915_param_named(enable_gvt, bool, 0400, +-- +2.27.0 + |