Commit abedc077 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter

drm/i915: Provide the quantization range in the AVI infoframe

The AVI infoframe is able to inform the display whether the source is
sending full or limited range RGB data.

As per CEA-861 [1] we must first check whether the display reports the
quantization range as selectable, and if so we can set the approriate
bits in the AVI inforframe.

[1] CEA-861-E - 6.4 Format of Version 2 AVI InfoFrame

v2: Give the Q bits better names, add spec chapter information
Reviewed-by: default avatarPaulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent b1edd6a6
...@@ -289,6 +289,9 @@ struct cxsr_latency { ...@@ -289,6 +289,9 @@ struct cxsr_latency {
#define DIP_LEN_AVI 13 #define DIP_LEN_AVI 13
#define DIP_AVI_PR_1 0 #define DIP_AVI_PR_1 0
#define DIP_AVI_PR_2 1 #define DIP_AVI_PR_2 1
#define DIP_AVI_RGB_QUANT_RANGE_DEFAULT (0 << 2)
#define DIP_AVI_RGB_QUANT_RANGE_LIMITED (1 << 2)
#define DIP_AVI_RGB_QUANT_RANGE_FULL (2 << 2)
#define DIP_TYPE_SPD 0x83 #define DIP_TYPE_SPD 0x83
#define DIP_VERSION_SPD 0x1 #define DIP_VERSION_SPD 0x1
...@@ -347,6 +350,7 @@ struct intel_hdmi { ...@@ -347,6 +350,7 @@ struct intel_hdmi {
bool has_hdmi_sink; bool has_hdmi_sink;
bool has_audio; bool has_audio;
enum hdmi_force_audio force_audio; enum hdmi_force_audio force_audio;
bool rgb_quant_range_selectable;
void (*write_infoframe)(struct drm_encoder *encoder, void (*write_infoframe)(struct drm_encoder *encoder,
struct dip_infoframe *frame); struct dip_infoframe *frame);
void (*set_infoframes)(struct drm_encoder *encoder, void (*set_infoframes)(struct drm_encoder *encoder,
......
...@@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder, ...@@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct dip_infoframe avi_if = { struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI, .type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI, .ver = DIP_VERSION_AVI,
...@@ -340,6 +341,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, ...@@ -340,6 +341,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
if (intel_hdmi->rgb_quant_range_selectable) {
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED;
else
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL;
}
avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode); avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode);
intel_set_infoframe(encoder, &avi_if); intel_set_infoframe(encoder, &avi_if);
...@@ -825,6 +833,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) ...@@ -825,6 +833,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_hdmi_sink = false;
intel_hdmi->has_audio = false; intel_hdmi->has_audio = false;
intel_hdmi->rgb_quant_range_selectable = false;
edid = drm_get_edid(connector, edid = drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv, intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus)); intel_hdmi->ddc_bus));
...@@ -836,6 +845,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) ...@@ -836,6 +845,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
intel_hdmi->has_hdmi_sink = intel_hdmi->has_hdmi_sink =
drm_detect_hdmi_monitor(edid); drm_detect_hdmi_monitor(edid);
intel_hdmi->has_audio = drm_detect_monitor_audio(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
intel_hdmi->rgb_quant_range_selectable =
drm_rgb_quant_range_selectable(edid);
} }
kfree(edid); kfree(edid);
} }
......
...@@ -126,6 +126,7 @@ struct intel_sdvo { ...@@ -126,6 +126,7 @@ struct intel_sdvo {
bool is_hdmi; bool is_hdmi;
bool has_hdmi_monitor; bool has_hdmi_monitor;
bool has_hdmi_audio; bool has_hdmi_audio;
bool rgb_quant_range_selectable;
/** /**
* This is set if we detect output of sdvo device as LVDS and * This is set if we detect output of sdvo device as LVDS and
...@@ -947,7 +948,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, ...@@ -947,7 +948,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
&tx_rate, 1); &tx_rate, 1);
} }
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
const struct drm_display_mode *adjusted_mode)
{ {
struct dip_infoframe avi_if = { struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI, .type = DIP_TYPE_AVI,
...@@ -956,6 +958,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) ...@@ -956,6 +958,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
}; };
uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
if (intel_sdvo->rgb_quant_range_selectable) {
if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE)
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED;
else
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL;
}
intel_dip_infoframe_csum(&avi_if); intel_dip_infoframe_csum(&avi_if);
/* sdvo spec says that the ecc is handled by the hw, and it looks like /* sdvo spec says that the ecc is handled by the hw, and it looks like
...@@ -1134,7 +1143,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, ...@@ -1134,7 +1143,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
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,
SDVO_COLORIMETRY_RGB256); SDVO_COLORIMETRY_RGB256);
intel_sdvo_set_avi_infoframe(intel_sdvo); intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);
} else } else
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
...@@ -1526,6 +1535,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) ...@@ -1526,6 +1535,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
if (intel_sdvo->is_hdmi) { if (intel_sdvo->is_hdmi) {
intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
intel_sdvo->rgb_quant_range_selectable =
drm_rgb_quant_range_selectable(edid);
} }
} else } else
status = connector_status_disconnected; status = connector_status_disconnected;
...@@ -1577,6 +1588,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) ...@@ -1577,6 +1588,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
intel_sdvo->has_hdmi_monitor = false; intel_sdvo->has_hdmi_monitor = false;
intel_sdvo->has_hdmi_audio = false; intel_sdvo->has_hdmi_audio = false;
intel_sdvo->rgb_quant_range_selectable = false;
if ((intel_sdvo_connector->output_flag & response) == 0) if ((intel_sdvo_connector->output_flag & response) == 0)
ret = connector_status_disconnected; ret = connector_status_disconnected;
......
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