commit: b75b7e6a336c28fa493be98a01eef5ce375e020b Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> AuthorDate: Mon Nov 29 23:34:54 2021 +0000 Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> CommitDate: Mon Nov 29 23:34:54 2021 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=b75b7e6a
Add suprt for panels w. VESA backlights with PWM enable/disable Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org> 0000_README | 4 + ...15-PWM-support-for-VESA-backlight-helpers.patch | 618 +++++++++++++++++++++ 2 files changed, 622 insertions(+) diff --git a/0000_README b/0000_README index 68d0c0db..0923a646 100644 --- a/0000_README +++ b/0000_README @@ -75,6 +75,10 @@ Patch: 2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch From: https://lore.kernel.org/linux-bluetooth/[email protected]/raw Desc: Bluetooth: Check key sizes only when Secure Simple Pairing is enabled. See bug #686758 +Patch: 2800_drm-i915-PWM-support-for-VESA-backlight-helpers.patch +From: https://patchwork.freedesktop.org/series/95127/ +Desc: drm/i915: Add support for panels with VESA backlights with PWM enable/disable + Patch: 2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch From: https://bugs.gentoo.org/710790 Desc: tmp513 requies REGMAP_I2C to build. Select it by default in Kconfig. See bug #710790. Thanks to Phil Stracchino diff --git a/2800_drm-i915-PWM-support-for-VESA-backlight-helpers.patch b/2800_drm-i915-PWM-support-for-VESA-backlight-helpers.patch new file mode 100644 index 00000000..45969bce --- /dev/null +++ b/2800_drm-i915-PWM-support-for-VESA-backlight-helpers.patch @@ -0,0 +1,618 @@ +From patchwork Fri Nov 5 18:33:38 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +Subject: [v5,1/5] drm/i915: Add support for panels with VESA backlights with + PWM enable/disable +From: Lyude Paul <[email protected]> +X-Patchwork-Id: 462369 +Message-Id: <[email protected]> +To: [email protected], [email protected], + [email protected] +Cc: David Airlie <[email protected]>, open list <[email protected]>, + [email protected] +Date: Fri, 5 Nov 2021 14:33:38 -0400 + +This simply adds proper support for panel backlights that can be controlled +via VESA's backlight control protocol, but which also require that we +enable and disable the backlight via PWM instead of via the DPCD interface. +We also enable this by default, in order to fix some people's backlights +that were broken by not having this enabled. + +For reference, backlights that require this and use VESA's backlight +interface tend to be laptops with hybrid GPUs, but this very well may +change in the future. + +v4: +* Make sure that we call intel_backlight_level_to_pwm() in + intel_dp_aux_vesa_enable_backlight() - vsyrjala + +Signed-off-by: Lyude Paul <[email protected]> +Link: https://gitlab.freedesktop.org/drm/intel/-/issues/3680 +Fixes: fe7d52bccab6 ("drm/i915/dp: Don't use DPCD backlights that need PWM enable/disable") +Reviewed-by: Ville Syrjälä <[email protected]> +Cc: <[email protected]> # v5.12+ +--- + .../drm/i915/display/intel_dp_aux_backlight.c | 27 ++++++++++++++----- + 1 file changed, 21 insertions(+), 6 deletions(-) + +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 569d17b4d00f..f05b71c01b8e 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +@@ -293,6 +293,13 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, + struct intel_panel *panel = &connector->panel; + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + ++ if (!panel->backlight.edp.vesa.info.aux_enable) { ++ u32 pwm_level = intel_backlight_invert_pwm_level(connector, ++ panel->backlight.pwm_level_max); ++ ++ panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level); ++ } ++ + drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); + } + +@@ -304,6 +311,10 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + + drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info); ++ ++ if (!panel->backlight.edp.vesa.info.aux_enable) ++ panel->backlight.pwm_funcs->disable(old_conn_state, ++ intel_backlight_invert_pwm_level(connector, 0)); + } + + static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe) +@@ -321,6 +332,15 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, + if (ret < 0) + return ret; + ++ if (!panel->backlight.edp.vesa.info.aux_enable) { ++ ret = panel->backlight.pwm_funcs->setup(connector, pipe); ++ if (ret < 0) { ++ drm_err(&i915->drm, ++ "Failed to setup PWM backlight controls for eDP backlight: %d\n", ++ ret); ++ return ret; ++ } ++ } + panel->backlight.max = panel->backlight.edp.vesa.info.max; + panel->backlight.min = 0; + if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { +@@ -340,12 +360,7 @@ intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + +- /* TODO: We currently only support AUX only backlight configurations, not backlights which +- * require a mix of PWM and AUX controls to work. In the mean time, these machines typically +- * work just fine using normal PWM controls anyway. +- */ +- if ((intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) && +- drm_edp_backlight_supported(intel_dp->edp_dpcd)) { ++ if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) { + drm_dbg_kms(&i915->drm, "AUX Backlight Control Supported!\n"); + return true; + } + +From patchwork Fri Nov 5 18:33:39 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v5,2/5] drm/nouveau/kms/nv50-: Explicitly check DPCD backlights for + aux enable/brightness +From: Lyude Paul <[email protected]> +X-Patchwork-Id: 462371 +Message-Id: <[email protected]> +To: [email protected], [email protected], + [email protected] +Cc: David Airlie <[email protected]>, Ben Skeggs <[email protected]>, + Karol Herbst <[email protected]>, open list <[email protected]> +Date: Fri, 5 Nov 2021 14:33:39 -0400 + +Since we don't support hybrid AUX/PWM backlights in nouveau right now, +let's add some explicit checks so that we don't break nouveau once we +enable support for these backlights in other drivers. + +Reviewed-by: Karol Herbst <[email protected]> +Signed-off-by: Lyude Paul <[email protected]> +--- + drivers/gpu/drm/nouveau/nouveau_backlight.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c +index 1cbd71abc80a..ae2f2abc8f5a 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c ++++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c +@@ -308,7 +308,10 @@ nv50_backlight_init(struct nouveau_backlight *bl, + if (ret < 0) + return ret; + +- if (drm_edp_backlight_supported(edp_dpcd)) { ++ /* TODO: Add support for hybrid PWM/DPCD panels */ ++ if (drm_edp_backlight_supported(edp_dpcd) && ++ (edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) && ++ (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) { + NV_DEBUG(drm, "DPCD backlight controls supported on %s\n", + nv_conn->base.name); + + +From patchwork Fri Nov 5 18:33:40 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v5,3/5] drm/dp: Don't read back backlight mode in + drm_edp_backlight_enable() +From: Lyude Paul <[email protected]> +X-Patchwork-Id: 462376 +Message-Id: <[email protected]> +To: [email protected], [email protected], + [email protected] +Cc: Thomas Zimmermann <[email protected]>, David Airlie <[email protected]>, + open list <[email protected]>, Maxime Ripard <[email protected]> +Date: Fri, 5 Nov 2021 14:33:40 -0400 + +As it turns out, apparently some machines will actually leave additional +backlight functionality like dynamic backlight control on before the OS +loads. Currently we don't take care to disable unsupported features when +writing back the backlight mode, which can lead to some rather strange +looking behavior when adjusting the backlight. + +So, let's fix this by just not reading back the current backlight mode on +initial enable. I don't think there should really be any downsides to this, +and this will ensure we don't leave any unsupported functionality enabled. + +This should fix at least one (but not all) of the issues seen with DPCD +backlight support on fi-bdw-samus + +v5: +* Just avoid reading back DPCD register - Doug Anderson + +Signed-off-by: Lyude Paul <[email protected]> +Fixes: 867cf9cd73c3 ("drm/dp: Extract i915's eDP backlight code into DRM helpers") +Reviewed-by: Douglas Anderson <[email protected]> +--- + drivers/gpu/drm/drm_dp_helper.c | 40 ++++++++++----------------------- + 1 file changed, 12 insertions(+), 28 deletions(-) + +diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c +index ada0a1ff262d..af2aad2f4725 100644 +--- a/drivers/gpu/drm/drm_dp_helper.c ++++ b/drivers/gpu/drm/drm_dp_helper.c +@@ -3363,27 +3363,13 @@ int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backli + const u16 level) + { + int ret; +- u8 dpcd_buf, new_dpcd_buf; ++ u8 dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; + +- ret = drm_dp_dpcd_readb(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf); +- if (ret != 1) { +- drm_dbg_kms(aux->drm_dev, +- "%s: Failed to read backlight mode: %d\n", aux->name, ret); +- return ret < 0 ? ret : -EIO; +- } +- +- new_dpcd_buf = dpcd_buf; +- +- if ((dpcd_buf & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK) != DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { +- new_dpcd_buf &= ~DP_EDP_BACKLIGHT_CONTROL_MODE_MASK; +- new_dpcd_buf |= DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; +- +- if (bl->pwmgen_bit_count) { +- ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count); +- if (ret != 1) +- drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux pwmgen bit count: %d\n", +- aux->name, ret); +- } ++ if (bl->pwmgen_bit_count) { ++ ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count); ++ if (ret != 1) ++ drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux pwmgen bit count: %d\n", ++ aux->name, ret); + } + + if (bl->pwm_freq_pre_divider) { +@@ -3393,16 +3379,14 @@ int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backli + "%s: Failed to write aux backlight frequency: %d\n", + aux->name, ret); + else +- new_dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE; ++ dpcd_buf |= DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE; + } + +- if (new_dpcd_buf != dpcd_buf) { +- ret = drm_dp_dpcd_writeb(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, new_dpcd_buf); +- if (ret != 1) { +- drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux backlight mode: %d\n", +- aux->name, ret); +- return ret < 0 ? ret : -EIO; +- } ++ ret = drm_dp_dpcd_writeb(aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, dpcd_buf); ++ if (ret != 1) { ++ drm_dbg_kms(aux->drm_dev, "%s: Failed to write aux backlight mode: %d\n", ++ aux->name, ret); ++ return ret < 0 ? ret : -EIO; + } + + ret = drm_edp_backlight_set_level(aux, bl, level); + +From patchwork Fri Nov 5 18:33:41 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v5,4/5] drm/dp, + drm/i915: Add support for VESA backlights using PWM for brightness control +From: Lyude Paul <[email protected]> +X-Patchwork-Id: 462379 +Message-Id: <[email protected]> +To: [email protected], [email protected], + [email protected] +Cc: Rajeev Nandan <[email protected]>, David Airlie <[email protected]>, + Doug Anderson <[email protected]>, Maxime Ripard <[email protected]>, + open list <[email protected]>, + Thomas Zimmermann <[email protected]> +Date: Fri, 5 Nov 2021 14:33:41 -0400 + +Now that we've added support to i915 for controlling panel backlights that +need PWM to be enabled/disabled, let's finalize this and add support for +controlling brightness levels via PWM as well. This should hopefully put us +towards the path of supporting _ALL_ backlights via VESA's DPCD interface +which would allow us to finally start trusting the DPCD again. + +Note however that we still don't enable using this by default on i915 when +it's not needed, primarily because I haven't yet had a chance to confirm if +it's safe to do this on the one machine in Intel's CI that had an issue +with this: samus-fi-bdw. I have done basic testing of this on other +machines though, by manually patching i915 to force it into PWM-only mode +on some of my laptops. + +v2: +* Correct documentation (thanks Doug!) +* Get rid of backlight caps + +Signed-off-by: Lyude Paul <[email protected]> +Reviewed-by: Doug Anderson <[email protected]> +Cc: Rajeev Nandan <[email protected]> +Cc: Satadru Pramanik <[email protected]> +--- + drivers/gpu/drm/drm_dp_helper.c | 72 +++++++++++++------ + .../drm/i915/display/intel_dp_aux_backlight.c | 44 +++++++++--- + include/drm/drm_dp_helper.h | 7 +- + 3 files changed, 89 insertions(+), 34 deletions(-) + +diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c +index af2aad2f4725..23f9073bc473 100644 +--- a/drivers/gpu/drm/drm_dp_helper.c ++++ b/drivers/gpu/drm/drm_dp_helper.c +@@ -3290,6 +3290,10 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac + int ret; + u8 buf[2] = { 0 }; + ++ /* The panel uses the PWM for controlling brightness levels */ ++ if (!bl->aux_set) ++ return 0; ++ + if (bl->lsb_reg_used) { + buf[0] = (level & 0xff00) >> 8; + buf[1] = (level & 0x00ff); +@@ -3316,7 +3320,7 @@ drm_edp_backlight_set_enable(struct drm_dp_aux *aux, const struct drm_edp_backli + int ret; + u8 buf; + +- /* The panel uses something other then DPCD for enabling its backlight */ ++ /* This panel uses the EDP_BL_PWR GPIO for enablement */ + if (!bl->aux_enable) + return 0; + +@@ -3351,11 +3355,11 @@ drm_edp_backlight_set_enable(struct drm_dp_aux *aux, const struct drm_edp_backli + * restoring any important backlight state such as the given backlight level, the brightness byte + * count, backlight frequency, etc. + * +- * Note that certain panels, while supporting brightness level controls over DPCD, may not support +- * having their backlights enabled via the standard %DP_EDP_DISPLAY_CONTROL_REGISTER. On such panels +- * &drm_edp_backlight_info.aux_enable will be set to %false, this function will skip the step of +- * programming the %DP_EDP_DISPLAY_CONTROL_REGISTER, and the driver must perform the required +- * implementation specific step for enabling the backlight after calling this function. ++ * Note that certain panels do not support being enabled or disabled via DPCD, but instead require ++ * that the driver handle enabling/disabling the panel through implementation-specific means using ++ * the EDP_BL_PWR GPIO. For such panels, &drm_edp_backlight_info.aux_enable will be set to %false, ++ * this function becomes a no-op, and the driver is expected to handle powering the panel on using ++ * the EDP_BL_PWR GPIO. + * + * Returns: %0 on success, negative error code on failure. + */ +@@ -3363,7 +3367,12 @@ int drm_edp_backlight_enable(struct drm_dp_aux *aux, const struct drm_edp_backli + const u16 level) + { + int ret; +- u8 dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; ++ u8 dpcd_buf; ++ ++ if (bl->aux_set) ++ dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD; ++ else ++ dpcd_buf = DP_EDP_BACKLIGHT_CONTROL_MODE_PWM; + + if (bl->pwmgen_bit_count) { + ret = drm_dp_dpcd_writeb(aux, DP_EDP_PWMGEN_BIT_COUNT, bl->pwmgen_bit_count); +@@ -3405,12 +3414,13 @@ EXPORT_SYMBOL(drm_edp_backlight_enable); + * @aux: The DP AUX channel to use + * @bl: Backlight capability info from drm_edp_backlight_init() + * +- * This function handles disabling DPCD backlight controls on a panel over AUX. Note that some +- * panels have backlights that are enabled/disabled by other means, despite having their brightness +- * values controlled through DPCD. On such panels &drm_edp_backlight_info.aux_enable will be set to +- * %false, this function will become a no-op (and we will skip updating +- * %DP_EDP_DISPLAY_CONTROL_REGISTER), and the driver must take care to perform it's own +- * implementation specific step for disabling the backlight. ++ * This function handles disabling DPCD backlight controls on a panel over AUX. ++ * ++ * Note that certain panels do not support being enabled or disabled via DPCD, but instead require ++ * that the driver handle enabling/disabling the panel through implementation-specific means using ++ * the EDP_BL_PWR GPIO. For such panels, &drm_edp_backlight_info.aux_enable will be set to %false, ++ * this function becomes a no-op, and the driver is expected to handle powering the panel off using ++ * the EDP_BL_PWR GPIO. + * + * Returns: %0 on success or no-op, negative error code on failure. + */ +@@ -3434,6 +3444,9 @@ drm_edp_backlight_probe_max(struct drm_dp_aux *aux, struct drm_edp_backlight_inf + int ret; + u8 pn, pn_min, pn_max; + ++ if (!bl->aux_set) ++ return 0; ++ + ret = drm_dp_dpcd_readb(aux, DP_EDP_PWMGEN_BIT_COUNT, &pn); + if (ret != 1) { + drm_dbg_kms(aux->drm_dev, "%s: Failed to read pwmgen bit count cap: %d\n", +@@ -3519,7 +3532,7 @@ drm_edp_backlight_probe_max(struct drm_dp_aux *aux, struct drm_edp_backlight_inf + } + + static inline int +-drm_edp_backlight_probe_level(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, ++drm_edp_backlight_probe_state(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl, + u8 *current_mode) + { + int ret; +@@ -3534,6 +3547,9 @@ drm_edp_backlight_probe_level(struct drm_dp_aux *aux, struct drm_edp_backlight_i + } + + *current_mode = (mode_reg & DP_EDP_BACKLIGHT_CONTROL_MODE_MASK); ++ if (!bl->aux_set) ++ return 0; ++ + if (*current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { + int size = 1 + bl->lsb_reg_used; + +@@ -3564,7 +3580,7 @@ drm_edp_backlight_probe_level(struct drm_dp_aux *aux, struct drm_edp_backlight_i + * @bl: The &drm_edp_backlight_info struct to fill out with information on the backlight + * @driver_pwm_freq_hz: Optional PWM frequency from the driver in hz + * @edp_dpcd: A cached copy of the eDP DPCD +- * @current_level: Where to store the probed brightness level ++ * @current_level: Where to store the probed brightness level, if any + * @current_mode: Where to store the currently set backlight control mode + * + * Initializes a &drm_edp_backlight_info struct by probing @aux for it's backlight capabilities, +@@ -3584,24 +3600,38 @@ drm_edp_backlight_init(struct drm_dp_aux *aux, struct drm_edp_backlight_info *bl + + if (edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) + bl->aux_enable = true; ++ if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP) ++ bl->aux_set = true; + if (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) + bl->lsb_reg_used = true; + ++ /* Sanity check caps */ ++ if (!bl->aux_set && !(edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) { ++ drm_dbg_kms(aux->drm_dev, ++ "%s: Panel supports neither AUX or PWM brightness control? Aborting\n", ++ aux->name); ++ return -EINVAL; ++ } ++ + ret = drm_edp_backlight_probe_max(aux, bl, driver_pwm_freq_hz, edp_dpcd); + if (ret < 0) + return ret; + +- ret = drm_edp_backlight_probe_level(aux, bl, current_mode); ++ ret = drm_edp_backlight_probe_state(aux, bl, current_mode); + if (ret < 0) + return ret; + *current_level = ret; + + drm_dbg_kms(aux->drm_dev, +- "%s: Found backlight level=%d/%d pwm_freq_pre_divider=%d mode=%x\n", +- aux->name, *current_level, bl->max, bl->pwm_freq_pre_divider, *current_mode); +- drm_dbg_kms(aux->drm_dev, +- "%s: Backlight caps: pwmgen_bit_count=%d lsb_reg_used=%d aux_enable=%d\n", +- aux->name, bl->pwmgen_bit_count, bl->lsb_reg_used, bl->aux_enable); ++ "%s: Found backlight: aux_set=%d aux_enable=%d mode=%d\n", ++ aux->name, bl->aux_set, bl->aux_enable, *current_mode); ++ if (bl->aux_set) { ++ drm_dbg_kms(aux->drm_dev, ++ "%s: Backlight caps: level=%d/%d pwm_freq_pre_divider=%d lsb_reg_used=%d\n", ++ aux->name, *current_level, bl->max, bl->pwm_freq_pre_divider, ++ bl->lsb_reg_used); ++ } ++ + return 0; + } + EXPORT_SYMBOL(drm_edp_backlight_init); +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 f05b71c01b8e..96fe3eaba44a 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +@@ -282,6 +282,12 @@ intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u3 + struct intel_panel *panel = &connector->panel; + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + ++ if (!panel->backlight.edp.vesa.info.aux_set) { ++ const u32 pwm_level = intel_backlight_level_to_pwm(connector, level); ++ ++ intel_backlight_set_pwm_level(conn_state, pwm_level); ++ } ++ + drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); + } + +@@ -294,8 +300,13 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, + struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); + + if (!panel->backlight.edp.vesa.info.aux_enable) { +- u32 pwm_level = intel_backlight_invert_pwm_level(connector, +- panel->backlight.pwm_level_max); ++ u32 pwm_level; ++ ++ if (!panel->backlight.edp.vesa.info.aux_set) ++ pwm_level = intel_backlight_level_to_pwm(connector, level); ++ else ++ pwm_level = intel_backlight_invert_pwm_level(connector, ++ panel->backlight.pwm_level_max); + + panel->backlight.pwm_funcs->enable(crtc_state, conn_state, pwm_level); + } +@@ -332,7 +343,7 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, + if (ret < 0) + return ret; + +- if (!panel->backlight.edp.vesa.info.aux_enable) { ++ if (!panel->backlight.edp.vesa.info.aux_set || !panel->backlight.edp.vesa.info.aux_enable) { + ret = panel->backlight.pwm_funcs->setup(connector, pipe); + if (ret < 0) { + drm_err(&i915->drm, +@@ -341,14 +352,27 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, + return ret; + } + } +- panel->backlight.max = panel->backlight.edp.vesa.info.max; +- panel->backlight.min = 0; +- if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { +- panel->backlight.level = current_level; +- panel->backlight.enabled = panel->backlight.level != 0; ++ ++ if (panel->backlight.edp.vesa.info.aux_set) { ++ panel->backlight.max = panel->backlight.edp.vesa.info.max; ++ panel->backlight.min = 0; ++ if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD) { ++ panel->backlight.level = current_level; ++ panel->backlight.enabled = panel->backlight.level != 0; ++ } else { ++ panel->backlight.level = panel->backlight.max; ++ panel->backlight.enabled = false; ++ } + } else { +- panel->backlight.level = panel->backlight.max; +- panel->backlight.enabled = false; ++ panel->backlight.max = panel->backlight.pwm_level_max; ++ panel->backlight.min = panel->backlight.pwm_level_min; ++ if (current_mode == DP_EDP_BACKLIGHT_CONTROL_MODE_PWM) { ++ panel->backlight.level = panel->backlight.pwm_funcs->get(connector, pipe); ++ panel->backlight.enabled = panel->backlight.pwm_enabled; ++ } else { ++ panel->backlight.level = panel->backlight.max; ++ panel->backlight.enabled = false; ++ } + } + + return 0; +diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h +index afdf7f4183f9..8b2ed4199284 100644 +--- a/include/drm/drm_dp_helper.h ++++ b/include/drm/drm_dp_helper.h +@@ -1868,7 +1868,7 @@ drm_dp_sink_can_do_video_without_timing_msa(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + * + * Note that currently this function will return %false for panels which support various DPCD + * backlight features but which require the brightness be set through PWM, and don't support setting +- * the brightness level via the DPCD. This is a TODO. ++ * the brightness level via the DPCD. + * + * Returns: %True if @edp_dpcd indicates that VESA backlight controls are supported, %false + * otherwise +@@ -1876,8 +1876,7 @@ drm_dp_sink_can_do_video_without_timing_msa(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) + static inline bool + drm_edp_backlight_supported(const u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]) + { +- return (edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP) && +- (edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP); ++ return !!(edp_dpcd[1] & DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP); + } + + /* +@@ -2238,6 +2237,7 @@ drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) + * @max: The maximum backlight level that may be set + * @lsb_reg_used: Do we also write values to the DP_EDP_BACKLIGHT_BRIGHTNESS_LSB register? + * @aux_enable: Does the panel support the AUX enable cap? ++ * @aux_set: Does the panel support setting the brightness through AUX? + * + * This structure contains various data about an eDP backlight, which can be populated by using + * drm_edp_backlight_init(). +@@ -2249,6 +2249,7 @@ struct drm_edp_backlight_info { + + bool lsb_reg_used : 1; + bool aux_enable : 1; ++ bool aux_set : 1; + }; + + int + +From patchwork Fri Nov 5 18:33:42 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +Subject: [v5,5/5] drm/i915: Clarify probing order in + intel_dp_aux_init_backlight_funcs() +From: Lyude Paul <[email protected]> +X-Patchwork-Id: 462382 +Message-Id: <[email protected]> +To: [email protected], [email protected], + [email protected] +Cc: David Airlie <[email protected]>, open list <[email protected]> +Date: Fri, 5 Nov 2021 14:33:42 -0400 + +Hooray! We've managed to hit enough bugs upstream that I've been able to +come up with a pretty solid explanation for how backlight controls are +actually supposed to be detected and used these days. As well, having the +rest of the PWM bits in VESA's backlight interface implemented seems to +have fixed all of the problematic brightness controls laptop panels that +we've hit so far. + +So, let's actually document this instead of just calling the laptop panels +liars. As well, I would like to formally apologize to all of the laptop +panels I called liars. I'm sorry laptop panels, hopefully you can all +forgive me and we can move past this~ + +Signed-off-by: Lyude Paul <[email protected]> +Acked-by: Ville Syrjälä <[email protected]> +--- + .../drm/i915/display/intel_dp_aux_backlight.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +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 96fe3eaba44a..8b9c925c4c16 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +@@ -456,11 +456,17 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) + } + + /* +- * 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. ++ * Since Intel has their own backlight control interface, the majority of machines out there ++ * using DPCD backlight controls with Intel GPUs will be using this interface as opposed to ++ * the VESA interface. However, other GPUs (such as Nvidia's) will always use the VESA ++ * interface. This means that there's quite a number of panels out there that will advertise ++ * support for both interfaces, primarily systems with Intel/Nvidia hybrid GPU setups. ++ * ++ * There's a catch to this though: on many panels that advertise support for both ++ * interfaces, the VESA backlight interface will stop working once we've programmed the ++ * panel with Intel's OUI - which is also required for us to be able to detect Intel's ++ * backlight interface at all. This means that the only sensible way for us to detect both ++ * interfaces is to probe for Intel's first, and VESA's second. + */ + if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector)) { + drm_dbg_kms(dev, "Using Intel proprietary eDP backlight controls\n");
