diff options
Diffstat (limited to 'drivers/video/meson/meson_dw_hdmi.c')
-rw-r--r-- | drivers/video/meson/meson_dw_hdmi.c | 61 |
1 files changed, 54 insertions, 7 deletions
diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index 9831d978fca..ae2e6288f3a 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -24,6 +24,7 @@ #define HDMITX_TOP_ADDR_REG 0x0 #define HDMITX_TOP_DATA_REG 0x4 #define HDMITX_TOP_CTRL_REG 0x8 +#define HDMITX_TOP_G12A_OFFSET 0x8000 /* Controller Communication Channel */ #define HDMITX_DWC_ADDR_REG 0x10 @@ -37,6 +38,8 @@ #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ +#define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ +#define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */ struct meson_dw_hdmi { struct udevice *dev; @@ -48,6 +51,7 @@ enum hdmi_compatible { HDMI_COMPATIBLE_GXBB = 0, HDMI_COMPATIBLE_GXL = 1, HDMI_COMPATIBLE_GXM = 2, + HDMI_COMPATIBLE_G12A = 3, }; static inline bool meson_hdmi_is_compatible(struct meson_dw_hdmi *priv, @@ -60,8 +64,14 @@ static inline bool meson_hdmi_is_compatible(struct meson_dw_hdmi *priv, static unsigned int dw_hdmi_top_read(struct dw_hdmi *hdmi, unsigned int addr) { + struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi, + hdmi); unsigned int data; + if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_G12A)) + return readl(hdmi->ioaddr + + HDMITX_TOP_G12A_OFFSET + (addr << 2)); + /* ADDR must be written twice */ writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); @@ -76,6 +86,15 @@ static unsigned int dw_hdmi_top_read(struct dw_hdmi *hdmi, unsigned int addr) static inline void dw_hdmi_top_write(struct dw_hdmi *hdmi, unsigned int addr, unsigned int data) { + struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi, + hdmi); + + if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_G12A)) { + writel(data, hdmi->ioaddr + + HDMITX_TOP_G12A_OFFSET + (addr << 2)); + return; + } + /* ADDR must be written twice */ writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); writel(addr & 0xffff, hdmi->ioaddr + HDMITX_TOP_ADDR_REG); @@ -237,7 +256,7 @@ static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv, hhi_write(HHI_HDMI_PHY_CNTL0, 0x33604142); hhi_write(HHI_HDMI_PHY_CNTL3, 0x0016315b); } - } else { + } else if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXBB)) { if (pixel_clock >= 371250) { /* 5.94Gbps, 3.7125Gbps */ hhi_write(HHI_HDMI_PHY_CNTL0, 0x33353245); @@ -251,6 +270,23 @@ static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv, hhi_write(HHI_HDMI_PHY_CNTL0, 0x33632122); hhi_write(HHI_HDMI_PHY_CNTL3, 0x2000115b); } + } else if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_G12A)) { + if (pixel_clock >= 371250) { + /* 5.94Gbps, 3.7125Gbps */ + hhi_write(HHI_HDMI_PHY_CNTL0, 0x37eb65c4); + hhi_write(HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); + hhi_write(HHI_HDMI_PHY_CNTL5, 0x0000080b); + } else if (pixel_clock >= 297000) { + /* 2.97Gbps */ + hhi_write(HHI_HDMI_PHY_CNTL0, 0x33eb6262); + hhi_write(HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); + hhi_write(HHI_HDMI_PHY_CNTL5, 0x00000003); + } else { + /* 1.485Gbps, and below */ + hhi_write(HHI_HDMI_PHY_CNTL0, 0x33eb4242); + hhi_write(HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); + hhi_write(HHI_HDMI_PHY_CNTL5, 0x00000003); + } } } @@ -292,7 +328,8 @@ static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock) /* BIT_INVERT */ if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXL) || - meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXM)) + meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_GXM) || + meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_G12A)) dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, BIT(17), 0); else dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1, @@ -356,8 +393,12 @@ static int meson_dw_hdmi_probe(struct udevice *dev) priv->hdmi.hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; priv->hdmi.hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_YUV8_1X24; priv->hdmi.phy_set = meson_dw_hdmi_phy_init; - priv->hdmi.write_reg = dw_hdmi_dwc_write; - priv->hdmi.read_reg = dw_hdmi_dwc_read; + if (meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_G12A)) + priv->hdmi.reg_io_width = 1; + else { + priv->hdmi.write_reg = dw_hdmi_dwc_write; + priv->hdmi.read_reg = dw_hdmi_dwc_read; + } priv->hdmi.i2c_clk_high = 0x67; priv->hdmi.i2c_clk_low = 0x78; @@ -409,9 +450,13 @@ static int meson_dw_hdmi_probe(struct udevice *dev) if (ret) return ret; - /* Enable APB3 fail on error */ - writel_bits(BIT(15), BIT(15), priv->hdmi.ioaddr + HDMITX_TOP_CTRL_REG); - writel_bits(BIT(15), BIT(15), priv->hdmi.ioaddr + HDMITX_DWC_CTRL_REG); + if (!meson_hdmi_is_compatible(priv, HDMI_COMPATIBLE_G12A)) { + /* Enable APB3 fail on error */ + writel_bits(BIT(15), BIT(15), + priv->hdmi.ioaddr + HDMITX_TOP_CTRL_REG); + writel_bits(BIT(15), BIT(15), + priv->hdmi.ioaddr + HDMITX_DWC_CTRL_REG); + } /* Bring out of reset */ dw_hdmi_top_write(&priv->hdmi, HDMITX_TOP_SW_RESET, 0); @@ -448,6 +493,8 @@ static const struct udevice_id meson_dw_hdmi_ids[] = { .data = HDMI_COMPATIBLE_GXL }, { .compatible = "amlogic,meson-gxm-dw-hdmi", .data = HDMI_COMPATIBLE_GXM }, + { .compatible = "amlogic,meson-g12a-dw-hdmi", + .data = HDMI_COMPATIBLE_G12A }, { } }; |