staticbool dw_hdmi_i2c_unwedge(struct dw_hdmi *hdmi)
{ /* If no unwedge state then give up */ if (!hdmi->unwedge_state) returnfalse;
dev_info(hdmi->dev, "Attempting to unwedge stuck i2c bus\n");
/* * This is a huge hack to workaround a problem where the dw_hdmi i2c * bus could sometimes get wedged. Once wedged there doesn't appear * to be any way to unwedge it (including the HDMI_I2CM_SOFTRSTZ) * other than pulsing the SDA line. * * We appear to be able to pulse the SDA line (in the eyes of dw_hdmi) * by: * 1. Remux the pin as a GPIO output, driven low. * 2. Wait a little while. 1 ms seems to work, but we'll do 10. * 3. Immediately jump to remux the pin as dw_hdmi i2c again. * * At the moment of remuxing, the line will still be low due to its * recent stint as an output, but then it will be pulled high by the * (presumed) external pullup. dw_hdmi seems to see this as a rising * edge and that seems to get it out of its jam. * * This wedging was only ever seen on one TV, and only on one of * its HDMI ports. It happened when the TV was powered on while the * device was plugged in. A scope trace shows the TV bringing both SDA * and SCL low, then bringing them both back up at roughly the same * time. Presumably this confuses dw_hdmi because it saw activity but * no real STOP (maybe it thinks there's another master on the bus?). * Giving it a clean rising edge of SDA while SCL is already high * presumably makes dw_hdmi see a STOP which seems to bring dw_hdmi out * of its stupor. * * Note that after coming back alive, transfers seem to immediately * resume, so if we unwedge due to a timeout we should wait a little * longer for our transfer to finish, since it might have just started * now.
*/
pinctrl_select_state(hdmi->pinctrl, hdmi->unwedge_state);
msleep(10);
pinctrl_select_state(hdmi->pinctrl, hdmi->default_state);
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); if (!stat) { /* If we can't unwedge, return timeout */ if (!dw_hdmi_i2c_unwedge(hdmi)) return -EAGAIN;
/* We tried to unwedge; give it another chance */
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); if (!stat) return -EAGAIN;
}
/* Check for error condition on the bus */ if (i2c->stat & HDMI_IH_I2CM_STAT0_ERROR) return -EIO;
ret = dw_hdmi_i2c_wait(hdmi); if (ret) return ret;
}
return 0;
}
staticint dw_hdmi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ struct dw_hdmi *hdmi = i2c_get_adapdata(adap); struct dw_hdmi_i2c *i2c = hdmi->i2c;
u8 addr = msgs[0].addr; int i, ret = 0;
if (addr == DDC_CI_ADDR) /* * The internal I2C controller does not support the multi-byte * read and write operations needed for DDC/CI. * TOFIX: Blacklist the DDC/CI address until we filter out * unsupported I2C operations.
*/ return -EOPNOTSUPP;
staticunsignedint hdmi_compute_n(unsignedint freq, unsignedlong pixel_clk)
{ unsignedint n = (128 * freq) / 1000; unsignedint mult = 1;
while (freq > 48000) {
mult *= 2;
freq /= 2;
}
switch (freq) { case 32000: if (pixel_clk == 25175000)
n = 4576; elseif (pixel_clk == 27027000)
n = 4096; elseif (pixel_clk == 74176000 || pixel_clk == 148352000)
n = 11648; elseif (pixel_clk == 297000000)
n = 3072; else
n = 4096;
n *= mult; break;
case 44100: if (pixel_clk == 25175000)
n = 7007; elseif (pixel_clk == 74176000)
n = 17836; elseif (pixel_clk == 148352000)
n = 8918; elseif (pixel_clk == 297000000)
n = 4704; else
n = 6272;
n *= mult; break;
case 48000: if (pixel_clk == 25175000)
n = 6864; elseif (pixel_clk == 27027000)
n = 6144; elseif (pixel_clk == 74176000)
n = 11648; elseif (pixel_clk == 148352000)
n = 5824; elseif (pixel_clk == 297000000)
n = 5120; else
n = 6144;
n *= mult; break;
default: break;
}
return n;
}
/* * When transmitting IEC60958 linear PCM audio, these registers allow to * configure the channel status information of all the channel status * bits in the IEC60958 frame. For the moment this configuration is only * used when the I2S audio interface, General Purpose Audio (GPA), * or AHB audio DMA (AHBAUDDMA) interface is active * (for S/PDIF interface this information comes from the stream).
*/ void dw_hdmi_set_channel_status(struct dw_hdmi *hdmi,
u8 *channel_status)
{ /* * Set channel status register for frequency and word length. * Use default values for other registers.
*/
hdmi_writeb(hdmi, channel_status[3], HDMI_FC_AUDSCHNLS7);
hdmi_writeb(hdmi, channel_status[4], HDMI_FC_AUDSCHNLS8);
}
EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_status);
/* Compute CTS when using internal AHB audio or General Parallel audio*/ if ((config3 & HDMI_CONFIG3_AHBAUDDMA) || (config3 & HDMI_CONFIG3_GPAUD)) { /* * Compute the CTS value from the N value. Note that CTS and N * can be up to 20 bits in total, so we need 64-bit math. Also * note that our TDMS clock is not fully accurate; it is * accurate to kHz. This can introduce an unnecessary remainder * in the calculation below, so we don't try to warn about that.
*/
tmp = (u64)ftdms * n;
do_div(tmp, 128 * sample_rate);
cts = tmp;
/* * For >2 channel PCM audio, we need to select layout 1 * and set an appropriate channel map.
*/ if (cnt > 2)
layout = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1; else
layout = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0;
staticbool hdmi_bus_fmt_is_rgb(unsignedint bus_format)
{ switch (bus_format) { case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_RGB101010_1X30: case MEDIA_BUS_FMT_RGB121212_1X36: case MEDIA_BUS_FMT_RGB161616_1X48: returntrue;
default: returnfalse;
}
}
staticbool hdmi_bus_fmt_is_yuv444(unsignedint bus_format)
{ switch (bus_format) { case MEDIA_BUS_FMT_YUV8_1X24: case MEDIA_BUS_FMT_YUV10_1X30: case MEDIA_BUS_FMT_YUV12_1X36: case MEDIA_BUS_FMT_YUV16_1X48: returntrue;
default: returnfalse;
}
}
staticbool hdmi_bus_fmt_is_yuv422(unsignedint bus_format)
{ switch (bus_format) { case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYVY10_1X20: case MEDIA_BUS_FMT_UYVY12_1X24: returntrue;
default: returnfalse;
}
}
staticbool hdmi_bus_fmt_is_yuv420(unsignedint bus_format)
{ switch (bus_format) { case MEDIA_BUS_FMT_UYYVYY8_0_5X24: case MEDIA_BUS_FMT_UYYVYY10_0_5X30: case MEDIA_BUS_FMT_UYYVYY12_0_5X36: case MEDIA_BUS_FMT_UYYVYY16_0_5X48: returntrue;
default: returnfalse;
}
}
staticint hdmi_bus_fmt_color_depth(unsignedint bus_format)
{ switch (bus_format) { case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_YUV8_1X24: case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYYVYY8_0_5X24: return 8;
case MEDIA_BUS_FMT_RGB101010_1X30: case MEDIA_BUS_FMT_YUV10_1X30: case MEDIA_BUS_FMT_UYVY10_1X20: case MEDIA_BUS_FMT_UYYVYY10_0_5X30: return 10;
case MEDIA_BUS_FMT_RGB121212_1X36: case MEDIA_BUS_FMT_YUV12_1X36: case MEDIA_BUS_FMT_UYVY12_1X24: case MEDIA_BUS_FMT_UYYVYY12_0_5X36: return 12;
case MEDIA_BUS_FMT_RGB161616_1X48: case MEDIA_BUS_FMT_YUV16_1X48: case MEDIA_BUS_FMT_UYYVYY16_0_5X48: return 16;
default: return 0;
}
}
/* * this submodule is responsible for the video data synchronization. * for example, for RGB 4:4:4 input, the data map is defined as * pin{47~40} <==> R[7:0] * pin{31~24} <==> G[7:0] * pin{15~8} <==> B[7:0]
*/ staticvoid hdmi_video_sample(struct dw_hdmi *hdmi)
{ int color_format = 0;
u8 val;
switch (hdmi->hdmi_data.enc_in_bus_format) { case MEDIA_BUS_FMT_RGB888_1X24:
color_format = 0x01; break; case MEDIA_BUS_FMT_RGB101010_1X30:
color_format = 0x03; break; case MEDIA_BUS_FMT_RGB121212_1X36:
color_format = 0x05; break; case MEDIA_BUS_FMT_RGB161616_1X48:
color_format = 0x07; break;
case MEDIA_BUS_FMT_YUV8_1X24: case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
color_format = 0x09; break; case MEDIA_BUS_FMT_YUV10_1X30: case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
color_format = 0x0B; break; case MEDIA_BUS_FMT_YUV12_1X36: case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
color_format = 0x0D; break; case MEDIA_BUS_FMT_YUV16_1X48: case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
color_format = 0x0F; break;
case MEDIA_BUS_FMT_UYVY8_1X16:
color_format = 0x16; break; case MEDIA_BUS_FMT_UYVY10_1X20:
color_format = 0x14; break; case MEDIA_BUS_FMT_UYVY12_1X24:
color_format = 0x12; break;
/* * HDMI video packetizer is used to packetize the data. * for example, if input is YCC422 mode or repeater is used, * data should be repacked this module can be bypassed.
*/ staticvoid hdmi_video_packetize(struct dw_hdmi *hdmi)
{ unsignedint color_depth = 0; unsignedint remap_size = HDMI_VP_REMAP_YCC422_16bit; unsignedint output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
u8 clear_gcp_auto = 0;
if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) ||
hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) { switch (hdmi_bus_fmt_color_depth(
hdmi->hdmi_data.enc_out_bus_format)) { case 8:
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
clear_gcp_auto = 1; break; case 10:
color_depth = 5; break; case 12:
color_depth = 6; break; case 16:
color_depth = 7; break; default:
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
}
} elseif (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { switch (hdmi_bus_fmt_color_depth(
hdmi->hdmi_data.enc_out_bus_format)) { case 0: case 8:
remap_size = HDMI_VP_REMAP_YCC422_16bit;
clear_gcp_auto = 1; break; case 10:
remap_size = HDMI_VP_REMAP_YCC422_20bit; break; case 12:
remap_size = HDMI_VP_REMAP_YCC422_24bit; break;
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
((hdmi_data->pix_repet_factor <<
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
/* HDMI1.4b specification section 6.5.3: * Source shall only send GCPs with non-zero CD to sinks * that indicate support for Deep Color. * GCP only transmit CD and do not handle AVMUTE, PP norDefault_Phase (yet). * Disable Auto GCP when 24-bit color for sinks that not support Deep Color.
*/
val = hdmi_readb(hdmi, HDMI_FC_DATAUTO3); if (clear_gcp_auto == 1)
val &= ~HDMI_FC_DATAUTO3_GCP_AUTO; else
val |= HDMI_FC_DATAUTO3_GCP_AUTO;
hdmi_writeb(hdmi, val, HDMI_FC_DATAUTO3);
/* Filter out invalid setups to avoid configuring SCDC and scrambling */ staticbool dw_hdmi_support_scdc(struct dw_hdmi *hdmi, conststruct drm_display_info *display)
{ /* Completely disable SCDC support for older controllers */ if (hdmi->version < 0x200a) returnfalse;
/* Disable if no DDC bus */ if (!hdmi->ddc) returnfalse;
/* Disable if SCDC is not supported, or if an HF-VSDB block is absent */ if (!display->hdmi.scdc.supported ||
!display->hdmi.scdc.scrambling.supported) returnfalse;
/* * Disable if display only support low TMDS rates and scrambling * for low rates is not supported either
*/ if (!display->hdmi.scdc.scrambling.low_rates &&
display->max_tmds_clock <= 340000) returnfalse;
returntrue;
}
/* * HDMI2.0 Specifies the following procedure for High TMDS Bit Rates: * - The Source shall suspend transmission of the TMDS clock and data * - The Source shall write to the TMDS_Bit_Clock_Ratio bit to change it * from a 0 to a 1 or from a 1 to a 0 * - The Source shall allow a minimum of 1 ms and a maximum of 100 ms from * the time the TMDS_Bit_Clock_Ratio bit is written until resuming * transmission of TMDS clock and data * * To respect the 100ms maximum delay, the dw_hdmi_set_high_tmds_clock_ratio() * helper should called right before enabling the TMDS Clock and Data in * the PHY configuration callback.
*/ void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi, conststruct drm_display_info *display)
{ unsignedlong mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */ if (dw_hdmi_support_scdc(hdmi, display)) { if (mtmdsclock > HDMI14_MAX_TMDSCLK)
drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, 1); else
drm_scdc_set_high_tmds_clock_ratio(hdmi->curr_conn, 0);
}
}
EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
void dw_hdmi_phy_gen1_reset(struct dw_hdmi *hdmi)
{ /* PHY reset. The reset signal is active low on Gen1 PHYs. */
hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
}
EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen1_reset);
void dw_hdmi_phy_gen2_reset(struct dw_hdmi *hdmi)
{ /* PHY reset. The reset signal is active high on Gen2 PHYs. */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
}
EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_reset);
/* * Wait for TX_PHY_LOCK to be deasserted to indicate that the PHY went * to low power mode.
*/ for (i = 0; i < 5; ++i) {
val = hdmi_readb(hdmi, HDMI_PHY_STAT0); if (!(val & HDMI_PHY_TX_PHY_LOCK)) break;
usleep_range(1000, 2000);
}
if (val & HDMI_PHY_TX_PHY_LOCK)
dev_warn(hdmi->dev, "PHY failed to power down\n"); else
dev_dbg(hdmi->dev, "PHY powered down in %u iterations\n", i);
/* * PHY configuration function for the DWC HDMI 3D TX PHY. Based on the available * information the DWC MHL PHY has the same register layout and is thus also * supported by this function.
*/ staticint hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, conststruct dw_hdmi_plat_data *pdata, unsignedlong mpixelclock)
{ conststruct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; conststruct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; conststruct dw_hdmi_phy_config *phy_config = pdata->phy_config;
/* TOFIX Will need 420 specific PHY configuration tables */
/* PLL/MPLL Cfg - always match on final entry */ for (; mpll_config->mpixelclock != ~0UL; mpll_config++) if (mpixelclock <= mpll_config->mpixelclock) break;
for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) if (mpixelclock <= curr_ctrl->mpixelclock) break;
for (; phy_config->mpixelclock != ~0UL; phy_config++) if (mpixelclock <= phy_config->mpixelclock) break;
/* Write to the PHY as configured by the platform */ if (pdata->configure_phy)
ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); else
ret = phy->configure(hdmi, pdata, mpixelclock); if (ret) {
dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
mpixelclock); return ret;
}
/* Wait for resuming transmission of TMDS clock and data */ if (mtmdsclock > HDMI14_MAX_TMDSCLK)
msleep(100);
return dw_hdmi_phy_power_on(hdmi);
}
staticint dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, conststruct drm_display_info *display, conststruct drm_display_mode *mode)
{ int i, ret;
/* HDMI Phy spec says to do the phy initialization sequence twice */ for (i = 0; i < 2; i++) {
dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
dw_hdmi_phy_sel_interface_control(hdmi, 0);
ret = hdmi_phy_configure(hdmi, display); if (ret) return ret;
}
/* Set up colorimetry */ if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) { switch (hdmi->hdmi_data.enc_out_encoding) { case V4L2_YCBCR_ENC_601: if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; else
frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
frame.extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; break; case V4L2_YCBCR_ENC_709: if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
frame.colorimetry = HDMI_COLORIMETRY_EXTENDED; else
frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
frame.extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; break; default: /* Carries no data */
frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
frame.extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; break;
}
} else {
frame.colorimetry = HDMI_COLORIMETRY_NONE;
frame.extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
}
/* * The Designware IP uses a different byte format from standard * AVI info frames, though generally the bits are in the correct * bytes.
*/
/* * AVI data byte 1 differences: Colorspace in bits 0,1 rather than 5,6, * scan info in bits 4,5 rather than 0,1 and active aspect present in * bit 6 rather than 4.
*/
val = (frame.scan_mode & 3) << 4 | (frame.colorspace & 3); if (frame.active_aspect & 15)
val |= HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT; if (frame.top_bar || frame.bottom_bar)
val |= HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR; if (frame.left_bar || frame.right_bar)
val |= HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR;
hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
/* AVI data byte 2 differences: none */
val = ((frame.colorimetry & 0x3) << 6) |
((frame.picture_aspect & 0x3) << 4) |
(frame.active_aspect & 0xf);
hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
/* AVI data byte 3 differences: none */
val = ((frame.extended_colorimetry & 0x7) << 4) |
((frame.quantization_range & 0x3) << 2) |
(frame.nups & 0x3); if (frame.itc)
val |= HDMI_FC_AVICONF2_IT_CONTENT_VALID;
hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
/* AVI data byte 4 differences: none */
val = frame.video_code & 0x7f;
hdmi_writeb(hdmi, val, HDMI_FC_AVIVID);
/* AVI Data Byte 5- set up input and output pixel repetition */
val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
/* * AVI data byte 5 differences: content type in 0,1 rather than 4,5, * ycc range in bits 2,3 rather than 6,7
*/
val = ((frame.ycc_quantization_range & 0x3) << 2) |
(frame.content_type & 0x3);
hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, connector,
mode); if (err < 0) /* * Going into that statement does not means vendor infoframe * fails. It just informed us that vendor infoframe is not * needed for the selected mode. Only 4k or stereoscopic 3D * mode requires vendor infoframe. So just simply return.
*/ return;
/* * When we're setting a YCbCr420 mode, we need * to adjust the horizontal timing to suit.
*/ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
hdisplay /= 2;
hblank /= 2;
h_de_hs /= 2;
hsync_len /= 2;
}
/* * When we're setting an interlaced mode, we need * to adjust the vertical timing to suit.
*/ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
vdisplay /= 2;
vblank /= 2;
v_de_vs /= 2;
vsync_len /= 2;
}
/* Scrambling Control */ if (dw_hdmi_support_scdc(hdmi, display)) { if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
hdmi_info->scdc.scrambling.low_rates) { /* * HDMI2.0 Specifies the following procedure: * After the Source Device has determined that * SCDC_Present is set (=1), the Source Device should * write the accurate Version of the Source Device * to the Source Version field in the SCDCS. * Source Devices compliant shall set the * Source Version = 1.
*/
drm_scdc_readb(hdmi->ddc, SCDC_SINK_VERSION,
&bytes);
drm_scdc_writeb(hdmi->ddc, SCDC_SOURCE_VERSION,
min_t(u8, bytes, SCDC_MIN_SOURCE_VERSION));
/* Enabled Scrambling in the Sink */
drm_scdc_set_scrambling(hdmi->curr_conn, 1);
/* * To activate the scrambler feature, you must ensure * that the quasi-static configuration bit * fc_invidconf.HDCP_keepout is set at configuration * time, before the required mc_swrstzreq.tmdsswrst_req * reset request is issued.
*/
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
HDMI_MC_SWRSTZ);
hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL);
} else {
hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
HDMI_MC_SWRSTZ);
drm_scdc_set_scrambling(hdmi->curr_conn, 0);
}
}
/* Set up horizontal active pixel width */
hdmi_writeb(hdmi, hdisplay >> 8, HDMI_FC_INHACTV1);
hdmi_writeb(hdmi, hdisplay, HDMI_FC_INHACTV0);
/* Set up vertical active lines */
hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1);
hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0);
/* Set up horizontal blanking pixel region width */
hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
/* Set up vertical blanking pixel region width */
hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
/* Set up HSYNC active edge delay width (in pixel clks) */
hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
/* Set up VSYNC active edge delay (in lines) */
hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
/* Set up HSYNC active pulse width (in pixel clks) */
hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
/* Set up VSYNC active edge delay (in lines) */
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
/* Set to fill TMDS data channels */
hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
/* Workaround to clear the overflow condition */ staticvoid dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{ unsignedint count; unsignedint i;
u8 val;
/* * Under some circumstances the Frame Composer arithmetic unit can miss * an FC register write due to being busy processing the previous one. * The issue can be worked around by issuing a TMDS software reset and * then write one of the FC registers several times. * * The number of iterations matters and depends on the HDMI TX revision * (and possibly on the platform). * 4 iterations for i.MX6Q(v1.30a) and 1 iteration for others. * i.MX6DL (v1.31a), Allwinner SoCs (v1.32a), Rockchip RK3288 SoC (v2.00a), * Amlogic Meson GX SoCs (v2.01a), RK3328/RK3399 SoCs (v2.11a) * and i.MX8MPlus (v2.13a) have been identified as needing the workaround * with a single iteration.
*/
if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
/* TOFIX: Get input encoding from plat data or fallback to none */ if (hdmi->plat_data->input_bus_encoding)
hdmi->hdmi_data.enc_in_encoding =
hdmi->plat_data->input_bus_encoding; else
hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
if (hdmi->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
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.