Skip to content

Commit

Permalink
drm/i915: Provide the quantization range in the AVI infoframe
Browse files Browse the repository at this point in the history
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: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Ville Syrjälä authored and Daniel Vetter committed Jan 20, 2013
1 parent b1edd6a commit abedc07
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 2 deletions.
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ struct cxsr_latency {
#define DIP_LEN_AVI 13
#define DIP_AVI_PR_1 0
#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_VERSION_SPD 0x1
Expand Down Expand Up @@ -347,6 +350,7 @@ struct intel_hdmi {
bool has_hdmi_sink;
bool has_audio;
enum hdmi_force_audio force_audio;
bool rgb_quant_range_selectable;
void (*write_infoframe)(struct drm_encoder *encoder,
struct dip_infoframe *frame);
void (*set_infoframes)(struct drm_encoder *encoder,
Expand Down
11 changes: 11 additions & 0 deletions drivers/gpu/drm/i915/intel_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI,
Expand All @@ -340,6 +341,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
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);

intel_set_infoframe(encoder, &avi_if);
Expand Down Expand Up @@ -825,6 +833,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)

intel_hdmi->has_hdmi_sink = false;
intel_hdmi->has_audio = false;
intel_hdmi->rgb_quant_range_selectable = false;
edid = drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus));
Expand All @@ -836,6 +845,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
intel_hdmi->has_hdmi_sink =
drm_detect_hdmi_monitor(edid);
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
intel_hdmi->rgb_quant_range_selectable =
drm_rgb_quant_range_selectable(edid);
}
kfree(edid);
}
Expand Down
16 changes: 14 additions & 2 deletions drivers/gpu/drm/i915/intel_sdvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ struct intel_sdvo {
bool is_hdmi;
bool has_hdmi_monitor;
bool has_hdmi_audio;
bool rgb_quant_range_selectable;

/**
* This is set if we detect output of sdvo device as LVDS and
Expand Down Expand Up @@ -947,7 +948,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
&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 = {
.type = DIP_TYPE_AVI,
Expand All @@ -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)];

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);

/* sdvo spec says that the ecc is handled by the hw, and it looks like
Expand Down Expand Up @@ -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_colorimetry(intel_sdvo,
SDVO_COLORIMETRY_RGB256);
intel_sdvo_set_avi_infoframe(intel_sdvo);
intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);
} else
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);

Expand Down Expand Up @@ -1526,6 +1535,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
if (intel_sdvo->is_hdmi) {
intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
intel_sdvo->rgb_quant_range_selectable =
drm_rgb_quant_range_selectable(edid);
}
} else
status = connector_status_disconnected;
Expand Down Expand Up @@ -1577,6 +1588,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)

intel_sdvo->has_hdmi_monitor = false;
intel_sdvo->has_hdmi_audio = false;
intel_sdvo->rgb_quant_range_selectable = false;

if ((intel_sdvo_connector->output_flag & response) == 0)
ret = connector_status_disconnected;
Expand Down

0 comments on commit abedc07

Please sign in to comment.