Commit 0d567f1e authored by Ville Syrjälä's avatar Ville Syrjälä

drm/i915/sdvo: Read out HDMI infoframes

Read the HDMI infoframes from the hbuf and unpack them into
the crtc state.

Well, actually just AVI infoframe for now but let's write the
infoframe readout code in a more generic fashion in case we
expand this later.

Note that Daniel was sceptical about the benefit if this and
also concerned about the potential for crappy sdvo encoders not
implementing the hbuf read commands. My (admittedly limited)
experience is that such encoders don't implement even the
get/set hdmi encoding commands and thus would always be treated
as dvi only. Hence I believe this is safe, and also IMO preferable
having quirks to deal with missing readout support. The readout
support is neatly isolated in the sdvo code whereas the quirk
would leak to other parts of the driver (state checker, fastboot,
etc.) thus complicating the lives of other people.
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20190225174106.2163-8-ville.syrjala@linux.intel.com
parent 769be632
......@@ -978,6 +978,58 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
&tx_rate, 1);
}
static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
unsigned int if_index,
u8 *data, unsigned int length)
{
u8 set_buf_index[2] = { if_index, 0 };
u8 hbuf_size, tx_rate, av_split;
int i;
if (!intel_sdvo_get_value(intel_sdvo,
SDVO_CMD_GET_HBUF_AV_SPLIT,
&av_split, 1))
return -ENXIO;
if (av_split < if_index)
return 0;
if (!intel_sdvo_get_value(intel_sdvo,
SDVO_CMD_GET_HBUF_TXRATE,
&tx_rate, 1))
return -ENXIO;
if (tx_rate == SDVO_HBUF_TX_DISABLED)
return 0;
if (!intel_sdvo_set_value(intel_sdvo,
SDVO_CMD_SET_HBUF_INDEX,
set_buf_index, 2))
return -ENXIO;
if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
&hbuf_size, 1))
return -ENXIO;
/* Buffer size is 0 based, hooray! */
hbuf_size++;
DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
if_index, length, hbuf_size);
hbuf_size = min_t(unsigned int, length, hbuf_size);
for (i = 0; i < hbuf_size; i += 8) {
if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
return -ENXIO;
if (!intel_sdvo_read_response(intel_sdvo, &data[i],
min_t(unsigned int, 8, hbuf_size - i)))
return -ENXIO;
}
return hbuf_size;
}
static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
......@@ -1036,6 +1088,40 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
sdvo_data, sizeof(sdvo_data));
}
static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
struct intel_crtc_state *crtc_state)
{
u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
ssize_t len;
int ret;
if (!crtc_state->has_hdmi_sink)
return;
len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
sdvo_data, sizeof(sdvo_data));
if (len < 0) {
DRM_DEBUG_KMS("failed to read AVI infoframe\n");
return;
} else if (len == 0) {
return;
}
crtc_state->infoframes.enable |=
intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
ret = hdmi_infoframe_unpack(frame, sdvo_data, sizeof(sdvo_data));
if (ret) {
DRM_DEBUG_KMS("Failed to unpack AVI infoframe\n");
return;
}
if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
DRM_DEBUG_KMS("Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
}
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
const struct drm_connector_state *conn_state)
{
......@@ -1535,6 +1621,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
}
}
WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
"SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
pipe_config->pixel_multiplier, encoder_pixel_multiplier);
if (sdvox & HDMI_COLOR_RANGE_16_235)
pipe_config->limited_color_range = true;
......@@ -1547,9 +1637,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
pipe_config->has_hdmi_sink = true;
}
WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
"SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
pipe_config->pixel_multiplier, encoder_pixel_multiplier);
intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
}
static void intel_disable_sdvo(struct intel_encoder *encoder,
......
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