Commit 4a8d7990 authored by Lyude Paul's avatar Lyude Paul

drm/i915/dp: 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.

On top of that however, there's also actually two different variants of
the Intel HDR backlight interface. The first uses the AUX channel for
controlling the brightness of the screen in both SDR and HDR mode, and
the second only uses the AUX channel for setting the brightness level in
HDR mode - relying on PWM for setting the brightness level in SDR mode.

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

Changes since v4:
* Fix checkpatch issues
Changes since v3:
* Stop using drm_device and use drm_i915_private instead
* Don't forget to return from intel_dp_aux_hdr_get_backlight() if we fail
  to read the current backlight mode from the DPCD
* s/uint8_t/u8/
* Remove unneeded parenthesis in intel_dp_aux_hdr_enable_backlight()
* Use drm_dbg_kms() in intel_dp_aux_init_backlight_funcs()
Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Reviewed-by: default avatarJani Nikula <jani.nikula@intel.com>
Cc: thaytan@noraisin.net
Cc: Vasily Khoruzhick <anarsoul@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210114221709.2261452-4-lyude@redhat.com
parent a575c00e
...@@ -261,7 +261,14 @@ struct intel_panel { ...@@ -261,7 +261,14 @@ struct intel_panel {
struct pwm_state pwm_state; struct pwm_state pwm_state;
/* DPCD backlight */ /* DPCD backlight */
u8 pwmgen_bit_count; union {
struct {
u8 pwmgen_bit_count;
} vesa;
struct {
bool sdr_uses_aux;
} intel;
} edp;
struct backlight_device *device; struct backlight_device *device;
......
...@@ -511,7 +511,7 @@ static u32 scale_hw_to_user(struct intel_connector *connector, ...@@ -511,7 +511,7 @@ static u32 scale_hw_to_user(struct intel_connector *connector,
0, user_max); 0, user_max);
} }
static u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val) u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 val)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel; struct intel_panel *panel = &connector->panel;
...@@ -539,6 +539,36 @@ void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 ...@@ -539,6 +539,36 @@ void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32
panel->backlight.pwm_funcs->set(conn_state, val); panel->backlight.pwm_funcs->set(conn_state, val);
} }
u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
drm_WARN_ON_ONCE(&dev_priv->drm,
panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
val = scale(val, panel->backlight.min, panel->backlight.max,
panel->backlight.pwm_level_min, panel->backlight.pwm_level_max);
return intel_panel_invert_pwm_level(connector, val);
}
u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
drm_WARN_ON_ONCE(&dev_priv->drm,
panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
if (dev_priv->params.invert_brightness > 0 ||
(dev_priv->params.invert_brightness == 0 && dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS))
val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);
return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
panel->backlight.min, panel->backlight.max);
}
static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused) static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
...@@ -2127,10 +2157,6 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) ...@@ -2127,10 +2157,6 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
container_of(panel, struct intel_connector, panel); container_of(panel, struct intel_connector, panel);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
intel_dp_aux_init_backlight_funcs(connector) == 0)
return;
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI && if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
intel_dsi_dcs_init_backlight_funcs(connector) == 0) intel_dsi_dcs_init_backlight_funcs(connector) == 0)
return; return;
...@@ -2158,6 +2184,10 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) ...@@ -2158,6 +2184,10 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
panel->backlight.pwm_funcs = &i9xx_pwm_funcs; panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
} }
if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP &&
intel_dp_aux_init_backlight_funcs(connector) == 0)
return;
/* We're using a standard PWM backlight interface */ /* We're using a standard PWM backlight interface */
panel->backlight.funcs = &pwm_bl_funcs; panel->backlight.funcs = &pwm_bl_funcs;
} }
......
...@@ -49,6 +49,10 @@ struct drm_display_mode * ...@@ -49,6 +49,10 @@ struct drm_display_mode *
intel_panel_edid_fixed_mode(struct intel_connector *connector); intel_panel_edid_fixed_mode(struct intel_connector *connector);
struct drm_display_mode * struct drm_display_mode *
intel_panel_vbt_fixed_mode(struct intel_connector *connector); intel_panel_vbt_fixed_mode(struct intel_connector *connector);
void intel_panel_set_pwm_level(const struct drm_connector_state *conn_state, u32 level);
u32 intel_panel_invert_pwm_level(struct intel_connector *connector, u32 level);
u32 intel_panel_backlight_level_to_pwm(struct intel_connector *connector, u32 level);
u32 intel_panel_backlight_level_from_pwm(struct intel_connector *connector, u32 val);
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
int intel_backlight_device_register(struct intel_connector *connector); int intel_backlight_device_register(struct intel_connector *connector);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment