void lspcon_set_infoframes(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { ssize_t ret; union hdmi_infoframe frame; u8 buf[VIDEO_DIP_DATA_SIZE]; struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); struct intel_lspcon *lspcon = &dig_port->lspcon; const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; if (!lspcon->active) { DRM_ERROR("Writing infoframes while LSPCON disabled ?\n"); return; } /* FIXME precompute infoframes */ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, conn_state->connector, adjusted_mode); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); return; } if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) { if (crtc_state->lspcon_downsampling) frame.avi.colorspace = HDMI_COLORSPACE_YUV420; else frame.avi.colorspace = HDMI_COLORSPACE_YUV444; } else { frame.avi.colorspace = HDMI_COLORSPACE_RGB; } drm_hdmi_avi_infoframe_quant_range(&frame.avi, conn_state->connector, adjusted_mode, crtc_state->limited_color_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL); ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf)); if (ret < 0) { DRM_ERROR("Failed to pack AVI IF\n"); return; } dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI, buf, ret); }
static void tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, union hdmi_infoframe *frame) { u8 buf[32]; ssize_t len; len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); if (len < 0) { dev_err(&priv->hdmi->dev, "hdmi_infoframe_pack() type=0x%02x failed: %zd\n", frame->any.type, len); return; } reg_clear(priv, REG_DIP_IF_FLAGS, bit); reg_write_range(priv, addr, buf, len); reg_set(priv, REG_DIP_IF_FLAGS, bit); }
/* * The data we write to the DIP data buffer registers is 1 byte bigger than the * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting * at 0). It's also a byte used by DisplayPort so the same DIP registers can be * used for both technologies. * * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0 * DW1: DB3 | DB2 | DB1 | DB0 * DW2: DB7 | DB6 | DB5 | DB4 * DW3: ... * * (HB is Header Byte, DB is Data Byte) * * The hdmi pack() functions don't know about that hardware specific hole so we * trick them by giving an offset into the buffer and moving back the header * bytes by one. */ static void intel_write_infoframe(struct drm_encoder *encoder, union hdmi_infoframe *frame) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); uint8_t buffer[VIDEO_DIP_DATA_SIZE]; ssize_t len; /* see comment above for the reason for this offset */ len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1); if (len < 0) return; /* Insert the 'hole' (see big comment above) at position 3 */ buffer[0] = buffer[1]; buffer[1] = buffer[2]; buffer[2] = buffer[3]; buffer[3] = 0; len++; intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len); }