#include <display.h>
#include <dm.h>
#include <edid.h>
+#include <log.h>
#include <asm/io.h>
#include <dw_hdmi.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+#include <linux/bitops.h>
#include <power/regulator.h>
#include <clk.h>
#include <linux/delay.h>
#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
#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;
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,
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);
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);
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);
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);
+ }
}
}
/* 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,
struct meson_dw_hdmi *priv = dev_get_priv(dev);
struct reset_ctl_bulk resets;
struct clk_bulk clocks;
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
struct udevice *supply;
+#endif
int ret;
priv->dev = 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;
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);
.data = HDMI_COMPATIBLE_GXL },
{ .compatible = "amlogic,meson-gxm-dw-hdmi",
.data = HDMI_COMPATIBLE_GXM },
+ { .compatible = "amlogic,meson-g12a-dw-hdmi",
+ .data = HDMI_COMPATIBLE_G12A },
{ }
};