diff options
Diffstat (limited to 'drivers/gpu/drm/drm_dp_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 108 |
1 files changed, 61 insertions, 47 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index ada0a1ff262d..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,27 +3367,18 @@ 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; - 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->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); - 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 +3388,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); @@ -3421,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. */ @@ -3450,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", @@ -3535,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; @@ -3550,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; @@ -3580,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, @@ -3600,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); |