Commit 90f8ed85 authored by Ville Syrjälä's avatar Ville Syrjälä

drm/i915/sdvo: Implement limited color range for SDVO HDMI properly

The SDVO/HDMI port register limited color range bit can only be used
with TMDS encoding and not SDVO encoding, ie. to be used only when
using the port as a HDMI port as opposed to a SDVO port. The SDVO
spec does have a note that some GMCHs might allow that, but gen4
bspec vehemently disagrees. I suppose on ILK+ it might work since
the color range handling is on the CPU side rather than on the PCH
side, so there is no clear linkage between the TMDS vs. SDVO
encoding and color range. Alas, I have no hardware to test that
theory.

To implement limited color range support for SDVO->HDMI we need to
ask the SDVO device to do the range compression. Do so, but first
check if the device even supports the colorimetry selection.
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200108181242.13650-5-ville.syrjala@linux.intel.comReviewed-by: default avatarImre Deak <imre.deak@intel.com>
parent 80f5ad62
...@@ -10073,7 +10073,8 @@ static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state) ...@@ -10073,7 +10073,8 @@ static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state)
drm_WARN_ON(&dev_priv->drm, crtc_state->limited_color_range && drm_WARN_ON(&dev_priv->drm, crtc_state->limited_color_range &&
crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB); crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB);
if (crtc_state->limited_color_range) if (crtc_state->limited_color_range &&
!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO))
val |= PIPECONF_COLOR_RANGE_SELECT; val |= PIPECONF_COLOR_RANGE_SELECT;
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB)
......
...@@ -2428,8 +2428,8 @@ static int intel_hdmi_compute_clock(struct intel_encoder *encoder, ...@@ -2428,8 +2428,8 @@ static int intel_hdmi_compute_clock(struct intel_encoder *encoder,
return 0; return 0;
} }
static bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state, bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state) const struct drm_connector_state *conn_state)
{ {
const struct intel_digital_connector_state *intel_conn_state = const struct intel_digital_connector_state *intel_conn_state =
to_intel_digital_connector_state(conn_state); to_intel_digital_connector_state(conn_state);
......
...@@ -46,5 +46,7 @@ void intel_read_infoframe(struct intel_encoder *encoder, ...@@ -46,5 +46,7 @@ void intel_read_infoframe(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
enum hdmi_infoframe_type type, enum hdmi_infoframe_type type,
union hdmi_infoframe *frame); union hdmi_infoframe *frame);
bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
#endif /* __INTEL_HDMI_H__ */ #endif /* __INTEL_HDMI_H__ */
...@@ -94,6 +94,8 @@ struct intel_sdvo { ...@@ -94,6 +94,8 @@ struct intel_sdvo {
*/ */
struct intel_sdvo_caps caps; struct intel_sdvo_caps caps;
u8 colorimetry_cap;
/* Pixel clock limitations reported by the SDVO device, in kHz */ /* Pixel clock limitations reported by the SDVO device, in kHz */
int pixel_clock_min, pixel_clock_max; int pixel_clock_min, pixel_clock_max;
...@@ -1277,6 +1279,18 @@ static bool intel_has_hdmi_sink(struct intel_sdvo *sdvo, ...@@ -1277,6 +1279,18 @@ static bool intel_has_hdmi_sink(struct intel_sdvo *sdvo,
READ_ONCE(to_intel_digital_connector_state(conn_state)->force_audio) != HDMI_AUDIO_OFF_DVI; READ_ONCE(to_intel_digital_connector_state(conn_state)->force_audio) != HDMI_AUDIO_OFF_DVI;
} }
static bool intel_sdvo_limited_color_range(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
if ((intel_sdvo->colorimetry_cap & SDVO_COLORIMETRY_RGB220) == 0)
return false;
return intel_hdmi_limited_color_range(crtc_state, conn_state);
}
static int intel_sdvo_compute_config(struct intel_encoder *encoder, static int intel_sdvo_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config, struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
...@@ -1342,21 +1356,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, ...@@ -1342,21 +1356,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON; intel_sdvo_state->base.force_audio == HDMI_AUDIO_ON;
} }
if (intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) { pipe_config->limited_color_range =
/* intel_sdvo_limited_color_range(encoder, pipe_config,
* See CEA-861-E - 5.1 Default Encoding Parameters conn_state);
*
* FIXME: This bit is only valid when using TMDS encoding and 8
* bit per color mode.
*/
if (pipe_config->has_hdmi_sink &&
drm_match_cea_mode(adjusted_mode) > 1)
pipe_config->limited_color_range = true;
} else {
if (pipe_config->has_hdmi_sink &&
intel_sdvo_state->base.broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED)
pipe_config->limited_color_range = true;
}
/* Clock computation needs to happen after pixel multiplier. */ /* Clock computation needs to happen after pixel multiplier. */
if (IS_TV(intel_sdvo_connector)) if (IS_TV(intel_sdvo_connector))
...@@ -1495,6 +1497,8 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, ...@@ -1495,6 +1497,8 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
if (crtc_state->has_hdmi_sink) { if (crtc_state->has_hdmi_sink) {
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
intel_sdvo_set_colorimetry(intel_sdvo, intel_sdvo_set_colorimetry(intel_sdvo,
crtc_state->limited_color_range ?
SDVO_COLORIMETRY_RGB220 :
SDVO_COLORIMETRY_RGB256); SDVO_COLORIMETRY_RGB256);
intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state); intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state);
} else } else
...@@ -1530,8 +1534,6 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, ...@@ -1530,8 +1534,6 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
/* The real mode polarity is set by the SDVO commands, using /* The real mode polarity is set by the SDVO commands, using
* struct intel_sdvo_dtd. */ * struct intel_sdvo_dtd. */
sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
if (!HAS_PCH_SPLIT(dev_priv) && crtc_state->limited_color_range)
sdvox |= HDMI_COLOR_RANGE_16_235;
if (INTEL_GEN(dev_priv) < 5) if (INTEL_GEN(dev_priv) < 5)
sdvox |= SDVO_BORDER_ENABLE; sdvox |= SDVO_BORDER_ENABLE;
} else { } else {
...@@ -1689,8 +1691,11 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, ...@@ -1689,8 +1691,11 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
"SDVO pixel multiplier mismatch, port: %i, encoder: %i\n", "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
pipe_config->pixel_multiplier, encoder_pixel_multiplier); pipe_config->pixel_multiplier, encoder_pixel_multiplier);
if (sdvox & HDMI_COLOR_RANGE_16_235) if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_COLORIMETRY,
pipe_config->limited_color_range = true; &val, 1)) {
if (val == SDVO_COLORIMETRY_RGB220)
pipe_config->limited_color_range = true;
}
if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT, if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
&val, 1)) { &val, 1)) {
...@@ -1914,6 +1919,17 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in ...@@ -1914,6 +1919,17 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
return true; return true;
} }
static u8 intel_sdvo_get_colorimetry_cap(struct intel_sdvo *intel_sdvo)
{
u8 cap;
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_COLORIMETRY_CAP,
&cap, sizeof(cap)))
return SDVO_COLORIMETRY_RGB256;
return cap;
}
static u16 intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo) static u16 intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
{ {
struct drm_i915_private *dev_priv = to_i915(intel_sdvo->base.base.dev); struct drm_i915_private *dev_priv = to_i915(intel_sdvo->base.base.dev);
...@@ -2669,12 +2685,9 @@ static void ...@@ -2669,12 +2685,9 @@ static void
intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *connector) struct intel_sdvo_connector *connector)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->base.base.dev);
intel_attach_force_audio_property(&connector->base.base); intel_attach_force_audio_property(&connector->base.base);
if (INTEL_GEN(dev_priv) >= 4 && IS_MOBILE(dev_priv)) { if (intel_sdvo->colorimetry_cap & SDVO_COLORIMETRY_RGB220)
intel_attach_broadcast_rgb_property(&connector->base.base); intel_attach_broadcast_rgb_property(&connector->base.base);
}
intel_attach_aspect_ratio_property(&connector->base.base); intel_attach_aspect_ratio_property(&connector->base.base);
} }
...@@ -3315,6 +3328,9 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, ...@@ -3315,6 +3328,9 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err; goto err;
intel_sdvo->colorimetry_cap =
intel_sdvo_get_colorimetry_cap(intel_sdvo);
if (intel_sdvo_output_setup(intel_sdvo, if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) { intel_sdvo->caps.output_flags) != true) {
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
......
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