staticint lspcon_get_mode_settle_timeout(struct intel_lspcon *lspcon)
{ /* * On some CometLake-based device designs the Parade PS175 takes more * than 400ms to settle in PCON mode. 100 reboot trials on one device * resulted in a median settle time of 440ms and a maximum of 444ms. * Even after increasing the timeout to 500ms, 2% of devices still had * this error. So this sets the timeout to 800ms.
*/ return lspcon->vendor == LSPCON_VENDOR_PARADE ? 800 : 400;
}
/* Lets probe the adaptor and check its type */ for (retry = 0; retry < 6; retry++) { if (retry)
usleep_range(500, 1000);
adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, ddc); if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON) break;
}
if (adaptor_type != DRM_DP_DUAL_MODE_LSPCON) {
drm_dbg_kms(display->drm, "No LSPCON detected, found %s\n",
drm_dp_get_dual_mode_type_name(adaptor_type)); returnfalse;
}
/* Yay ... got a LSPCON device */
drm_dbg_kms(display->drm, "LSPCON detected\n");
lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
/* * In the SW state machine, lets Put LSPCON in PCON mode only. * In this way, it will work with both HDMI 1.4 sinks as well as HDMI * 2.0 sinks.
*/ if (lspcon->mode != DRM_LSPCON_MODE_PCON) { if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
drm_err(display->drm, "LSPCON mode change to PCON failed\n"); returnfalse;
}
} returntrue;
}
while (1) { if (intel_digital_port_connected(&dig_port->base)) {
drm_dbg_kms(display->drm, "LSPCON recovering in PCON mode after %u ms\n",
jiffies_to_msecs(jiffies - start)); return;
}
if (time_after(jiffies, start + msecs_to_jiffies(1000))) break;
usleep_range(10000, 15000);
}
drm_dbg_kms(display->drm, "LSPCON DP descriptor mismatch after resume\n");
}
/* Check if LSPCON FW is ready for data */ for (retry = 0; retry < 5; retry++) { if (retry)
usleep_range(200, 300);
ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
&avi_if_ctrl, 1); if (ret < 0) {
drm_err(aux->drm_dev, "Failed to read AVI IF control\n"); returnfalse;
}
if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0) returntrue;
}
drm_err(aux->drm_dev, "Parade FW not ready to accept AVI IF\n"); returnfalse;
}
while (block_count < 4) { if (!lspcon_parade_fw_ready(aux)) {
drm_dbg_kms(aux->drm_dev, "LSPCON FW not ready, block %d\n",
block_count); returnfalse;
}
reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
data = avi_buf + block_count * 8;
ret = drm_dp_dpcd_write(aux, reg, data, 8); if (ret < 0) {
drm_err(aux->drm_dev, "Failed to write AVI IF block %d\n",
block_count); returnfalse;
}
/* * Once a block of data is written, we have to inform the FW * about this by writing into avi infoframe control register: * - set the kickoff bit[7] to 1 * - write the block no. to bits[1:0]
*/
reg = LSPCON_PARADE_AVI_IF_CTRL;
avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1); if (ret < 0) {
drm_err(aux->drm_dev, "Failed to update (0x%x), block %d\n",
reg, block_count); returnfalse;
}
block_count++;
}
drm_dbg_kms(aux->drm_dev, "Wrote AVI IF blocks successfully\n"); returntrue;
}
/* * Parade's frames contains 32 bytes of data, divided * into 4 frames: * Token byte (first byte of first frame, must be non-zero) * HB0 to HB2 from AVI IF (3 bytes header) * PB0 to PB27 from AVI IF (28 bytes data) * So it should look like this * first block: | <token> <HB0-HB2> <DB0-DB3> | * next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
*/
if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
drm_err(aux->drm_dev, "Invalid length of infoframes\n"); returnfalse;
}
memcpy(&avi_if[1], frame, len);
if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
drm_dbg_kms(aux->drm_dev, "Failed to write infoframe blocks\n"); returnfalse;
}
switch (type) { case HDMI_INFOFRAME_TYPE_AVI: if (lspcon->vendor == LSPCON_VENDOR_MCA)
ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
frame, len); else
ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
frame, len); break; case HDMI_PACKET_TYPE_GAMUT_METADATA:
drm_dbg_kms(display->drm, "Update HDR metadata for lspcon\n"); /* It uses the legacy hsw implementation for the same */
hsw_write_infoframe(encoder, crtc_state, type, frame, len); break; default: return;
}
if (!ret) {
drm_err(display->drm, "Failed to write infoframes\n"); return;
}
}
void lspcon_read_infoframe(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state, unsignedint type, void *frame, ssize_t len)
{ /* FIXME implement for AVI Infoframe as well */ if (type == HDMI_PACKET_TYPE_GAMUT_METADATA)
hsw_read_infoframe(encoder, crtc_state, type,
frame, len);
}
if (!lspcon->active) {
drm_err(display->drm, "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_err(display->drm, "couldn't fill AVI infoframe\n"); return;
}
/* * Currently there is no interface defined to * check user preference between RGB/YCBCR444 * or YCBCR420. So the only possible case for * YCBCR444 usage is driving YCBCR420 output * with LSPCON, when pipe is configured for * YCBCR444 output and LSPCON takes care of * downsampling it.
*/ if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
frame.avi.colorspace = HDMI_COLORSPACE_YUV420; else
frame.avi.colorspace = HDMI_COLORSPACE_RGB;
/* Set the Colorspace as per the HDMI spec */
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, conn_state);
if (!intel_bios_encoder_is_lspcon(dig_port->base.devdata)) return;
if (!lspcon->active) { if (!intel_lspcon_init(dig_port)) {
drm_err(display->drm, "LSPCON init failed on port %c\n",
port_name(dig_port->base.port)); return;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.