@@ -40,11 +40,6 @@
#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.
@@ -127,9 +122,6 @@ 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",
connector->base.base.id, connector->base.name,
is_intel_tcon_cap(tcon_cap) ? "Intel" : "unsupported", tcon_cap[0]);
@@ -137,6 +129,9 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector)
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
@@ -225,13 +220,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_cap.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);
@@ -240,6 +249,64 @@ 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_dp *intel_dp = enc_to_intel_dp(connector->encoder);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ 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(&i915->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 drm_i915_private *i915 = to_i915(connector->base.dev);
+
+ /*
+ * 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(i915) < 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)
@@ -248,6 +315,7 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
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;
@@ -261,8 +329,10 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state,
}
ctrl = old_ctrl;
- if (panel->backlight.edp.intel_cap.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);
@@ -272,10 +342,17 @@ 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",
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
@@ -332,7 +409,6 @@ intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pi
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;