drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
val |= g4x_infoframe_index(type);
val &= ~g4x_infoframe_enable(type);
intel_de_write(display, VIDEO_DIP_CTL, val);
for (i = 0; i < len; i += 4) {
intel_de_write(display, VIDEO_DIP_DATA, *data);
data++;
} /* Write every possible data byte to force correct ECC calculation. */ for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
intel_de_write(display, VIDEO_DIP_DATA, 0);
val |= g4x_infoframe_enable(type);
val &= ~VIDEO_DIP_FREQ_MASK;
val |= VIDEO_DIP_FREQ_VSYNC;
drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
val |= g4x_infoframe_index(type);
val &= ~g4x_infoframe_enable(type);
intel_de_write(display, reg, val);
for (i = 0; i < len; i += 4) {
intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe),
*data);
data++;
} /* Write every possible data byte to force correct ECC calculation. */ for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe), 0);
val |= g4x_infoframe_enable(type);
val &= ~VIDEO_DIP_FREQ_MASK;
val |= VIDEO_DIP_FREQ_VSYNC;
drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
val |= g4x_infoframe_index(type);
/* The DIP control register spec says that we need to update the AVI
* infoframe without clearing its enable bit */ if (type != HDMI_INFOFRAME_TYPE_AVI)
val &= ~g4x_infoframe_enable(type);
intel_de_write(display, reg, val);
for (i = 0; i < len; i += 4) {
intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe),
*data);
data++;
} /* Write every possible data byte to force correct ECC calculation. */ for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe), 0);
val |= g4x_infoframe_enable(type);
val &= ~VIDEO_DIP_FREQ_MASK;
val |= VIDEO_DIP_FREQ_VSYNC;
drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
val |= g4x_infoframe_index(type);
val &= ~g4x_infoframe_enable(type);
intel_de_write(display, reg, val);
for (i = 0; i < len; i += 4) {
intel_de_write(display,
VLV_TVIDEO_DIP_DATA(crtc->pipe), *data);
data++;
} /* Write every possible data byte to force correct ECC calculation. */ for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
intel_de_write(display,
VLV_TVIDEO_DIP_DATA(crtc->pipe), 0);
val |= g4x_infoframe_enable(type);
val &= ~VIDEO_DIP_FREQ_MASK;
val |= VIDEO_DIP_FREQ_VSYNC;
val &= ~hsw_infoframe_enable(type);
intel_de_write(display, ctl_reg, val);
for (i = 0; i < len; i += 4) {
intel_de_write(display,
hsw_dip_data_reg(display, cpu_transcoder, type, i >> 2),
*data);
data++;
} /* Write every possible data byte to force correct ECC calculation. */ for (; i < data_size; i += 4)
intel_de_write(display,
hsw_dip_data_reg(display, cpu_transcoder, type, i >> 2),
0);
/* Wa_14013475917 */ if (!(IS_DISPLAY_VER(display, 13, 14) && crtc_state->has_psr &&
!crtc_state->has_panel_replay && type == DP_SDP_VSC))
val |= hsw_infoframe_enable(type);
if (type == DP_SDP_VSC)
val |= VSC_DIP_HW_DATA_SW_HEA;
val = dig_port->infoframes_enabled(encoder, crtc_state);
/* map from hardware bits to dip idx */ for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) { unsignedint type = infoframe_type_to_idx[i];
if (HAS_DDI(display)) { if (val & hsw_infoframe_enable(type))
ret |= BIT(i);
} else { if (val & g4x_infoframe_enable(type))
ret |= BIT(i);
}
}
return ret;
}
/* * 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.
*/ staticvoid intel_write_infoframe(struct intel_encoder *encoder, conststruct intel_crtc_state *crtc_state, enum hdmi_infoframe_type type, constunion hdmi_infoframe *frame)
{ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
u8 buffer[VIDEO_DIP_DATA_SIZE];
ssize_t len;
if ((crtc_state->infoframes.enable &
intel_hdmi_infoframe_enable(type)) == 0) return;
if (drm_WARN_ON(encoder->base.dev, frame->any.type != type)) return;
/* see comment above for the reason for this offset */
len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1); if (drm_WARN_ON(encoder->base.dev, len < 0)) return;
/* Insert the 'hole' (see big comment above) at position 3 */
memmove(&buffer[0], &buffer[1], 3);
buffer[3] = 0;
len++;
/* Fill the 'hole' (see big comment above) at position 3 */
memmove(&buffer[1], &buffer[0], 3);
/* see comment above for the reason for this offset */
ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1); if (ret) {
drm_dbg_kms(encoder->base.dev, "Failed to unpack infoframe type 0x%02x\n", type); return;
}
if (frame->any.type != type)
drm_dbg_kms(encoder->base.dev, "Found the wrong infoframe type 0x%x (expected 0x%02x)\n",
frame->any.type, type);
}
if (display->platform.dgfx)
ret = hdmi_spd_infoframe_init(frame, "Intel", "Discrete gfx"); else
ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
if (drm_WARN_ON(encoder->base.dev, ret)) returnfalse;
frame->sdi = HDMI_SPD_SDI_PC;
ret = hdmi_spd_infoframe_check(frame); if (drm_WARN_ON(encoder->base.dev, ret)) returnfalse;
ret = drm_hdmi_vendor_infoframe_from_display_mode(frame,
conn_state->connector,
&crtc_state->hw.adjusted_mode); if (drm_WARN_ON(encoder->base.dev, ret)) returnfalse;
ret = hdmi_vendor_infoframe_check(frame); if (drm_WARN_ON(encoder->base.dev, ret)) returnfalse;
ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state); if (ret < 0) {
drm_dbg_kms(display->drm, "couldn't set HDR metadata in infoframe\n"); returnfalse;
}
ret = hdmi_drm_infoframe_check(frame); if (drm_WARN_ON(display->drm, ret)) returnfalse;
/* If the registers were not initialized yet, they might be zeroes, * which means we're selecting the AVI DIP and we're setting its * frequency to once. This seems to really confuse the HW and make * things stop working (the register spec says the AVI always needs to * be sent every VSync). So here we avoid writing to the register more * than we need and also explicitly select the AVI DIP and explicitly * set its frequency to every VSync. Avoiding to write it twice seems to * be enough to solve the problem, but being defensive shouldn't hurt us
* either. */
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; if (port != (val & VIDEO_DIP_PORT_MASK)) {
drm_dbg_kms(display->drm, "video DIP still enabled on port %c\n",
(val & VIDEO_DIP_PORT_MASK) >> 29); return;
}
val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
intel_de_write(display, reg, val);
intel_de_posting_read(display, reg); return;
}
if (port != (val & VIDEO_DIP_PORT_MASK)) { if (val & VIDEO_DIP_ENABLE) {
drm_dbg_kms(display->drm, "video DIP already enabled on port %c\n",
(val & VIDEO_DIP_PORT_MASK) >> 29); return;
}
val &= ~VIDEO_DIP_PORT_MASK;
val |= port;
}
val |= VIDEO_DIP_ENABLE;
val &= ~(VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
/* * Determine if default_phase=1 can be indicated in the GCP infoframe. * * From HDMI specification 1.4a: * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0 * - The first pixel following each Video Data Period shall have a pixel packing phase of 0 * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing * phase of 0
*/ staticbool gcp_default_phase_possible(int pipe_bpp, conststruct drm_display_mode *mode)
{ unsignedint pixels_per_group;
switch (pipe_bpp) { case 30: /* 4 pixels in 5 clocks */
pixels_per_group = 4; break; case 36: /* 2 pixels in 3 clocks */
pixels_per_group = 2; break; case 48: /* 1 pixel in 2 clocks */
pixels_per_group = 1; break; default: /* phase information not relevant for 8bpc */ returnfalse;
}
/* See the big comment in g4x_set_infoframes() */
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return;
val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
intel_de_write(display, reg, val);
intel_de_posting_read(display, reg); return;
}
if (port != (val & VIDEO_DIP_PORT_MASK)) {
drm_WARN(display->drm, val & VIDEO_DIP_ENABLE, "DIP already enabled on port %c\n",
(val & VIDEO_DIP_PORT_MASK) >> 29);
val &= ~VIDEO_DIP_PORT_MASK;
val |= port;
}
val |= VIDEO_DIP_ENABLE;
val &= ~(VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
val |= VIDEO_DIP_ENABLE_GCP;
/* See the big comment in g4x_set_infoframes() */
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return;
val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
intel_de_write(display, reg, val);
intel_de_posting_read(display, reg); return;
}
/* Set both together, unset both together: see the spec. */
val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
val |= VIDEO_DIP_ENABLE_GCP;
/* See the big comment in g4x_set_infoframes() */
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return;
val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
intel_de_write(display, reg, val);
intel_de_posting_read(display, reg); return;
}
if (port != (val & VIDEO_DIP_PORT_MASK)) {
drm_WARN(display->drm, val & VIDEO_DIP_ENABLE, "DIP already enabled on port %c\n",
(val & VIDEO_DIP_PORT_MASK) >> 29);
val &= ~VIDEO_DIP_PORT_MASK;
val |= port;
}
val |= VIDEO_DIP_ENABLE;
val &= ~(VIDEO_DIP_ENABLE_AVI |
VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
val |= VIDEO_DIP_ENABLE_GCP;
ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
DRM_HDCP_AN_LEN); if (ret) {
drm_dbg_kms(display->drm, "Write An over DDC failed (%d)\n",
ret); return ret;
}
ret = intel_gmbus_output_aksv(ddc); if (ret < 0) {
drm_dbg_kms(display->drm, "Failed to output aksv (%d)\n", ret); return ret;
} return 0;
}
int ret;
ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
ri_prime, DRM_HDCP_RI_LEN); if (ret)
drm_dbg_kms(display->drm, "Read Ri' over DDC failed (%d)\n",
ret); return ret;
}
static int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port, bool *ksv_ready)
{ struct intel_display *display = to_intel_display(dig_port); int ret;
u8 val;
ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1); if (ret) {
drm_dbg_kms(display->drm, "Read bcaps over DDC failed (%d)\n",
ret); return ret;
}
*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY; return 0;
}
static int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port, int num_downstream, u8 *ksv_fifo)
{ struct intel_display *display = to_intel_display(dig_port); int ret;
ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN); if (ret) {
drm_dbg_kms(display->drm, "Read ksv fifo over DDC failed (%d)\n", ret); return ret;
} return 0;
}
static int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port, int i, u32 *part)
{ struct intel_display *display = to_intel_display(dig_port); int ret;
if (i >= DRM_HDCP_V_PRIME_NUM_PARTS) return -EINVAL;
ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_V_PRIME(i),
part, DRM_HDCP_V_PRIME_PART_LEN); if (ret)
drm_dbg_kms(display->drm, "Read V'[%d] over DDC failed (%d)\n",
i, ret); return ret;
}
/* * WA: To fix incorrect positioning of the window of * opportunity and enc_en signalling in KABYLAKE.
*/ if (display->platform.kabylake && enable) return kbl_repositioning_enc_en_signal(connector,
cpu_transcoder);
return 0;
}
static bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port, struct intel_connector *connector)
{ struct intel_display *display = to_intel_display(dig_port); enum port port = dig_port->base.port; enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder; int ret; union {
u32 reg;
u8 shim[DRM_HDCP_RI_LEN];
} ri;
ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim); if (ret) returnfalse;
ret = intel_hdmi_hdcp2_wait_for_msg(dig_port, msg_id,
hdcp->is_paired); if (ret < 0) return ret;
/* * Available msg size should be equal to or lesser than the * available buffer.
*/ if (ret > size) {
drm_dbg_kms(display->drm, "msg_sz(%zd) is more than exp size(%zu)\n",
ret, size); return -EINVAL;
}
offset = HDCP_2_2_HDMI_REG_RD_MSG_OFFSET;
ret = intel_hdmi_hdcp_read(dig_port, offset, buf, ret); if (ret)
drm_dbg_kms(display->drm, "Failed to read msg_id: %d(%zd)\n",
msg_id, ret);
return ret;
}
static int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port, struct intel_connector *connector)
{
u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN]; int ret;
ret = intel_hdmi_hdcp2_read_rx_status(dig_port, rx_status); if (ret) return ret;
/* * Re-auth request and Link Integrity Failures are represented by * same bit. i.e reauth_req.
*/ if (HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(rx_status[1]))
ret = HDCP_REAUTH_REQUEST; elseif (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]))
ret = HDCP_TOPOLOGY_CHANGE;
return ret;
}
static int intel_hdmi_hdcp2_get_capability(struct intel_connector *connector, bool *capable)
{ struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
u8 hdcp2_version; int ret;
*capable = false;
ret = intel_hdmi_hdcp_read(dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
&hdcp2_version, sizeof(hdcp2_version)); if (!ret && hdcp2_version & HDCP_2_2_HDMI_SUPPORT_MASK)
*capable = true;
/* * Try all color depths since valid port clock range * can have holes. Any mode that can be used with at * least one color depth is accepted.
*/ for (bpc = 12; bpc >= 8; bpc -= 2) { int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, sink_format);
if (!intel_hdmi_source_bpc_possible(display, bpc)) continue;
if (!intel_hdmi_sink_bpc_possible(&connector->base, bpc, has_hdmi_sink,
sink_format)) continue;
status = hdmi_port_clock_valid(hdmi, tmds_clock, true, has_hdmi_sink); if (status == MODE_OK) return MODE_OK;
}
/* can never happen */
drm_WARN_ON(display->drm, status == MODE_OK);
status = intel_cpu_transcoder_mode_valid(display, mode); if (status != MODE_OK) return status;
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
clock *= 2;
if (clock > max_dotclk) return MODE_CLOCK_HIGH;
if (mode->flags & DRM_MODE_FLAG_DBLCLK) { if (!has_hdmi_sink) return MODE_CLOCK_LOW;
clock *= 2;
}
/* * HDMI2.1 requires higher resolution modes like 8k60, 4K120 to be * enumerated only if FRL is supported. Current platforms do not support * FRL so prune the higher resolution modes that require doctclock more * than 600MHz.
*/ if (clock > 600000) return MODE_CLOCK_HIGH;
staticint intel_hdmi_compute_bpc(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int clock, bool respect_downstream_limits)
{ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); int bpc;
/* * pipe_bpp could already be below 8bpc due to FDI * bandwidth constraints. HDMI minimum is 8bpc however.
*/
bpc = max(crtc_state->pipe_bpp / 3, 8);
/* * We will never exceed downstream TMDS clock limits while * attempting deep color. If the user insists on forcing an * out of spec mode they will have to be satisfied with 8bpc.
*/ if (!respect_downstream_limits)
bpc = 8;
for (; bpc >= 8; bpc -= 2) { int tmds_clock = intel_hdmi_tmds_clock(clock, bpc,
crtc_state->sink_format);
/* * pipe_bpp could already be below 8bpc due to * FDI bandwidth constraints. We shouldn't bump it * back up to the HDMI minimum 8bpc in that case.
*/
crtc_state->pipe_bpp = min(crtc_state->pipe_bpp, bpc * 3);
/* * Our YCbCr output is always limited range. * crtc_state->limited_color_range only applies to RGB, * and it must never be set for YCbCr or we risk setting * some conflicting bits in TRANSCONF which will mess up * the colors on the monitor.
*/ if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) returnfalse;
if (ycbcr_420_only && crtc_state->sink_format != INTEL_OUTPUT_FORMAT_YCBCR420) {
drm_dbg_kms(display->drm, "YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n");
crtc_state->sink_format = INTEL_OUTPUT_FORMAT_RGB;
}
crtc_state->output_format = intel_hdmi_output_format(crtc_state);
ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits); if (ret) { if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
!crtc_state->has_hdmi_sink ||
!connector->base.ycbcr_420_allowed ||
!drm_mode_is_420_also(info, adjusted_mode)) return ret;
staticbool source_supports_scrambling(struct intel_encoder *encoder)
{ /* * Gen 10+ support HDMI 2.0 : the max tmds clock is 594MHz, and * scrambling is supported. * But there seem to be cases where certain platforms that support * HDMI 2.0, have an HDMI1.4 retimer chip, and the max tmds clock is * capped by VBT to less than 340MHz. * * In such cases when an HDMI2.0 sink is connected, it creates a * problem : the platform and the sink both support scrambling but the * HDMI 1.4 retimer chip doesn't. * * So go for scrambling, based on the max tmds clock taking into account, * restrictions coming from VBT.
*/ return intel_hdmi_source_max_tmds_clock(encoder) > 340000;
}
/* * Give a hand to buggy BIOSen which forget to turn * the TMDS output buffers back on after a reboot.
*/
intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
}
type = drm_dp_dual_mode_detect(display->drm, ddc);
/* * Type 1 DVI adaptors are not required to implement any * registers, so we can't always detect their presence. * Ideally we should be able to check the state of the * CONFIG1 pin, but no such luck on our hardware. * * The only method left to us is to check the VBT to see * if the port is a dual mode capable DP port.
*/ if (type == DRM_DP_DUAL_MODE_UNKNOWN) { if (!connector->base.force &&
intel_bios_encoder_supports_dp_dual_mode(encoder->devdata)) {
drm_dbg_kms(display->drm, "Assuming DP dual mode adaptor presence based on VBT\n");
type = DRM_DP_DUAL_MODE_TYPE1_DVI;
} else {
type = DRM_DP_DUAL_MODE_NONE;
}
}
/* Older VBTs are often buggy and can't be trusted :( Play it safe. */ if ((DISPLAY_VER(display) >= 8 || display->platform.haswell) &&
!intel_bios_encoder_supports_dp_dual_mode(encoder->devdata)) {
drm_dbg_kms(display->drm, "Ignoring DP dual mode adaptor max TMDS clock for native HDMI port\n");
hdmi->dp_dual_mode.max_tmds_clock = 0;
}
}
if (DISPLAY_VER(display) >= 10)
drm_connector_attach_hdr_output_metadata_property(&connector->base);
if (!HAS_GMCH(display))
drm_connector_attach_max_bpc_property(&connector->base, 8, 12);
}
/* * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup * @encoder: intel_encoder * @connector: drm_connector * @high_tmds_clock_ratio = bool to indicate if the function needs to set * or reset the high tmds clock ratio for scrambling * @scrambling: bool to Indicate if the function needs to set or reset * sink scrambling * * This function handles scrambling on HDMI 2.0 capable sinks. * If required clock rate is > 340 Mhz && scrambling is supported by sink * it enables scrambling. This should be called before enabling the HDMI * 2.0 port, as the sink can choose to disable the scrambling if it doesn't * detect a scrambled clock within 100 ms. * * Returns: * True on success, false on failure.
*/ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, struct drm_connector *_connector, bool high_tmds_clock_ratio, bool scrambling)
{ struct intel_connector *connector = to_intel_connector(_connector); struct intel_display *display = to_intel_display(encoder); struct drm_scrambling *sink_scrambling =
&connector->base.display_info.hdmi.scdc.scrambling;
/* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */ return drm_scdc_set_high_tmds_clock_ratio(&connector->base, high_tmds_clock_ratio) &&
drm_scdc_set_scrambling(&connector->base, scrambling);
}
static u8 chv_encoder_to_ddc_pin(struct intel_encoder *encoder)
{ enum port port = encoder->port;
u8 ddc_pin;
/* * Pin mapping for RKL depends on which PCH is present. With TGP, the * final two outputs use type-c pins, even though they're actually * combo outputs. With CMP, the traditional DDI A-D pins are used for * all outputs.
*/ if (INTEL_PCH_TYPE(display) >= PCH_TGP && phy >= PHY_C) return GMBUS_PIN_9_TC1_ICP + phy - PHY_C;
/* * Pin mapping for GEN9 BC depends on which PCH is present. With TGP, * final two outputs use type-c pins, even though they're actually * combo outputs. With CMP, the traditional DDI A-D pins are used for * all outputs.
*/ if (INTEL_PCH_TYPE(display) >= PCH_TGP && phy >= PHY_C) return GMBUS_PIN_9_TC1_ICP + phy - PHY_C;
if (is_hdcp_supported(display, port)) { int ret = intel_hdcp_init(intel_connector, dig_port,
&intel_hdmi_hdcp_shim); if (ret)
drm_dbg_kms(display->drm, "HDCP init failed, skipping.\n");
}
intel_hdmi->cec_notifier =
cec_notifier_conn_register(dev->dev, port_identifier(port),
&conn_info); if (!intel_hdmi->cec_notifier)
drm_dbg_kms(display->drm, "CEC notifier get failed\n");
returntrue;
}
/* * intel_hdmi_dsc_get_slice_height - get the dsc slice_height * @vactive: Vactive of a display mode * * @return: appropriate dsc slice height for a given mode.
*/ int intel_hdmi_dsc_get_slice_height(int vactive)
{ int slice_height;
/* * Slice Height determination : HDMI2.1 Section 7.7.5.2 * Select smallest slice height >=96, that results in a valid PPS and * requires minimum padding lines required for final slice. * * Assumption : Vactive is even.
*/ for (slice_height = 96; slice_height <= vactive; slice_height += 2) if (vactive % slice_height == 0) return slice_height;
return 0;
}
/* * intel_hdmi_dsc_get_num_slices - get no. of dsc slices based on dsc encoder * and dsc decoder capabilities * * @crtc_state: intel crtc_state * @src_max_slices: maximum slices supported by the DSC encoder * @src_max_slice_width: maximum slice width supported by DSC encoder * @hdmi_max_slices: maximum slices supported by sink DSC decoder * @hdmi_throughput: maximum clock per slice (MHz) supported by HDMI sink * * @return: num of dsc slices that can be supported by the dsc encoder * and decoder.
*/ int
intel_hdmi_dsc_get_num_slices(conststruct intel_crtc_state *crtc_state, int src_max_slices, int src_max_slice_width, int hdmi_max_slices, int hdmi_throughput)
{ /* Pixel rates in KPixels/sec */ #define HDMI_DSC_PEAK_PIXEL_RATE 2720000 /* * Rates at which the source and sink are required to process pixels in each * slice, can be two levels: either atleast 340000KHz or atleast 40000KHz.
*/ #define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000 #define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000
/* Spec limits the slice width to 2720 pixels */ #define MAX_HDMI_SLICE_WIDTH 2720 int kslice_adjust; int adjusted_clk_khz; int min_slices; int target_slices; int max_throughput; /* max clock freq. in khz per slice */ int max_slice_width; int slice_width; int pixel_clock = crtc_state->hw.adjusted_mode.crtc_clock;
if (!hdmi_throughput) return 0;
/* * Slice Width determination : HDMI2.1 Section 7.7.5.1 * kslice_adjust factor for 4:2:0, and 4:2:2 formats is 0.5, where as * for 4:4:4 is 1.0. Multiplying these factors by 10 and later * dividing adjusted clock value by 10.
*/ if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 ||
crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB)
kslice_adjust = 10; else
kslice_adjust = 5;
/* * As per spec, the rate at which the source and the sink process * the pixels per slice are at two levels: atleast 340Mhz or 400Mhz. * This depends upon the pixel clock rate and output formats * (kslice adjust). * If pixel clock * kslice adjust >= 2720MHz slices can be processed * at max 340MHz, otherwise they can be processed at max 400MHz.
*/
/* * Taking into account the sink's capability for maximum * clock per slice (in MHz) as read from HF-VSDB.
*/
max_throughput = min(max_throughput, hdmi_throughput * 1000);
/* * Keep on increasing the num of slices/line, starting from min_slices * per line till we get such a number, for which the slice_width is * just less than max_slice_width. The slices/line selected should be * less than or equal to the max horizontal slices that the combination * of PCON encoder and HDMI decoder can support.
*/
slice_width = max_slice_width;
slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay, target_slices); if (slice_width >= max_slice_width)
min_slices = target_slices + 1;
} while (slice_width >= max_slice_width);
return target_slices;
}
/* * intel_hdmi_dsc_get_bpp - get the appropriate compressed bits_per_pixel based on * source and sink capabilities. * * @src_fraction_bpp: fractional bpp supported by the source * @slice_width: dsc slice width supported by the source and sink * @num_slices: num of slices supported by the source and sink * @output_format: video output format * @hdmi_all_bpp: sink supports decoding of 1/16th bpp setting * @hdmi_max_chunk_bytes: max bytes in a line of chunks supported by sink * * @return: compressed bits_per_pixel in step of 1/16 of bits_per_pixel
*/ int
intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices, int output_format, bool hdmi_all_bpp, int hdmi_max_chunk_bytes)
{ int max_dsc_bpp, min_dsc_bpp; int target_bytes; bool bpp_found = false; int bpp_decrement_x16; int bpp_target; int bpp_target_x16;
/* * Get min bpp and max bpp as per Table 7.23, in HDMI2.1 spec * Start with the max bpp and keep on decrementing with * fractional bpp, if supported by PCON DSC encoder * * for each bpp we check if no of bytes can be supported by HDMI sink
*/
/* * Taking into account if all dsc_all_bpp supported by HDMI2.1 sink * Section 7.7.34 : Source shall not enable compressed Video * Transport with bpp_target settings above 12 bpp unless * DSC_all_bpp is set to 1.
*/ if (!hdmi_all_bpp)
max_dsc_bpp = min(max_dsc_bpp, 12);
/* * The Sink has a limit of compressed data in bytes for a scanline, * as described in max_chunk_bytes field in HFVSDB block of edid. * The no. of bytes depend on the target bits per pixel that the * source configures. So we start with the max_bpp and calculate * the target_chunk_bytes. We keep on decrementing the target_bpp, * till we get the target_chunk_bytes just less than what the sink's * max_chunk_bytes, or else till we reach the min_dsc_bpp. * * The decrement is according to the fractional support from PCON DSC * encoder. For fractional BPP we use bpp_target as a multiple of 16. * * bpp_target_x16 = bpp_target * 16 * So we need to decrement by {1, 2, 4, 8, 16} for fractional bpps * {1/16, 1/8, 1/4, 1/2, 1} respectively.
*/
bpp_target = max_dsc_bpp;
/* src does not support fractional bpp implies decrement by 16 for bppx16 */ if (!src_fractional_bpp)
src_fractional_bpp = 1;
bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp);
bpp_target_x16 = (bpp_target * 16) - bpp_decrement_x16;
while (bpp_target_x16 > (min_dsc_bpp * 16)) { int bpp;
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.