MLK-18267-4: hdmi rx: hdmi rx driver for imx8qm
authorSandor Yu <Sandor.yu@nxp.com>
Thu, 10 May 2018 03:25:40 +0000 (11:25 +0800)
committerSandor Yu <Sandor.yu@nxp.com>
Fri, 19 Apr 2019 02:40:50 +0000 (10:40 +0800)
Enable hdmi rx driver for imx8qm.
Driver implement with V4L2 architecture.
RGB32 and YUV444 are verified.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
15 files changed:
drivers/media/platform/imx8/Kconfig
drivers/media/platform/imx8/Makefile
drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c [new file with mode: 0644]
drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h [new file with mode: 0644]
drivers/media/platform/imx8/hdmi/Kconfig [new file with mode: 0644]
drivers/media/platform/imx8/hdmi/Makefile [new file with mode: 0644]
drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c [new file with mode: 0644]
drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c [new file with mode: 0644]
drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h [new file with mode: 0644]
drivers/media/platform/imx8/mxc-isi-cap.c
drivers/media/platform/imx8/mxc-isi-core.c
drivers/media/platform/imx8/mxc-isi-hw.c
drivers/media/platform/imx8/mxc-isi-hw.h
drivers/media/platform/imx8/mxc-media-dev.c
drivers/media/platform/imx8/mxc-media-dev.h

index dcef1e2..b8c4a98 100644 (file)
@@ -49,6 +49,8 @@ config IMX8_JPEG
        select VIDEOBUF2_DMA_CONTIG
        default y
 
+source "drivers/media/platform/imx8/hdmi/Kconfig"
+
 endmenu
 endif #VIDEO_MX8_CAPTURE
 
index b9f3698..5dc1802 100644 (file)
@@ -11,3 +11,4 @@ max9286_gmsl-objs := max9286.o
 obj-$(CONFIG_GMSL_MAX9286) += max9286_gmsl.o
 obj-$(CONFIG_IMX8_MEDIA_DEVICE) += mxc-media-dev.o
 obj-$(CONFIG_IMX8_JPEG) += mxc-jpeg-hw.o mxc-jpeg.o
+obj-$(CONFIG_IMX8_HDMI_RX) += hdmi/
diff --git a/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c b/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c
new file mode 100644 (file)
index 0000000..7743412
--- /dev/null
@@ -0,0 +1,1223 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_hdmirx.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_AFE_ss28fdsoi_hdmirx.h"
+
+static inline void write16(state_struct *state, u32 addr, u16 val)
+{
+       Afe_write(state, addr, val);
+}
+
+static inline void multi_write16(state_struct *state, u32 addr,
+                                u16 val)
+{
+       u16 addr_tmp = addr;
+
+       if ((addr & 0x1E00) == LINK_ID << 9) {
+               addr_tmp |= LINK_WRITE;
+               Afe_write(state, addr_tmp, val);
+       } else {
+               Afe_write(state, addr_tmp, val);
+       }
+}
+
+static inline u16 read16(state_struct *state, u32 addr)
+{
+       u16 reg_val;
+
+       reg_val = Afe_read(state, addr);
+       return reg_val;
+}
+
+u16 inside_i(u16 value, u16 left_sharp_corner,
+                 u16 right_sharp_corner)
+{
+       if (value < left_sharp_corner)
+               return 0;
+       if (value > right_sharp_corner)
+               return 0;
+       return 1;
+}
+
+u16 inside_f(u32 value, u32 left_sharp_corner, u32 right_sharp_corner)
+{
+       if (value < left_sharp_corner)
+               return 0;
+       if (value > right_sharp_corner)
+               return 0;
+       return 1;
+}
+
+void arc_config(state_struct *state)
+{
+       u16 reg_val;
+
+       write16(state, TX_DIG_CTRL_REG_2_ADDR, 0x0024);
+
+       reg_val = read16(state, TX_ANA_CTRL_REG_1_ADDR);
+       reg_val |= 0x2000;
+       write16(state, TX_ANA_CTRL_REG_1_ADDR, reg_val);
+
+       write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x0100);
+       write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x0300);
+       write16(state, TX_ANA_CTRL_REG_3_ADDR, 0x0000);
+       write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2008);
+       write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2018);
+       write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2098);
+       write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x030C);
+       write16(state, TX_ANA_CTRL_REG_5_ADDR, 0x0000);
+       write16(state, TX_ANA_CTRL_REG_4_ADDR, 0x4001);
+       write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2198);
+       write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x030D);
+       write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x030F);
+}
+
+void pma_config(state_struct *state)
+{
+       int i;
+       u16 reg_val = 0;
+       pr_info("pma_config() Configuring PMA\n");
+
+       write16(state, CMN_CMSMT_REF_CLK_TMR_VALUE_ADDR, 0x0801);
+       write16(state, RX_CLK_SLICER_CAL_INIT_TMR_ADDR, 0x00FF);
+       write16(state, CMN_RXCAL_INIT_TMR_ADDR, 0x003F);
+       write16(state, CMN_DIAG_PLL0_TEST_MODE_ADDR, 0x0022);
+       multi_write16(state, XCVR_PSM_CAL_TMR_ADDR, 0x0160);
+
+       /* Drives the rx_differential_invert PMA input for the associated lane */
+       for (i = 0; i < 3; i++) {
+               reg_val = 0x0c61;
+               write16(state, (PHY_PMA_XCVR_CTRL_ADDR | (i << 6)), reg_val);
+       }
+}
+
+void pre_data_rate_change(state_struct *state)
+{
+       u16 reg_val;
+
+       pr_info("pre_data_rate_change() Set the A3 power mode\n");
+       reg_val = read16(state, PHY_MODE_CTL_ADDR);
+       reg_val &= 0xFFF0;
+       reg_val |= 0x0008;
+       write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+       msleep(20);
+
+       /* Disable PLL */
+       pr_info("pre_data_rate_change() Disable PLL0\n");
+       reg_val = read16(state, PHY_MODE_CTL_ADDR);
+       reg_val &= 0xEFFF;
+       write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+       msleep(20);
+}
+
+u8 pma_cmn_ready(state_struct *state)
+{
+       u32 i;
+
+       for (i = 0; i < 20; i++) {
+               if (read16(state, PHY_PMA_CMN_CTRL1_ADDR) & (1 << 0))
+                       break;
+               msleep(10);
+       }
+       if (i == 20)
+               return -1;
+       return 0;
+}
+
+u8 pma_rx_clk_signal_detect(state_struct *state)
+{
+       u32 i;
+
+       for (i = 0; i < 20; i++) {
+               if (read16(state, PHY_MODE_CTL_ADDR) & (1 << 8))
+                       break;
+               msleep(10);
+       }
+       if (i == 20)
+               return -1;
+       return 0;
+}
+
+u32 pma_rx_clk_freq_detect(state_struct *state)
+{
+       u16 reg_val;
+       u32 rx_clk_freq;
+       u32 i;
+
+       pr_info("pma_rx_clk_freq_detect() Starting Rx clock frequency detection...\n");
+
+       /* Start frequency detection: */
+       write16(state, CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR, 0x8000);
+
+       /* Wait for pma_rx_clk_freq_detect_done */
+       for (i = 0; i < 20; i++) {
+               if (read16(state, CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR) & (1 << 14))
+                       break;
+               msleep(10);
+       }
+       if (i == 20)
+               return -1;
+
+       /* Read the measured value */
+       reg_val = read16(state, CMN_CMSMT_TEST_CLK_CNT_VALUE_ADDR);
+
+       /* Calculate TMDS clock frequency */
+       rx_clk_freq = reg_val * REFCLK_FREQ_KHZ / 2048;
+
+       /* Turn off frequency measurement: */
+       write16(state, CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR, 0x0000);
+       pr_info("pma_rx_clk_freq_detect() Starting Rx clock frequency detection... DONE (TMDS clock freq: %d kHz)\n",
+            rx_clk_freq);
+       return rx_clk_freq;
+}
+
+void pma_pll_config(state_struct *state,
+                   u32 rx_clk_freq,
+                   clk_ratio_t clk_ratio,
+                   tmds_bit_clock_ratio_t tmds_bit_clk_ratio,
+                   unsigned char data_rate_change)
+{
+       int i, loop;
+       u16 reg_val;
+       u64 vco_freq_khz;
+
+       reg_field_t cmnda_pll0_ip_div;
+       reg_field_t cmnda_pll0_hs_sym_div_sel;
+       reg_field_t cmn_pll0_fb_div_high_ovrd_en;
+       reg_field_t cmnda_pll0_fb_div_high_out;
+       reg_field_t cmn_pll0_fb_div_low_ovrd_en;
+       reg_field_t cmnda_pll0_fb_div_low_out;
+       reg_field_t cmn_pll_clk_osr;
+       reg_field_t cmn_pll_clk_div2_ratio;
+       reg_field_t cmn_pll_clk_div2_sel;
+       reg_field_t rx_diag_smplr_osr;
+       reg_field_t rx_psc_a0;
+       reg_field_t rx_ree_pergcsm_eqenm_ph1;
+       reg_field_t rx_ree_pergcsm_eqenm_ph2;
+       reg_field_t vga_gain_accum_override_en;
+       reg_field_t vga_gain_accum_override;
+       reg_field_t vga_gain_tgt_adj_override_en;
+       reg_field_t vga_gain_tgt_adj_override;
+       reg_field_t ree_gen_sm_en_usb;
+       reg_field_t ree_gen_sm_en_periodic;
+       reg_field_t ana_en_epath_gen_ctrl_sm_usb;
+       reg_field_t ana_en_epath_gen_ctrl_sm_periodic;
+       reg_field_t rxda_eq_range_sel;
+       reg_field_t rxda_vga_sa_range_sel;
+       reg_field_t vco_ring_select;
+       reg_field_t cmnda_pll0_v2i_prog;
+       reg_field_t cmnda_pll0_coarse_prog;
+       reg_field_t cmnda_pll0_cp_gain;
+       reg_field_t cmnda_pll0_const_ndac_cntrl;
+       reg_field_t cmnda_pll0_const_pmos_cntrl;
+       reg_field_t cmnda_pll0_ptat_ndac_cntrl;
+       reg_field_t rxda_pi_iq_bias_trim;
+       reg_field_t rxda_pi_iq_pload_bias_trim;
+       reg_field_t rxda_pi_iq_pload_trim;
+       reg_field_t rxda_pi_e_bias_trim;
+       reg_field_t rxda_pi_e_pload_bias_trim;
+       reg_field_t rxda_pi_e_pload_trim;
+       reg_field_t rxda_pi_range_sel;
+       reg_field_t rxda_pi_cal_cm_trim;
+       reg_field_t xcvr_pll_en;
+       reg_field_t xcvr_link_reset_n;
+       reg_field_t xcvr_power_state_req;
+       reg_field_t xcvr_power_state_ack;
+       reg_field_t iso_pma_cmn_pll0_clk_datart1_div;
+       reg_field_t iso_pma_cmn_pll0_clk_datart0_div;
+       reg_field_t iso_pma_cmn_pll0_clk_en;
+
+       /* Set fields' labels */
+       cmnda_pll0_ip_div.label = "cmnda_pll0_ip_div";
+       cmnda_pll0_hs_sym_div_sel.label = "cmnda_pll0_hs_sym_div_sel";
+       cmn_pll0_fb_div_high_ovrd_en.label = "cmn_pll0_fb_div_high_ovrd_en";
+       cmnda_pll0_fb_div_high_out.label = "cmnda_pll0_fb_div_high_out";
+       cmn_pll0_fb_div_low_ovrd_en.label = "cmn_pll0_fb_div_low_ovrd_en";
+       cmnda_pll0_fb_div_low_out.label = "cmnda_pll0_fb_div_low_out";
+       cmn_pll_clk_osr.label = "cmn_pll_clk_osr";
+       cmn_pll_clk_div2_ratio.label = "cmn_pll_clk_div2_ratio";
+       cmn_pll_clk_div2_sel.label = "cmn_pll_clk_div2_sel";
+       rx_diag_smplr_osr.label = "rx_diag_smplr_osr";
+       rx_psc_a0.label = "rx_psc_a0";
+       rx_ree_pergcsm_eqenm_ph1.label = "rx_ree_pergcsm_eqenm_ph1";
+       rx_ree_pergcsm_eqenm_ph2.label = "rx_ree_pergcsm_eqenm_ph2";
+       vga_gain_accum_override_en.label = "vga_gain_accum_override_en";
+       vga_gain_accum_override.label = "vga_gain_accum_override";
+       vga_gain_tgt_adj_override_en.label = "vga_gain_tgt_adj_override_en";
+       vga_gain_tgt_adj_override.label = "vga_gain_tgt_adj_override";
+       ree_gen_sm_en_usb.label = "ree_gen_sm_en_usb";
+       ree_gen_sm_en_periodic.label = "ree_gen_sm_en_periodic";
+       ana_en_epath_gen_ctrl_sm_usb.label = "ana_en_epath_gen_ctrl_sm_usb";
+       ana_en_epath_gen_ctrl_sm_periodic.label =
+           "ana_en_epath_gen_ctrl_sm_periodic";
+       rxda_eq_range_sel.label = "rxda_eq_range_sel";
+       rxda_vga_sa_range_sel.label = "rxda_vga_sa_range_sel";
+       vco_ring_select.label = "vco_ring_select";
+       cmnda_pll0_v2i_prog.label = "cmnda_pll0_v2i_prog";
+       cmnda_pll0_coarse_prog.label = "cmnda_pll0_coarse_prog";
+       cmnda_pll0_cp_gain.label = "cmnda_pll0_cp_gain";
+       cmnda_pll0_const_ndac_cntrl.label = "cmnda_pll0_const_ndac_cntrl";
+       cmnda_pll0_const_pmos_cntrl.label = "cmnda_pll0_const_pmos_cntrl";
+       cmnda_pll0_ptat_ndac_cntrl.label = "cmnda_pll0_ptat_ndac_cntrl";
+       rxda_pi_iq_bias_trim.label = "rxda_pi_iq_bias_trim";
+       rxda_pi_iq_pload_bias_trim.label = "rxda_pi_iq_pload_bias_trim";
+       rxda_pi_iq_pload_trim.label = "rxda_pi_iq_pload_trim";
+       rxda_pi_e_bias_trim.label = "rxda_pi_e_bias_trim";
+       rxda_pi_e_pload_bias_trim.label = "rxda_pi_e_pload_bias_trim";
+       rxda_pi_e_pload_trim.label = "rxda_pi_e_pload_trim";
+       rxda_pi_range_sel.label = "rxda_pi_range_sel";
+       rxda_pi_cal_cm_trim.label = "rxda_pi_cal_cm_trim";
+       xcvr_pll_en.label = "xcvr_pll_en";
+       xcvr_link_reset_n.label = "xcvr_link_reset_n";
+       xcvr_power_state_req.label = "xcvr_power_state_req";
+       xcvr_power_state_ack.label = "xcvr_power_state_ack";
+       iso_pma_cmn_pll0_clk_datart1_div.label = "iso_pma_cmn_pll0_clk_datart1_div";
+       iso_pma_cmn_pll0_clk_datart0_div.label = "iso_pma_cmn_pll0_clk_datart0_div";
+       iso_pma_cmn_pll0_clk_en.label = "iso_pma_cmn_pll0_clk_en";
+
+       /* Set field position in a target register */
+       cmnda_pll0_ip_div.msb = 7;
+       cmnda_pll0_ip_div.lsb = 0;
+       cmnda_pll0_hs_sym_div_sel.msb = 9;
+       cmnda_pll0_hs_sym_div_sel.lsb = 8;
+       cmn_pll0_fb_div_high_ovrd_en.msb = 15;
+       cmn_pll0_fb_div_high_ovrd_en.lsb = 15;
+       cmnda_pll0_fb_div_high_out.msb = 9;
+       cmnda_pll0_fb_div_high_out.lsb = 0;
+       cmn_pll0_fb_div_low_ovrd_en.msb = 15;
+       cmn_pll0_fb_div_low_ovrd_en.lsb = 15;
+       cmnda_pll0_fb_div_low_out.msb = 9;
+       cmnda_pll0_fb_div_low_out.lsb = 0;
+       cmn_pll_clk_osr.msb = 2;
+       cmn_pll_clk_osr.lsb = 0;
+       cmn_pll_clk_div2_ratio.msb = 6;
+       cmn_pll_clk_div2_ratio.lsb = 4;
+       cmn_pll_clk_div2_sel.msb = 9;
+       cmn_pll_clk_div2_sel.lsb = 8;
+       rx_diag_smplr_osr.msb = 2;
+       rx_diag_smplr_osr.lsb = 0;
+       rx_psc_a0.msb = 15;
+       rx_psc_a0.lsb = 0;
+       rx_ree_pergcsm_eqenm_ph1.msb = 15;
+       rx_ree_pergcsm_eqenm_ph1.lsb = 0;
+       rx_ree_pergcsm_eqenm_ph2.msb = 15;
+       rx_ree_pergcsm_eqenm_ph2.lsb = 0;
+       vga_gain_accum_override_en.msb = 7;
+       vga_gain_accum_override_en.lsb = 7;
+       vga_gain_accum_override.msb = 4;
+       vga_gain_accum_override.lsb = 0;
+       vga_gain_tgt_adj_override_en.msb = 15;
+       vga_gain_tgt_adj_override_en.lsb = 15;
+       vga_gain_tgt_adj_override.msb = 12;
+       vga_gain_tgt_adj_override.lsb = 8;
+       ree_gen_sm_en_usb.msb = 3;
+       ree_gen_sm_en_usb.lsb = 0;
+       ree_gen_sm_en_periodic.msb = 11;
+       ree_gen_sm_en_periodic.lsb = 8;
+       ana_en_epath_gen_ctrl_sm_usb.msb = 7;
+       ana_en_epath_gen_ctrl_sm_usb.lsb = 4;
+       ana_en_epath_gen_ctrl_sm_periodic.msb = 15;
+       ana_en_epath_gen_ctrl_sm_periodic.lsb = 12;
+       rxda_eq_range_sel.msb = 2;
+       rxda_eq_range_sel.lsb = 0;
+       rxda_vga_sa_range_sel.msb = 6;
+       rxda_vga_sa_range_sel.lsb = 4;
+       vco_ring_select.msb = 12;
+       vco_ring_select.lsb = 12;
+       cmnda_pll0_v2i_prog.msb = 5;
+       cmnda_pll0_v2i_prog.lsb = 4;
+       cmnda_pll0_coarse_prog.msb = 2;
+       cmnda_pll0_coarse_prog.lsb = 0;
+       cmnda_pll0_cp_gain.msb = 8;
+       cmnda_pll0_cp_gain.lsb = 0;
+       cmnda_pll0_const_ndac_cntrl.msb = 11;
+       cmnda_pll0_const_ndac_cntrl.lsb = 8;
+       cmnda_pll0_const_pmos_cntrl.msb = 7;
+       cmnda_pll0_const_pmos_cntrl.lsb = 0;
+       cmnda_pll0_ptat_ndac_cntrl.msb = 5;
+       cmnda_pll0_ptat_ndac_cntrl.lsb = 0;
+       rxda_pi_iq_bias_trim.msb = 14;
+       rxda_pi_iq_bias_trim.lsb = 12;
+       rxda_pi_iq_pload_bias_trim.msb = 10;
+       rxda_pi_iq_pload_bias_trim.lsb = 8;
+       rxda_pi_iq_pload_trim.msb = 7;
+       rxda_pi_iq_pload_trim.lsb = 0;
+       rxda_pi_e_bias_trim.msb = 14;
+       rxda_pi_e_bias_trim.lsb = 12;
+       rxda_pi_e_pload_bias_trim.msb = 10;
+       rxda_pi_e_pload_bias_trim.lsb = 8;
+       rxda_pi_e_pload_trim.msb = 7;
+       rxda_pi_e_pload_trim.lsb = 0;
+       rxda_pi_range_sel.msb = 11;
+       rxda_pi_range_sel.lsb = 8;
+       rxda_pi_cal_cm_trim.msb = 7;
+       rxda_pi_cal_cm_trim.lsb = 0;
+       xcvr_pll_en.msb = 12;
+       xcvr_pll_en.lsb = 12;
+       xcvr_link_reset_n.msb = 13;
+       xcvr_link_reset_n.lsb = 13;
+       xcvr_power_state_req.msb = 3;
+       xcvr_power_state_req.lsb = 0;
+       xcvr_power_state_ack.msb = 7;
+       xcvr_power_state_ack.lsb = 4;
+       iso_pma_cmn_pll0_clk_datart1_div.msb = 14;
+       iso_pma_cmn_pll0_clk_datart1_div.lsb = 11;
+       iso_pma_cmn_pll0_clk_datart0_div.msb = 10;
+       iso_pma_cmn_pll0_clk_datart0_div.lsb = 7;
+       iso_pma_cmn_pll0_clk_en.msb = 5;
+       iso_pma_cmn_pll0_clk_en.lsb = 5;
+
+       pr_info("pma_pll_config() Configuring PLL0 ...\n");
+
+       if (tmds_bit_clk_ratio == TMDS_BIT_CLOCK_RATIO_1_10) {
+               if (inside_f(rx_clk_freq, 18750, 37500)) {
+                       set_field_value(&cmnda_pll0_ip_div, 0x1);
+                       set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+                       set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_high_out, 0x1E);
+                       set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_low_out, 0x7E);
+                       set_field_value(&rx_diag_smplr_osr, 0x4);
+                       set_field_value(&rx_psc_a0, 0x8BF5);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+                       set_field_value(&vga_gain_accum_override_en, 0x1);
+                       set_field_value(&vga_gain_accum_override, 0x1A);
+                       set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+                       set_field_value(&vga_gain_tgt_adj_override, 0x00);
+                       set_field_value(&ree_gen_sm_en_usb, 0x1);
+                       set_field_value(&ree_gen_sm_en_periodic, 0x1);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+                                       0x0);
+                       set_field_value(&rxda_eq_range_sel, 0x1);
+                       set_field_value(&rxda_vga_sa_range_sel, 0x2);
+                       switch (clk_ratio) {
+                       case CLK_RATIO_1_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+                               break;
+                       case CLK_RATIO_5_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_2_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+                               break;
+                       case CLK_RATIO_1_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_5_8:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       }
+               } else if (inside_f(rx_clk_freq, 37500, 75000)) {
+                       set_field_value(&cmnda_pll0_ip_div, 0x1);
+                       set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+                       set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_high_out, 0x0E);
+                       set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_low_out, 0x3E);
+                       set_field_value(&rx_diag_smplr_osr, 0x3);
+                       set_field_value(&rx_psc_a0, 0x8BF5);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+                       set_field_value(&vga_gain_accum_override_en, 0x1);
+                       set_field_value(&vga_gain_accum_override, 0x1A);
+                       set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+                       set_field_value(&vga_gain_tgt_adj_override, 0x00);
+                       set_field_value(&ree_gen_sm_en_usb, 0x1);
+                       set_field_value(&ree_gen_sm_en_periodic, 0x1);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+                                       0x0);
+                       set_field_value(&rxda_eq_range_sel, 0x1);
+                       set_field_value(&rxda_vga_sa_range_sel, 0x2);
+                       switch (clk_ratio) {
+                       case CLK_RATIO_1_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+                               break;
+                       case CLK_RATIO_5_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_2_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+                               break;
+                       case CLK_RATIO_1_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_5_8:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x3);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       }
+               } else if (inside_f(rx_clk_freq, 75000, 150000)) {
+                       set_field_value(&cmnda_pll0_ip_div, 0x1);
+                       set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+                       set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+                       set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_low_out, 0x1A);
+                       set_field_value(&rx_diag_smplr_osr, 0x2);
+                       set_field_value(&rx_psc_a0, 0x8BF5);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+                       set_field_value(&vga_gain_accum_override_en, 0x1);
+                       set_field_value(&vga_gain_accum_override, 0x1A);
+                       set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+                       set_field_value(&vga_gain_tgt_adj_override, 0x00);
+                       set_field_value(&ree_gen_sm_en_usb, 0x1);
+                       set_field_value(&ree_gen_sm_en_periodic, 0x1);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+                                       0x0);
+                       set_field_value(&rxda_eq_range_sel, 0x1);
+                       set_field_value(&rxda_vga_sa_range_sel, 0x2);
+                       switch (clk_ratio) {
+                       case CLK_RATIO_1_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+                               break;
+                       case CLK_RATIO_5_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_2_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+                               break;
+                       case CLK_RATIO_1_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_5_8:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       }
+               } else if (inside_f(rx_clk_freq, 150000, 300000)) {
+                       set_field_value(&cmnda_pll0_ip_div, 0x2);
+                       set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+                       set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+                       set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_low_out, 0x1A);
+                       set_field_value(&rx_diag_smplr_osr, 0x1);
+                       set_field_value(&rx_psc_a0, 0x8BF5);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+                       set_field_value(&vga_gain_accum_override_en, 0x1);
+                       set_field_value(&vga_gain_accum_override, 0x1A);
+                       set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+                       set_field_value(&vga_gain_tgt_adj_override, 0x00);
+                       set_field_value(&ree_gen_sm_en_usb, 0x1);
+                       set_field_value(&ree_gen_sm_en_periodic, 0x1);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+                                       0x0);
+                       set_field_value(&rxda_eq_range_sel, 0x2);
+                       set_field_value(&rxda_vga_sa_range_sel, 0x3);
+                       switch (clk_ratio) {
+                       case CLK_RATIO_1_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+                               break;
+                       case CLK_RATIO_5_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_2_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+                               break;
+                       case CLK_RATIO_1_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_5_8:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       }
+               } else if (inside_f(rx_clk_freq, 300000, 340000)) {
+                       set_field_value(&cmnda_pll0_ip_div, 0x3);
+                       set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+                       set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+                       set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_low_out, 0x10);
+                       set_field_value(&rx_diag_smplr_osr, 0x0);
+                       set_field_value(&rx_psc_a0, 0x8BF5);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+                       set_field_value(&vga_gain_accum_override_en, 0x1);
+                       set_field_value(&vga_gain_accum_override, 0x1A);
+                       set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+                       set_field_value(&vga_gain_tgt_adj_override, 0x00);
+                       set_field_value(&ree_gen_sm_en_usb, 0x1);
+                       set_field_value(&ree_gen_sm_en_periodic, 0x1);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+                                       0x0);
+                       set_field_value(&rxda_eq_range_sel, 0x3);
+                       set_field_value(&rxda_vga_sa_range_sel, 0x3);
+                       switch (clk_ratio) {
+                       case CLK_RATIO_1_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+                               break;
+                       case CLK_RATIO_5_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_2_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+                               break;
+                       case CLK_RATIO_1_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_5_8:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       }
+               } else
+                       pr_err("TMDS clock frequency (%d KHz) is out of range\n", rx_clk_freq);
+
+       } else {                /* TMDS_BIT_CLOCK_RATIO_1_40 */
+               if (inside_f(rx_clk_freq, 85000, 150000)) {
+                       set_field_value(&cmnda_pll0_ip_div, 0x1);
+                       set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+                       set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+                       set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+                       set_field_value(&cmnda_pll0_fb_div_low_out, 0x1A);
+                       set_field_value(&rx_diag_smplr_osr, 0x0);
+                       set_field_value(&rx_psc_a0, 0x8BFD);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x019F);
+                       set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x019F);
+                       set_field_value(&vga_gain_accum_override_en, 0x0);
+                       set_field_value(&vga_gain_accum_override, 0x01);
+                       set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+                       set_field_value(&vga_gain_tgt_adj_override, 0x1F);
+                       set_field_value(&ree_gen_sm_en_usb, 0x1);
+                       set_field_value(&ree_gen_sm_en_periodic, 0x1);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+                       set_field_value(&ana_en_epath_gen_ctrl_sm_periodic, 0x1);
+                       set_field_value(&rxda_eq_range_sel, 0x3);
+                       set_field_value(&rxda_vga_sa_range_sel, 0x3);
+                       switch (clk_ratio) {
+                       case CLK_RATIO_1_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+                               break;
+                       case CLK_RATIO_5_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_2_1:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+                               break;
+                       case CLK_RATIO_1_2:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_5_8:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       case CLK_RATIO_3_4:
+                               set_field_value(&cmn_pll_clk_osr, 0x00);
+                               set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+                               set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+                               break;
+                       }
+               } else
+                       pr_err("pma_pll_config() *E: TMDS clock frequency (%d kHz) is out of range\n",
+                            rx_clk_freq);
+       }
+
+       vco_freq_khz =
+           (2048 * (u64) rx_clk_freq * (1 << cmn_pll_clk_osr.value) * tmds_bit_clk_ratio) / 2047;
+
+       pr_info("VCO frequency (refclk: %d kHz, TMDS clk: %d kHz, OSR: %0d, tmds_bit_clk_ratio: %d) equals %llu kHz\n",
+            REFCLK_FREQ_KHZ, rx_clk_freq, 1 << cmn_pll_clk_osr.value,
+            tmds_bit_clk_ratio, vco_freq_khz);
+
+       if (inside_f(vco_freq_khz, 3000000, 3400000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x0);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x0);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x3);
+               switch (cmnda_pll0_fb_div_low_out.value) {
+               case 0x7E:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x78);
+                       break;
+               case 0x3E:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x78);
+                       break;
+               case 0x10:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x58);
+                       break;
+               default:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x78);
+               }
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+       } else if (inside_f(vco_freq_khz, 3400000, 3687000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               switch (cmnda_pll0_fb_div_low_out.value) {
+               case 0x7E:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x68);
+                       break;
+               case 0x3E:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x68);
+                       break;
+               case 0x10:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x59);
+                       break;
+               default:
+                       set_field_value(&cmnda_pll0_cp_gain, 0x68);
+               }
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+       } else if (inside_f(vco_freq_khz, 3687000, 3999000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               set_field_value(&cmnda_pll0_cp_gain, 0x64);
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+       } else if (inside_f(vco_freq_khz, 3999000, 4337000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               set_field_value(&cmnda_pll0_cp_gain, 0x56);
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+       } else if (inside_f(vco_freq_khz, 4337000, 4703000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               set_field_value(&cmnda_pll0_cp_gain, 0x58);
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+       } else if (inside_f(vco_freq_khz, 4703000, 5101000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               set_field_value(&cmnda_pll0_cp_gain, 0x54);
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+       } else if (inside_f(vco_freq_khz, 5101000, 5532000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               set_field_value(&cmnda_pll0_cp_gain, 0x49);
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+       } else if (inside_f(vco_freq_khz, 5532000, 6000000 - 1000)) {
+               set_field_value(&vco_ring_select, 0x1);
+               set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+               set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+               set_field_value(&cmnda_pll0_cp_gain, 0x3E);
+               set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+               set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+               set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+       } else
+               pr_err("%s VCO frequency (%llu KHz) is out of range\n", __func__, vco_freq_khz);
+
+       if (inside_f(vco_freq_khz, 3000000, 4000000)) {
+               set_field_value(&rxda_pi_iq_bias_trim, 0x5);
+               set_field_value(&rxda_pi_iq_pload_bias_trim, 0x2);
+               set_field_value(&rxda_pi_iq_pload_trim, 0x3F);
+               set_field_value(&rxda_pi_e_bias_trim, 0x5);
+               set_field_value(&rxda_pi_e_pload_bias_trim, 0x2);
+               set_field_value(&rxda_pi_e_pload_trim, 0x3F);
+               set_field_value(&rxda_pi_range_sel, 0x2);
+               set_field_value(&rxda_pi_cal_cm_trim, 0x00);
+       } else if (inside_f(vco_freq_khz, 4000000, 6000000)) {
+               set_field_value(&rxda_pi_iq_bias_trim, 0x5);
+               set_field_value(&rxda_pi_iq_pload_bias_trim, 0x4);
+               set_field_value(&rxda_pi_iq_pload_trim, 0x3F);
+               set_field_value(&rxda_pi_e_bias_trim, 0x5);
+               set_field_value(&rxda_pi_e_pload_bias_trim, 0x4);
+               set_field_value(&rxda_pi_e_pload_trim, 0x3F);
+               set_field_value(&rxda_pi_range_sel, 0x3);
+               set_field_value(&rxda_pi_cal_cm_trim, 0x00);
+       }
+       set_field_value(&xcvr_pll_en, 0x1);
+       set_field_value(&xcvr_link_reset_n, 0x0);
+       set_field_value(&xcvr_power_state_req, 0x0);
+       set_field_value(&iso_pma_cmn_pll0_clk_datart1_div, 0x1);
+       set_field_value(&iso_pma_cmn_pll0_clk_datart0_div, 0x2);
+       set_field_value(&iso_pma_cmn_pll0_clk_en, 0x1);
+
+       /*******************************************************
+       * Register setting
+       ********************************************************/
+
+       /* CMN_DIAG_PLL0_INCLK_CTRL */
+       reg_val = set_reg_value(cmnda_pll0_ip_div);
+       reg_val |= set_reg_value(cmnda_pll0_hs_sym_div_sel);
+       write16(state, CMN_DIAG_PLL0_INCLK_CTRL_ADDR, reg_val);
+
+       /* CMN_DIAG_PLL0_FBH_OVRD */
+       reg_val = set_reg_value(cmn_pll0_fb_div_high_ovrd_en);
+       reg_val |= set_reg_value(cmnda_pll0_fb_div_high_out);
+       write16(state, CMN_DIAG_PLL0_FBH_OVRD_ADDR, reg_val);
+
+       /* CMN_DIAG_PLL0_FBL_OVRD */
+       reg_val = set_reg_value(cmn_pll0_fb_div_low_ovrd_en);
+       reg_val |= set_reg_value(cmnda_pll0_fb_div_low_out);
+       write16(state, CMN_DIAG_PLL0_FBL_OVRD_ADDR, reg_val);
+
+       /* CMN_PLL0_DIV2SEL_OSR_CTRL */
+       reg_val = set_reg_value(cmn_pll_clk_osr);
+       reg_val |= set_reg_value(cmn_pll_clk_div2_ratio);
+       reg_val |= set_reg_value(cmn_pll_clk_div2_sel);
+       write16(state, CMN_PLL0_DIV2SEL_OSR_CTRL_ADDR, reg_val);
+
+       /* RX_DIAG_SMPLR_OSR */
+       reg_val = set_reg_value(rx_diag_smplr_osr);
+       multi_write16(state, RX_DIAG_SMPLR_OSR_ADDR, reg_val);
+
+       /* RX_PSC_A0 */
+       reg_val = set_reg_value(rx_psc_a0);
+       multi_write16(state, RX_PSC_A0_ADDR, reg_val);
+
+       /* RX_REE_PERGCSM_EQENM_PH1 */
+       reg_val = set_reg_value(rx_ree_pergcsm_eqenm_ph1);
+       multi_write16(state, RX_REE_PERGCSM_EQENM_PH1_ADDR, reg_val);
+
+       /* RX_REE_PERGCSM_EQENM_PH1 */
+       reg_val = set_reg_value(rx_ree_pergcsm_eqenm_ph2);
+       multi_write16(state, RX_REE_PERGCSM_EQENM_PH2_ADDR, reg_val);
+
+       /* RX_REE_VGA_GAIN_OVRD */
+       reg_val = set_reg_value(vga_gain_accum_override_en);
+       reg_val |= set_reg_value(vga_gain_accum_override);
+       reg_val |= set_reg_value(vga_gain_tgt_adj_override_en);
+       reg_val |= set_reg_value(vga_gain_tgt_adj_override);
+       multi_write16(state, RX_REE_VGA_GAIN_OVRD_ADDR, reg_val);
+
+       /* RX_REE_SMGM_CTRL1 */
+       reg_val = set_reg_value(ree_gen_sm_en_usb);
+       reg_val |= set_reg_value(ree_gen_sm_en_periodic);
+       reg_val |= set_reg_value(ana_en_epath_gen_ctrl_sm_usb);
+       reg_val |= set_reg_value(ana_en_epath_gen_ctrl_sm_periodic);
+       multi_write16(state, RX_REE_SMGM_CTRL1_ADDR, reg_val);
+
+       /* RX_DIAG_DFE_CTRL2 */
+       reg_val = set_reg_value(rxda_eq_range_sel);
+       reg_val |= set_reg_value(rxda_vga_sa_range_sel);
+       multi_write16(state, RX_DIAG_DFE_CTRL2_ADDR, reg_val);
+
+       /* CMN_PLLSM0_USER_DEF_CTRL */
+       reg_val = set_reg_value(vco_ring_select);
+       write16(state, CMN_PLLSM0_USER_DEF_CTRL_ADDR, reg_val);
+
+       /* CMN_DIAG_PLL0_V2I_TUNE */
+       reg_val = set_reg_value(cmnda_pll0_v2i_prog);
+       reg_val |= set_reg_value(cmnda_pll0_coarse_prog);
+       write16(state, CMN_DIAG_PLL0_V2I_TUNE_ADDR, reg_val);
+
+       /* CMN_DIAG_PLL0_CP_TUNE */
+       reg_val = set_reg_value(cmnda_pll0_cp_gain);
+       write16(state, CMN_DIAG_PLL0_CP_TUNE_ADDR, reg_val);
+
+       /* CMN_DIAG_PLL0_PTATIS_TUNE1 */
+       reg_val = set_reg_value(cmnda_pll0_const_ndac_cntrl);
+       reg_val |= set_reg_value(cmnda_pll0_const_pmos_cntrl);
+       write16(state, CMN_DIAG_PLL0_PTATIS_TUNE1_ADDR, reg_val);
+
+       /* CMN_DIAG_PLL0_PTATIS_TUNE2 */
+       reg_val = set_reg_value(cmnda_pll0_ptat_ndac_cntrl);
+       write16(state, CMN_DIAG_PLL0_PTATIS_TUNE2_ADDR, reg_val);
+
+       /* RX_DIAG_ILL_IQ_TRIM0 */
+       reg_val = set_reg_value(rxda_pi_iq_bias_trim);
+       reg_val |= set_reg_value(rxda_pi_iq_pload_bias_trim);
+       reg_val |= set_reg_value(rxda_pi_iq_pload_trim);
+       write16(state, RX_DIAG_ILL_IQ_TRIM0_ADDR, reg_val);
+
+       /* RX_DIAG_ILL_E_TRIM0 */
+       reg_val = set_reg_value(rxda_pi_e_bias_trim);
+       reg_val |= set_reg_value(rxda_pi_e_pload_bias_trim);
+       reg_val |= set_reg_value(rxda_pi_e_pload_trim);
+       write16(state, RX_DIAG_ILL_E_TRIM0_ADDR, reg_val);
+
+       /* RX_DIAG_ILL_IQE_TRIM2 */
+       reg_val = set_reg_value(rxda_pi_range_sel);
+       reg_val |= set_reg_value(rxda_pi_cal_cm_trim);
+       write16(state, RX_DIAG_ILL_IQE_TRIM2_ADDR, reg_val);
+
+       /* Enable PLL */
+       /* PHY_MODE_CTL */
+       reg_val = set_reg_value(xcvr_pll_en);
+       reg_val |= set_reg_value(xcvr_link_reset_n);
+       reg_val |= set_reg_value(xcvr_power_state_req);
+       write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+       /* Wait for PLL0 ready: */
+       /* PHY_PMA_CMN_CTRL2 */
+       for (i = 0; i < 20; i++) {
+               if (read16(state, PHY_PMA_CMN_CTRL2_ADDR) & (1 << 0))
+                       break;
+               msleep(10);
+       }
+       if (i == 20)
+               pr_info("pma_pll_ready failed\n");
+
+       /* Turn on output clocks: */
+       /* PHY_PMA_CMN_CTRL2 */
+       reg_val = set_reg_value(iso_pma_cmn_pll0_clk_datart1_div);
+       reg_val |= set_reg_value(iso_pma_cmn_pll0_clk_datart0_div);
+       reg_val |= set_reg_value(iso_pma_cmn_pll0_clk_en);
+       write16(state, PHY_PMA_CMN_CTRL2_ADDR, reg_val);
+
+       if (data_rate_change) {
+               pr_info("pma_pll_config() Disable Rx Eq Training\n");
+               for (i = 0; i < 3; i++) {
+                       reg_val =
+                           read16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6));
+                       reg_val &= 0xFFEF;
+                       write16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6), reg_val);
+               }
+       }
+       /* Get current power state: */
+       /* PHY_MODE_CTL */
+       reg_val = read16(state, PHY_MODE_CTL_ADDR);
+       reg_val &= 0x00F0;
+       pr_info("pma_pll_config() Current power state: 0x%02X\n", (reg_val >> 4));
+
+       /* Deassert link reset: */
+       /* PHY_MODE_CTL */
+       pr_info("pma_pll_config() Deassert link reset\n");
+       set_field_value(&xcvr_link_reset_n, 0x1);
+       reg_val |= set_reg_value(xcvr_pll_en);
+       reg_val |= set_reg_value(xcvr_link_reset_n);
+       write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+       /* Wait for xcvr_psm_ready for all the lanes */
+       loop = 0;
+       do {
+               reg_val = (1 << 13);
+               for (i = 0; i < 3; i++) {
+                       reg_val &= read16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6)) & (1 << 13);
+                       pr_info("pma_pll_config() xcvr_psm_ready(%0d): 0x%0X\n", i, reg_val >> 13);
+               }
+               msleep(10);
+               loop++;
+       } while (!reg_val && loop < 20);
+       /* Timeout */
+       if (loop == 20)
+               pr_err("pma_pll_config() Waiting for xcvr_psm_ready... failed\n");
+
+       /* Set A0 power state: */
+       /* PHY_MODE_CTL */
+       set_field_value(&xcvr_power_state_req, 0x1);
+       reg_val = set_reg_value(xcvr_pll_en);
+       reg_val |= set_reg_value(xcvr_link_reset_n);
+       reg_val |= set_reg_value(xcvr_power_state_req);
+       write16(state, PHY_MODE_CTL_ADDR, reg_val);
+       pr_info("pma_pll_config() Requested A0 power mode\n");
+
+       /* Wait for A0 power mode acknowledged: */
+       /* PHY_MODE_CTL */
+       set_field_value(&xcvr_power_state_ack, 0x1);
+
+       for (i = 0; i < 20; i++) {
+               if (((read16(state, PHY_MODE_CTL_ADDR) & 0x00F0) == set_reg_value(xcvr_power_state_ack)))
+                       break;
+               msleep(10);
+       }
+       if (i == 20)
+               pr_err("Waiting for A0 power mode acknowledged failed\n");
+
+       if (data_rate_change) {
+               pr_info("pma_pll_config() Enable Rx Eq Training\n");
+               for (i = 0; i < 3; i++) {
+                       reg_val =
+                           read16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6));
+                       reg_val |= 0x0010;
+                       write16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6),
+                               reg_val);
+               }
+       }
+}
+
+clk_ratio_t clk_ratio_detect(state_struct *state,
+                               u32 rx_clk_freq,        /* khz */
+                               u32 pxl_clk_freq,       /* khz */
+                               u8 vic,
+                               pixel_encoding_t pixel_encoding,
+                               tmds_bit_clock_ratio_t tmds_bit_clk_ratio)
+{
+       clk_ratio_t clk_ratio_detected = CLK_RATIO_1_1;
+
+       u64 tmds_freq_nominal_1_1, tmds_freq_nominal_1_1_min,
+           tmds_freq_nominal_1_1_max;
+       u64 tmds_freq_nominal_5_4, tmds_freq_nominal_5_4_min,
+           tmds_freq_nominal_5_4_max;
+       u64 tmds_freq_nominal_3_2, tmds_freq_nominal_3_2_min,
+           tmds_freq_nominal_3_2_max;
+       u64 tmds_freq_nominal_2_1, tmds_freq_nominal_2_1_min,
+           tmds_freq_nominal_2_1_max;
+       u64 tmds_freq_nominal_1_2, tmds_freq_nominal_1_2_min,
+           tmds_freq_nominal_1_2_max;
+       u64 tmds_freq_nominal_5_8, tmds_freq_nominal_5_8_min,
+           tmds_freq_nominal_5_8_max;
+       u64 tmds_freq_nominal_3_4, tmds_freq_nominal_3_4_min,
+           tmds_freq_nominal_3_4_max;
+       u64 min, max;
+
+       /* Check the TMDS/pixel clock ratio. */
+       pr_info("VIC %0d, pixel encoding: %0d, TMDS bit clock ratio: %0d and TMDS clk %d KHz\n",
+            vic, pixel_encoding, tmds_bit_clk_ratio, rx_clk_freq);
+
+       tmds_freq_nominal_1_1 = pxl_clk_freq;
+
+       min = 990;
+       max = 1010;
+
+       tmds_freq_nominal_5_4 = tmds_freq_nominal_1_1;
+       tmds_freq_nominal_3_2 = tmds_freq_nominal_1_1;
+       tmds_freq_nominal_2_1 = tmds_freq_nominal_1_1;
+       tmds_freq_nominal_1_2 = tmds_freq_nominal_1_1;
+       tmds_freq_nominal_5_8 = tmds_freq_nominal_1_1;
+       tmds_freq_nominal_3_4 = tmds_freq_nominal_1_1;
+
+       /* Exclude some of the clock ratios based on pixel excoding */
+       switch (pixel_encoding) {
+       case PIXEL_ENCODING_YUV422:
+               tmds_freq_nominal_5_4 = 0;
+               tmds_freq_nominal_3_2 = 0;
+               tmds_freq_nominal_2_1 = 0;
+               tmds_freq_nominal_1_2 = 0;
+               tmds_freq_nominal_5_8 = 0;
+               tmds_freq_nominal_3_4 = 0;
+               break;
+       case PIXEL_ENCODING_YUV420:
+               tmds_freq_nominal_5_4 = 0;
+               tmds_freq_nominal_3_2 = 0;
+               tmds_freq_nominal_2_1 = 0;
+               break;
+       default:                /* RGB/YUV444 */
+               tmds_freq_nominal_1_2 = 0;
+               tmds_freq_nominal_5_8 = 0;
+               tmds_freq_nominal_3_4 = 0;
+       }
+
+       tmds_freq_nominal_1_1_min =
+           min * tmds_freq_nominal_1_1 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 1);
+       tmds_freq_nominal_1_1_max =
+           max * tmds_freq_nominal_1_1 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 1);
+       tmds_freq_nominal_5_4_min =
+           min * tmds_freq_nominal_5_4 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 4);
+       tmds_freq_nominal_5_4_max =
+           max * tmds_freq_nominal_5_4 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 4);
+       tmds_freq_nominal_3_2_min =
+           min * tmds_freq_nominal_3_2 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 2);
+       tmds_freq_nominal_3_2_max =
+           max * tmds_freq_nominal_3_2 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 2);
+       tmds_freq_nominal_2_1_min =
+           min * tmds_freq_nominal_2_1 * 10 * 2 / (tmds_bit_clk_ratio * 1000 * 1);
+       tmds_freq_nominal_2_1_max =
+           max * tmds_freq_nominal_2_1 * 10 * 2 / (tmds_bit_clk_ratio * 1000 * 1);
+       tmds_freq_nominal_1_2_min =
+           min * tmds_freq_nominal_1_2 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 2);
+       tmds_freq_nominal_1_2_max =
+           max * tmds_freq_nominal_1_2 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 2);
+       tmds_freq_nominal_5_8_min =
+           min * tmds_freq_nominal_5_8 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 8);
+       tmds_freq_nominal_5_8_max =
+           max * tmds_freq_nominal_5_8 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 8);
+       tmds_freq_nominal_3_4_min =
+           min * tmds_freq_nominal_3_4 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 4);
+       tmds_freq_nominal_3_4_max =
+           max * tmds_freq_nominal_3_4 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 4);
+
+       if (rx_clk_freq > tmds_freq_nominal_1_1_min
+           && rx_clk_freq < tmds_freq_nominal_1_1_max) {
+               clk_ratio_detected = CLK_RATIO_1_1;
+               pr_info("Detected TMDS/pixel clock ratio of 1:1\n");
+       } else if (rx_clk_freq > tmds_freq_nominal_5_4_min
+                  && rx_clk_freq < tmds_freq_nominal_5_4_max) {
+               clk_ratio_detected = CLK_RATIO_5_4;
+               pr_info("Detected TMDS/pixel clock ratio of 5:4\n");
+       } else if (rx_clk_freq > tmds_freq_nominal_3_2_min
+                  && rx_clk_freq < tmds_freq_nominal_3_2_max) {
+               clk_ratio_detected = CLK_RATIO_3_2;
+               pr_info("Detected TMDS/pixel clock ratio of 3:2\n");
+       } else if (rx_clk_freq > tmds_freq_nominal_2_1_min
+                  && rx_clk_freq < tmds_freq_nominal_2_1_max) {
+               clk_ratio_detected = CLK_RATIO_2_1;
+               pr_info("Detected TMDS/pixel clock ratio of 2:1\n");
+       } else if (rx_clk_freq > tmds_freq_nominal_1_2_min
+                  && rx_clk_freq < tmds_freq_nominal_1_2_max) {
+               clk_ratio_detected = CLK_RATIO_1_2;
+               pr_info("Detected TMDS/pixel clock ratio of 1:2\n");
+       } else if (rx_clk_freq > tmds_freq_nominal_5_8_min
+                  && rx_clk_freq < tmds_freq_nominal_5_8_max) {
+               clk_ratio_detected = CLK_RATIO_5_8;
+               pr_info("Detected TMDS/pixel clock ratio of 5:8\n");
+       } else if (rx_clk_freq > tmds_freq_nominal_3_4_min
+                  && rx_clk_freq < tmds_freq_nominal_3_4_max) {
+               clk_ratio_detected = CLK_RATIO_3_4;
+               pr_info("Detected TMDS/pixel clock ratio of 3:4\n");
+       } else {
+               pr_err("Failed to detected TMDS/pixel clock ratio\n");
+               pr_err("VIC: %02d and TMDS clock of %d KHz\n", vic, rx_clk_freq);
+       }
+
+       return clk_ratio_detected;
+}
diff --git a/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h b/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h
new file mode 100644 (file)
index 0000000..f8b9c86
--- /dev/null
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_hdmirx.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_SS28FDSOI_HDMIRX_H_
+#define API_AFE_SS28FDSOI_HDMIRX_H_
+
+#include <linux/io.h>
+#include "../../../../mxc/hdp/all.h"
+
+#define REFCLK_FREQ_KHZ                        24000
+#define LINK_WRITE                             0x2000
+#define LINK_ID                                0x0
+
+#define CMN_PLLSM0_PLLEN_TMR_ADDR              0x0029
+#define CMN_PLLSM0_PLLPRE_TMR_ADDR             0x002A
+#define CMN_PLLSM0_PLLVREF_TMR_ADDR            0x002B
+#define CMN_PLLSM0_PLLLOCK_TMR_ADDR            0x002C
+#define CMN_PLLSM0_USER_DEF_CTRL_ADDR          0x002F
+#define CMN_PLL0_VCOCAL_CTRL_ADDR              0x0080
+#define CMN_PLL0_VCOCAL_OVRD_ADDR              0x0083
+#define CMN_PLL0_LOCK_REFCNT_START_ADDR        0x0090
+#define CMN_PLL0_LOCK_PLLCNT_START_ADDR        0x0092
+#define CMN_PLL0_DIV2SEL_OSR_CTRL_ADDR         0x009B
+#define CMN_ICAL_CTRL_ADDR                     0x00C0
+#define CMN_ICAL_OVRD_ADDR                     0x00C1
+#define CMN_RXCAL_CTRL_ADDR                    0x00D0
+#define CMN_RXCAL_OVRD_ADDR                    0x00D1
+#define CMN_RXCAL_INIT_TMR_ADDR                0x00D4
+#define CMN_TXPUCAL_OVRD_ADDR                  0x00E1
+#define CMN_TXPDCAL_OVRD_ADDR                  0x00F1
+#define CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR      0x01A0
+#define CMN_CMSMT_REF_CLK_TMR_VALUE_ADDR       0x01A2
+#define CMN_CMSMT_TEST_CLK_CNT_VALUE_ADDR      0x01A3
+#define CMN_DIAG_PLL0_FBH_OVRD_ADDR            0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD_ADDR            0x01C1
+#define CMN_DIAG_PLL0_TEST_MODE_ADDR           0x01C4
+#define CMN_DIAG_PLL0_INCLK_CTRL_ADDR          0x01CA
+#define CMN_DIAG_PLL0_V2I_TUNE_ADDR            0x01C5
+#define CMN_DIAG_PLL0_CP_TUNE_ADDR             0x01C6
+#define CMN_DIAG_PLL0_PTATIS_TUNE1_ADDR        0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2_ADDR        0x01C9
+#define XCVR_PSM_CAL_TMR_ADDR                  0x4002
+#define XCVR_PSM_A0IN_TMR_ADDR                 0x4003
+#define XCVR_DIAG_RX_LANE_CAL_RST_TMR_ADDR     0x40EA
+#define TX_ANA_CTRL_REG_1_ADDR                 0x5020
+#define TX_ANA_CTRL_REG_2_ADDR                 0x5021
+#define TX_DIG_CTRL_REG_2_ADDR                 0x5024
+#define TX_ANA_CTRL_REG_3_ADDR                 0x5026
+#define TX_ANA_CTRL_REG_4_ADDR                 0x5027
+#define TX_ANA_CTRL_REG_5_ADDR                 0x5029
+#define RX_PSC_A0_ADDR                         0x8000
+#define RX_IQPI_ILL_CAL_OVRD_ADDR              0x8023
+#define RX_EPI_ILL_CAL_OVRD_ADDR               0x8033
+#define RX_SLC_CTRL_ADDR                       0x80E0
+#define RX_REE_PERGCSM_EQENM_PH1_ADDR          0x8179
+#define RX_REE_PERGCSM_EQENM_PH2_ADDR          0x817A
+#define RX_REE_VGA_GAIN_OVRD_ADDR              0x81AD
+#define RX_REE_SMGM_CTRL1_ADDR                 0x81BD
+#define RX_DIAG_ILL_IQ_TRIM0_ADDR              0x81C1
+#define RX_DIAG_ILL_E_TRIM0_ADDR               0x81C2
+#define RX_DIAG_ILL_IQE_TRIM2_ADDR             0x81C5
+#define RX_DIAG_DFE_CTRL2_ADDR                 0x81D4
+#define RX_DIAG_SC2C_DELAY_ADDR                0x81E1
+#define RX_DIAG_SMPLR_OSR_ADDR                 0x81E2
+#define RX_CLK_SLICER_CAL_OVRD_ADDR            0x8621
+#define RX_CLK_SLICER_CAL_INIT_TMR_ADDR        0x8624
+#define PHY_MODE_CTL_ADDR                      0xC008
+#define PHY_PMA_CMN_CTRL1_ADDR                 0xC800
+#define PHY_PMA_CMN_CTRL2_ADDR                 0xC801
+#define PHY_PMA_SSM_STATE_ADDR                 0xC802
+#define PHY_PMA_PLL_SM_STATE_ADDR              0xC803
+#define PHY_PMA_XCVR_CTRL_ADDR                 0xCC00
+
+typedef enum {
+  TMDS_BIT_CLOCK_RATIO_1_10 = 10,
+  TMDS_BIT_CLOCK_RATIO_1_40 = 40
+} tmds_bit_clock_ratio_t;
+
+typedef enum {
+  PIXEL_ENCODING_RGB    = 0,
+  PIXEL_ENCODING_YUV422 = 1,
+  PIXEL_ENCODING_YUV444 = 2,
+  PIXEL_ENCODING_YUV420 = 3,
+} pixel_encoding_t;
+
+void speedup_config(state_struct *state);
+void arc_config(state_struct *state);
+void pma_config(state_struct *state);
+u8 pma_cmn_ready(state_struct *state);
+u8 pma_rx_clk_signal_detect(state_struct *state);
+u32 pma_rx_clk_freq_detect(state_struct *state);
+void pre_data_rate_change(state_struct *state);
+void pma_pll_config(state_struct *state, u32, clk_ratio_t, tmds_bit_clock_ratio_t, unsigned char);
+clk_ratio_t clk_ratio_detect(state_struct *state, u32, u32, u8, pixel_encoding_t, tmds_bit_clock_ratio_t);
+void phy_status(state_struct *state);
+
+#endif
diff --git a/drivers/media/platform/imx8/hdmi/Kconfig b/drivers/media/platform/imx8/hdmi/Kconfig
new file mode 100644 (file)
index 0000000..ed2736f
--- /dev/null
@@ -0,0 +1,4 @@
+config IMX8_HDMI_RX
+       tristate "IMX8 HDMI RX Controller"
+       select MX8_HDP_RX
+       default y
diff --git a/drivers/media/platform/imx8/hdmi/Makefile b/drivers/media/platform/imx8/hdmi/Makefile
new file mode 100644 (file)
index 0000000..9a466a5
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_IMX8_HDMI_RX) += mxc-hdmi-rx.o mxc-hdmi-hw.o API_AFE_ss28fdsoi_hdmirx.o
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c b/drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c
new file mode 100644 (file)
index 0000000..f524f7b
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "API_AFE_ss28fdsoi_hdmirx.h"
+#include "mxc-hdmi-rx.h"
+
+u8 block0[128] = {
+       0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+       0x1e, 0x6d, 0xfd, 0x5a, 0x9b, 0x5f, 0x02, 0x00,
+       0x07, 0x19, 0x01, 0x04, 0xb5, 0x3c, 0x22, 0x78,
+       0x9f, 0x30, 0x35, 0xa7, 0x55, 0x4e, 0xa3, 0x26,
+       0x0f, 0x50, 0x54, 0x21, 0x08, 0x00, 0x71, 0x40,
+       0x81, 0x80, 0x81, 0xc0, 0xa9, 0xc0, 0xd1, 0xc0,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x50, 0xd0,
+       0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x08, 0x90,
+       0x65, 0x0c, 0x58, 0x54, 0x21, 0x00, 0x00, 0x1a,
+       0x28, 0x68, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80,
+       0x08, 0x90, 0x65, 0x0c, 0x58, 0x54, 0x21, 0x00,
+       0x00, 0x1a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x28,
+       0x3d, 0x87, 0x87, 0x38, 0x01, 0x0a, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+       0x00, 0x32, 0x37, 0x4d, 0x55, 0x36, 0x37, 0x0a,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xd4
+};
+
+u8 block1[128] = {
+       0x02, 0x03, 0x11, 0x71, 0x44, 0x90, 0x04, 0x03,
+       0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00,
+       0x00, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d,
+       0x40, 0x58, 0x2c, 0x45, 0x00, 0x58, 0x54, 0x21,
+       0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41
+};
+
+S_HDMI_SCDC_SET_MSG scdcExampleData = {
+       .sink_ver = 6,
+       .manufacturer_oui_1 = 0x1,
+       .manufacturer_oui_2 = 0x2,
+       .manufacturer_oui_3 = 0x3,
+       .devId = {1, 2, 3, 4, 5, 6, 7, 8},
+       .hardware_major_rev = 12,
+       .hardware_minor_rev = 13,
+       .software_major_rev = 0xAB,
+       .software_minor_rev = 0XBC,
+       .manufacturerSpecific = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+            20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}
+};
+
+u8 hdmi_infoframe_poll(state_struct *state)
+{
+       GENERAL_Read_Register_response regresp;
+       u32 regread;
+       struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+
+       /* Unmask "AVI InfoFrame received" interrupt */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_MASK << 2),
+                                               F_TMDS_MHL_HD_MASK(0xFD));
+       dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt unmasked.\n");
+
+       /* Unmask "tmds_mhl_hd_int" interrupt */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (MHL_HD_INT_MASK << 2),
+                                               F_MHL_HD_INT_MASK(0xE));
+       dev_dbg(&hdmi_rx->pdev->dev, "tmds_mhl_hd_int interrupt unmasked.\n");
+
+       /* MHL_HD_INT_STAT */
+       dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...\n");
+       do {
+               CDN_API_General_Read_Register_blocking(state,
+                                                      ADDR_SINK_MHL_HD + (MHL_HD_INT_STAT << 2),
+                                                      &regresp);
+       } while (!(regresp.val & (1 << 0)));
+       dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...DONE\n");
+
+       /* Mask "AVI InfoFrame received" interrupt */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_MASK << 2),
+                                               F_TMDS_MHL_HD_MASK(0xFF));
+       dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt masked.\n");
+
+       /* Mask "tmds_mhl_hd_int" interrupt */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (MHL_HD_INT_MASK << 2),
+                                               F_MHL_HD_INT_MASK(0xF));
+       dev_dbg(&hdmi_rx->pdev->dev, "tmds_mhl_hd_int interrupt masked.\n");
+
+       /* Read back TMDS_MHL_HD_INT_STAT to clear the interrupt */
+       CDN_API_General_Read_Register_blocking(state,
+                                              ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_STAT << 2),
+                                              &regresp);
+       dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt cleared.\n");
+
+       /* Packet 0 read request */
+       cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_CTRL << 2),
+                     F_PACKET_RDN_WR(0x0) | F_PACKET_NUM(0x0));
+       dev_dbg(&hdmi_rx->pdev->dev, "PIF Packet 0 read request.\n");
+
+       /* Wait for pkt_host_rdy_status */
+       dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...\n");
+       do {
+               cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), &regread);
+       } while (!(regread & (1 << 16)));
+       dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...DONE\n");
+
+       return 0;
+}
+
+/* Exemplary code to configure the controller */
+/* for the AVI_InfoFrame reception */
+static void get_avi_infoframe(state_struct *state)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+       GENERAL_Read_Register_response regresp;
+
+       dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+       /* Get VIC code and pixel encoding */
+       hdmi_infoframe_poll(state);
+
+       CDN_API_General_Read_Register_blocking(state, ADDR_SINK_MHL_HD + (PKT_AVI_DATA_LOW << 2), &regresp);
+       hdmi_rx->vic_code = (regresp.val & 0xFF000000) >> 24;
+       hdmi_rx->pixel_encoding = (regresp.val & 0x00000060) >> 5;
+}
+
+static void get_vendor_infoframe(state_struct *state)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+       u32 regread;
+
+       dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+       /* Set info_type1 to vendor Info Frame */
+       cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2),
+                     F_INFO_TYPE1(0x81));
+
+       hdmi_infoframe_poll(state);
+
+       /* Get IEEE OUI */
+       cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INFO_DATA1 << 2), &regread);
+       if (regread >> 8 == 0x000c03)
+               dev_info(&hdmi_rx->pdev->dev, "HDMI 1.4b Vendor Specific Infoframe\n");
+       else if (regread >> 8 == 0xC45DD8)
+               dev_info(&hdmi_rx->pdev->dev, "HDMI 2.0 Vendor Specific Infoframe\n");
+       else
+               dev_err(&hdmi_rx->pdev->dev,
+                                       "Error Vendro Infoframe IEEE OUI=0x%6X\n", regread >> 8);
+
+       /* Get HDMI Video format */
+       cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INFO_DATA2 << 2), &regread);
+
+       /* Extened resoluction format */
+       if (((regread >> 5) & 0x0000007) == 1) {
+               hdmi_rx->hdmi_vic = (regread >> 8) & 0xff;
+               dev_info(&hdmi_rx->pdev->dev, "hdmi_vic=%d\n", hdmi_rx->hdmi_vic);
+       }
+
+       /* Clear info_type1 */
+       cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2),
+                     F_INFO_TYPE1(0x00));
+}
+
+static void get_color_depth(struct mxc_hdmi_rx_dev *hdmi_rx,
+                           clk_ratio_t clk_ratio)
+{
+       u8 pixel_encoding = hdmi_rx->pixel_encoding;
+
+       hdmi_rx->color_depth = 8;
+
+       switch (pixel_encoding) {
+       case PIXEL_ENCODING_YUV422:
+               switch (clk_ratio) {
+               case CLK_RATIO_1_1:
+                       hdmi_rx->color_depth = 8;
+                       break;
+               case CLK_RATIO_5_4:
+               case CLK_RATIO_3_2:
+               case CLK_RATIO_2_1:
+               case CLK_RATIO_1_2:
+               case CLK_RATIO_5_8:
+               case CLK_RATIO_3_4:
+               default:
+                       pr_err("YUV422 Not supported clk ration\n");
+               }
+               break;
+       case PIXEL_ENCODING_YUV420:
+               switch (clk_ratio) {
+               case CLK_RATIO_1_1:
+                       hdmi_rx->color_depth = 16;
+                       break;
+               case CLK_RATIO_1_2:
+                       hdmi_rx->color_depth = 8;
+                       break;
+               case CLK_RATIO_5_8:
+                       hdmi_rx->color_depth = 10;
+                       break;
+               case CLK_RATIO_3_4:
+                       hdmi_rx->color_depth = 12;
+                       break;
+               case CLK_RATIO_5_4:
+               case CLK_RATIO_3_2:
+               case CLK_RATIO_2_1:
+               default:
+                       pr_err("YUV420 Not supported clk ration\n");
+               }
+               break;
+       default:                /* RGB/YUV444 */
+               switch (clk_ratio) {
+               case CLK_RATIO_1_1:
+                       hdmi_rx->color_depth = 8;
+                       break;
+               case CLK_RATIO_5_4:
+                       hdmi_rx->color_depth = 10;
+                       break;
+               case CLK_RATIO_3_2:
+                       hdmi_rx->color_depth = 12;
+                       break;
+               case CLK_RATIO_2_1:
+                       hdmi_rx->color_depth = 16;
+                       break;
+               case CLK_RATIO_1_2:
+               case CLK_RATIO_5_8:
+               case CLK_RATIO_3_4:
+               default:
+                       pr_err("RGB/YUV444 Not supported clk ration\n");
+               }
+       }
+}
+
+int hdmi_rx_init(state_struct *state)
+{
+       u32 ret = 0;
+       /* Set uCPU Clock frequency for FW's use [MHz]; */
+       CDN_API_SetClock(state, 200);
+
+       /* Relase uCPU */
+       cdn_apb_write(state, ADDR_APB_CFG, 0);
+
+       /* Check if the firmware is running */
+       ret = CDN_API_CheckAlive_blocking(state);
+       return ret;
+}
+
+/* Bring-up sequence for the HDMI-RX */
+int hdmirx_startup(state_struct *state)
+{
+       u8 sts;
+       u32 rx_clk_freq;
+       u8 event5V = 0;
+       u8 data_rate_change = 0;
+       u8 scrambling_en;
+       clk_ratio_t clk_ratio, clk_ratio_detected;
+       tmds_bit_clock_ratio_t tmds_bit_clock_ratio;
+       struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+       S_HDMI_SCDC_GET_MSG *scdcData = &hdmi_rx->scdcData;
+       u8 ret = 0;
+
+       /* Start from TMDS/pixel clock ratio of 1:1.
+        * It affects only pixel clock frequency as the character/data clocks are generated based on
+        * a measured TMDS clock.
+        * This guarantees that the TMDS characters are correctly decoded in the controller regardless
+        * of the pixel clock ratio being programmed. */
+       clk_ratio = CLK_RATIO_1_1;
+
+       /* Set driver and firmware active */
+       CDN_API_MainControl_blocking(state, 1, &sts);
+
+       /* Set EDID - block 0 */
+       CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 0, &block0[0]);
+
+       /* Set EDID - block 1 */
+       CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 1, &block1[0]);
+       dev_dbg(&hdmi_rx->pdev->dev, "EDID block 0/1 set complete.\n");
+
+       /* Set SCDC data sample */
+       CDN_API_HDMIRX_SET_SCDC_SLAVE_blocking(state, &scdcExampleData);
+       dev_dbg(&hdmi_rx->pdev->dev, "SCDC set complete.\n");
+
+       /* Get TMDS_Bit_Clock_Ratio and Scrambling setting */
+       CDN_API_HDMIRX_GET_SCDC_SLAVE_blocking(state, scdcData);
+       tmds_bit_clock_ratio =
+           ((scdcData->TMDS_Config & (1 << 1)) >> 1) ?
+               TMDS_BIT_CLOCK_RATIO_1_40 : TMDS_BIT_CLOCK_RATIO_1_10;
+       scrambling_en = scdcData->TMDS_Config & (1 << 0);
+       dev_dbg(&hdmi_rx->pdev->dev,
+                       "TMDS ratio: 1/%0d, Scrambling %0d).\n", tmds_bit_clock_ratio, scrambling_en);
+
+       /* Clear HPD */
+       CDN_API_HDMIRX_SetHpd_blocking(state, 0);
+       dev_dbg(&hdmi_rx->pdev->dev, "Clear HDP\n");
+
+       /* Wait for 5v */
+       while ((event5V & (1 << HDMI_RX_EVENT_5V_VAL)) == 0) {
+               CDN_API_HDMIRX_ReadEvent(state, &event5V);
+               dev_dbg(&hdmi_rx->pdev->dev, "event5V = 0x%02X\n", event5V);
+       }
+       /* Got 5v, set hpd */
+       msleep(100);    /* provide minimum low pulse length (100ms) */
+       CDN_API_HDMIRX_SetHpd_blocking(state, 1);
+       dev_dbg(&hdmi_rx->pdev->dev, "Set HDP\n");
+
+       /* Configure the PHY */
+       pma_config(state);
+
+       /* Reset HDMI RX PHY */
+       imx8qm_hdmi_phy_reset(state, 1);
+
+       ret = pma_cmn_ready(state);
+       if (ret < 0)
+               pr_err("pma_cmn_ready failed\n");
+
+       msleep(500);
+
+       arc_config(state);
+
+       ret = pma_rx_clk_signal_detect(state);
+       if (ret < 0)
+               pr_err("pma_rx_clk_signal_detect failed\n");
+       /* Get TMDS clock frequency */
+       rx_clk_freq = pma_rx_clk_freq_detect(state);
+
+       pma_pll_config(state, rx_clk_freq, clk_ratio, tmds_bit_clock_ratio,
+                      data_rate_change);
+       msleep(500);
+
+       /* Setup the scrambling mode */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (TMDS_SCR_CTRL << 2),
+                                               F_SCRAMBLER_MODE(scrambling_en));
+       dev_info(&hdmi_rx->pdev->dev,
+                               "Scrambling %s.\n", (scrambling_en) ? "enabled" : "disabled");
+       /*Just to initiate the counters: */
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (TMDS_SCR_CNT_INT_CTRL << 2),
+                                               F_SCRAMBLER_SSCP_LINE_DET_THR(0) |
+                                               F_SCRAMBLER_CTRL_LINE_DET_THR(0));
+       CDN_API_General_Write_Register_blocking(state,
+                                               ADDR_SINK_MHL_HD + (TMDS_SCR_VALID_CTRL << 2),
+                                               F_SCRAMBLER_SSCP_LINE_VALID_THR(1) |
+                                               F_SCRAMBLER_CTRL_LINE_VALID_THR(0));
+
+       /* The PHY got programmed with the assumed TMDS/pixel clock ratio of 1:1.
+        * Implement the link training procedure to find out the real clock ratio:
+        * 1. Wait for AVI InfoFrame packet
+        * 2. Get the VIC code and pixel encoding from the packet
+        * 3. Evaluate the TMDS/pixel clock ratio based on the vic_table.c
+        * 4. Compare the programmed clock ratio with evaluated one
+        * 5. If mismatch found - reprogram the PHY
+        * 6. Enable the video data path in the controller */
+
+       get_avi_infoframe(state);
+       get_vendor_infoframe(state);
+
+       dev_dbg(&hdmi_rx->pdev->dev,
+                       "get_avi_infoframe() vic_code: %0d, pixel_encoding: %0d.\n",
+                       hdmi_rx->vic_code, hdmi_rx->pixel_encoding);
+       mxc_hdmi_frame_timing(hdmi_rx);
+
+       clk_ratio_detected = clk_ratio_detect(state, rx_clk_freq,
+                                             hdmi_rx->timings->timings.bt.
+                                             pixelclock / 1000,
+                                             hdmi_rx->vic_code,
+                                             hdmi_rx->pixel_encoding,
+                                             tmds_bit_clock_ratio);
+
+       data_rate_change = (clk_ratio != clk_ratio_detected);
+       if (data_rate_change) {
+               dev_dbg(&hdmi_rx->pdev->dev,
+                               "TMDS/pixel clock ratio mismatch detected (programmed: %0d, detected: %0d)\n",
+                               clk_ratio, clk_ratio_detected);
+
+               /* Reconfigure the PHY */
+               pre_data_rate_change(state);
+               pma_rx_clk_signal_detect(state);
+               rx_clk_freq = pma_rx_clk_freq_detect(state);
+               pma_pll_config(state, rx_clk_freq, clk_ratio_detected,
+                              tmds_bit_clock_ratio, data_rate_change);
+       } else
+               dev_info(&hdmi_rx->pdev->dev, "TMDS/pixel clock ratio correct\n");
+
+       get_color_depth(hdmi_rx, clk_ratio_detected);
+       dev_dbg(&hdmi_rx->pdev->dev, "Get colordepth is %d bpc\n", hdmi_rx->color_depth);
+
+       /* Do post PHY programming settings */
+       CDN_API_MainControl_blocking(state, 0x80, &sts);
+       dev_dbg(&hdmi_rx->pdev->dev,
+                               "CDN_API_MainControl_blocking() Stage 2 complete.\n");
+
+       /* Initialize HDMI RX */
+       CDN_API_HDMIRX_Init_blocking(state);
+       dev_dbg(&hdmi_rx->pdev->dev,
+                               "CDN_API_HDMIRX_Init_blocking() complete.\n");
+
+       return 0;
+}
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c
new file mode 100644 (file)
index 0000000..6cd53c9
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "mxc-hdmi-rx.h"
+#include "API_AFE_ss28fdsoi_hdmirx.h"
+
+#define MXC_HDMI_DRIVER_NAME "iMX HDMI RX"
+#define MXC_HDMI_MIN_WIDTH             640
+#define MXC_HDMI_MAX_WIDTH             3840
+#define MXC_HDMI_MIN_HEIGHT            480
+#define MXC_HDMI_MAX_HEIGHT            2160
+
+/* V4L2_DV_BT_CEA_640X480P59_94 */
+#define MXC_HDMI_MIN_PIXELCLOCK        24000000
+/* V4L2_DV_BT_CEA_3840X2160P30 */
+#define MXC_HDMI_MAX_PIXELCLOCK        297000000
+
+#define imx_sd_to_hdmi(sd) container_of(sd, struct mxc_hdmi_rx_dev, sd)
+
+static const struct v4l2_dv_timings_cap mxc_hdmi_timings_cap = {
+       .type = V4L2_DV_BT_656_1120,
+       /* keep this initialization for compatibility with GCC < 4.4.6 */
+       .reserved = { 0 },
+
+       V4L2_INIT_BT_TIMINGS(MXC_HDMI_MIN_WIDTH, MXC_HDMI_MAX_WIDTH,
+                            MXC_HDMI_MIN_HEIGHT, MXC_HDMI_MAX_HEIGHT,
+                            MXC_HDMI_MIN_PIXELCLOCK,
+                            MXC_HDMI_MAX_PIXELCLOCK,
+                            V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+                            V4L2_DV_BT_CAP_PROGRESSIVE)
+};
+
+struct mxc_hdmi_rx_dev_video_standards
+mxc_hdmi_video_standards[] = {
+       {V4L2_DV_BT_CEA_640X480P59_94, 1, 0, 60},
+       {V4L2_DV_BT_CEA_720X480P59_94, 2, 0, 60},
+       {V4L2_DV_BT_CEA_720X480P59_94, 3, 0, 60},
+       {V4L2_DV_BT_CEA_720X576P50,   18, 0, 50},
+       {V4L2_DV_BT_CEA_720X576P50,   17, 0, 50},
+       {V4L2_DV_BT_CEA_1280X720P60,   4, 0, 60},
+       {V4L2_DV_BT_CEA_1280X720P50,  19, 0, 50},
+       {V4L2_DV_BT_CEA_1280X720P30,  62, 0, 30},
+       {V4L2_DV_BT_CEA_1280X720P25,  61, 0, 25},
+       {V4L2_DV_BT_CEA_1280X720P24,  60, 0, 24},
+       {V4L2_DV_BT_CEA_1920X1080P60, 16, 0, 60},
+       {V4L2_DV_BT_CEA_1920X1080P50, 31, 0, 50},
+       {V4L2_DV_BT_CEA_1920X1080P30, 34, 0, 30},
+       {V4L2_DV_BT_CEA_1920X1080P25, 33, 0, 25},
+       {V4L2_DV_BT_CEA_1920X1080P24, 32, 0, 24},
+       {V4L2_DV_BT_CEA_3840X2160P24, 93, 3, 24},
+       {V4L2_DV_BT_CEA_3840X2160P25, 94, 2, 25},
+       {V4L2_DV_BT_CEA_3840X2160P30, 95, 1, 30},
+       {V4L2_DV_BT_CEA_4096X2160P24, 98, 4, 24},
+       {V4L2_DV_BT_CEA_4096X2160P25, 99, 0, 25},
+       {V4L2_DV_BT_CEA_4096X2160P30, 100, 0, 30},
+       /* SVGA */
+       {V4L2_DV_BT_DMT_800X600P56, 0x0, 0, 56},
+       {V4L2_DV_BT_DMT_800X600P60, 0x0, 0, 60},
+       {V4L2_DV_BT_DMT_800X600P72, 0x0, 0, 72},
+       {V4L2_DV_BT_DMT_800X600P75, 0x0, 0, 75},
+       {V4L2_DV_BT_DMT_800X600P85, 0x0, 0, 85},
+       /* SXGA */
+       {V4L2_DV_BT_DMT_1280X1024P60, 0x0, 0, 60},
+       {V4L2_DV_BT_DMT_1280X1024P75, 0x0, 0, 75},
+       /* VGA */
+       { V4L2_DV_BT_DMT_640X480P72, 0x0, 0, 72},
+       { V4L2_DV_BT_DMT_640X480P75, 0x0, 0, 75},
+       { V4L2_DV_BT_DMT_640X480P85, 0x0, 0, 85},
+       /* XGA */
+       { V4L2_DV_BT_DMT_1024X768P60, 0x0, 0, 60},
+       { V4L2_DV_BT_DMT_1024X768P70, 0x0, 0, 70},
+       { V4L2_DV_BT_DMT_1024X768P75, 0x0, 0, 75},
+       { V4L2_DV_BT_DMT_1024X768P85, 0x0, 0, 85},
+       /* UXGA */
+       { V4L2_DV_BT_DMT_1600X1200P60, 0x0, 0, 60},
+};
+
+int mxc_hdmi_frame_timing(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       struct mxc_hdmi_rx_dev_video_standards *stds;
+       u32 i, vic, hdmi_vic;
+
+       vic = hdmi_rx->vic_code;
+       hdmi_vic = hdmi_rx->hdmi_vic;
+       stds = mxc_hdmi_video_standards;
+
+       if (vic == 0 && hdmi_vic != 0) {
+               for (i = 0; i < ARRAY_SIZE(mxc_hdmi_video_standards); i++) {
+                       if (stds[i].hdmi_vic == hdmi_vic) {
+                               hdmi_rx->timings = &stds[i];
+                               return true;
+                       }
+               }
+       } else if (vic > 109) {
+               dev_err(&hdmi_rx->pdev->dev,
+                               "Unsupported mode vic=%d, hdmi_vic=%d\n", vic, hdmi_vic);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mxc_hdmi_video_standards); i++) {
+               if (stds[i].vic == vic) {
+                       hdmi_rx->timings = &stds[i];
+                       return true;
+               }
+       }
+
+       if (i >= ARRAY_SIZE(mxc_hdmi_video_standards))
+               return -EINVAL;
+
+       return true;
+}
+
+static int mxc_hdmi_clock_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       struct device *dev = &hdmi_rx->pdev->dev;
+
+       hdmi_rx->ref_clk = devm_clk_get(dev, "ref_clk");
+       if (IS_ERR(hdmi_rx->ref_clk)) {
+               dev_err(dev, "failed to get hdmi rx ref clk\n");
+               return PTR_ERR(hdmi_rx->ref_clk);
+       }
+
+       hdmi_rx->pxl_clk = devm_clk_get(dev, "pxl_clk");
+       if (IS_ERR(hdmi_rx->pxl_clk)) {
+               dev_err(dev, "failed to get hdmi rx pxl clk\n");
+               return PTR_ERR(hdmi_rx->pxl_clk);
+       }
+       hdmi_rx->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(hdmi_rx->pclk)) {
+               dev_err(dev, "failed to get hdmi rx pclk\n");
+               return PTR_ERR(hdmi_rx->pclk);
+       }
+
+       hdmi_rx->sclk = devm_clk_get(dev, "sclk");
+       if (IS_ERR(hdmi_rx->sclk)) {
+               dev_err(dev, "failed to get hdmi rx sclk\n");
+               return PTR_ERR(hdmi_rx->sclk);
+       }
+
+       hdmi_rx->enc_clk = devm_clk_get(dev, "enc_clk");
+       if (IS_ERR(hdmi_rx->enc_clk)) {
+               dev_err(dev, "failed to get hdmi rx enc clk\n");
+               return PTR_ERR(hdmi_rx->enc_clk);
+       }
+
+       hdmi_rx->spdif_clk = devm_clk_get(dev, "spdif_clk");
+       if (IS_ERR(hdmi_rx->spdif_clk)) {
+               dev_err(dev, "failed to get hdmi rx spdif clk\n");
+               return PTR_ERR(hdmi_rx->spdif_clk);
+       }
+
+       hdmi_rx->pxl_link_clk = devm_clk_get(dev, "pxl_link_clk");
+       if (IS_ERR(hdmi_rx->pxl_link_clk)) {
+               dev_err(dev, "failed to get hdmi rx pixel link clk\n");
+               return PTR_ERR(hdmi_rx->pxl_link_clk);
+       }
+
+       return 0;
+}
+
+static int mxc_hdmi_clock_enable(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       struct device *dev = &hdmi_rx->pdev->dev;
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+       ret = clk_prepare_enable(hdmi_rx->ref_clk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre ref_clk error %d\n", __func__, ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(hdmi_rx->pxl_clk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre pxl_clk error %d\n", __func__, ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(hdmi_rx->enc_clk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre enc_clk error %d\n", __func__, ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(hdmi_rx->sclk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre sclk error %d\n", __func__, ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(hdmi_rx->pclk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre pclk error %d\n", __func__, ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(hdmi_rx->spdif_clk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre spdif_clk error %d\n", __func__, ret);
+               return ret;
+       }
+       ret = clk_prepare_enable(hdmi_rx->pxl_link_clk);
+       if (ret < 0) {
+               dev_err(dev, "%s, pre pxl_link_clk error %d\n", __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mxc_hdmi_clock_disable(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+
+       clk_disable_unprepare(hdmi_rx->ref_clk);
+       clk_disable_unprepare(hdmi_rx->pxl_clk);
+       clk_disable_unprepare(hdmi_rx->enc_clk);
+       clk_disable_unprepare(hdmi_rx->sclk);
+       clk_disable_unprepare(hdmi_rx->pclk);
+       clk_disable_unprepare(hdmi_rx->spdif_clk);
+       clk_disable_unprepare(hdmi_rx->pxl_link_clk);
+}
+
+static void imx8qm_pixel_link_encoder(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       u32 val;
+
+       switch (hdmi_rx->pixel_encoding) {
+       case PIXEL_ENCODING_YUV422:
+               val = 3;
+               break;
+       case PIXEL_ENCODING_YUV420:
+               val = 4;
+               break;
+       case PIXEL_ENCODING_YUV444:
+               val = 2;
+               break;
+       case PIXEL_ENCODING_RGB:
+               val = 0;
+               break;
+       default:
+               val = 0x6;
+       }
+
+       /* HDMI RX H/Vsync Polarity */
+       if (hdmi_rx->timings->timings.bt.polarities & V4L2_DV_VSYNC_POS_POL)
+               val |= 1 << PL_ENC_CTL_PXL_VCP;
+       if (hdmi_rx->timings->timings.bt.polarities & V4L2_DV_HSYNC_POS_POL)
+               val |= 1 << PL_ENC_CTL_PXL_HCP;
+
+       writel(val, hdmi_rx->mem.ss_base);
+}
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_video_ops
+ */
+
+static int mxc_hdmi_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+       struct v4l2_captureparm *cparm = &a->parm.capture;
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+       int ret = 0;
+
+       switch (a->type) {
+       /* This is the only case currently handled. */
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               memset(a, 0, sizeof(*a));
+               a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cparm->timeperframe.denominator = hdmi_rx->timings->fps;
+               cparm->timeperframe.numerator = 1;
+               ret = 0;
+               break;
+
+       /* These are all the possible cases. */
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               ret = -EINVAL;
+               break;
+       default:
+               pr_debug("   type is unknown - %d\n", a->type);
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int mxc_hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+       u32 val;
+
+       dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+       imx8qm_pixel_link_encoder(hdmi_rx);
+
+       if (enable) {
+               val = readl(hdmi_rx->mem.ss_base);
+               val |=  1 << PL_ENC_CTL_PXL_EN;
+               writel(val, hdmi_rx->mem.ss_base);
+               mdelay(17);
+
+               val = readl(hdmi_rx->mem.ss_base);
+               val |=  1 << PL_ENC_CTL_PXL_VAL;
+               writel(val, hdmi_rx->mem.ss_base);
+       } else {
+               val = readl(hdmi_rx->mem.ss_base);
+               val |=  ~(1 << PL_ENC_CTL_PXL_VAL);
+               writel(val, hdmi_rx->mem.ss_base);
+               mdelay(17);
+
+               val = readl(hdmi_rx->mem.ss_base);
+               val |=  ~(1 << PL_ENC_CTL_PXL_EN);
+               writel(val, hdmi_rx->mem.ss_base);
+       }
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx_video_ops_hdmi = {
+       .s_stream = mxc_hdmi_s_stream,
+       .g_parm =       mxc_hdmi_g_parm,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations hdmi_media_ops = {
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_pad_ops
+ */
+static int mxc_hdmi_enum_framesizes(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+
+       if (fse->index > 1)
+               return -EINVAL;
+
+       fse->min_width = hdmi_rx->timings->timings.bt.width;
+       fse->max_width = fse->min_width;
+
+       fse->min_height = hdmi_rx->timings->timings.bt.height;
+       fse->max_height = fse->min_height;
+       return 0;
+}
+static int mxc_hdmi_enum_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_frame_interval_enum *fie)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+
+       if (fie->index < 0 || fie->index > 8)
+               return -EINVAL;
+
+       if (fie->width == 0 || fie->height == 0 ||
+           fie->code == 0) {
+               pr_warning("Please assign pixel format, width and height.\n");
+               return -EINVAL;
+       }
+
+       fie->interval.numerator = 1;
+
+        /* TODO Reserved to extension */
+       fie->interval.denominator = hdmi_rx->timings->fps;
+       return 0;
+}
+
+static int mxc_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index != 0)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_RGB888_1X24;
+
+       return 0;
+}
+
+static int mxc_hdmi_get_format(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_format *sdformat)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+       struct v4l2_mbus_framefmt *mbusformat = &sdformat->format;
+
+       if (sdformat->pad != MXC_HDMI_RX_PAD_SOURCE)
+               return -EINVAL;
+
+       switch (hdmi_rx->pixel_encoding) {
+       case PIXEL_ENCODING_YUV422:
+               mbusformat->code = MEDIA_BUS_FMT_YUYV8_1X16;
+               break;
+       case PIXEL_ENCODING_YUV420:
+               mbusformat->code = MEDIA_BUS_FMT_UV8_1X8;
+               break;
+       case PIXEL_ENCODING_YUV444:
+               mbusformat->code = MEDIA_BUS_FMT_AYUV8_1X32;
+               break;
+       default:
+               mbusformat->code = MEDIA_BUS_FMT_RGB888_1X24;
+       }
+
+       mbusformat->width =  hdmi_rx->timings->timings.bt.width;
+       mbusformat->height = hdmi_rx->timings->timings.bt.height;
+       mbusformat->colorspace = V4L2_COLORSPACE_JPEG;
+
+       return 0;
+}
+
+static int mxc_hdmi_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+
+       if (!hdmi_rx->edid.present)
+               return -ENODATA;
+
+       if (edid->start_block == 0 && edid->blocks == 0) {
+               edid->blocks = hdmi_rx->edid.blocks;
+               return 0;
+       }
+
+       if (edid->start_block >= hdmi_rx->edid.blocks)
+               return -EINVAL;
+
+       if (edid->start_block + edid->blocks > hdmi_rx->edid.blocks)
+               edid->blocks = hdmi_rx->edid.blocks - edid->start_block;
+
+       memcpy(edid->edid, hdmi_rx->edid.edid + edid->start_block * 128,
+                       edid->blocks * 128);
+
+       return 0;
+}
+
+static int mxc_hdmi_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+       state_struct *state = &hdmi_rx->state;
+       int err, i;
+
+       memset(edid->reserved, 0, sizeof(edid->reserved));
+
+       if (edid->start_block != 0)
+               return -EINVAL;
+
+       if (edid->blocks == 0) {
+               /* Default EDID */
+               hdmi_rx->edid.blocks = 2;
+               hdmi_rx->edid.present = true;
+       } else if (edid->blocks > 4) {
+               edid->blocks = 4;
+               return -E2BIG;
+       } else {
+               memcpy(hdmi_rx->edid.edid, edid->edid, 128 * edid->blocks);
+               hdmi_rx->edid.blocks = edid->blocks;
+               hdmi_rx->edid.present = true;
+       }
+
+       for (i = 0; i < hdmi_rx->edid.blocks; i++) {
+               /* EDID block */
+               err = CDN_API_HDMIRX_SET_EDID_blocking(state, 0, i, &hdmi_rx->edid.edid[i * 128]);
+               if (err != CDN_OK) {
+                       v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad);
+                       return -err;
+               }
+       }
+
+       return 0;
+}
+
+static bool mxc_hdmi_check_dv_timings(const struct v4l2_dv_timings *timings,
+                                         void *hdl)
+{
+       const struct mxc_hdmi_rx_dev_video_standards *stds =
+               mxc_hdmi_video_standards;
+       u32 i;
+
+       for (i = 0; stds[i].timings.bt.width; i++)
+               if (v4l2_match_dv_timings(timings, &stds[i].timings, 0, false))
+                       return true;
+
+       return false;
+}
+
+static int mxc_hdmi_enum_dv_timings(struct v4l2_subdev *sd,
+                                       struct v4l2_enum_dv_timings *timings)
+{
+       return v4l2_enum_dv_timings_cap(timings, &mxc_hdmi_timings_cap,
+                                       mxc_hdmi_check_dv_timings, NULL);
+}
+
+static int mxc_hdmi_dv_timings_cap(struct v4l2_subdev *sd,
+                                      struct v4l2_dv_timings_cap *cap)
+{
+       *cap = mxc_hdmi_timings_cap;
+       return 0;
+}
+
+static const struct v4l2_subdev_pad_ops imx_pad_ops_hdmi = {
+       .enum_mbus_code = mxc_hdmi_enum_mbus_code,
+       .enum_frame_size = mxc_hdmi_enum_framesizes,
+       .enum_frame_interval = mxc_hdmi_enum_frame_interval,
+       .get_fmt = mxc_hdmi_get_format,
+       .get_edid = mxc_hdmi_get_edid,
+       .set_edid = mxc_hdmi_set_edid,
+       .dv_timings_cap = mxc_hdmi_dv_timings_cap,
+       .enum_dv_timings = mxc_hdmi_enum_dv_timings,
+};
+
+static int mxc_hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+       state_struct *state = &hdmi_rx->state;
+       struct device *dev = &hdmi_rx->pdev->dev;
+       u8 sts;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (on) {
+               pm_runtime_get_sync(dev);
+               hdmirx_startup(&hdmi_rx->state);
+       } else {
+               /* Reset HDMI RX PHY */
+               CDN_API_HDMIRX_Stop_blocking(state);
+               CDN_API_MainControl_blocking(state, 0, &sts);
+               pm_runtime_put_sync(dev);
+       }
+
+       return 0;
+}
+static struct v4l2_subdev_core_ops imx_core_ops_hdmi = {
+       .s_power = mxc_hdmi_s_power,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_ops
+ */
+static const struct v4l2_subdev_ops imx_ops_hdmi = {
+       .core = &imx_core_ops_hdmi,
+       .video = &imx_video_ops_hdmi,
+       .pad = &imx_pad_ops_hdmi,
+};
+
+void imx8qm_hdmi_phy_reset(state_struct *state, u8 reset)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+       sc_err_t sciErr;
+
+       dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+       /* set the pixel link mode and pixel type */
+       sciErr = sc_misc_set_control(hdmi_rx->ipcHndl, SC_R_HDMI_RX, SC_C_PHY_RESET, reset);
+       if (sciErr != SC_ERR_NONE)
+               DRM_ERROR("SC_R_HDMI PHY reset failed %d!\n", sciErr);
+}
+
+static int imx8qm_hdp_read(struct hdp_mem *mem, u32 addr, u32 *value)
+{
+       u32 temp;
+       void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+       void *off_addr = 0x4 + mem->ss_base;;
+
+       __raw_writel(addr >> 12, off_addr);
+       temp = __raw_readl((volatile u32 *)tmp_addr);
+
+       *value = temp;
+       return 0;
+}
+
+static int imx8qm_hdp_write(struct hdp_mem *mem, u32 addr, u32 value)
+{
+       void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+       void *off_addr = 0x4 + mem->ss_base;;
+
+       __raw_writel(addr >> 12, off_addr);
+
+       __raw_writel(value, (volatile u32 *) tmp_addr);
+
+       return 0;
+}
+
+static int imx8qm_hdp_sread(struct hdp_mem *mem, u32 addr, u32 *value)
+{
+       u32 temp;
+       void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+       void *off_addr = 0xc + mem->ss_base;;
+
+       __raw_writel(addr >> 12, off_addr);
+
+       temp = __raw_readl((volatile u32 *)tmp_addr);
+       *value = temp;
+       return 0;
+}
+
+static int imx8qm_hdp_swrite(struct hdp_mem *mem, u32 addr, u32 value)
+{
+       void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+       void *off_addr = 0xc + mem->ss_base;
+
+       __raw_writel(addr >> 12, off_addr);
+       __raw_writel(value, (volatile u32 *)tmp_addr);
+
+       return 0;
+}
+static struct hdp_rw_func imx8qm_rw = {
+       .read_reg = imx8qm_hdp_read,
+       .write_reg = imx8qm_hdp_write,
+       .sread_reg = imx8qm_hdp_sread,
+       .swrite_reg = imx8qm_hdp_swrite,
+};
+
+static void mxc_hdmi_state_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       state_struct *state = &hdmi_rx->state;
+
+       memset(state, 0, sizeof(state_struct));
+       mutex_init(&state->mutex);
+
+       state->mem = &hdmi_rx->mem;
+       state->rw = &imx8qm_rw;
+}
+
+int mxc_hdmi_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       sc_err_t sciErr;
+       u32 ret = 0;
+
+       dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+       mxc_hdmi_state_init(hdmi_rx);
+
+       sciErr = sc_ipc_getMuID(&hdmi_rx->mu_id);
+       if (sciErr != SC_ERR_NONE) {
+               DRM_ERROR("Cannot obtain MU ID\n");
+               return -EINVAL;
+       }
+
+       sciErr = sc_ipc_open(&hdmi_rx->ipcHndl, hdmi_rx->mu_id);
+       if (sciErr != SC_ERR_NONE) {
+               DRM_ERROR("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+               return -EINVAL;
+       }
+
+       ret = hdmi_rx_init(&hdmi_rx->state);
+
+       return ret;
+}
+
+static int mxc_hdmi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxc_hdmi_rx_dev *hdmi_rx;
+       struct resource *res;
+       int ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+       hdmi_rx = devm_kzalloc(dev, sizeof(*hdmi_rx), GFP_KERNEL);
+       if (!hdmi_rx)
+               return -ENOMEM;
+
+       hdmi_rx->pdev = pdev;
+
+       spin_lock_init(&hdmi_rx->slock);
+
+       /* register map */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hdmi_rx->mem.regs_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(hdmi_rx->mem.regs_base)) {
+               dev_err(dev, "Failed to get HDMI RX CTRL base register\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       hdmi_rx->mem.ss_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(hdmi_rx->mem.ss_base)) {
+               dev_err(dev, "Failed to get HDMI RX CRS base register\n");
+               return -EINVAL;
+       }
+
+#if 0
+       /* TODO B0 */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_warn(dev, "Failed to get IRQ resource\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(dev, res->start, mxc_hdmi_irq_handler,
+                              0, dev_name(dev), mxc_hdmi);
+       if (ret < 0) {
+               dev_err(dev, "failed to install irq (%d)\n", ret);
+               return -EINVAL;
+       }
+#endif
+
+       v4l2_subdev_init(&hdmi_rx->sd, &imx_ops_hdmi);
+       /* sd.dev may use by match_of */
+       hdmi_rx->sd.dev = dev;
+
+       /* the owner is the same as the i2c_client's driver owner */
+       hdmi_rx->sd.owner = THIS_MODULE;
+       hdmi_rx->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       hdmi_rx->sd.entity.function = MEDIA_ENT_F_IO_DTV;
+
+       /* This allows to retrieve the platform device id by the host driver */
+       v4l2_set_subdevdata(&hdmi_rx->sd, pdev);
+
+       /* initialize name */
+       snprintf(hdmi_rx->sd.name, sizeof(hdmi_rx->sd.name), "%s",
+               MXC_HDMI_RX_SUBDEV_NAME);
+
+       hdmi_rx->pads[MXC_HDMI_RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       hdmi_rx->pads[MXC_HDMI_RX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+       hdmi_rx->sd.entity.ops = &hdmi_media_ops;
+       ret = media_entity_pads_init(&hdmi_rx->sd.entity,
+                                    MXC_HDMI_RX_PADS_NUM, hdmi_rx->pads);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, hdmi_rx);
+       ret = v4l2_async_register_subdev(&hdmi_rx->sd);
+       if (ret < 0) {
+               dev_err(dev,
+                                       "%s--Async register failed, ret=%d\n", __func__, ret);
+               media_entity_cleanup(&hdmi_rx->sd.entity);
+       }
+
+       mxc_hdmi_clock_init(hdmi_rx);
+
+       hdmi_rx->flags = MXC_HDMI_RX_PM_POWERED;
+
+       mxc_hdmi_clock_enable(hdmi_rx);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       ret = mxc_hdmi_init(hdmi_rx);
+       pm_runtime_put_sync(dev);
+       if (ret) {
+               dev_info(dev, "mxc hdmi rx init failed\n");
+               goto failed;
+       }
+
+       dev_info(dev, "mxc hdmi rx probe successfully\n");
+
+       return ret;
+failed:
+       v4l2_async_unregister_subdev(&hdmi_rx->sd);
+       media_entity_cleanup(&hdmi_rx->sd.entity);
+
+       mxc_hdmi_clock_disable(hdmi_rx);
+       pm_runtime_disable(dev);
+       return ret;
+}
+
+static int mxc_hdmi_remove(struct platform_device *pdev)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+       v4l2_async_unregister_subdev(&hdmi_rx->sd);
+       media_entity_cleanup(&hdmi_rx->sd.entity);
+
+       mxc_hdmi_clock_disable(hdmi_rx);
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mxc_hdmi_pm_suspend(struct device *dev)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+       if ((hdmi_rx->flags & MXC_HDMI_RX_PM_SUSPENDED) ||
+               (hdmi_rx->flags & MXC_HDMI_RX_RUNTIME_SUSPEND))
+               return 0;
+
+       mxc_hdmi_clock_disable(hdmi_rx);
+       hdmi_rx->flags |= MXC_HDMI_RX_PM_SUSPENDED;
+       hdmi_rx->flags &= ~MXC_HDMI_RX_PM_POWERED;
+
+       return 0;
+}
+
+static int mxc_hdmi_pm_resume(struct device *dev)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (hdmi_rx->flags & MXC_HDMI_RX_PM_POWERED)
+               return 0;
+
+       hdmi_rx->flags |= MXC_HDMI_RX_PM_POWERED;
+       hdmi_rx->flags &= ~MXC_HDMI_RX_PM_SUSPENDED;
+
+       ret = mxc_hdmi_clock_enable(hdmi_rx);
+       return (ret) ? -EAGAIN : 0;
+}
+#endif
+
+static int mxc_hdmi_runtime_suspend(struct device *dev)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (hdmi_rx->flags & MXC_HDMI_RX_RUNTIME_SUSPEND)
+               return 0;
+
+       if (hdmi_rx->flags & MXC_HDMI_RX_PM_POWERED) {
+               mxc_hdmi_clock_disable(hdmi_rx);
+               hdmi_rx->flags |= MXC_HDMI_RX_RUNTIME_SUSPEND;
+               hdmi_rx->flags &= ~MXC_HDMI_RX_PM_POWERED;
+       }
+       return 0;
+}
+
+static int mxc_hdmi_runtime_resume(struct device *dev)
+{
+       struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (hdmi_rx->flags & MXC_HDMI_RX_PM_POWERED)
+               return 0;
+
+       if (hdmi_rx->flags & MXC_HDMI_RX_RUNTIME_SUSPEND) {
+               mxc_hdmi_clock_enable(hdmi_rx);
+               hdmi_rx->flags |= MXC_HDMI_RX_PM_POWERED;
+               hdmi_rx->flags &= ~MXC_HDMI_RX_RUNTIME_SUSPEND;
+       }
+       return 0;
+}
+
+static const struct dev_pm_ops mxc_hdmi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(mxc_hdmi_pm_suspend, mxc_hdmi_pm_resume)
+       SET_RUNTIME_PM_OPS(mxc_hdmi_runtime_suspend, mxc_hdmi_runtime_resume, NULL)
+};
+
+static const struct of_device_id mxc_hdmi_of_match[] = {
+       {.compatible = "fsl,imx-hdmi-rx",},
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mxc_hdmi_of_match);
+
+static struct platform_driver mxc_hdmi_driver = {
+       .probe          = mxc_hdmi_probe,
+       .remove         = mxc_hdmi_remove,
+       .driver = {
+               .of_match_table = mxc_hdmi_of_match,
+               .name           = MXC_HDMI_RX_DRIVER_NAME,
+               .pm             = &mxc_hdmi_pm_ops,
+       }
+};
+
+module_platform_driver(mxc_hdmi_driver);
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h
new file mode 100644 (file)
index 0000000..6f15f7b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MXC_HDMI_RX_
+#define _MXC_HDMI_RX_
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <soc/imx8/sc/sci.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+
+#include <uapi/linux/v4l2-dv-timings.h>
+
+#include "../../../../mxc/hdp/all.h"
+
+#define state_to_mxc_hdmirx(env) \
+       container_of(env, struct mxc_hdmi_rx_dev, state)
+
+#define MXC_HDMI_RX_DRIVER_NAME        "mxc-hdmi-rx"
+#define MXC_HDMI_RX_SUBDEV_NAME        MXC_HDMI_RX_DRIVER_NAME
+
+#define MXC_HDMI_RX_NODE_NAME  "hdmi_rx"
+
+#define MXC_HDMI_RX_MAX_DEVS           2
+#define MXC_HDMI_RX_MAX_LANES          4
+
+#define MXC_HDMI_RX_PAD_SINK           1
+#define MXC_HDMI_RX_PAD_SOURCE         2
+#define MXC_HDMI_RX_PADS_NUM           3
+
+#define CSR_PIXEL_LINK_ENC_CTL         0x00
+#define PL_ENC_CTL_PXL_VAL          15
+#define PL_ENC_CTL_PXL_VPP          14
+#define PL_ENC_CTL_PXL_HPP          13
+#define PL_ENC_CTL_PXL_VCP          12
+#define PL_ENC_CTL_PXL_HCP          11
+#define PL_ENC_CTL_PXL_ADD          9
+#define PL_ENC_CTL_PXL_EXT          7
+#define PL_ENC_CTL_PXL_EN           6
+#define PL_ENC_CTL_PXL_ITC          4
+#define PL_ENC_CTL_PXL_ODD_EVEN     3
+#define PL_ENC_CTL_PXL_TYP          1
+#define PL_ENC_CTL_PXL_YUV          0
+
+#define CSR_HDP_RX_CTRL_CTRL0          0x04
+#define CSR_HDP_RX_CTRL_CTRL1          0x08
+
+struct mxc_hdmi_rx_dev_video_standards {
+       struct v4l2_dv_timings timings;
+       u8 vic;
+       u8 hdmi_vic;
+       u8 fps;
+};
+
+struct mxc_hdmi_rx_dev {
+       spinlock_t                              slock;
+       struct mutex                    lock;
+       wait_queue_head_t               irq_queue;
+       struct media_pad pads[MXC_HDMI_RX_PADS_NUM];
+
+       struct platform_device          *pdev;
+       struct v4l2_device                      *v4l2_dev;
+       struct v4l2_subdev sd;
+       struct v4l2_async_subdev asd;
+       struct v4l2_ctrl_handler ctrl_hdl;
+       struct v4l2_mbus_framefmt format;
+       struct v4l2_fract aspect_ratio;
+       struct {
+               u8 edid[512];
+               u32 present;
+               u32 blocks;
+       } edid;
+
+       state_struct state;
+       struct clk              *sclk;
+       struct clk              *pclk;
+       struct clk              *ref_clk;
+       struct clk              *pxl_clk;
+       struct clk              *enc_clk;
+       struct clk              *spdif_clk;
+       struct clk              *pxl_link_clk;
+       struct hdp_rw_func *rw;
+       struct hdp_mem mem;
+
+       u32 flags;
+       sc_ipc_t ipcHndl;
+       u32 mu_id;
+    S_HDMI_SCDC_GET_MSG          scdcData;
+
+       struct mxc_hdmi_rx_dev_video_standards *timings;
+    u8 vic_code;
+       u8 hdmi_vic;
+    u8 pixel_encoding;
+       u8 color_depth;
+};
+
+enum mxc_hdmi_rx_power_state {
+       MXC_HDMI_RX_PM_SUSPENDED = 0x01,
+       MXC_HDMI_RX_PM_POWERED = 0x02,
+       MXC_HDMI_RX_RUNTIME_SUSPEND = 0x04,
+};
+
+int hdmirx_startup(state_struct *state);
+void imx8qm_hdmi_phy_reset(state_struct *state, u8 reset);
+int hdmi_rx_init(state_struct *state);
+int mxc_hdmi_frame_timing(struct mxc_hdmi_rx_dev *hdmi_rx);
+
+#endif
index bca2ea6..16d43b6 100644 (file)
@@ -164,6 +164,7 @@ struct mxc_isi_fmt *mxc_isi_get_src_fmt(struct v4l2_subdev_format *sd_fmt)
        /* two fmt RGB32 and YUV444 from pixellink */
        if (sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16 ||
                sd_fmt->format.code == MEDIA_BUS_FMT_YVYU8_2X8 ||
+               sd_fmt->format.code == MEDIA_BUS_FMT_AYUV8_1X32 ||
                sd_fmt->format.code == MEDIA_BUS_FMT_UYVY8_2X8)
                index = 1;
        else
index 007b3dc..cdb7ce8 100644 (file)
@@ -105,6 +105,8 @@ static int mxc_isi_parse_dt(struct mxc_isi_dev *mxc_isi)
 
        dev_dbg(dev, "%s, isi_%d,interface(%d, %d, %d)\n", __func__, mxc_isi->id,
                        mxc_isi->interface[0], mxc_isi->interface[1], mxc_isi->interface[2]);
+
+       mxc_isi->chain_buf = of_property_read_bool(node, "fsl,chain_buf");
        return 0;
 }
 
index 0d5d274..94c01ea 100644 (file)
@@ -21,44 +21,44 @@ void dump_isi_regs(struct mxc_isi_dev *mxc_isi)
        struct device *dev = &mxc_isi->pdev->dev;
 
        dev_dbg(dev, "ISI CHNLC register dump, isi%d\n", mxc_isi->id);
-       dev_dbg(dev, "CHNL_CTRL              0x0h  = 0x%x\n", readl(mxc_isi->regs + 0x0));
-       dev_dbg(dev, "CHNL_IMG_CTRL          0x4h  = 0x%x\n", readl(mxc_isi->regs + 0x4));
-       dev_dbg(dev, "CHNL_OUT_BUF_CTRL      0x8h  = 0x%x\n", readl(mxc_isi->regs + 0x8));
-       dev_dbg(dev, "CHNL_IMG_CFG           0xCh  = 0x%x\n", readl(mxc_isi->regs + 0xC));
-       dev_dbg(dev, "CHNL_IER               0x10h = 0x%x\n", readl(mxc_isi->regs + 0x10));
-       dev_dbg(dev, "CHNL_STS               0x14h = 0x%x\n", readl(mxc_isi->regs + 0x14));
-       dev_dbg(dev, "CHNL_SCALE_FACTOR      0x18h = 0x%x\n", readl(mxc_isi->regs + 0x18));
-       dev_dbg(dev, "CHNL_SCALE_OFFSET      0x1Ch = 0x%x\n", readl(mxc_isi->regs + 0x1C));
-       dev_dbg(dev, "CHNL_CROP_ULC          0x20h = 0x%x\n", readl(mxc_isi->regs + 0x20));
-       dev_dbg(dev, "CHNL_CROP_LRC          0x24h = 0x%x\n", readl(mxc_isi->regs + 0x24));
-       dev_dbg(dev, "CHNL_CSC_COEFF0        0x28h = 0x%x\n", readl(mxc_isi->regs + 0x28));
-       dev_dbg(dev, "CHNL_CSC_COEFF1        0x2Ch = 0x%x\n", readl(mxc_isi->regs + 0x2C));
-       dev_dbg(dev, "CHNL_CSC_COEFF2        0x30h = 0x%x\n", readl(mxc_isi->regs + 0x30));
-       dev_dbg(dev, "CHNL_CSC_COEFF3        0x34h = 0x%x\n", readl(mxc_isi->regs + 0x34));
-       dev_dbg(dev, "CHNL_CSC_COEFF4        0x38h = 0x%x\n", readl(mxc_isi->regs + 0x38));
-       dev_dbg(dev, "CHNL_CSC_COEFF5        0x3Ch = 0x%x\n", readl(mxc_isi->regs + 0x3C));
-       dev_dbg(dev, "CHNL_ROI_0_ALPHA       0x40h = 0x%x\n", readl(mxc_isi->regs + 0x40));
-       dev_dbg(dev, "CHNL_ROI_0_ULC         0x44h = 0x%x\n", readl(mxc_isi->regs + 0x44));
-       dev_dbg(dev, "CHNL_ROI_0_LRC         0x48h = 0x%x\n", readl(mxc_isi->regs + 0x48));
-       dev_dbg(dev, "CHNL_ROI_1_ALPHA       0x4Ch = 0x%x\n", readl(mxc_isi->regs + 0x4C));
-       dev_dbg(dev, "CHNL_ROI_1_ULC         0x50h = 0x%x\n", readl(mxc_isi->regs + 0x50));
-       dev_dbg(dev, "CHNL_ROI_1_LRC         0x54h = 0x%x\n", readl(mxc_isi->regs + 0x54));
-       dev_dbg(dev, "CHNL_ROI_2_ALPHA       0x58h = 0x%x\n", readl(mxc_isi->regs + 0x58));
-       dev_dbg(dev, "CHNL_ROI_2_ULC         0x5Ch = 0x%x\n", readl(mxc_isi->regs + 0x5C));
-       dev_dbg(dev, "CHNL_ROI_2_LRC         0x60h = 0x%x\n", readl(mxc_isi->regs + 0x60));
-       dev_dbg(dev, "CHNL_ROI_3_ALPHA       0x64h = 0x%x\n", readl(mxc_isi->regs + 0x64));
-       dev_dbg(dev, "CHNL_ROI_3_ULC         0x68h = 0x%x\n", readl(mxc_isi->regs + 0x68));
-       dev_dbg(dev, "CHNL_ROI_3_LRC         0x6Ch = 0x%x\n", readl(mxc_isi->regs + 0x6C));
-       dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_Y   0x70h = 0x%x\n", readl(mxc_isi->regs + 0x70));
-       dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_U   0x74h = 0x%x\n", readl(mxc_isi->regs + 0x74));
-       dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_V   0x78h = 0x%x\n", readl(mxc_isi->regs + 0x78));
-       dev_dbg(dev, "CHNL_OUT_BUF_PITCH     0x7Ch = 0x%x\n", readl(mxc_isi->regs + 0x7C));
-       dev_dbg(dev, "CHNL_IN_BUF_ADDR       0x80h = 0x%x\n", readl(mxc_isi->regs + 0x80));
-       dev_dbg(dev, "CHNL_IN_BUF_PITCH      0x84h = 0x%x\n", readl(mxc_isi->regs + 0x84));
-       dev_dbg(dev, "CHNL_MEM_RD_CTRL       0x88h = 0x%x\n", readl(mxc_isi->regs + 0x88));
-       dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_Y   0x8Ch = 0x%x\n", readl(mxc_isi->regs + 0x8C));
-       dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_U   0x90h = 0x%x\n", readl(mxc_isi->regs + 0x90));
-       dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_V   0x94h = 0x%x\n", readl(mxc_isi->regs + 0x94));
+       dev_dbg(dev, "CHNL_CTRL              0x0h  = 0x%8x\n", readl(mxc_isi->regs + 0x0));
+       dev_dbg(dev, "CHNL_IMG_CTRL          0x4h  = 0x%8x\n", readl(mxc_isi->regs + 0x4));
+       dev_dbg(dev, "CHNL_OUT_BUF_CTRL      0x8h  = 0x%8x\n", readl(mxc_isi->regs + 0x8));
+       dev_dbg(dev, "CHNL_IMG_CFG           0xCh  = 0x%8x\n", readl(mxc_isi->regs + 0xC));
+       dev_dbg(dev, "CHNL_IER               0x10h = 0x%8x\n", readl(mxc_isi->regs + 0x10));
+       dev_dbg(dev, "CHNL_STS               0x14h = 0x%8x\n", readl(mxc_isi->regs + 0x14));
+       dev_dbg(dev, "CHNL_SCALE_FACTOR      0x18h = 0x%8x\n", readl(mxc_isi->regs + 0x18));
+       dev_dbg(dev, "CHNL_SCALE_OFFSET      0x1Ch = 0x%8x\n", readl(mxc_isi->regs + 0x1C));
+       dev_dbg(dev, "CHNL_CROP_ULC          0x20h = 0x%8x\n", readl(mxc_isi->regs + 0x20));
+       dev_dbg(dev, "CHNL_CROP_LRC          0x24h = 0x%8x\n", readl(mxc_isi->regs + 0x24));
+       dev_dbg(dev, "CHNL_CSC_COEFF0        0x28h = 0x%8x\n", readl(mxc_isi->regs + 0x28));
+       dev_dbg(dev, "CHNL_CSC_COEFF1        0x2Ch = 0x%8x\n", readl(mxc_isi->regs + 0x2C));
+       dev_dbg(dev, "CHNL_CSC_COEFF2        0x30h = 0x%8x\n", readl(mxc_isi->regs + 0x30));
+       dev_dbg(dev, "CHNL_CSC_COEFF3        0x34h = 0x%8x\n", readl(mxc_isi->regs + 0x34));
+       dev_dbg(dev, "CHNL_CSC_COEFF4        0x38h = 0x%8x\n", readl(mxc_isi->regs + 0x38));
+       dev_dbg(dev, "CHNL_CSC_COEFF5        0x3Ch = 0x%8x\n", readl(mxc_isi->regs + 0x3C));
+       dev_dbg(dev, "CHNL_ROI_0_ALPHA       0x40h = 0x%8x\n", readl(mxc_isi->regs + 0x40));
+       dev_dbg(dev, "CHNL_ROI_0_ULC         0x44h = 0x%8x\n", readl(mxc_isi->regs + 0x44));
+       dev_dbg(dev, "CHNL_ROI_0_LRC         0x48h = 0x%8x\n", readl(mxc_isi->regs + 0x48));
+       dev_dbg(dev, "CHNL_ROI_1_ALPHA       0x4Ch = 0x%8x\n", readl(mxc_isi->regs + 0x4C));
+       dev_dbg(dev, "CHNL_ROI_1_ULC         0x50h = 0x%8x\n", readl(mxc_isi->regs + 0x50));
+       dev_dbg(dev, "CHNL_ROI_1_LRC         0x54h = 0x%8x\n", readl(mxc_isi->regs + 0x54));
+       dev_dbg(dev, "CHNL_ROI_2_ALPHA       0x58h = 0x%8x\n", readl(mxc_isi->regs + 0x58));
+       dev_dbg(dev, "CHNL_ROI_2_ULC         0x5Ch = 0x%8x\n", readl(mxc_isi->regs + 0x5C));
+       dev_dbg(dev, "CHNL_ROI_2_LRC         0x60h = 0x%8x\n", readl(mxc_isi->regs + 0x60));
+       dev_dbg(dev, "CHNL_ROI_3_ALPHA       0x64h = 0x%8x\n", readl(mxc_isi->regs + 0x64));
+       dev_dbg(dev, "CHNL_ROI_3_ULC         0x68h = 0x%8x\n", readl(mxc_isi->regs + 0x68));
+       dev_dbg(dev, "CHNL_ROI_3_LRC         0x6Ch = 0x%8x\n", readl(mxc_isi->regs + 0x6C));
+       dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_Y   0x70h = 0x%8x\n", readl(mxc_isi->regs + 0x70));
+       dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_U   0x74h = 0x%8x\n", readl(mxc_isi->regs + 0x74));
+       dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_V   0x78h = 0x%8x\n", readl(mxc_isi->regs + 0x78));
+       dev_dbg(dev, "CHNL_OUT_BUF_PITCH     0x7Ch = 0x%8x\n", readl(mxc_isi->regs + 0x7C));
+       dev_dbg(dev, "CHNL_IN_BUF_ADDR       0x80h = 0x%8x\n", readl(mxc_isi->regs + 0x80));
+       dev_dbg(dev, "CHNL_IN_BUF_PITCH      0x84h = 0x%8x\n", readl(mxc_isi->regs + 0x84));
+       dev_dbg(dev, "CHNL_MEM_RD_CTRL       0x88h = 0x%8x\n", readl(mxc_isi->regs + 0x88));
+       dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_Y   0x8Ch = 0x%8x\n", readl(mxc_isi->regs + 0x8C));
+       dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_U   0x90h = 0x%8x\n", readl(mxc_isi->regs + 0x90));
+       dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_V   0x94h = 0x%8x\n", readl(mxc_isi->regs + 0x94));
 }
 #else
 void dump_isi_regs(struct mxc_isi_dev *mxc_isi)
@@ -339,17 +339,18 @@ void mxc_isi_channel_set_alpha(struct mxc_isi_dev *mxc_isi)
        writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
 }
 
-void mxc_isi_channel_set_4k(struct mxc_isi_dev *mxc_isi)
+void mxc_isi_channel_set_chain_buf(struct mxc_isi_dev *mxc_isi)
 {
-       struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
        u32 val;
 
-       val = readl(mxc_isi->regs + CHNL_CTRL);
-       val &= ~CHNL_CTRL_CHAIN_BUF_MASK;
-       if (src_f->width > 2046)
+       if (mxc_isi->chain_buf) {
+               printk("%s\n", __func__);
+               val = readl(mxc_isi->regs + CHNL_CTRL);
+               val &= ~CHNL_CTRL_CHAIN_BUF_MASK;
                val |= (CHNL_CTRL_CHAIN_BUF_2_CHAIN << CHNL_CTRL_CHAIN_BUF_OFFSET);
 
-       writel(val, mxc_isi->regs + CHNL_CTRL);
+               writel(val, mxc_isi->regs + CHNL_CTRL);
+       }
 }
 
 void mxc_isi_channel_deinterlace_init(struct mxc_isi_dev *mxc_isi)
index 4537a97..30010cb 100644 (file)
@@ -479,7 +479,7 @@ void mxc_isi_channel_set_csc(struct mxc_isi_dev *mxc_isi);
 void mxc_isi_channel_set_alpha_roi0(struct mxc_isi_dev *mxc_isi,
                        struct v4l2_rect *rect);
 void mxc_isi_channel_set_alpha(struct mxc_isi_dev *mxc_isi);
-void mxc_isi_channel_set_4k(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_chain_buf(struct mxc_isi_dev *mxc_isi);
 void mxc_isi_channel_set_deinterlace(struct mxc_isi_dev *mxc_isi);
 void mxc_isi_channel_set_crop(struct mxc_isi_dev *mxc_isi);
 void mxc_isi_channel_set_memory_image(struct mxc_isi_dev *mxc_isi);
index 8a48199..5c7ee3b 100644 (file)
@@ -162,6 +162,13 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
                        break;
 
                case ISI_INPUT_INTERFACE_HDMI:
+                       if (mxc_md->hdmi_rx == NULL)
+                               continue;
+                       source = &mxc_md->hdmi_rx->sd.entity;
+                       source_pad = MXC_HDMI_RX_PAD_SOURCE;
+                       sink_pad = MXC_ISI_SD_PAD_SINK_HDMI;
+                       break;
+
                case ISI_INPUT_INTERFACE_DC0:
                case ISI_INPUT_INTERFACE_DC1:
                case ISI_INPUT_INTERFACE_MEM:
@@ -228,15 +235,15 @@ static int mxc_md_create_links(struct mxc_md *mxc_md)
                                return ret;
                        v4l2_info(&mxc_md->v4l2_dev, "created link [%s] => [%s]\n",
                                                sensor->sd->entity.name, pcsidev->sd.entity.name);
-               } else {
+               } else if (mxc_md->mipi_csi2) {
                        mipi_csi2 = mxc_md->mipi_csi2[sensor->id];
                        if (mipi_csi2 ==  NULL)
                                continue;
                        source = &sensor->sd->entity;
                        sink = &mipi_csi2->sd.entity;
 
-                       source_pad = 0;  //sensor source pad: MIPI_CSI2_SENS_VC0_PAD_SOURCE
-                       sink_pad = source_pad;  //mipi sink pad: MXC_MIPI_CSI2_VC0_PAD_SINK;
+                       source_pad = 0;  /* sensor source pad: MIPI_CSI2_SENS_VC0_PAD_SOURCE */
+                       sink_pad = source_pad;  /* mipi sink pad: MXC_MIPI_CSI2_VC0_PAD_SINK; */
 
                        if (mipi_csi2->vchannel == true)
                                mipi_vc = 4;
@@ -277,6 +284,7 @@ static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
        struct mxc_sensor_info *sensor = NULL;
        int i;
 
+       dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
        /* Find platform data for this sensor subdev */
        for (i = 0; i < ARRAY_SIZE(mxc_md->sensor); i++) {
                if (mxc_md->sensor[i].asd.match.fwnode ==
@@ -304,6 +312,7 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
        struct mxc_md *mxc_md = notifier_to_mxc_md(notifier);
        int ret;
 
+       dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
        mutex_lock(&mxc_md->media_dev.graph_mutex);
 
        ret = mxc_md_create_links(mxc_md);
@@ -337,7 +346,7 @@ void mxc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
        return;
 }
 
-/* Register mipi sensor sub-devices */
+/* Register mipi sensor / Parallel CSI / HDMI Rx sub-devices */
 static int register_sensor_entities(struct mxc_md *mxc_md)
 {
        struct device_node *parent = mxc_md->pdev->dev.of_node;
@@ -347,10 +356,20 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
 
        mxc_md->num_sensors = 0;
 
-       /* Attach sensors linked to MIPI CSI2 */
+       /* Attach sensors linked to MIPI CSI2 / paralle csi / HDMI Rx */
        for_each_available_child_of_node(parent, node) {
                struct device_node *port;
 
+               if (!of_node_cmp(node->name, "hdmi_rx")) {
+                       mxc_md->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+                       mxc_md->sensor[index].asd.match.fwnode = of_fwnode_handle(node);
+                       mxc_md->async_subdevs[index] = &mxc_md->sensor[index].asd;
+
+                       mxc_md->num_sensors++;
+                       index++;
+                       continue;
+               }
+
                if (of_node_cmp(node->name, "csi") &&
                        of_node_cmp(node->name, "pcsi"))
                        continue;
@@ -369,7 +388,7 @@ static int register_sensor_entities(struct mxc_md *mxc_md)
                        return -EINVAL;
 
                v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint);
-               if (WARN_ON(endpoint.base.port >= MXC_MAX_MIPI_SENSORS)) {
+               if (WARN_ON(endpoint.base.port >= MXC_MAX_SENSORS)) {
                        v4l2_err(&mxc_md->v4l2_dev, "Failed to get sensor endpoint\n");
                        return -EINVAL;
                }
@@ -455,6 +474,18 @@ static int register_parallel_csi_entity(struct mxc_md *mxc_md,
        return ret;
 }
 
+static int register_hdmi_rx_entity(struct mxc_md *mxc_md,
+                               struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+       struct v4l2_subdev *sd = &hdmi_rx->sd;;
+
+       dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
+       sd->grp_id = GRP_ID_MXC_HDMI_RX;
+       mxc_md->hdmi_rx = hdmi_rx;
+
+       return 0;
+}
+
 static int mxc_md_register_platform_entity(struct mxc_md *mxc_md,
                                            struct platform_device *pdev,
                                            int plat_entity)
@@ -482,6 +513,9 @@ static int mxc_md_register_platform_entity(struct mxc_md *mxc_md,
                case IDX_PARALLEL_CSI:
                        ret = register_parallel_csi_entity(mxc_md, drvdata);
                        break;
+               case IDX_HDMI_RX:
+                       ret = register_hdmi_rx_entity(mxc_md, drvdata);
+                       break;
                default:
                        ret = -ENODEV;
                }
@@ -500,7 +534,7 @@ dev_unlock:
        return ret;
 }
 
-/* Register ISI, MIPI CSI2 and HDMI In Media entities */
+/* Register ISI, MIPI CSI2 and HDMI Rx Media entities */
 static int mxc_md_register_platform_entities(struct mxc_md *mxc_md,
                                              struct device_node *parent)
 {
@@ -522,6 +556,8 @@ static int mxc_md_register_platform_entities(struct mxc_md *mxc_md,
                        plat_entity = IDX_MIPI_CSI2;
                else if (!strcmp(node->name, PARALLEL_CSI_OF_NODE_NAME))
                        plat_entity = IDX_PARALLEL_CSI;
+               else if (!strcmp(node->name, MXC_HDMI_RX_NODE_NAME))
+                       plat_entity = IDX_HDMI_RX;
 
                if (plat_entity >= 0)
                        ret = mxc_md_register_platform_entity(mxc_md, pdev,
@@ -781,7 +817,7 @@ static int mxc_md_probe(struct platform_device *pdev)
                ret = v4l2_async_notifier_register(&mxc_md->v4l2_dev,
                                                &mxc_md->subdev_notifier);
                if (ret < 0) {
-                       printk("Sensor register failed\n");
+                       dev_warn(&mxc_md->pdev->dev, "Sensor register failed\n");
                        goto err_m_ent;
                }
 
index 5869cc1..d5ee923 100644 (file)
 #include "mxc-mipi-csi2.h"
 #include "mxc-isi-core.h"
 #include "mxc-isi-hw.h"
+#include "hdmi/mxc-hdmi-rx.h"
 
 #define MXC_MD_DRIVER_NAME     "mxc-md"
-#define MXC_MAX_MIPI_SENSORS 2
+#define MXC_MAX_SENSORS 3
 
 #define MJPEG_DEC_OF_NODE_NAME "jpegdec"
 #define MJPEG_ENC_OF_NODE_NAME "jpegenc"
@@ -52,7 +53,7 @@
 #define GRP_ID_MXC_SENSOR              (1 << 8)
 #define GRP_ID_MXC_ISI                 (1 << 9)
 #define GRP_ID_MXC_MIPI_CSI2   (1 << 11)
-#define GRP_ID_MXC_HDMI_IN             (1 << 12)
+#define GRP_ID_MXC_HDMI_RX             (1 << 12)
 #define GRP_ID_MXC_MJPEG_DEC   (1 << 13)
 #define GRP_ID_MXC_MJPEG_ENC   (1 << 14)
 #define GRP_ID_MXC_PARALLEL_CSI (1 << 15)
@@ -61,7 +62,7 @@ enum mxc_subdev_index {
        IDX_SENSOR,
        IDX_ISI,
        IDX_MIPI_CSI2,
-       IDX_HDMI_IN,
+       IDX_HDMI_RX,
        IDX_MJPEG_ENC,
        IDX_MJPEG_DEC,
        IDX_PARALLEL_CSI,
@@ -88,10 +89,10 @@ struct mxc_mjpeg_enc{
 
 struct mxc_md {
        struct mxc_isi_dev *mxc_isi[MXC_ISI_MAX_DEVS];
-       struct mxc_hdmi_in_dev *hdmi_in;
+       struct mxc_hdmi_rx_dev *hdmi_rx;
        struct mxc_parallel_csi_dev *pcsidev;
        struct mxc_mipi_csi2_dev *mipi_csi2[MXC_MIPI_CSI2_MAX_DEVS];
-       struct mxc_sensor_info sensor[MXC_MAX_MIPI_SENSORS];
+       struct mxc_sensor_info sensor[MXC_MAX_SENSORS];
        struct mxc_mjpeg_dec  *mjpeg_dec;
        struct mxc_mjpeg_enc  *mjpeg_enc;
 
@@ -105,7 +106,7 @@ struct mxc_md {
        struct platform_device *pdev;
 
        struct v4l2_async_notifier subdev_notifier;
-       struct v4l2_async_subdev *async_subdevs[MXC_MAX_MIPI_SENSORS];
+       struct v4l2_async_subdev *async_subdevs[MXC_MAX_SENSORS];
 };
 
 static inline struct mxc_md *notifier_to_mxc_md(struct v4l2_async_notifier *n)