summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c385
1 files changed, 304 insertions, 81 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 4f58efdc688a..271b27c9de51 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c
@@ -34,17 +34,14 @@
* for some reason.
*/
-#include "i915_drv.h"
+#include <drm/drm_print.h>
+
#include "intel_backlight.h"
+#include "intel_display_core.h"
#include "intel_display_types.h"
#include "intel_dp.h"
#include "intel_dp_aux_backlight.h"
-/* TODO:
- * Implement HDR, right now we just implement the bare minimum to bring us back into SDR mode so we
- * can make people's backlights work in the mean time
- */
-
/*
* 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.
@@ -69,14 +66,14 @@
#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_TONE_MAPPING_ENABLE BIT(2)
# 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_TCON_SDP_OVERRIDE_AUX BIT(7)
-#define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346 /* Pre-TGL+ */
+#define INTEL_EDP_HDR_CONTENT_LUMINANCE 0x346
#define INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE 0x34A
#define INTEL_EDP_SDR_LUMINANCE_LEVEL 0x352
#define INTEL_EDP_BRIGHTNESS_NITS_LSB 0x354
@@ -114,7 +111,7 @@ static bool is_intel_tcon_cap(const u8 tcon_cap[4])
static bool
intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
{
- struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_display *display = to_intel_display(connector);
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
struct drm_dp_aux *aux = &intel_dp->aux;
struct intel_panel *panel = &connector->panel;
@@ -127,16 +124,17 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
if (ret != sizeof(tcon_cap))
return false;
- if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP))
- return false;
-
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Detected %s HDR backlight interface version %d\n",
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] Detected %s HDR backlight interface version %d\n",
connector->base.base.id, connector->base.name,
is_intel_tcon_cap(tcon_cap) ? "Intel" : "unsupported", tcon_cap[0]);
if (!is_intel_tcon_cap(tcon_cap))
return false;
+ if (!(tcon_cap[1] & INTEL_EDP_HDR_TCON_BRIGHTNESS_NITS_CAP))
+ return false;
+
/*
* If we don't have HDR static metadata there is no way to
* runtime detect used range for nits based control. For now
@@ -146,18 +144,28 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
* HDR static metadata we need to start maintaining table of
* ranges for such panels.
*/
- if (i915->display.params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL &&
+ if (display->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL &&
!(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type &
BIT(HDMI_STATIC_METADATA_TYPE1))) {
- drm_info(&i915->drm,
- "[CONNECTOR:%d:%s] Panel is missing HDR static metadata. Possible support for Intel HDR backlight interface is not used. If your backlight controls don't work try booting with i915.enable_dpcd_backlight=%d. needs this, please file a _new_ bug report on drm/i915, see " FDO_BUG_URL " for details.\n",
+ drm_info(display->drm,
+ "[CONNECTOR:%d:%s] Panel is missing HDR static metadata. Possible support for Intel HDR backlight interface is not used. If your backlight controls don't work try booting with i915.enable_dpcd_backlight=%d.\n",
connector->base.base.id, connector->base.name,
INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL);
return false;
}
- panel->backlight.edp.intel.sdr_uses_aux =
+ panel->backlight.edp.intel_cap.sdr_uses_aux =
tcon_cap[2] & INTEL_EDP_SDR_TCON_BRIGHTNESS_AUX_CAP;
+ panel->backlight.edp.intel_cap.supports_2084_decode =
+ tcon_cap[1] & INTEL_EDP_HDR_TCON_2084_DECODE_CAP;
+ panel->backlight.edp.intel_cap.supports_2020_gamut =
+ tcon_cap[1] & INTEL_EDP_HDR_TCON_2020_GAMUT_CAP;
+ panel->backlight.edp.intel_cap.supports_segmented_backlight =
+ tcon_cap[1] & INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_CAP;
+ panel->backlight.edp.intel_cap.supports_sdp_colorimetry =
+ tcon_cap[1] & INTEL_EDP_HDR_TCON_SDP_COLORIMETRY_CAP;
+ panel->backlight.edp.intel_cap.supports_tone_mapping =
+ tcon_cap[1] & INTEL_EDP_HDR_TCON_TONE_MAPPING_CAP;
return true;
}
@@ -165,20 +173,21 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
static u32
intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe)
{
- struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_display *display = to_intel_display(connector);
struct intel_panel *panel = &connector->panel;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
u8 tmp;
u8 buf[2] = {};
if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) {
- drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to read current backlight mode from DPCD\n",
+ drm_err(display->drm,
+ "[CONNECTOR:%d:%s] Failed to read current backlight mode from DPCD\n",
connector->base.base.id, connector->base.name);
return 0;
}
if (!(tmp & INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE)) {
- if (!panel->backlight.edp.intel.sdr_uses_aux) {
+ if (!panel->backlight.edp.intel_cap.sdr_uses_aux) {
u32 pwm_level = panel->backlight.pwm_funcs->get(connector, pipe);
return intel_backlight_level_from_pwm(connector, pwm_level);
@@ -190,7 +199,8 @@ intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe
if (drm_dp_dpcd_read(&intel_dp->aux, INTEL_EDP_BRIGHTNESS_NITS_LSB, buf,
sizeof(buf)) != sizeof(buf)) {
- drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to read brightness from DPCD\n",
+ drm_err(display->drm,
+ "[CONNECTOR:%d:%s] Failed to read brightness from DPCD\n",
connector->base.base.id, connector->base.name);
return 0;
}
@@ -215,13 +225,27 @@ intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state,
connector->base.base.id, connector->base.name);
}
+static bool
+intel_dp_in_hdr_mode(const struct drm_connector_state *conn_state)
+{
+ struct hdr_output_metadata *hdr_metadata;
+
+ if (!conn_state->hdr_output_metadata)
+ return false;
+
+ hdr_metadata = conn_state->hdr_output_metadata->data;
+
+ return hdr_metadata->hdmi_metadata_type1.eotf == HDMI_EOTF_SMPTE_ST2084;
+}
+
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 intel_panel *panel = &connector->panel;
- if (panel->backlight.edp.intel.sdr_uses_aux) {
+ if (intel_dp_in_hdr_mode(conn_state) ||
+ panel->backlight.edp.intel_cap.sdr_uses_aux) {
intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
} else {
const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
@@ -231,13 +255,72 @@ intel_dp_aux_hdr_set_backlight(const struct drm_connector_state *conn_state, u32
}
static void
+intel_dp_aux_write_content_luminance(struct intel_connector *connector,
+ struct hdr_output_metadata *hdr_metadata)
+{
+ struct intel_display *display = to_intel_display(connector);
+ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ int ret;
+ u8 buf[4];
+
+ if (!intel_dp_has_gamut_metadata_dip(connector->encoder))
+ return;
+
+ buf[0] = hdr_metadata->hdmi_metadata_type1.max_cll & 0xFF;
+ buf[1] = (hdr_metadata->hdmi_metadata_type1.max_cll & 0xFF00) >> 8;
+ buf[2] = hdr_metadata->hdmi_metadata_type1.max_fall & 0xFF;
+ buf[3] = (hdr_metadata->hdmi_metadata_type1.max_fall & 0xFF00) >> 8;
+
+ ret = drm_dp_dpcd_write(&intel_dp->aux,
+ INTEL_EDP_HDR_CONTENT_LUMINANCE,
+ buf, sizeof(buf));
+ if (ret < 0)
+ drm_dbg_kms(display->drm,
+ "Content Luminance DPCD reg write failed, err:-%d\n",
+ ret);
+}
+
+static void
+intel_dp_aux_fill_hdr_tcon_params(const struct drm_connector_state *conn_state, u8 *ctrl)
+{
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_panel *panel = &connector->panel;
+ struct intel_display *display = to_intel_display(connector);
+
+ /*
+ * According to spec segmented backlight needs to be set whenever panel is in
+ * HDR mode.
+ */
+ if (intel_dp_in_hdr_mode(conn_state)) {
+ *ctrl |= INTEL_EDP_HDR_TCON_SEGMENTED_BACKLIGHT_ENABLE;
+ *ctrl |= INTEL_EDP_HDR_TCON_2084_DECODE_ENABLE;
+ }
+
+ if (DISPLAY_VER(display) < 11)
+ *ctrl &= ~INTEL_EDP_HDR_TCON_TONE_MAPPING_ENABLE;
+
+ if (panel->backlight.edp.intel_cap.supports_2020_gamut &&
+ (conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_RGB ||
+ conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_YCC ||
+ conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_CYCC))
+ *ctrl |= INTEL_EDP_HDR_TCON_2020_GAMUT_ENABLE;
+
+ if (panel->backlight.edp.intel_cap.supports_sdp_colorimetry &&
+ intel_dp_has_gamut_metadata_dip(connector->encoder))
+ *ctrl |= INTEL_EDP_HDR_TCON_SDP_OVERRIDE_AUX;
+ else
+ *ctrl &= ~INTEL_EDP_HDR_TCON_SDP_OVERRIDE_AUX;
+}
+
+static void
intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
+ struct intel_display *display = to_intel_display(crtc_state);
struct intel_connector *connector = to_intel_connector(conn_state->connector);
struct intel_panel *panel = &connector->panel;
- struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ struct hdr_output_metadata *hdr_metadata;
int ret;
u8 old_ctrl, ctrl;
@@ -245,14 +328,17 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl);
if (ret != 1) {
- drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to read current backlight control mode: %d\n",
+ drm_err(display->drm,
+ "[CONNECTOR:%d:%s] Failed to read current backlight control mode: %d\n",
connector->base.base.id, connector->base.name, ret);
return;
}
ctrl = old_ctrl;
- if (panel->backlight.edp.intel.sdr_uses_aux) {
+ if (intel_dp_in_hdr_mode(conn_state) ||
+ panel->backlight.edp.intel_cap.sdr_uses_aux) {
ctrl |= INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
+
intel_dp_aux_hdr_set_aux_backlight(conn_state, level);
} else {
u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
@@ -262,10 +348,18 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
ctrl &= ~INTEL_EDP_HDR_TCON_BRIGHTNESS_AUX_ENABLE;
}
+ intel_dp_aux_fill_hdr_tcon_params(conn_state, &ctrl);
+
if (ctrl != old_ctrl &&
drm_dp_dpcd_writeb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, ctrl) != 1)
- drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to configure DPCD brightness controls\n",
+ drm_err(display->drm,
+ "[CONNECTOR:%d:%s] Failed to configure DPCD brightness controls\n",
connector->base.base.id, connector->base.name);
+
+ if (intel_dp_in_hdr_mode(conn_state)) {
+ hdr_metadata = conn_state->hdr_output_metadata->data;
+ intel_dp_aux_write_content_luminance(connector, hdr_metadata);
+ }
}
static void
@@ -275,7 +369,7 @@ intel_dp_aux_hdr_disable_backlight(const struct drm_connector_state *conn_state,
struct intel_panel *panel = &connector->panel;
/* Nothing to do for AUX based backlight controls */
- if (panel->backlight.edp.intel.sdr_uses_aux)
+ if (panel->backlight.edp.intel_cap.sdr_uses_aux)
return;
/* Note we want the actual pwm_level to be 0, regardless of pwm_min */
@@ -287,23 +381,47 @@ static const char *dpcd_vs_pwm_str(bool aux)
return aux ? "DPCD" : "PWM";
}
+static void
+intel_dp_aux_write_panel_luminance_override(struct intel_connector *connector)
+{
+ struct intel_display *display = to_intel_display(connector);
+ struct intel_panel *panel = &connector->panel;
+ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ int ret;
+ u8 buf[4] = {};
+
+ buf[0] = panel->backlight.min & 0xFF;
+ buf[1] = (panel->backlight.min & 0xFF00) >> 8;
+ buf[2] = panel->backlight.max & 0xFF;
+ buf[3] = (panel->backlight.max & 0xFF00) >> 8;
+
+ ret = drm_dp_dpcd_write(&intel_dp->aux,
+ INTEL_EDP_HDR_PANEL_LUMINANCE_OVERRIDE,
+ buf, sizeof(buf));
+ if (ret < 0)
+ drm_dbg_kms(display->drm,
+ "Panel Luminance DPCD reg write failed, err:-%d\n",
+ ret);
+}
+
static int
intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pipe)
{
- struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_display *display = to_intel_display(connector);
struct intel_panel *panel = &connector->panel;
struct drm_luminance_range_info *luminance_range =
&connector->base.display_info.luminance_range;
int ret;
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] SDR backlight is controlled through %s\n",
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] SDR backlight is controlled through %s\n",
connector->base.base.id, connector->base.name,
- dpcd_vs_pwm_str(panel->backlight.edp.intel.sdr_uses_aux));
+ dpcd_vs_pwm_str(panel->backlight.edp.intel_cap.sdr_uses_aux));
- if (!panel->backlight.edp.intel.sdr_uses_aux) {
+ if (!panel->backlight.edp.intel_cap.sdr_uses_aux) {
ret = panel->backlight.pwm_funcs->setup(connector, pipe);
if (ret < 0) {
- drm_err(&i915->drm,
+ drm_err(display->drm,
"[CONNECTOR:%d:%s] Failed to setup SDR backlight controls through PWM: %d\n",
connector->base.base.id, connector->base.name, ret);
return ret;
@@ -318,11 +436,13 @@ intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pi
panel->backlight.min = 0;
}
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Using AUX HDR interface for backlight control (range %d..%d)\n",
+ intel_dp_aux_write_panel_luminance_override(connector);
+
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] Using AUX HDR interface for backlight control (range %d..%d)\n",
connector->base.base.id, connector->base.name,
panel->backlight.min, panel->backlight.max);
-
panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe);
panel->backlight.enabled = panel->backlight.level != 0;
@@ -332,9 +452,54 @@ intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pi
/* VESA backlight callbacks */
static u32 intel_dp_aux_vesa_get_backlight(struct intel_connector *connector, enum pipe unused)
{
+ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ struct intel_panel *panel = &connector->panel;
+ u8 buf[3];
+ u32 val = 0;
+ int ret;
+
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ ret = drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE, buf,
+ sizeof(buf));
+ if (ret < 0) {
+ drm_err(intel_dp->aux.drm_dev,
+ "[CONNECTOR:%d:%s] Failed to read Luminance from DPCD\n",
+ connector->base.base.id, connector->base.name);
+ return 0;
+ }
+
+ val |= buf[0] | buf[1] << 8 | buf[2] << 16;
+ return val / 1000;
+ }
+
return connector->panel.backlight.level;
}
+static int
+intel_dp_aux_vesa_set_luminance(struct intel_connector *connector, u32 level)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ u8 buf[3];
+ int ret;
+
+ level = level * 1000;
+ level &= 0xffffff;
+ buf[0] = (level & 0x0000ff);
+ buf[1] = (level & 0x00ff00) >> 8;
+ buf[2] = (level & 0xff0000) >> 16;
+
+ ret = drm_dp_dpcd_write(&intel_dp->aux, DP_EDP_PANEL_TARGET_LUMINANCE_VALUE,
+ buf, sizeof(buf));
+ if (ret != sizeof(buf)) {
+ drm_err(intel_dp->aux.drm_dev,
+ "%s: Failed to set VESA Aux Luminance: %d\n",
+ intel_dp->aux.name, ret);
+ return -EINVAL;
+ } else {
+ return 0;
+ }
+}
+
static void
intel_dp_aux_vesa_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
@@ -342,6 +507,11 @@ 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.luminance_control_support) {
+ if (!intel_dp_aux_vesa_set_luminance(connector, level))
+ return;
+ }
+
if (!panel->backlight.edp.vesa.info.aux_set) {
const u32 pwm_level = intel_backlight_level_to_pwm(connector, level);
@@ -358,6 +528,18 @@ 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);
+ int ret;
+
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER,
+ DP_EDP_PANEL_LUMINANCE_CONTROL_ENABLE);
+
+ if (ret == 1)
+ return;
+
+ if (!intel_dp_aux_vesa_set_luminance(connector, level))
+ return;
+ }
if (!panel->backlight.edp.vesa.info.aux_enable) {
u32 pwm_level;
@@ -381,6 +563,9 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state
struct intel_panel *panel = &connector->panel;
struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ if (panel->backlight.edp.vesa.luminance_control_support)
+ return;
+
drm_edp_backlight_disable(&intel_dp->aux, &panel->backlight.edp.vesa.info);
if (!panel->backlight.edp.vesa.info.aux_enable)
@@ -390,59 +575,81 @@ static void intel_dp_aux_vesa_disable_backlight(const struct drm_connector_state
static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, enum pipe pipe)
{
+ struct intel_display *display = to_intel_display(connector);
+ struct drm_luminance_range_info *luminance_range =
+ &connector->base.display_info.luminance_range;
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_panel *panel = &connector->panel;
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
u16 current_level;
u8 current_mode;
int ret;
- ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
- panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
- &current_level, &current_mode);
- if (ret < 0)
- return ret;
-
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n",
- connector->base.base.id, connector->base.name,
- dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable));
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n",
- connector->base.base.id, connector->base.name,
- dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set));
-
- 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,
- "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n",
- connector->base.base.id, connector->base.name, ret);
- return ret;
- }
- }
-
- 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;
+ if (panel->backlight.edp.vesa.luminance_control_support) {
+ if (luminance_range->max_luminance) {
+ panel->backlight.max = luminance_range->max_luminance;
+ panel->backlight.min = luminance_range->min_luminance;
} else {
- panel->backlight.level = panel->backlight.max;
- panel->backlight.enabled = false;
+ panel->backlight.max = 512;
+ panel->backlight.min = 0;
}
+ panel->backlight.level = intel_dp_aux_vesa_get_backlight(connector, 0);
+ panel->backlight.enabled = panel->backlight.level != 0;
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX VESA Nits backlight level is controlled through DPCD\n",
+ connector->base.base.id, connector->base.name);
} else {
- 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;
+ ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info,
+ panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd,
+ &current_level, &current_mode);
+ if (ret < 0)
+ return ret;
+
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX VESA backlight enable is controlled through %s\n",
+ connector->base.base.id, connector->base.name,
+ dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_enable));
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX VESA backlight level is controlled through %s\n",
+ connector->base.base.id, connector->base.name,
+ dpcd_vs_pwm_str(panel->backlight.edp.vesa.info.aux_set));
+
+ 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(display->drm,
+ "[CONNECTOR:%d:%s] Failed to setup PWM backlight controls for eDP backlight: %d\n",
+ connector->base.base.id, connector->base.name, ret);
+ return ret;
+ }
+ }
+
+ 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;
+ }
}
}
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] Using AUX VESA interface for backlight control\n",
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] Using AUX VESA interface for backlight control\n",
connector->base.base.id, connector->base.name);
return 0;
@@ -451,11 +658,22 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector,
static bool
intel_dp_aux_supports_vesa_backlight(struct intel_connector *connector)
{
+ struct intel_display *display = to_intel_display(connector);
struct intel_dp *intel_dp = intel_attached_dp(connector);
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_panel *panel = &connector->panel;
+
+ if ((intel_dp->edp_dpcd[3] & DP_EDP_PANEL_LUMINANCE_CONTROL_CAPABLE) &&
+ (intel_dp->edp_dpcd[3] & DP_EDP_SMOOTH_BRIGHTNESS_CAPABLE)) {
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX Luminance Based Backlight Control Supported!\n",
+ connector->base.base.id, connector->base.name);
+ panel->backlight.edp.vesa.luminance_control_support = true;
+ return true;
+ }
if (drm_edp_backlight_supported(intel_dp->edp_dpcd)) {
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] AUX Backlight Control Supported!\n",
+ drm_dbg_kms(display->drm,
+ "[CONNECTOR:%d:%s] AUX Backlight Control Supported!\n",
connector->base.base.id, connector->base.name);
return true;
}
@@ -480,16 +698,16 @@ static const struct intel_panel_bl_funcs intel_dp_vesa_bl_funcs = {
int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
{
+ struct intel_display *display = to_intel_display(connector);
+ struct intel_dp *intel_dp = intel_attached_dp(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);
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
bool try_intel_interface = false, try_vesa_interface = false;
/* Check the VBT and user's module parameters to figure out which
* interfaces to probe
*/
- switch (i915->display.params.enable_dpcd_backlight) {
+ switch (display->params.enable_dpcd_backlight) {
case INTEL_DP_AUX_BACKLIGHT_OFF:
return -ENODEV;
case INTEL_DP_AUX_BACKLIGHT_AUTO:
@@ -518,6 +736,10 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
break;
}
+ /* For eDP 1.5 and above we are supposed to use VESA interface for brightness control */
+ if (intel_dp->edp_dpcd[0] >= DP_EDP_15)
+ try_vesa_interface = true;
+
/*
* 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
@@ -531,7 +753,8 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector)
* 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)) {
+ if (try_intel_interface && intel_dp_aux_supports_hdr_backlight(connector) &&
+ intel_dp->edp_dpcd[0] <= DP_EDP_14b) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Using Intel proprietary eDP backlight controls\n",
connector->base.base.id, connector->base.name);
panel->backlight.funcs = &intel_dp_hdr_bl_funcs;