summarylogtreecommitdiffstats
path: root/0002-WIP-drm-i915-Enable-Intel-s-HDR-backlight-interface-.patch
diff options
context:
space:
mode:
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-.patch583
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
+