static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) { struct imx_hdmi *hdmi = dev_id; u8 intr_stat; u8 phy_int_pol; intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0); if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { if (phy_int_pol & HDMI_PHY_HPD) { dev_dbg(hdmi->dev, "EVENT=plugin\n"); hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); imx_hdmi_poweron(hdmi); } else { dev_dbg(hdmi->dev, "EVENT=plugout\n"); hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0); imx_hdmi_poweroff(hdmi); } drm_helper_hpd_irq_event(hdmi->connector.dev); } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); return IRQ_HANDLED; }
static void hdmi_video_csc(struct imx_hdmi *hdmi) { int color_depth = 0; int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; int decimation = 0; /* YCC422 interpolation to 444 mode */ if (is_color_space_interpolation(hdmi)) interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1; else if (is_color_space_decimation(hdmi)) decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3; if (hdmi->hdmi_data.enc_color_depth == 8) color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP; else if (hdmi->hdmi_data.enc_color_depth == 10) color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP; else if (hdmi->hdmi_data.enc_color_depth == 12) color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP; else if (hdmi->hdmi_data.enc_color_depth == 16) color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP; else return; /* Configure the CSC registers */ hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, HDMI_CSC_SCALE); imx_hdmi_update_csc_coeffs(hdmi); }
static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) { u8 de; if (hdmi->hdmi_data.video_mode.mdataenablepolarity) de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; else de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW; /* disable rx detect */ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE, HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0); hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG); hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); }
static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, unsigned int n) { /* Must be set/cleared first */ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); /* nshift factor = 0 */ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3); hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2); hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1); }
static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts) { /* Must be set/cleared first */ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); }
static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, unsigned int value) { hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); /* nshift factor = 0 */ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); }
static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) { const u16 (*csc_coeff)[3][4] = &csc_coeff_default; unsigned i; u32 csc_scale = 1; if (is_color_space_conversion(hdmi)) { if (hdmi->hdmi_data.enc_out_format == RGB) { if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) csc_coeff = &csc_coeff_rgb_out_eitu601; else csc_coeff = &csc_coeff_rgb_out_eitu709; } else if (hdmi->hdmi_data.enc_in_format == RGB) { if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) csc_coeff = &csc_coeff_rgb_in_eitu601; else csc_coeff = &csc_coeff_rgb_in_eitu709; csc_scale = 0; } } /* The CSC registers are sequential, alternating MSB then LSB */ for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) { u16 coeff_a = (*csc_coeff)[0][i]; u16 coeff_b = (*csc_coeff)[1][i]; u16 coeff_c = (*csc_coeff)[2][i]; hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2); hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2); hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); } hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK, HDMI_CSC_SCALE); }
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); }
/* * 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. */ static void hdmi_video_packetize(struct imx_hdmi *hdmi) { unsigned int color_depth = 0; unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; u8 val, vp_conf; if (hdmi_data->enc_out_format == RGB || hdmi_data->enc_out_format == YCBCR444) { if (!hdmi_data->enc_color_depth) output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; else if (hdmi_data->enc_color_depth == 8) { color_depth = 4; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; } else if (hdmi_data->enc_color_depth == 10) color_depth = 5; else if (hdmi_data->enc_color_depth == 12) color_depth = 6; else if (hdmi_data->enc_color_depth == 16) color_depth = 7; else return; } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { if (!hdmi_data->enc_color_depth || hdmi_data->enc_color_depth == 8) remap_size = HDMI_VP_REMAP_YCC422_16bit; else if (hdmi_data->enc_color_depth == 10) remap_size = HDMI_VP_REMAP_YCC422_20bit; else if (hdmi_data->enc_color_depth == 12) remap_size = HDMI_VP_REMAP_YCC422_24bit; else return; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; } else return; /* 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); hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE, HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF); /* Data from pixel repeater block */ if (hdmi_data->pix_repet_factor > 1) { vp_conf = HDMI_VP_CONF_PR_EN_ENABLE | HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; } else { /* data from packetizer block */ vp_conf = HDMI_VP_CONF_PR_EN_DISABLE | HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; } hdmi_modb(hdmi, vp_conf, HDMI_VP_CONF_PR_EN_MASK | HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF); hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF); hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP); if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | HDMI_VP_CONF_PP_EN_ENABLE | HDMI_VP_CONF_YCC422_EN_DISABLE; } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | HDMI_VP_CONF_PP_EN_DISABLE | HDMI_VP_CONF_YCC422_EN_ENABLE; } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE | HDMI_VP_CONF_PP_EN_DISABLE | HDMI_VP_CONF_YCC422_EN_DISABLE; } else { return; } hdmi_modb(hdmi, vp_conf, HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK | HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF); hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE, HDMI_VP_STUFF_PP_STUFFING_MASK | HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF); hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK, HDMI_VP_CONF); }
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, u8 shift, u8 mask) { hdmi_modb(hdmi, data << shift, mask, reg); }
static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) { hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); }
static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi, unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); }
static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi, unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); }