| From f34383e25d63adcc9da38f3a476700a40555a232 Mon Sep 17 00:00:00 2001 |
| From: Kevin Chowski <chowski@google.com> |
| Date: Sat, 8 Aug 2020 15:40:51 -0600 |
| Subject: [PATCH] CHROMIUM: Changes needed for backlight control on Eve-5.4 |
| |
| #1: Port https://crrev.com/c/439873 to the 5.4 tree |
| #2: Port https://crrev.com/c/440445 to the 5.4 tree |
| #3: Port https://crrev.com/c/456118 to the 5.4 tree |
| |
| The first two patches are needed to correctly enable the backlight for |
| Eve; they were submitted upstream in 2017 but were rolled back. |
| |
| The third patch was not rolled back upstream, but the code related to it |
| changed quite a bit between 4.4 and 5.4: the write of |
| DP_EDP_PWMGEN_BIT_COUNT used to happen on every screen enable via |
| intel_dp_aux_set_pwm_freq (that's how it works in 4.4), but in 5.4 the |
| write was refactored into intel_dp_aux_calc_max_backlight and only |
| called once per screen setup. This patch brings back the old |
| functionality of intel_dp_aux_set_pwm_freq to ensure we set that |
| register on each screen enable, but this is at the cost of duplication |
| between intel_dp_aux_calc_max_backlight. Unfortunately, I don't see a |
| better way to do this without making the cros code diverge even further |
| from 4.4 and 5.4. |
| |
| I'd like to submit this CL into the chromium tree, and use b/163412221 |
| to track its upstreaming and the ultimate revert of this change. |
| |
| Test: |
| * `emerge-eve-kernelnext sys-kernel/chromeos-kernel-5_4` |
| * `./update_kernel.sh --remote=192.168.0.22 --remote_bootarg` |
| * On DUT, set options `i915.enable_dpcd_backlight=1 i915.enable_dbc=1` |
| (using e.g. `/usr/share/vboot/bin/make_dev_ssd.sh`) |
| * reboot |
| * Change brightness on DUT |
| * Allow DUT screen to fall asleep |
| * Wake DUT screen, change brightness again |
| |
| BUG=b:162255390 |
| TEST=See above |
| |
| Change-Id: I9eafa28226f1c6b8332fcf9730259bea05cf7975 |
| Signed-off-by: Kevin Chowski <chowski@google.com> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2344844 |
| Reviewed-by: Puthikorn Voravootivat <puthik@chromium.org> |
| Conflicts: drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c |
| [rebase510(groeck): Picked code from continuous rebase project to resolve conflicts] |
| Signed-off-by: Guenter Roeck <groeck@chromium.org> |
| --- |
| drivers/gpu/drm/drm_dp_helper.c | 4 + |
| .../drm/i915/display/intel_dp_aux_backlight.c | 105 ++++++++++++++++++ |
| drivers/gpu/drm/i915/i915_params.c | 3 + |
| drivers/gpu/drm/i915/i915_params.h | 3 +- |
| 4 files changed, 114 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c |
| --- a/drivers/gpu/drm/drm_dp_helper.c |
| +++ b/drivers/gpu/drm/drm_dp_helper.c |
| @@ -3301,6 +3301,10 @@ drm_edp_backlight_probe_max(struct drm_dp_aux *aux, struct drm_edp_backlight_inf |
| int ret; |
| u8 pn, pn_min, pn_max; |
| |
| + drm_dbg_kms(aux->drm_dev, |
| + "VBT defined backlight frequency %u Hz\n", |
| + driver_pwm_freq_hz); |
| + |
| 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", |
| diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c |
| --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c |
| +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c |
| @@ -285,6 +285,26 @@ intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u3 |
| drm_edp_backlight_set_level(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); |
| } |
| |
| +/* |
| + * Set minimum / maximum dynamic brightness percentage. This value is expressed |
| + * as the percentage of normal brightness in 5% increments. |
| + */ |
| +static bool |
| +intel_dp_aux_set_dynamic_backlight_percent(struct intel_dp *intel_dp, |
| + u32 min, u32 max) |
| +{ |
| + struct drm_i915_private *i915 = dp_to_i915(intel_dp); |
| + u8 dbc[] = { DIV_ROUND_CLOSEST(min, 5), DIV_ROUND_CLOSEST(max, 5) }; |
| + |
| + if (drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET, |
| + dbc, sizeof(dbc)) < 0) { |
| + drm_dbg_kms(&i915->drm, |
| + "Failed to write aux DBC brightness level\n"); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| static void |
| intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, |
| const struct drm_connector_state *conn_state, u32 level) |
| @@ -292,6 +312,36 @@ intel_dp_aux_vesa_enable_backlight(const struct intel_crtc_state *crtc_state, |
| struct intel_connector *connector = to_intel_connector(conn_state->connector); |
| struct intel_panel *panel = &connector->panel; |
| struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); |
| + struct drm_i915_private *i915 = dp_to_i915(intel_dp); |
| + u8 dpcd_buf, new_dpcd_buf; |
| + |
| + if (drm_dp_dpcd_readb(&intel_dp->aux, |
| + DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) { |
| + drm_dbg_kms(&i915->drm, "Failed to read DPCD register 0x%x\n", |
| + DP_EDP_BACKLIGHT_MODE_SET_REGISTER); |
| + return; |
| + } |
| + |
| + new_dpcd_buf = dpcd_buf; |
| + |
| + if (i915_modparams.enable_dbc && |
| + (intel_dp->edp_dpcd[2] & DP_EDP_DYNAMIC_BACKLIGHT_CAP)) { |
| + if (intel_dp_aux_set_dynamic_backlight_percent(intel_dp, |
| + 0, 100)) { |
| + new_dpcd_buf |= DP_EDP_DYNAMIC_BACKLIGHT_ENABLE; |
| + drm_dbg_kms(&i915->drm, |
| + "Enable dynamic brightness.\n"); |
| + } |
| + } |
| + |
| + if (new_dpcd_buf != dpcd_buf) { |
| + if (drm_dp_dpcd_writeb(&intel_dp->aux, |
| + DP_EDP_BACKLIGHT_MODE_SET_REGISTER, new_dpcd_buf) < 0) { |
| + drm_dbg_kms(&i915->drm, |
| + "Failed to write aux backlight mode\n"); |
| + } |
| + } |
| + |
| |
| drm_edp_backlight_enable(&intel_dp->aux, &panel->backlight.edp.vesa.info, level); |
| } |
| @@ -352,6 +402,59 @@ intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector) |
| return false; |
| } |
| |
| +/* |
| + * Heuristic function whether we should use AUX for backlight adjustment or not. |
| + * |
| + * We should use AUX for backlight brightness adjustment if panel doesn't this |
| + * via PWM pin or using AUX is better than using PWM pin. |
| + * |
| + * The heuristic to determine that using AUX pin is better than using PWM pin is |
| + * that the panel support any of the feature list here. |
| + * - Regional backlight brightness adjustment |
| + * - Backlight PWM frequency set |
| + * - More than 8 bits resolution of brightness level |
| + * - Backlight enablement via AUX and not by BL_ENABLE pin |
| + * |
| + * If all above are not true, assume that using PWM pin is better. |
| + */ |
| +static bool |
| +intel_dp_aux_display_control_heuristic(struct intel_connector *connector) |
| +{ |
| + struct intel_dp *intel_dp = intel_attached_dp(connector); |
| + struct drm_i915_private *i915 = dp_to_i915(intel_dp); |
| + uint8_t reg_val; |
| + |
| + /* Panel doesn't support adjusting backlight brightness via PWN pin */ |
| + if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP)) |
| + return true; |
| + |
| + /* Panel supports regional backlight brightness adjustment */ |
| + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_GENERAL_CAP_3, |
| + ®_val) != 1) { |
| + drm_dbg_kms(&i915->drm, "Failed to read DPCD register 0x%x\n", |
| + DP_EDP_GENERAL_CAP_3); |
| + return false; |
| + } |
| + if (reg_val > 0) |
| + return true; |
| + |
| + /* Panel supports backlight PWM frequency set */ |
| + if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP) |
| + return true; |
| + |
| + /* Panel supports more than 8 bits resolution of brightness level */ |
| + if (intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT) |
| + return true; |
| + |
| + /* Panel supports enabling backlight via AUX but not by BL_ENABLE pin */ |
| + if ((intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP) && |
| + !(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_PIN_ENABLE_CAP)) |
| + return true; |
| + |
| + return false; |
| + |
| +} |
| + |
| static const struct intel_panel_bl_funcs intel_dp_hdr_bl_funcs = { |
| .setup = intel_dp_aux_hdr_setup_backlight, |
| .enable = intel_dp_aux_hdr_enable_backlight, |
| @@ -401,6 +504,8 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) |
| default: |
| return -ENODEV; |
| } |
| + if (!intel_dp_aux_display_control_heuristic(connector)) |
| + return -ENODEV; |
| break; |
| case INTEL_DP_AUX_BACKLIGHT_ON: |
| if (i915->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE) |
| diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c |
| --- a/drivers/gpu/drm/i915/i915_params.c |
| +++ b/drivers/gpu/drm/i915/i915_params.c |
| @@ -187,6 +187,9 @@ i915_param_named(enable_dpcd_backlight, int, 0400, |
| "Enable support for DPCD backlight control" |
| "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); |
| |
| +i915_param_named(enable_dbc, bool, 0600, |
| + "Enable support for dynamic backlight control (default:false)"); |
| + |
| #if IS_ENABLED(CONFIG_DRM_I915_GVT) |
| i915_param_named(enable_gvt, bool, 0400, |
| "Enable support for Intel GVT-g graphics virtualization host support(default:false)"); |
| diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h |
| --- a/drivers/gpu/drm/i915/i915_params.h |
| +++ b/drivers/gpu/drm/i915/i915_params.h |
| @@ -82,7 +82,8 @@ struct drm_printer; |
| param(bool, verbose_state_checks, true, 0) \ |
| param(bool, nuclear_pageflip, false, 0400) \ |
| param(bool, enable_dp_mst, true, 0600) \ |
| - param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) |
| + param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) \ |
| + param(bool, enable_dbc, false, 0600) |
| |
| #define MEMBER(T, member, ...) T member; |
| struct i915_params { |
| -- |
| 2.33.0.685.g46640cef36-goog |
| |