+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/rockchip/cru.h>
#include <linux/rockchip/grf.h>
#include <linux/rockchip/iomap.h>
#include "rockchip_hdmiv2.h"
#include "rockchip_hdmiv2_hw.h"
+#include <linux/rockchip/grf.h>
+
+#define HDMI_SEL_LCDC(x, bit) ((((x) & 1) << bit) | (1 << (16 + bit)))
+#define grf_writel(v, offset) writel_relaxed(v, RK_GRF_VIRT + offset)
+#define RK3399_GRF_SOC_CON20 0x6250
static const struct phy_mpll_config_tab PHY_MPLL_TABLE[] = {
- /*tmdsclk = (pixclk / ref_cntrl ) * (fbdiv2 * fbdiv1) / nctrl / tmdsmhl
- opmode: 0:HDMI1.4 1:HDMI2.0
- */
-/* |pixclock| tmdsclock|pixrepet|colordepth|prepdiv|tmdsmhl|opmode|
- fbdiv2|fbdiv1|ref_cntrl|nctrl|propctrl|intctrl|gmpctrl| */
+/* tmdsclk = (pixclk / ref_cntrl ) * (fbdiv2 * fbdiv1) / nctrl / tmdsmhl
+ * opmode: 0:HDMI1.4 1:HDMI2.0
+ *
+ * |pixclock| tmdsclock|pixrepet|colordepth|prepdiv|tmdsmhl|opmode|
+ * fbdiv2|fbdiv1|ref_cntrl|nctrl|propctrl|intctrl|gmpctrl|
+ */
{27000000, 27000000, 0, 8, 0, 0, 0,
2, 3, 0, 3, 3, 0, 0},
+ {27000000, 27000000, 1, 8, 0, 0, 0,
+ 2, 3, 0, 3, 3, 0, 0},
{27000000, 33750000, 0, 10, 1, 0, 0,
5, 1, 0, 3, 3, 0, 0},
+ {27000000, 33750000, 1, 10, 1, 0, 0,
+ 5, 1, 0, 3, 3, 0, 0},
{27000000, 40500000, 0, 12, 2, 0, 0,
3, 3, 0, 3, 3, 0, 0},
{27000000, 54000000, 0, 16, 3, 0, 0,
2, 3, 0, 2, 5, 0, 1},
-/* {74250000, 74250000, 0, 8, 0, 0, 0,
- 1, 3, 0, 2, 5, 0, 1}, */
+ {59400000, 59400000, 0, 8, 0, 0, 0,
+ 1, 3, 0, 2, 5, 0, 1},
+ {59400000, 74250000, 0, 10, 1, 0, 0,
+ 5, 0, 0, 2, 5, 0, 1},
+ {59400000, 89100000, 0, 12, 2, 0, 0,
+ 2, 2, 0, 2, 5, 0, 1},
+ {59400000, 118800000, 0, 16, 3, 0, 0,
+ 1, 3, 0, 1, 7, 0, 2},
+ {65000000, 65000000, 0, 8, 0, 0, 0,
+ 1, 3, 0, 2, 5, 0, 1},
{74250000, 74250000, 0, 8, 0, 0, 0,
4, 3, 3, 2, 7, 0, 3},
{74250000, 92812500, 0, 10, 1, 0, 0,
1, 2, 0, 1, 7, 0, 2},
{74250000, 148500000, 0, 16, 3, 0, 0,
1, 3, 0, 1, 7, 0, 2},
+ {83500000, 83500000, 0, 8, 0, 0, 0,
+ 1, 3, 0, 2, 5, 0, 1},
+ {85500000, 85500000, 0, 8, 0, 0, 0,
+ 1, 3, 0, 2, 5, 0, 1},
+ {106500000, 106500000, 0, 8, 0, 0, 0,
+ 1, 1, 0, 1, 7, 0, 2},
+ {108000000, 108000000, 0, 8, 0, 0, 0,
+ 1, 1, 0, 1, 7, 0, 2},
+ {146250000, 146250000, 0, 8, 0, 0, 0,
+ 1, 1, 0, 1, 7, 0, 2},
{148500000, 74250000, 0, 8, 0, 0, 0,
1, 1, 1, 1, 0, 0, 3},
{148500000, 148500000, 0, 8, 0, 0, 0,
1, 2, 1, 0, 7, 0, 3},
{148500000, 297000000, 0, 16, 3, 0, 0,
1, 1, 0, 0, 7, 0, 3},
+ {148500000, 297000000, 0, 8, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0, 3},
+ {148500000, 594000000, 0, 8, 0, 3, 1,
+ 1, 3, 0, 0, 0, 0, 3},
+ {269390000, 269390000, 0, 8, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 3},
+ {285000000, 285000000, 0, 8, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 3},
{297000000, 148500000, 0, 8, 0, 0, 0,
1, 0, 1, 0, 0, 0, 3},
{297000000, 297000000, 0, 8, 0, 0, 0,
1, 0, 0, 0, 0, 0, 3},
{297000000, 371250000, 0, 10, 1, 3, 1,
- 5, 0, 3, 0, 7, 0, 3},
+ 5, 1, 3, 1, 7, 0, 3},
{297000000, 445500000, 0, 12, 2, 3, 1,
- 1, 2, 2, 0, 7, 0, 3},
- {297000000, 594000000, 0, 16, 1, 3, 1,
+ 1, 2, 0, 1, 7, 0, 3},
+ {297000000, 594000000, 0, 16, 3, 3, 1,
1, 3, 1, 0, 0, 0, 3},
-/* {594000000, 297000000, 0, 8, 0, 0, 0,
- 1, 3, 3, 1, 0, 0, 3},*/
+ {340000000, 340000000, 0, 8, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 3},
+ {403000000, 403000000, 0, 8, 0, 3, 1,
+ 1, 3, 3, 0, 0, 0, 3},
{594000000, 297000000, 0, 8, 0, 0, 0,
1, 0, 1, 0, 0, 0, 3},
+ {594000000, 371250000, 0, 10, 1, 3, 1,
+ 5, 0, 3, 1, 7, 0, 3},
+ {594000000, 445500000, 0, 12, 2, 3, 1,
+ 1, 2, 1, 1, 7, 0, 3},
+ {594000000, 594000000, 0, 16, 3, 3, 1,
+ 1, 3, 3, 0, 0, 0, 3},
{594000000, 594000000, 0, 8, 0, 3, 1,
1, 3, 3, 0, 0, 0, 3},
};
+
+static const struct ext_pll_config_tab EXT_PLL_TABLE[] = {
+ {27000000, 27000000, 8, 1, 90, 3, 2,
+ 2, 10, 3, 3, 4, 0, 1, 40,
+ 8},
+ {27000000, 33750000, 10, 1, 90, 1, 3,
+ 3, 10, 3, 3, 4, 0, 1, 40,
+ 8},
+ {59400000, 59400000, 8, 1, 99, 3, 2,
+ 2, 1, 3, 3, 4, 0, 1, 40,
+ 8},
+ {59400000, 74250000, 10, 1, 99, 1, 2,
+ 2, 1, 3, 3, 4, 0, 1, 40,
+ 8},
+ {74250000, 74250000, 8, 1, 99, 1, 2,
+ 2, 1, 2, 3, 4, 0, 1, 40,
+ 8},
+ {74250000, 92812500, 10, 4, 495, 1, 2,
+ 2, 1, 3, 3, 4, 0, 2, 40,
+ 4},
+ {148500000, 148500000, 8, 1, 99, 1, 1,
+ 1, 1, 2, 2, 2, 0, 2, 40,
+ 4},
+ {148500000, 185625000, 10, 4, 495, 0, 2,
+ 2, 1, 3, 2, 2, 0, 4, 40,
+ 2},
+ {297000000, 297000000, 8, 1, 99, 0, 1,
+ 1, 1, 0, 2, 2, 0, 4, 40,
+ 2},
+ {297000000, 371250000, 10, 4, 495, 1, 2,
+ 0, 1, 3, 1, 1, 0, 8, 40,
+ 1},
+ {594000000, 297000000, 8, 1, 99, 0, 1,
+ 1, 1, 0, 2, 1, 0, 4, 40,
+ 2},
+ {594000000, 371250000, 10, 4, 495, 1, 2,
+ 0, 1, 3, 1, 1, 1, 8, 40,
+ 1},
+ {594000000, 594000000, 8, 1, 99, 0, 2,
+ 0, 1, 0, 1, 1, 0, 8, 40,
+ 1},
+};
+
/* ddc i2c master reset */
static void rockchip_hdmiv2_i2cm_reset(struct hdmi_dev *hdmi_dev)
{
static void rockchip_hdmiv2_i2cm_write_data(struct hdmi_dev *hdmi_dev,
u8 data, u8 offset)
{
- u8 interrupt;
+ u8 interrupt = 0;
int trytime = 2;
int i = 20;
static int rockchip_hdmiv2_i2cm_read_data(struct hdmi_dev *hdmi_dev, u8 offset)
{
- u8 interrupt, val;
+ u8 interrupt = 0, val;
int trytime = 2;
int i = 20;
static void rockchip_hdmiv2_i2cm_mask_int(struct hdmi_dev *hdmi_dev, int mask)
{
- if (0 == mask) {
+ if (!mask) {
hdmi_msk_reg(hdmi_dev, I2CM_INT,
m_I2CM_DONE_MASK, v_I2CM_DONE_MASK(0));
hdmi_msk_reg(hdmi_dev, I2CM_CTLINT,
}
}
-#define I2C_DIV_FACTOR 100000
+#define I2C_DIV_FACTOR 1000000
static u16 i2c_count(u16 sfrclock, u16 sclmintime)
{
unsigned long tmp_scl_period = 0;
return (u16)(tmp_scl_period);
}
-#define EDID_I2C_MIN_SS_SCL_HIGH_TIME 50000
-#define EDID_I2C_MIN_SS_SCL_LOW_TIME 50000
+#define EDID_I2C_MIN_SS_SCL_HIGH_TIME 9625
+#define EDID_I2C_MIN_SS_SCL_LOW_TIME 10000
static void rockchip_hdmiv2_i2cm_clk_init(struct hdmi_dev *hdmi_dev)
{
- /* Set DDC I2C CLK which devided from DDC_CLK. */
+ int value;
+
+ /* Set DDC I2C CLK which divided from DDC_CLK. */
+ value = i2c_count(24000, EDID_I2C_MIN_SS_SCL_HIGH_TIME);
hdmi_writel(hdmi_dev, I2CM_SS_SCL_HCNT_0_ADDR,
- i2c_count(24000, EDID_I2C_MIN_SS_SCL_HIGH_TIME));
+ value & 0xff);
+ hdmi_writel(hdmi_dev, I2CM_SS_SCL_HCNT_1_ADDR,
+ (value >> 8) & 0xff);
+ value = i2c_count(24000, EDID_I2C_MIN_SS_SCL_LOW_TIME);
hdmi_writel(hdmi_dev, I2CM_SS_SCL_LCNT_0_ADDR,
- i2c_count(24000, EDID_I2C_MIN_SS_SCL_LOW_TIME));
+ value & 0xff);
+ hdmi_writel(hdmi_dev, I2CM_SS_SCL_LCNT_1_ADDR,
+ (value >> 8) & 0xff);
hdmi_msk_reg(hdmi_dev, I2CM_DIV, m_I2CM_FAST_STD_MODE,
v_I2CM_FAST_STD_MODE(STANDARD_MODE));
}
rockchip_hdmiv2_i2cm_write_data(hdmi_dev, version, SCDC_SOURCE_VER);
}
-
static void rockchip_hdmiv2_scdc_read_request(struct hdmi_dev *hdmi_dev,
int enable)
{
m_I2CM_READ_UPDATE, v_I2CM_READ_UPDATE(1));
}
-
static int rockchip_hdmiv2_scdc_get_scambling_status(struct hdmi_dev *hdmi_dev)
{
int val;
rockchip_hdmiv2_i2cm_mask_int(hdmi_dev, 0);/*enable interrupt*/
}
+static void rockchip_hdmiv2_scdc_set_tmds_rate(struct hdmi_dev *hdmi_dev)
+{
+ int stat;
+
+ mutex_lock(&hdmi_dev->ddc_lock);
+ rockchip_hdmiv2_scdc_init(hdmi_dev);
+ stat = rockchip_hdmiv2_i2cm_read_data(hdmi_dev,
+ SCDC_TMDS_CONFIG);
+ if (hdmi_dev->tmdsclk > 340000000)
+ stat |= 2;
+ else
+ stat &= 0x1;
+ rockchip_hdmiv2_i2cm_write_data(hdmi_dev,
+ stat, SCDC_TMDS_CONFIG);
+ mutex_unlock(&hdmi_dev->ddc_lock);
+}
static int rockchip_hdmiv2_scrambling_enable(struct hdmi_dev *hdmi_dev,
int enable)
{
HDMIDBG("%s enable %d\n", __func__, enable);
- if (1 == enable) {
+ if (enable == 1) {
/* Write on Rx the bit Scrambling_Enable, register 0x20 */
rockchip_hdmiv2_i2cm_write_data(hdmi_dev, 1, SCDC_TMDS_CONFIG);
/* TMDS software reset request */
return 0;
}
+static const struct ext_pll_config_tab *get_phy_ext_tab(
+ unsigned int pixclock, unsigned int tmdsclk,
+ char colordepth)
+{
+ int i;
+ if (pixclock == 0)
+ return NULL;
+ HDMIDBG("%s pixClock %u tmdsclk %u colorDepth %d\n",
+ __func__, pixclock, tmdsclk, colordepth);
+ for (i = 0; i < ARRAY_SIZE(EXT_PLL_TABLE); i++) {
+ if ((EXT_PLL_TABLE[i].pix_clock == pixclock) &&
+ (EXT_PLL_TABLE[i].tmdsclock == tmdsclk) &&
+ (EXT_PLL_TABLE[i].color_depth == colordepth))
+ return &EXT_PLL_TABLE[i];
+ }
+ return NULL;
+}
static const struct phy_mpll_config_tab *get_phy_mpll_tab(
unsigned int pixclock, unsigned int tmdsclk,
if (pixclock == 0)
return NULL;
- HDMIDBG("%s pixClock %u pixRepet %d colorDepth %d\n",
- __func__, pixclock, pixrepet, colordepth);
+ HDMIDBG("%s pixClock %u tmdsclk %u pixRepet %d colorDepth %d\n",
+ __func__, pixclock, tmdsclk, pixrepet, colordepth);
for (i = 0; i < ARRAY_SIZE(PHY_MPLL_TABLE); i++) {
if ((PHY_MPLL_TABLE[i].pix_clock == pixclock) &&
(PHY_MPLL_TABLE[i].tmdsclock == tmdsclk) &&
static void rockchip_hdmiv2_powerdown(struct hdmi_dev *hdmi_dev)
{
- hdmi_msk_reg(hdmi_dev, PHY_CONF0,
- m_PDDQ_SIG | m_TXPWRON_SIG | m_ENHPD_RXSENSE_SIG,
- v_PDDQ_SIG(1) | v_TXPWRON_SIG(0) |
- v_ENHPD_RXSENSE_SIG(1));
+ hdmi_msk_reg(hdmi_dev, PHY_MASK, m_PHY_LOCK, v_PHY_LOCK(1));
+ if (hdmi_dev->soctype != HDMI_SOC_RK322X) {
+ hdmi_msk_reg(hdmi_dev, PHY_CONF0,
+ m_PDDQ_SIG | m_TXPWRON_SIG |
+ m_ENHPD_RXSENSE_SIG | m_SVSRET_SIG,
+ v_PDDQ_SIG(1) | v_TXPWRON_SIG(0) |
+ v_ENHPD_RXSENSE_SIG(1)) | v_SVSRET_SIG(0);
+ } else {
+ hdmi_msk_reg(hdmi_dev, PHY_CONF0,
+ m_TXPWRON_SIG | m_ENHPD_RXSENSE_SIG,
+ v_TXPWRON_SIG(0) | v_ENHPD_RXSENSE_SIG(0));
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON2,
+ RK322X_PLL_PDATA_DEN);
+ }
hdmi_writel(hdmi_dev, MC_CLKDIS, 0x7f);
}
-static int rockchip_hdmiv2_write_phy(struct hdmi_dev *hdmi_dev,
- int reg_addr, int val)
+int rockchip_hdmiv2_write_phy(struct hdmi_dev *hdmi_dev,
+ int reg_addr, int val)
{
int trytime = 2, i = 0, op_status = 0;
+ if (hdmi_dev->phybase) {
+ writel_relaxed(val, hdmi_dev->phybase + (reg_addr) * 0x04);
+ return 0;
+ }
while (trytime--) {
hdmi_writel(hdmi_dev, PHY_I2CM_ADDRESS, reg_addr);
hdmi_writel(hdmi_dev, PHY_I2CM_DATAO_1, (val >> 8) & 0xff);
break;
}
- if (op_status & m_I2CMPHY_DONE)
- return 0;
- else
+ if (!(op_status & m_I2CMPHY_DONE))
dev_err(hdmi_dev->hdmi->dev,
"[%s] operation error,trytime=%d\n",
__func__, trytime);
+ else
+ return 0;
msleep(100);
}
return -1;
}
-static int __maybe_unused rockchip_hdmiv2_read_phy(struct hdmi_dev *hdmi_dev,
- int reg_addr)
+int rockchip_hdmiv2_read_phy(struct hdmi_dev *hdmi_dev,
+ int reg_addr)
{
int trytime = 2, i = 0, op_status = 0;
int val = 0;
+ if (hdmi_dev->phybase)
+ return readl_relaxed(hdmi_dev->phybase + (reg_addr) * 0x04);
+
while (trytime--) {
hdmi_writel(hdmi_dev, PHY_I2CM_ADDRESS, reg_addr);
hdmi_writel(hdmi_dev, PHY_I2CM_DATAI_1, 0x00);
break;
}
- if (op_status & m_I2CMPHY_DONE) {
+ if (!(op_status & m_I2CMPHY_DONE)) {
+ pr_err("[%s] operation error,trytime=%d\n",
+ __func__, trytime);
+ } else {
val = hdmi_readl(hdmi_dev, PHY_I2CM_DATAI_1);
val = (val & 0xff) << 8;
val += (hdmi_readl(hdmi_dev, PHY_I2CM_DATAI_0) & 0xff);
pr_debug("phy_reg0x%02x: 0x%04x",
reg_addr, val);
return val;
- } else {
- pr_err("[%s] operation error,trytime=%d\n",
- __func__, trytime);
}
msleep(100);
}
return -1;
}
-void rockchip_hdmiv2_dump_phy_regs(struct hdmi_dev *hdmi_dev)
+#define PHY_TIMEOUT 10000
+
+static int ext_phy_config(struct hdmi_dev *hdmi_dev)
{
- int i;
+ int stat = 0, i = 0, temp;
+ const struct ext_pll_config_tab *phy_ext = NULL;
+
+ if (hdmi_dev->grf_base)
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON2,
+ RK322X_PLL_POWER_DOWN |
+ RK322X_PLL_PDATA_DEN);
+ if (hdmi_dev->tmdsclk_ratio_change &&
+ hdmi_dev->hdmi->edid.scdc_present == 1)
+ rockchip_hdmiv2_scdc_set_tmds_rate(hdmi_dev);
+
+ /* config the required PHY I2C register */
+ phy_ext = get_phy_ext_tab(hdmi_dev->pixelclk,
+ hdmi_dev->tmdsclk,
+ hdmi_dev->colordepth);
+ if (phy_ext) {
+ stat = ((phy_ext->pll_nf >> 1) & EXT_PHY_PLL_FB_BIT8_MASK) |
+ ((phy_ext->vco_div_5 & 1) << 5) |
+ (phy_ext->pll_nd & EXT_PHY_PLL_PRE_DIVIDER_MASK);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PLL_PRE_DIVIDER, stat);
+ stat = phy_ext->pll_nf & 0xff;
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PLL_FB_DIVIDER, stat);
+ stat = (phy_ext->pclk_divider_a & EXT_PHY_PCLK_DIVIDERA_MASK) |
+ ((phy_ext->pclk_divider_b & 3) << 5);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PCLK_DIVIDER1, stat);
+ stat = (phy_ext->pclk_divider_d & EXT_PHY_PCLK_DIVIDERD_MASK) |
+ ((phy_ext->pclk_divider_c & 3) << 5);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PCLK_DIVIDER2, stat);
+ stat = ((phy_ext->tmsd_divider_c & 3) << 4) |
+ ((phy_ext->tmsd_divider_a & 3) << 2) |
+ (phy_ext->tmsd_divider_b & 3);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_TMDSCLK_DIVIDER, stat);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PPLL_FB_DIVIDER,
+ phy_ext->ppll_nf);
+
+ if (phy_ext->ppll_no == 1) {
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PPLL_POST_DIVIDER,
+ 0);
+ stat = 0x20 | phy_ext->ppll_nd;
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PPLL_PRE_DIVIDER,
+ stat);
+ } else {
+ stat = ((phy_ext->ppll_no / 2) - 1) << 4;
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PPLL_POST_DIVIDER,
+ stat);
+ stat = 0xe0 | phy_ext->ppll_nd;
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PPLL_PRE_DIVIDER,
+ stat);
+ }
+ } else {
+ pr_err("%s no supported phy configuration.\n", __func__);
+ return -1;
+ }
- for (i = 0; i < 0x28; i++)
- pr_info("phy reg %02x val %04x\n",
- i, rockchip_hdmiv2_read_phy(hdmi_dev, i));
+ if (hdmi_dev->phy_table) {
+ for (i = 0; i < hdmi_dev->phy_table_size; i++) {
+ temp = hdmi_dev->phy_table[i].maxfreq;
+ if (hdmi_dev->tmdsclk <= temp)
+ break;
+ }
+ }
+
+ if (i != hdmi_dev->phy_table_size) {
+ if (hdmi_dev->phy_table[i].slopeboost) {
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_SIGNAL_CTRL, 0xff);
+ temp = hdmi_dev->phy_table[i].slopeboost - 1;
+ stat = ((temp & 3) << 6) | ((temp & 3) << 4) |
+ ((temp & 3) << 2) | (temp & 3);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_SLOPEBOOST, stat);
+ } else {
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_SIGNAL_CTRL, 0x0f);
+ }
+ stat = ((hdmi_dev->phy_table[i].pre_emphasis & 3) << 4) |
+ ((hdmi_dev->phy_table[i].pre_emphasis & 3) << 2) |
+ (hdmi_dev->phy_table[i].pre_emphasis & 3);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_PREEMPHASIS, stat);
+ stat = ((hdmi_dev->phy_table[i].clk_level & 0xf) << 4) |
+ (hdmi_dev->phy_table[i].data2_level & 0xf);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_LEVEL1, stat);
+ stat = ((hdmi_dev->phy_table[i].data1_level & 0xf) << 4) |
+ (hdmi_dev->phy_table[i].data0_level & 0xf);
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_LEVEL2, stat);
+ } else {
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ EXT_PHY_SIGNAL_CTRL, 0x0f);
+ }
+ rockchip_hdmiv2_write_phy(hdmi_dev, 0xf3, 0x22);
+
+ stat = clk_get_rate(hdmi_dev->pclk_phy) / 100000;
+ rockchip_hdmiv2_write_phy(hdmi_dev, EXT_PHY_TERM_CAL,
+ ((stat >> 8) & 0xff) | 0x80);
+ rockchip_hdmiv2_write_phy(hdmi_dev, EXT_PHY_TERM_CAL_DIV_L,
+ stat & 0xff);
+ if (hdmi_dev->tmdsclk > 340000000)
+ stat = EXT_PHY_AUTO_R100_OHMS;
+ else if (hdmi_dev->tmdsclk > 200000000)
+ stat = EXT_PHY_AUTO_R50_OHMS;
+ else
+ stat = EXT_PHY_AUTO_ROPEN_CIRCUIT;
+ rockchip_hdmiv2_write_phy(hdmi_dev, EXT_PHY_TERM_RESIS_AUTO,
+ stat | 0x20);
+ rockchip_hdmiv2_write_phy(hdmi_dev, EXT_PHY_TERM_CAL,
+ (stat >> 8) & 0xff);
+ if (hdmi_dev->tmdsclk > 200000000)
+ stat = 0;
+ else
+ stat = 0x11;
+ rockchip_hdmiv2_write_phy(hdmi_dev, EXT_PHY_PLL_BW, stat);
+ rockchip_hdmiv2_write_phy(hdmi_dev, EXT_PHY_PPLL_BW, 0x27);
+ if (hdmi_dev->grf_base)
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON2,
+ RK322X_PLL_POWER_UP);
+ if (hdmi_dev->tmdsclk_ratio_change)
+ msleep(100);
+ else
+ usleep_range(900, 1000);
+ hdmi_msk_reg(hdmi_dev, PHY_CONF0,
+ m_TXPWRON_SIG, v_TXPWRON_SIG(1));
+ i = 0;
+ while (i++ < PHY_TIMEOUT) {
+ if ((i % 10) == 0) {
+ temp = EXT_PHY_PPLL_POST_DIVIDER;
+ stat = rockchip_hdmiv2_read_phy(hdmi_dev, temp);
+ if (stat & EXT_PHY_PPLL_LOCK_STATUS_MASK)
+ break;
+ usleep_range(1000, 2000);
+ }
+ }
+ if ((stat & EXT_PHY_PPLL_LOCK_STATUS_MASK) == 0) {
+ stat = hdmi_readl(hdmi_dev, MC_LOCKONCLOCK);
+ dev_err(hdmi_dev->hdmi->dev,
+ "PHY PLL not locked: PCLK_ON=%ld,TMDSCLK_ON=%ld\n",
+ (stat & m_PCLK_ON) >> 6, (stat & m_TMDSCLK_ON) >> 5);
+ return -1;
+ }
+
+ if (hdmi_dev->grf_base)
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON2,
+ RK322X_PLL_PDATA_EN);
+
+ return 0;
}
static int rockchip_hdmiv2_config_phy(struct hdmi_dev *hdmi_dev)
int stat = 0, i = 0;
const struct phy_mpll_config_tab *phy_mpll = NULL;
+ if (hdmi_dev->soctype == HDMI_SOC_RK322X) {
+ return ext_phy_config(hdmi_dev);
+ } else if (hdmi_dev->soctype == HDMI_SOC_RK3366) {
+ if (hdmi_dev->pixelclk > 148500000)
+ clk_set_rate(hdmi_dev->pclk_phy, 148500000);
+ else
+ clk_set_rate(hdmi_dev->pclk_phy, hdmi_dev->pixelclk);
+ } else if (hdmi_dev->soctype == HDMI_SOC_RK3399) {
+ clk_set_rate(hdmi_dev->pclk_phy, hdmi_dev->pixelclk);
+ }
+
hdmi_msk_reg(hdmi_dev, PHY_I2CM_DIV,
m_PHY_I2CM_FAST_STD, v_PHY_I2CM_FAST_STD(0));
+ hdmi_msk_reg(hdmi_dev, PHY_MASK, m_PHY_LOCK, v_PHY_LOCK(1));
/* power off PHY */
- /* hdmi_writel(hdmi_dev, PHY_CONF0, 0x1e); */
hdmi_msk_reg(hdmi_dev, PHY_CONF0,
m_PDDQ_SIG | m_TXPWRON_SIG | m_SVSRET_SIG,
v_PDDQ_SIG(1) | v_TXPWRON_SIG(0) | v_SVSRET_SIG(1));
if (hdmi_dev->tmdsclk_ratio_change &&
- hdmi_dev->hdmi->edid.scdc_present == 1) {
- mutex_lock(&hdmi_dev->ddc_lock);
- rockchip_hdmiv2_scdc_init(hdmi_dev);
- stat = rockchip_hdmiv2_i2cm_read_data(hdmi_dev,
- SCDC_TMDS_CONFIG);
- if (hdmi_dev->tmdsclk > 340000000)
- stat |= 2;
- else
- stat &= 0x1;
- rockchip_hdmiv2_i2cm_write_data(hdmi_dev,
- stat, SCDC_TMDS_CONFIG);
- mutex_unlock(&hdmi_dev->ddc_lock);
- }
+ hdmi_dev->hdmi->edid.scdc_present == 1)
+ rockchip_hdmiv2_scdc_set_tmds_rate(hdmi_dev);
+
/* reset PHY */
hdmi_writel(hdmi_dev, MC_PHYRSTZ, v_PHY_RSTZ(1));
usleep_range(1000, 2000);
hdmi_writel(hdmi_dev, PHY_I2CM_SLAVE, PHY_GEN2_ADDR);
/* config the required PHY I2C register */
- phy_mpll = get_phy_mpll_tab(hdmi_dev->pixelclk,
- hdmi_dev->tmdsclk,
- hdmi_dev->pixelrepeat - 1,
- hdmi_dev->colordepth);
+ if (hdmi_dev->soctype == HDMI_SOC_RK3366 &&
+ hdmi_dev->pixelclk > 148500000)
+ phy_mpll = get_phy_mpll_tab(148500000,
+ hdmi_dev->tmdsclk,
+ hdmi_dev->pixelrepeat - 1,
+ hdmi_dev->colordepth);
+ else
+ phy_mpll = get_phy_mpll_tab(hdmi_dev->pixelclk,
+ hdmi_dev->tmdsclk,
+ hdmi_dev->pixelrepeat - 1,
+ hdmi_dev->colordepth);
if (phy_mpll) {
rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_OPMODE_PLLCFG,
v_PREP_DIV(phy_mpll->prep_div) |
v_MPLL_GMP_CNTRL(
phy_mpll->gmp_cntrl));
}
- if (hdmi_dev->tmdsclk <= 74250000) {
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_CLKSYMCTRL,
- v_OVERRIDE(1) | v_SLOPEBOOST(0) |
- v_TX_SYMON(1) | v_TX_TRAON(0) |
- v_TX_TRBON(0) | v_CLK_SYMON(1));
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_TERM_RESIS,
- v_TX_TERM(R100_OHMS));
- } else if (hdmi_dev->tmdsclk <= 148500000) {
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_CLKSYMCTRL,
- v_OVERRIDE(1) | v_SLOPEBOOST(1) |
- v_TX_SYMON(1) | v_TX_TRAON(0) |
- v_TX_TRBON(0) | v_CLK_SYMON(1));
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_TERM_RESIS,
- v_TX_TERM(R100_OHMS));
- } else if (hdmi_dev->tmdsclk <= 340000000) {
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_CLKSYMCTRL,
- v_OVERRIDE(1) | v_SLOPEBOOST(1) |
- v_TX_SYMON(1) | v_TX_TRAON(0) |
- v_TX_TRBON(0) | v_CLK_SYMON(1));
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_TERM_RESIS,
- v_TX_TERM(R100_OHMS));
- } else if (hdmi_dev->tmdsclk > 340000000) {
+
+ if (hdmi_dev->phy_table) {
+ for (i = 0; i < hdmi_dev->phy_table_size; i++)
+ if (hdmi_dev->tmdsclk <= hdmi_dev->phy_table[i].maxfreq)
+ break;
+ }
+ if (i == hdmi_dev->phy_table_size) {
+ pr_info("%s use default phy settings\n", __func__);
rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_CLKSYMCTRL,
v_OVERRIDE(1) | v_SLOPEBOOST(0) |
- v_TX_SYMON(1) | v_TX_TRAON(0) |
- v_TX_TRBON(0) | v_CLK_SYMON(1));
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_TERM_RESIS,
- v_TX_TERM(R100_OHMS));
+ v_TX_SYMON(1) | v_CLK_SYMON(1) |
+ v_PREEMPHASIS(0));
+ if (hdmi_dev->tmdsclk > 340000000)
+ rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_VLEVCTRL,
+ v_SUP_TXLVL(9) |
+ v_SUP_CLKLVL(17));
+ else if (hdmi_dev->tmdsclk > 165000000)
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ PHYTX_VLEVCTRL,
+ v_SUP_TXLVL(14) |
+ v_SUP_CLKLVL(17));
+ else
+ rockchip_hdmiv2_write_phy(hdmi_dev,
+ PHYTX_VLEVCTRL,
+ v_SUP_TXLVL(18) |
+ v_SUP_CLKLVL(17));
+ } else {
+ stat = v_OVERRIDE(1) | v_TX_SYMON(1) | v_CLK_SYMON(1) |
+ v_PREEMPHASIS(hdmi_dev->phy_table[i].pre_emphasis) |
+ v_SLOPEBOOST(hdmi_dev->phy_table[i].slopeboost);
+ rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_CLKSYMCTRL, stat);
+
+ stat = v_SUP_CLKLVL(hdmi_dev->phy_table[i].clk_level) |
+ v_SUP_TXLVL(hdmi_dev->phy_table[i].data0_level);
+ rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_VLEVCTRL, stat);
}
- if (hdmi_dev->tmdsclk < 297000000)
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_VLEVCTRL,
- v_SUP_TXLVL(18) | v_SUP_CLKLVL(17));
+ if (hdmi_dev->tmdsclk > 340000000)
+ rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_TERM_RESIS,
+ v_TX_TERM(R50_OHMS));
else
- rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_VLEVCTRL,
- v_SUP_TXLVL(14) | v_SUP_CLKLVL(13));
-
- rockchip_hdmiv2_write_phy(hdmi_dev, 0x05, 0x8000);
+ rockchip_hdmiv2_write_phy(hdmi_dev, PHYTX_TERM_RESIS,
+ v_TX_TERM(R100_OHMS));
+ /* rockchip_hdmiv2_write_phy(hdmi_dev, 0x05, 0x8000); */
if (hdmi_dev->tmdsclk_ratio_change)
msleep(100);
/* power on PHY */
hdmi_writel(hdmi_dev, PHY_CONF0, 0x2e);
- /*
- hdmi_msk_reg(hdmi_dev, PHY_CONF0,
- m_PDDQ_SIG | m_TXPWRON_SIG | m_ENHPD_RXSENSE_SIG,
- v_PDDQ_SIG(0) | v_TXPWRON_SIG(1) |
- v_ENHPD_RXSENSE_SIG(1));
- */
+
/* check if the PHY PLL is locked */
- #define PHY_TIMEOUT 10000
+
+ i = 0;
while (i++ < PHY_TIMEOUT) {
if ((i % 10) == 0) {
stat = hdmi_readl(hdmi_dev, PHY_STAT0);
if ((stat & m_PHY_LOCK) == 0) {
stat = hdmi_readl(hdmi_dev, MC_LOCKONCLOCK);
dev_err(hdmi_dev->hdmi->dev,
- "PHY PLL not locked: PCLK_ON=%d,TMDSCLK_ON=%d\n",
+ "PHY PLL not locked: PCLK_ON=%ld,TMDSCLK_ON=%ld\n",
(stat & m_PCLK_ON) >> 6, (stat & m_TMDSCLK_ON) >> 5);
return -1;
}
-
+ hdmi_msk_reg(hdmi_dev, PHY_MASK, m_PHY_LOCK, v_PHY_LOCK(0));
return 0;
}
v_HSYNC_POL(hsync_pol));
timing = (struct hdmi_video_timing *)hdmi_vic2timing(vpara->vic);
- if (timing == NULL) {
+ if (!timing) {
dev_err(hdmi_drv->dev,
"[%s] not found vic %d\n", __func__, vpara->vic);
return -ENOENT;
}
- mode = &(timing->mode);
+ mode = &timing->mode;
if (vpara->color_input == HDMI_COLOR_YCBCR420)
tmdsclk = mode->pixclock / 2;
+ else if (vpara->format_3d == HDMI_3D_FRAME_PACKING)
+ tmdsclk = 2 * mode->pixclock;
else
tmdsclk = mode->pixclock;
- switch (vpara->color_output_depth) {
- case 10:
- tmdsclk += tmdsclk / 4;
- break;
- case 12:
- tmdsclk += tmdsclk / 2;
- break;
- case 16:
- tmdsclk += tmdsclk;
- break;
- case 8:
- default:
- break;
+ if (vpara->color_output != HDMI_COLOR_YCBCR422) {
+ switch (vpara->color_output_depth) {
+ case 10:
+ tmdsclk += tmdsclk / 4;
+ break;
+ case 12:
+ tmdsclk += tmdsclk / 2;
+ break;
+ case 16:
+ tmdsclk += tmdsclk;
+ break;
+ case 8:
+ default:
+ break;
+ }
+ } else if (vpara->color_output_depth > 12) {
+ /* YCbCr422 mode only support up to 12bit */
+ vpara->color_output_depth = 12;
}
-
- if (tmdsclk > 594000000) {
+ if ((tmdsclk > 594000000) ||
+ (tmdsclk > 340000000 &&
+ tmdsclk > hdmi_drv->edid.maxtmdsclock)) {
+ pr_warn("out of max tmds clock, limit to 8bit\n");
vpara->color_output_depth = 8;
- tmdsclk = mode->pixclock;
+ if (vpara->color_input == HDMI_COLOR_YCBCR420)
+ tmdsclk = mode->pixclock / 2;
+ else if (vpara->format_3d != HDMI_3D_FRAME_PACKING)
+ tmdsclk = mode->pixclock;
+ else
+ return -1;
}
- pr_info("pixel clk is %u tmds clk is %u\n", mode->pixclock, tmdsclk);
- if ((tmdsclk > 340000000 && hdmi_dev->tmdsclk < 340000000) ||
+
+ if ((tmdsclk > 340000000) ||
(tmdsclk < 340000000 && hdmi_dev->tmdsclk > 340000000))
hdmi_dev->tmdsclk_ratio_change = true;
else
hdmi_dev->tmdsclk_ratio_change = false;
hdmi_dev->tmdsclk = tmdsclk;
- hdmi_dev->pixelclk = mode->pixclock;
+ if (vpara->format_3d == HDMI_3D_FRAME_PACKING)
+ hdmi_dev->pixelclk = 2 * mode->pixclock;
+ else
+ hdmi_dev->pixelclk = mode->pixclock;
hdmi_dev->pixelrepeat = timing->pixelrepeat;
- hdmi_dev->colordepth = vpara->color_output_depth;
-
- /* Video Register has already been set in uboot,
- so we no need to set again */
-
- if (hdmi_drv->uboot)
- return -1;
-
+ /* hdmi_dev->colordepth is used for find pll config.
+ * For YCbCr422, tmdsclk is same on all color depth.
+ */
+ if (vpara->color_output == HDMI_COLOR_YCBCR422)
+ hdmi_dev->colordepth = 8;
+ else
+ hdmi_dev->colordepth = vpara->color_output_depth;
+ pr_info("pixel clk is %lu tmds clk is %u\n",
+ hdmi_dev->pixelclk, hdmi_dev->tmdsclk);
/* Start/stop HDCP keepout window generation */
hdmi_msk_reg(hdmi_dev, FC_INVIDCONF,
m_FC_HDCP_KEEPOUT, v_FC_HDCP_KEEPOUT(1));
- if (hdmi_drv->edid.scdc_present == 1) {
- if (tmdsclk > 340000000) {/* used for HDMI 2.0 TX */
+ if (hdmi_drv->edid.scdc_present == 1 && !hdmi_drv->uboot) {
+ if (tmdsclk > 340000000 ||
+ hdmi_drv->edid.lte_340mcsc_scramble) {
+ /* used for HDMI 2.0 TX */
mutex_lock(&hdmi_dev->ddc_lock);
rockchip_hdmiv2_scdc_init(hdmi_dev);
sink_version =
rockchip_hdmiv2_scrambling_enable(hdmi_dev, 0);
mutex_unlock(&hdmi_dev->ddc_lock);
}
+ } else {
+ hdmi_msk_reg(hdmi_dev, FC_SCRAMBLER_CTRL,
+ m_FC_SCRAMBLE_EN, v_FC_SCRAMBLE_EN(0));
}
hdmi_msk_reg(hdmi_dev, FC_INVIDCONF,
v_FC_VSYNC_POL(vsync_pol) | v_FC_HSYNC_POL(hsync_pol) |
v_FC_DE_POL(de_pol) | v_FC_HDMI_DVI(vpara->sink_hdmi) |
v_FC_INTERLACE_MODE(mode->vmode));
- if (mode->vmode == FB_VMODE_INTERLACED)
+ if ((mode->vmode & FB_VMODE_INTERLACED) &&
+ vpara->format_3d != HDMI_3D_FRAME_PACKING)
hdmi_msk_reg(hdmi_dev, FC_INVIDCONF,
m_FC_VBLANK, v_FC_VBLANK(1));
else
hdmi_writel(hdmi_dev, FC_INHACTIV1, v_FC_HACTIVE1(value >> 8));
hdmi_writel(hdmi_dev, FC_INHACTIV0, (value & 0xff));
- value = mode->yres;
+ if (vpara->format_3d == HDMI_3D_FRAME_PACKING) {
+ if (mode->vmode == 0)
+ value = 2 * mode->yres +
+ mode->upper_margin +
+ mode->lower_margin +
+ mode->vsync_len;
+ else
+ value = 2 * mode->yres +
+ 3 * (mode->upper_margin +
+ mode->lower_margin +
+ mode->vsync_len) + 2;
+ } else {
+ value = mode->yres;
+ }
hdmi_writel(hdmi_dev, FC_INVACTIV1, v_FC_VACTIVE1(value >> 8));
hdmi_writel(hdmi_dev, FC_INVACTIV0, (value & 0xff));
value = mode->vsync_len;
hdmi_writel(hdmi_dev, FC_VSYNCINWIDTH, (value & 0xff));
- /*Set the control period minimum duration
- (min. of 12 pixel clock cycles, refer to HDMI 1.4b specification)*/
+ /* Set the control period minimum duration (min. of 12 pixel
+ * clock cycles, refer to HDMI 1.4b specification)
+ */
hdmi_writel(hdmi_dev, FC_CTRLDUR, 12);
hdmi_writel(hdmi_dev, FC_EXCTRLDUR, 32);
- hdmi_writel(hdmi_dev, FC_EXCTRLSPAC,
- (hdmi_dev->tmdsclk/1000) * 50 / (256 * 512));
-
-#if 0
/* spacing < 256^2 * config / tmdsClock, spacing <= 50ms
* worst case: tmdsClock == 25MHz => config <= 19
*/
- hdmi_writel(hdmi_dev, FC_EXCTRLSPAC, 1);
-
- /*Set PreambleFilter*/
- for (i = 0; i < 3; i++) {
- value = (i + 1) * 11;
- if (i == 0) /*channel 0*/
- hdmi_writel(hdmi_dev, FC_CH0PREAM, value);
- else if (i == 1) /*channel 1*/
- hdmi_writel(hdmi_dev, FC_CH1PREAM, value & 0x3f);
- else if (i == 2) /*channel 2*/
- hdmi_writel(hdmi_dev, FC_CH2PREAM, value & 0x3f);
- }
-#endif
+ hdmi_writel(hdmi_dev, FC_EXCTRLSPAC,
+ (hdmi_dev->tmdsclk / 1000) * 50 / (256 * 512));
- hdmi_writel(hdmi_dev, FC_PRCONF, v_FC_PR_FACTOR(timing->pixelrepeat));
+ hdmi_writel(hdmi_dev, FC_PRCONF,
+ v_FC_PR_FACTOR(timing->pixelrepeat) |
+ v_FC_PR_FACTOR_OUT(timing->pixelrepeat - 1));
return 0;
}
static int rockchip_hdmiv2_video_packetizer(struct hdmi_dev *hdmi_dev,
struct hdmi_video *vpara)
{
- unsigned char color_depth = 0;
+ unsigned char color_depth = COLOR_DEPTH_24BIT_DEFAULT;
unsigned char output_select = 0;
unsigned char remap_size = 0;
output_select = OUT_FROM_8BIT_BYPASS;
break;
}
-
- /*Config Color Depth*/
- hdmi_msk_reg(hdmi_dev, VP_PR_CD,
- m_COLOR_DEPTH, v_COLOR_DEPTH(color_depth));
}
-
+ /*Config Color Depth*/
+ hdmi_msk_reg(hdmi_dev, VP_PR_CD,
+ m_COLOR_DEPTH, v_COLOR_DEPTH(color_depth));
/*Config pixel repettion*/
hdmi_msk_reg(hdmi_dev, VP_PR_CD, m_DESIRED_PR_FACTOR,
v_DESIRED_PR_FACTOR(hdmi_dev->pixelrepeat - 1));
}
/* Set Data enable signal from external
- and set video sample input mapping */
+ * and set video sample input mapping
+ */
hdmi_msk_reg(hdmi_dev, TX_INVID0,
m_INTERNAL_DE_GEN | m_VIDEO_MAPPING,
v_INTERNAL_DE_GEN(0) | v_VIDEO_MAPPING(map_code));
static const char coeff_csc[][24] = {
/* G R B Bias
- A1 | A2 | A3 | A4 |
- B1 | B2 | B3 | B4 |
- C1 | C2 | C3 | C4 | */
+ * A1 | A2 | A3 | A4 |
+ * B1 | B2 | B3 | B4 |
+ * C1 | C2 | C3 | C4 |
+ */
+ { /* CSC_BYPASS */
+ 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ },
{ /* CSC_RGB_0_255_TO_RGB_16_235_8BIT */
0x36, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, /*G*/
0x00, 0x00, 0x36, 0xf7, 0x00, 0x00, 0x00, 0x40, /*R*/
static int rockchip_hdmiv2_video_csc(struct hdmi_dev *hdmi_dev,
struct hdmi_video *vpara)
{
- int i, mode, interpolation, decimation, csc_scale;
+ int i, mode, interpolation, decimation, csc_scale = 0;
const char *coeff = NULL;
unsigned char color_depth = 0;
m_CSC_DECIMODE, v_CSC_DECIMODE(decimation));
}
+ mode = CSC_BYPASS;
+ csc_scale = 0;
+
switch (vpara->vic) {
case HDMI_720X480I_60HZ_4_3:
case HDMI_720X576I_50HZ_4_3:
return 0;
}
-
static int hdmi_dev_detect_hotplug(struct hdmi *hdmi)
{
struct hdmi_dev *hdmi_dev = hdmi->property->priv;
- u32 value = hdmi_readl(hdmi_dev, PHY_STAT0);
+ u32 value;
+ value = hdmi_readl(hdmi_dev, PHY_STAT0);
HDMIDBG("[%s] reg%x value %02x\n", __func__, PHY_STAT0, value);
-
if (value & m_PHY_HPD)
return HDMI_HPD_ACTIVED;
- else
- return HDMI_HPD_REMOVED;
+
+ return HDMI_HPD_REMOVED;
}
static int hdmi_dev_read_edid(struct hdmi *hdmi, int block, unsigned char *buff)
rockchip_hdmiv2_i2cm_reset(hdmi_dev);
- /* Set DDC I2C CLK which devided from DDC_CLK to 100KHz. */
+ /* Set DDC I2C CLK which divided from DDC_CLK to 100KHz. */
rockchip_hdmiv2_i2cm_clk_init(hdmi_dev);
/* Enable I2C interrupt for reading edid */
exit:
/* Disable I2C interrupt */
rockchip_hdmiv2_i2cm_mask_int(hdmi_dev, 1);
-
- #ifdef DEBUG
- if (!ret) {
- for (index = 0; index < 128; index++) {
- printk("0x%02x ,", buff[index]);
- if ((index + 1) % 16 == 0)
- printk("\n");
- }
- }
- #endif
return ret;
}
static void hdmi_dev_config_avi(struct hdmi_dev *hdmi_dev,
struct hdmi_video *vpara)
{
- unsigned char colorimetry, ext_colorimetry, aspect_ratio, y1y0;
+ unsigned char colorimetry, ext_colorimetry = 0, aspect_ratio, y1y0;
unsigned char rgb_quan_range = AVI_QUANTIZATION_RANGE_DEFAULT;
+ hdmi_msk_reg(hdmi_dev, FC_DATAUTO3, m_AVI_AUTO, v_AVI_AUTO(0));
+ hdmi_msk_reg(hdmi_dev, IH_FC_STAT1,
+ m_AVI_INFOFRAME, v_AVI_INFOFRAME(1));
/* Set AVI infoFrame Data byte1 */
if (vpara->color_output == HDMI_COLOR_YCBCR444)
y1y0 = AVI_COLOR_MODE_YCBCR444;
case HDMI_720X480P_60HZ_4_3:
case HDMI_720X576P_50HZ_4_3:
aspect_ratio = AVI_CODED_FRAME_ASPECT_4_3;
- colorimetry = AVI_COLORIMETRY_SMPTE_170M;
+ if (vpara->colorimetry == HDMI_COLORIMETRY_NO_DATA)
+ colorimetry = AVI_COLORIMETRY_SMPTE_170M;
break;
case HDMI_720X480I_60HZ_16_9:
case HDMI_720X576I_50HZ_16_9:
case HDMI_720X480P_60HZ_16_9:
case HDMI_720X576P_50HZ_16_9:
aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9;
- colorimetry = AVI_COLORIMETRY_SMPTE_170M;
+ if (vpara->colorimetry == HDMI_COLORIMETRY_NO_DATA)
+ colorimetry = AVI_COLORIMETRY_SMPTE_170M;
break;
default:
aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9;
- colorimetry = AVI_COLORIMETRY_ITU709;
+ if (vpara->colorimetry == HDMI_COLORIMETRY_NO_DATA)
+ colorimetry = AVI_COLORIMETRY_ITU709;
}
- if (vpara->color_output_depth > 8) {
+ if (vpara->colorimetry > HDMI_COLORIMETRY_ITU709) {
colorimetry = AVI_COLORIMETRY_EXTENDED;
- ext_colorimetry = 6;
+ ext_colorimetry = vpara->colorimetry;
} else if (vpara->color_output == HDMI_COLOR_RGB_16_235 ||
vpara->color_output == HDMI_COLOR_RGB_0_255) {
colorimetry = AVI_COLORIMETRY_NO_DATA;
- ext_colorimetry = 0;
+ } else if (vpara->colorimetry != HDMI_COLORIMETRY_NO_DATA) {
+ colorimetry = vpara->colorimetry;
}
hdmi_writel(hdmi_dev, FC_AVICONF1,
v_FC_QUAN_RANGE(rgb_quan_range));
/* Set AVI infoFrame Data byte4 */
- if ((vpara->vic > 92 && vpara->vic < 96) || (vpara->vic == 98))
+ if ((vpara->vic > 92 && vpara->vic < 96) ||
+ (vpara->vic == 98) ||
+ (vpara->vic & HDMI_VIDEO_DMT) ||
+ (vpara->vic & HDMI_VIDEO_DISCRETE_VR))
hdmi_writel(hdmi_dev, FC_AVIVID, 0);
else
hdmi_writel(hdmi_dev, FC_AVIVID, vpara->vic & 0xff);
/* Set AVI infoFrame Data byte5 */
hdmi_msk_reg(hdmi_dev, FC_AVICONF3, m_FC_YQ | m_FC_CN,
v_FC_YQ(YQ_LIMITED_RANGE) | v_FC_CN(CN_GRAPHICS));
+ hdmi_msk_reg(hdmi_dev, FC_DATAUTO3, m_AVI_AUTO, v_AVI_AUTO(1));
}
static int hdmi_dev_config_vsi(struct hdmi *hdmi,
for (i = 0; i < 3; i++)
hdmi_writel(hdmi_dev, FC_VSDPAYLOAD0 + i, data[i]);
hdmi_writel(hdmi_dev, FC_VSDSIZE, 0x6);
-/* if (auto_send) { */
+
hdmi_writel(hdmi_dev, FC_DATAUTO1, 0);
hdmi_writel(hdmi_dev, FC_DATAUTO2, 0x11);
hdmi_msk_reg(hdmi_dev, FC_DATAUTO0, m_VSD_AUTO, v_VSD_AUTO(1));
-/* }
- else {
- hdmi_msk_reg(hdmi_dev, FC_DATMAN, m_VSD_MAN, v_VSD_MAN(1));
+ return 0;
+}
+
+static int hdmi_dev_config_spd(struct hdmi *hdmi, const char *vendor,
+ const char *product, char deviceinfo)
+{
+ struct hdmi_dev *hdmi_dev;
+ int i, len;
+
+ if (!hdmi || !vendor || !product)
+ return -1;
+ hdmi_dev = hdmi->property->priv;
+
+ hdmi_msk_reg(hdmi_dev, FC_DATAUTO0, m_SPD_AUTO, v_SPD_AUTO(0));
+ len = strlen(vendor);
+ for (i = 0; i < 8; i++) {
+ if (i < len)
+ hdmi_writel(hdmi_dev, FC_SPDVENDORNAME0 + i,
+ vendor[i]);
+ else
+ hdmi_writel(hdmi_dev, FC_SPDVENDORNAME0 + i,
+ 0);
+ }
+ len = strlen(product);
+ for (i = 0; i < 16; i++) {
+ if (i < len)
+ hdmi_writel(hdmi_dev, FC_SPDPRODUCTNAME0 + i,
+ product[i]);
+ else
+ hdmi_writel(hdmi_dev, FC_SPDPRODUCTNAME0 + i,
+ 0);
}
-*/
+ hdmi_writel(hdmi_dev, FC_SPDDEVICEINF, deviceinfo);
+ hdmi_msk_reg(hdmi_dev, FC_DATAUTO0, m_SPD_AUTO, v_SPD_AUTO(1));
return 0;
}
vpara->color_input = HDMI_COLOR_RGB_0_255;
if (!hdmi->uboot) {
- /* befor configure video, we power off phy */
- hdmi_msk_reg(hdmi_dev, PHY_CONF0,
- m_PDDQ_SIG | m_TXPWRON_SIG,
- v_PDDQ_SIG(1) | v_TXPWRON_SIG(0));
-
+ /* before configure video, we power off phy */
+ if (hdmi_dev->soctype != HDMI_SOC_RK322X) {
+ hdmi_msk_reg(hdmi_dev, PHY_CONF0,
+ m_PDDQ_SIG | m_TXPWRON_SIG,
+ v_PDDQ_SIG(1) | v_TXPWRON_SIG(0));
+ } else {
+ hdmi_msk_reg(hdmi_dev, PHY_CONF0,
+ m_ENHPD_RXSENSE_SIG,
+ v_ENHPD_RXSENSE_SIG(1));
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON2,
+ RK322X_PLL_POWER_DOWN);
+ }
/* force output blue */
if (vpara->color_output == HDMI_COLOR_RGB_0_255) {
hdmi_writel(hdmi_dev, FC_DBGTMDS2, 0x00); /*R*/
hdmi_writel(hdmi_dev, FC_DBGTMDS1, 0x10); /*G*/
hdmi_writel(hdmi_dev, FC_DBGTMDS0, 0x10); /*B*/
} else {
- hdmi_writel(hdmi_dev, FC_DBGTMDS2, 0x80); /*R*/
- hdmi_writel(hdmi_dev, FC_DBGTMDS1, 0x10); /*G*/
- hdmi_writel(hdmi_dev, FC_DBGTMDS0, 0x80); /*B*/
+ hdmi_writel(hdmi_dev, FC_DBGTMDS2, 0x80); /*Cr*/
+ hdmi_writel(hdmi_dev, FC_DBGTMDS1, 0x10); /*Y*/
+ hdmi_writel(hdmi_dev, FC_DBGTMDS0, 0x80); /*Cb*/
}
hdmi_msk_reg(hdmi_dev, FC_DBGFORCE,
m_FC_FORCEVIDEO, v_FC_FORCEVIDEO(1));
+ hdmi_writel(hdmi_dev, MC_CLKDIS, m_HDCPCLK_DISABLE);
}
- hdmi_writel(hdmi_dev, MC_CLKDIS, m_HDCPCLK_DISABLE);
if (rockchip_hdmiv2_video_framecomposer(hdmi, vpara) < 0)
return -1;
if (vpara->sink_hdmi == OUTPUT_HDMI) {
hdmi_dev_config_avi(hdmi_dev, vpara);
+ hdmi_dev_config_spd(hdmi, hdmi_dev->vendor_name,
+ hdmi_dev->product_name,
+ hdmi_dev->deviceinfo);
if (vpara->format_3d != HDMI_3D_NONE) {
hdmi_dev_config_vsi(hdmi,
vpara->format_3d,
vpara->vic,
HDMI_VIDEO_FORMAT_NORMAL);
}
- dev_info(hdmi->dev, "[%s] sucess output HDMI.\n", __func__);
+ dev_info(hdmi->dev, "[%s] success output HDMI.\n", __func__);
} else {
- dev_info(hdmi->dev, "[%s] sucess output DVI.\n", __func__);
+ dev_info(hdmi->dev, "[%s] success output DVI.\n", __func__);
}
- rockchip_hdmiv2_config_phy(hdmi_dev);
+ if (!hdmi->uboot)
+ rockchip_hdmiv2_config_phy(hdmi_dev);
+ else
+ hdmi_msk_reg(hdmi_dev, PHY_MASK, m_PHY_LOCK, v_PHY_LOCK(0));
return 0;
}
static void hdmi_dev_config_aai(struct hdmi_dev *hdmi_dev,
struct hdmi_audio *audio)
{
- /*Refer to CEA861-E Audio infoFrame*/
- /*Set both Audio Channel Count and Audio Coding
- Type Refer to Stream Head for HDMI*/
+ /* Refer to CEA861-E Audio infoFrame
+ * Set both Audio Channel Count and Audio Coding
+ * Type Refer to Stream Head for HDMI
+ */
hdmi_msk_reg(hdmi_dev, FC_AUDICONF0,
- m_FC_CHN_CNT | m_FC_CODING_TYEP,
- v_FC_CHN_CNT(audio->channel-1) | v_FC_CODING_TYEP(0));
+ m_FC_CHN_CNT | m_FC_CODING_TYPE,
+ v_FC_CHN_CNT(audio->channel - 1) | v_FC_CODING_TYPE(0));
- /*Set both Audio Sample Size and Sample Frequency
- Refer to Stream Head for HDMI*/
+ /* Set both Audio Sample Size and Sample Frequency
+ * Refer to Stream Head for HDMI
+ */
hdmi_msk_reg(hdmi_dev, FC_AUDICONF1,
m_FC_SAMPLE_SIZE | m_FC_SAMPLE_FREQ,
v_FC_SAMPLE_SIZE(0) | v_FC_SAMPLE_FREQ(0));
- /*Set Channel Allocation*/
+ /* Set Channel Allocation */
hdmi_writel(hdmi_dev, FC_AUDICONF2, 0x00);
- /*Set LFEPBL¡¢DOWN-MIX INH and LSV*/
+ /* Set LFEPBLDOWN-MIX INH and LSV */
hdmi_writel(hdmi_dev, FC_AUDICONF3, 0x00);
}
int word_length = 0, channel = 0, mclk_fs;
unsigned int N = 0, CTS = 0;
int rate = 0;
+ char design_id;
HDMIDBG("%s\n", __func__);
else
N = N_32K_LOWCLK;
/*div a num to avoid the value is exceed 2^32(int)*/
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 32);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 1000, 32);
break;
case HDMI_AUDIO_FS_44100:
mclk_fs = FS_128;
else
N = N_441K_LOWCLK;
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/100, 441);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 100, 441);
break;
case HDMI_AUDIO_FS_48000:
mclk_fs = FS_128;
else
N = N_48K_LOWCLK;
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 48);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 1000, 48);
break;
case HDMI_AUDIO_FS_88200:
mclk_fs = FS_128;
else
N = N_882K_LOWCLK;
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/100, 882);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 100, 882);
break;
case HDMI_AUDIO_FS_96000:
mclk_fs = FS_128;
else
N = N_96K_LOWCLK;
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 96);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 1000, 96);
break;
case HDMI_AUDIO_FS_176400:
mclk_fs = FS_128;
else
N = N_1764K_LOWCLK;
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/100, 1764);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 100, 1764);
break;
case HDMI_AUDIO_FS_192000:
mclk_fs = FS_128;
else
N = N_192K_LOWCLK;
- CTS = CALC_CTS(N, hdmi_dev->tmdsclk/1000, 192);
+ CTS = CALC_CTS(N, hdmi_dev->tmdsclk / 1000, 192);
break;
default:
dev_err(hdmi_dev->hdmi->dev,
hdmi_msk_reg(hdmi_dev, AUD_CONF0,
m_SW_AUD_FIFO_RST, v_SW_AUD_FIFO_RST(1));
hdmi_writel(hdmi_dev, MC_SWRSTZREQ, 0xF7);
- hdmi_writel(hdmi_dev, AUD_CONF2, 0x0);
+ design_id = hdmi_readl(hdmi_dev, DESIGN_ID);
+ if (design_id >= 0x21)
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x4);
+ else
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x0);
usleep_range(90, 100);
- if (I2S_CHANNEL_7_8 == channel) {
- HDMIDBG("hbr mode.\n");
- hdmi_writel(hdmi_dev, AUD_CONF2, 0x1);
- word_length = I2S_24BIT_SAMPLE;
- } else if ((HDMI_AUDIO_FS_48000 == audio->rate)
- || (HDMI_AUDIO_FS_192000 == audio->rate)) {
- HDMIDBG("nlpcm mode.\n");
- hdmi_writel(hdmi_dev, AUD_CONF2, 0x2);
- word_length = I2S_24BIT_SAMPLE;
+ /*
+ * when we try to use hdmi nlpcm mode
+ * we should use set AUD_CONF2 to open this route and set
+ * word_length to 24bit for b.p.c.u.v with 16bit raw data
+ * when the bitstream data up to 8 channel, we should use
+ * the hdmi hbr mode
+ * HBR Mode : Dolby TrueHD
+ * Dolby Atmos
+ * DTS-HDMA
+ * NLPCM Mode :
+ * FS_32000 FS_44100 FS_48000 : Dolby Digital & DTS
+ * FS_176400 FS_192000 : Dolby Digital Plus
+ */
+ if (audio->type == HDMI_AUDIO_NLPCM) {
+ if (channel == I2S_CHANNEL_7_8) {
+ HDMIDBG("hbr mode.\n");
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x1);
+ word_length = I2S_24BIT_SAMPLE;
+ } else if ((audio->rate == HDMI_AUDIO_FS_32000) ||
+ (audio->rate == HDMI_AUDIO_FS_44100) ||
+ (audio->rate == HDMI_AUDIO_FS_48000) ||
+ (audio->rate == HDMI_AUDIO_FS_176400) ||
+ (audio->rate == HDMI_AUDIO_FS_192000)) {
+ HDMIDBG("nlpcm mode.\n");
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x2);
+ word_length = I2S_24BIT_SAMPLE;
+ } else {
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x0);
+ }
} else {
- hdmi_writel(hdmi_dev, AUD_CONF2, 0x0);
+ if (design_id >= 0x21)
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x4);
+ else
+ hdmi_writel(hdmi_dev, AUD_CONF2, 0x0);
}
hdmi_msk_reg(hdmi_dev, AUD_CONF0,
m_I2S_SEL | m_I2S_IN_EN,
m_AUDIO_SAMPLE_RATE, v_AUDIO_SAMPLE_RATE(rate));
hdmi_writel(hdmi_dev, FC_AUDSCHNLS8, ((~rate) << 4) | 0x2);
+ hdmi_msk_reg(hdmi_dev, AUD_CONF0,
+ m_SW_AUD_FIFO_RST, v_SW_AUD_FIFO_RST(1));
+
hdmi_dev_config_aai(hdmi_dev, audio);
return 0;
static int hdmi_dev_control_output(struct hdmi *hdmi, int enable)
{
struct hdmi_dev *hdmi_dev = hdmi->property->priv;
+ struct hdmi_video vpara;
HDMIDBG("[%s] %d\n", __func__, enable);
-
if (enable == HDMI_AV_UNMUTE) {
hdmi_writel(hdmi_dev, FC_DBGFORCE, 0x00);
- hdmi_msk_reg(hdmi_dev, FC_GCP,
- m_FC_SET_AVMUTE | m_FC_CLR_AVMUTE,
- v_FC_SET_AVMUTE(0) | v_FC_CLR_AVMUTE(1));
+ if (hdmi->edid.sink_hdmi == OUTPUT_HDMI)
+ hdmi_msk_reg(hdmi_dev, FC_GCP,
+ m_FC_SET_AVMUTE | m_FC_CLR_AVMUTE,
+ v_FC_SET_AVMUTE(0) | v_FC_CLR_AVMUTE(1));
} else {
if (enable & HDMI_VIDEO_MUTE) {
hdmi_msk_reg(hdmi_dev, FC_DBGFORCE,
m_FC_FORCEVIDEO, v_FC_FORCEVIDEO(1));
- hdmi_msk_reg(hdmi_dev, FC_GCP,
- m_FC_SET_AVMUTE | m_FC_CLR_AVMUTE,
- v_FC_SET_AVMUTE(1) | v_FC_CLR_AVMUTE(0));
+ if (hdmi->edid.sink_hdmi == OUTPUT_HDMI) {
+ hdmi_msk_reg(hdmi_dev, FC_GCP,
+ m_FC_SET_AVMUTE |
+ m_FC_CLR_AVMUTE,
+ v_FC_SET_AVMUTE(1) |
+ v_FC_CLR_AVMUTE(0));
+ vpara.vic = hdmi->vic;
+ vpara.color_output = HDMI_COLOR_RGB_0_255;
+ hdmi_dev_config_avi(hdmi_dev, &vpara);
+ while ((!hdmi_readl(hdmi_dev, IH_FC_STAT1)) &
+ m_AVI_INFOFRAME) {
+ usleep_range(900, 1000);
+ }
+ }
}
/* if (enable & HDMI_AUDIO_MUTE) {
- hdmi_msk_reg(hdmi_dev, FC_AUDSCONF,
- m_AUD_PACK_SAMPFIT,
- v_AUD_PACK_SAMPFIT(0x0F));
- }
-*/ if (enable == (HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE)) {
- msleep(100);
+ * hdmi_msk_reg(hdmi_dev, FC_AUDSCONF,
+ * m_AUD_PACK_SAMPFIT,
+ * v_AUD_PACK_SAMPFIT(0x0F));
+ * }
+ */
+ if (enable == (HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE)) {
+ if (hdmi->ops->hdcp_power_off_cb)
+ hdmi->ops->hdcp_power_off_cb(hdmi);
rockchip_hdmiv2_powerdown(hdmi_dev);
- hdmi_dev->tmdsclk = 0;
-/*
- hdmi_msk_reg(hdmi_dev, PHY_CONF0,
- m_PDDQ_SIG | m_TXPWRON_SIG,
- v_PDDQ_SIG(1) | v_TXPWRON_SIG(0));
- hdmi_writel(hdmi_dev, MC_CLKDIS, 0x7f);
-*/ }
+ }
}
return 0;
}
struct hdmi_dev *hdmi_dev = hdmi->property->priv;
HDMIDBG("%s\n", __func__);
- hdmi_writel(hdmi_dev, MC_CLKDIS, m_HDCPCLK_DISABLE);
- return HDMI_ERROR_SUCESS;
+ if (!hdmi->uboot)
+ hdmi_writel(hdmi_dev, MC_CLKDIS, m_HDCPCLK_DISABLE);
+ return HDMI_ERROR_SUCCESS;
}
static int hdmi_dev_remove(struct hdmi *hdmi)
struct hdmi_dev *hdmi_dev = hdmi->property->priv;
HDMIDBG("%s\n", __func__);
+ if (hdmi->ops->hdcp_power_off_cb)
+ hdmi->ops->hdcp_power_off_cb(hdmi);
rockchip_hdmiv2_powerdown(hdmi_dev);
hdmi_dev->tmdsclk = 0;
- return HDMI_ERROR_SUCESS;
+ return HDMI_ERROR_SUCCESS;
}
static int hdmi_dev_enable(struct hdmi *hdmi)
hdmi_writel(hdmi_dev, IH_MUTE, 0x00);
hdmi_dev->enable = 1;
}
- hdmi_submit_work(hdmi, HDMI_HPD_CHANGE, 10, NULL);
+ hdmi_submit_work(hdmi, HDMI_HPD_CHANGE, 10, 0);
return 0;
}
{
struct hdmi *hdmi = hdmi_dev->hdmi;
+ /*lcdc source select*/
+ if (hdmi_dev->soctype == HDMI_SOC_RK3288) {
+ grf_writel(HDMI_SEL_LCDC(hdmi->property->videosrc, 4),
+ RK3288_GRF_SOC_CON6);
+ /* select GPIO7_C0 as cec pin */
+ grf_writel(((1 << 12) | (1 << 28)), RK3288_GRF_SOC_CON8);
+ } else if (hdmi_dev->soctype == HDMI_SOC_RK3399) {
+ regmap_write(hdmi_dev->grf_base,
+ RK3399_GRF_SOC_CON20,
+ HDMI_SEL_LCDC(hdmi->property->videosrc, 6));
+ }
+
if (!hdmi->uboot) {
- /* reset hdmi */
+ pr_info("reset hdmi\n");
if (hdmi_dev->soctype == HDMI_SOC_RK3288) {
- writel_relaxed((1 << 9) | (1 << 25),
- RK_CRU_VIRT + 0x01d4);
- udelay(1);
- writel_relaxed((0 << 9) | (1 << 25),
- RK_CRU_VIRT + 0x01d4);
- } else if (hdmi_dev->soctype == HDMI_SOC_RK3368) {
- pr_info("reset hdmi\n");
- regmap_write(hdmi_dev->grf_base, 0x031c,
- (1 << 9) | (1 << 25));
- udelay(5);
- regmap_write(hdmi_dev->grf_base, 0x031c,
- (0 << 9) | (1 << 25));
+ rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HDMI, true);
+ usleep_range(10, 20);
+ rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HDMI, false);
+ } else {
+ if (hdmi_dev->soctype == HDMI_SOC_RK322X) {
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON2,
+ RK322X_DDC_MASK_EN);
+ regmap_write(hdmi_dev->grf_base,
+ RK322X_GRF_SOC_CON6,
+ RK322X_IO_3V_DOMAIN);
+ }
+ reset_control_assert(hdmi_dev->reset);
+ usleep_range(10, 20);
+ reset_control_deassert(hdmi_dev->reset);
}
rockchip_hdmiv2_powerdown(hdmi_dev);
+ } else {
+ hdmi->hotplug = hdmi_dev_detect_hotplug(hdmi);
+ if (hdmi->hotplug != HDMI_HPD_ACTIVED)
+ hdmi->uboot = 0;
}
- /*mute unnecessary interrrupt, only enable hpd*/
+ /*mute unnecessary interrupt, only enable hpd*/
hdmi_writel(hdmi_dev, IH_MUTE_FC_STAT0, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_FC_STAT1, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_FC_STAT2, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_AS_STAT0, 0xff);
- hdmi_writel(hdmi_dev, IH_MUTE_PHY_STAT0, 0xfe);
+ hdmi_writel(hdmi_dev, IH_MUTE_PHY_STAT0, 0xfc);
hdmi_writel(hdmi_dev, IH_MUTE_I2CM_STAT0, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_CEC_STAT0, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_VP_STAT0, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_I2CMPHY_STAT0, 0xff);
hdmi_writel(hdmi_dev, IH_MUTE_AHBDMAAUD_STAT0, 0xff);
- /* disable hdcp interrup */
+ /* disable hdcp interrupt */
hdmi_writel(hdmi_dev, A_APIINTMSK, 0xff);
hdmi_writel(hdmi_dev, PHY_MASK, 0xf1);
hdmi_writel(hdmi_dev, IH_VP_STAT0, vp_stat0);
if (phy_int0 || phy_int) {
+ if ((phy_int0 & m_PHY_LOCK) &&
+ (phy_pol & m_PHY_LOCK) == 0) {
+ pr_info("hdmi phy pll unlock\n");
+ hdmi_submit_work(hdmi, HDMI_SET_VIDEO, 0, 0);
+ }
phy_pol = (phy_int0 & (~phy_status)) | ((~phy_int0) & phy_pol);
hdmi_writel(hdmi_dev, PHY_POL0, phy_pol);
hdmi_writel(hdmi_dev, IH_PHY_STAT0, phy_int);
if ((phy_int & m_HPD) || ((phy_int & 0x3c) == 0x3c))
- hdmi_submit_work(hdmi, HDMI_HPD_CHANGE, 20, NULL);
+ hdmi_submit_work(hdmi, HDMI_HPD_CHANGE, 20, 0);
}
/* Audio error */
/* CEC */
if (cec_int) {
hdmi_writel(hdmi_dev, IH_CEC_STAT0, cec_int);
- rockchip_hdmiv2_cec_isr(hdmi_dev, cec_int);
+ if (hdmi_dev->hdmi->property->feature & SUPPORT_CEC)
+ rockchip_hdmiv2_cec_isr(hdmi_dev, cec_int);
}
/* HDCP */
if (hdcp_int) {
hdmi_writel(hdmi_dev, A_APIINTCLR, hdcp_int);
- pr_info("hdcp_int is 0x%02x\n", hdcp_int);
+ rockchip_hdmiv2_hdcp_isr(hdmi_dev, hdcp_int);
}
/* HDCP2 */
if (hdcp2_int) {
hdmi_writel(hdmi_dev, HDCP2REG_STAT, hdcp2_int);
pr_info("hdcp2_int is 0x%02x\n", hdcp2_int);
+ if ((hdcp2_int & m_HDCP2_AUTH_FAIL ||
+ hdcp2_int & m_HDCP2_AUTH_LOST) &&
+ hdmi_dev->hdcp2_start) {
+ pr_info("hdcp2 failed or lost\n");
+ hdmi_dev->hdcp2_start();
+ }
}
return IRQ_HANDLED;
}