diff mbox series

[14/19] video: sunxi: dw-hdmi: rework PHY initialization

Message ID 20210223204631.1609597-15-jernej.skrabec@siol.net
State New
Delegated to: Andre Przywara
Headers show
Series video: sunxi: Rework DE2 driver | expand

Commit Message

Jernej Škrabec Feb. 23, 2021, 8:46 p.m. UTC
Now that bit meanings are somewhat known, rework PHY initialization.
This is modelled after Linux driver.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 411 +++++++++++++++++++---------
 1 file changed, 279 insertions(+), 132 deletions(-)

Comments

Jernej Škrabec Feb. 24, 2021, 6:21 p.m. UTC | #1
Hi!

Dne torek, 23. februar 2021 ob 21:46:26 CET je Jernej Skrabec napisal(a):
> Now that bit meanings are somewhat known, rework PHY initialization.
> This is modelled after Linux driver.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  drivers/video/sunxi/sunxi_dw_hdmi.c | 411 +++++++++++++++++++---------
>  1 file changed, 279 insertions(+), 132 deletions(-)

If you all agree, I would replace this patch with new, proper PHY driver. This 
would match DT structure and allow to init clocks and resets based on DT info.

Best regards,
Jernej
diff mbox series

Patch

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 4cc175d714ea..c4cded569bfb 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -18,100 +18,200 @@ 
 #include <linux/bitops.h>
 #include <linux/delay.h>
 
+#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK		BIT(0)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK	GENMASK(15, 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC	BIT(8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC	BIT(9)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK	GENMASK(23, 16)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr)	(addr << 16)
+
+#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN	BIT(31)
+
+#define SUN8I_HDMI_PHY_READ_EN_MAGIC		0x54524545
+
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC		0x42494E47
+
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SWI		BIT(31)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWEND	BIT(30)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWENC	BIT(29)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW	BIT(28)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVRCAL(x)	((x) << 26)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(x)	((x) << 24)
+#define SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT		BIT(23)
+#define SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT		BIT(22)
+#define SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT	BIT(21)
+#define SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT	BIT(20)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL		BIT(19)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG		BIT(18)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS	BIT(17)
+#define SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN	BIT(16)
+#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK	GENMASK(15, 12)
+#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL	(0xf << 12)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK	BIT(11)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2	BIT(10)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1	BIT(9)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0	BIT(8)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK	BIT(7)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2	BIT(6)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1	BIT(5)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0	BIT(4)
+#define SUN8I_HDMI_PHY_ANA_CFG1_CKEN		BIT(3)
+#define SUN8I_HDMI_PHY_ANA_CFG1_LDOEN		BIT(2)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENVBS		BIT(1)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENBI		BIT(0)
+
+#define SUN8I_HDMI_PHY_ANA_CFG2_M_EN		BIT(31)
+#define SUN8I_HDMI_PHY_ANA_CFG2_PLLDBEN		BIT(30)
+#define SUN8I_HDMI_PHY_ANA_CFG2_SEN		BIT(29)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDPD	BIT(28)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDEN	BIT(27)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLRCK	BIT(26)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLR(x)	((x) << 23)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK	BIT(22)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN		BIT(21)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CD(x)	((x) << 19)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(x)	((x) << 17)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK	BIT(16)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW	BIT(15)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(x)	((x) << 13)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(x)	((x) << 10)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOSTCK(x)	((x) << 8)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOST(x)	((x) << 6)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(x)	((x) << 0)
+
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOWCK(x)	((x) << 30)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOW(x)	((x) << 28)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(x)	((x) << 18)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(x)	((x) << 14)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMPCK(x)	((x) << 11)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(x)	((x) << 7)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(x)	((x) << 4)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SDAPD		BIT(3)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SDAEN		BIT(2)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SCLPD		BIT(1)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SCLEN		BIT(0)
+
+#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1		BIT(31)
+#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD		BIT(30)
+#define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN		BIT(29)
+#define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN		BIT(28)
+#define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33	BIT(27)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK	BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT	26
+#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN		BIT(25)
+#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x)	((x) << 22)
+#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x)	((x) << 20)
+#define SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN		BIT(19)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CS		BIT(18)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CP_S(x)		((x) << 13)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(x)	((x) << 7)
+#define SUN8I_HDMI_PHY_PLL_CFG1_BWS		BIT(6)
+#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK	GENMASK(5, 0)
+#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT	0
+
+#define SUN8I_HDMI_PHY_PLL_CFG2_SV_H		BIT(31)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PDCLKSEL(x)	((x) << 29)
+#define SUN8I_HDMI_PHY_PLL_CFG2_CLKSTEP(x)	((x) << 27)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PSET(x)		((x) << 24)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PCLK_SEL	BIT(23)
+#define SUN8I_HDMI_PHY_PLL_CFG2_AUTOSYNC_DIS	BIT(22)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VREG2_OUT_EN	BIT(21)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VREG1_OUT_EN	BIT(20)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN	BIT(19)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN(x)	((x) << 16)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(x)	((x) << 12)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_RST_IN	BIT(11)
+#define SUN8I_HDMI_PHY_PLL_CFG2_SINT_FRAC	BIT(10)
+#define SUN8I_HDMI_PHY_PLL_CFG2_SDIV2		BIT(9)
+#define SUN8I_HDMI_PHY_PLL_CFG2_S(x)		((x) << 6)
+#define SUN8I_HDMI_PHY_PLL_CFG2_S6P25_7P5	BIT(5)
+#define SUN8I_HDMI_PHY_PLL_CFG2_S5_7		BIT(4)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK	GENMASK(3, 0)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT	0
+#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(x)	(((x) - 1) << 0)
+
+#define SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2	BIT(0)
+
+#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT	11
+#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK	GENMASK(16, 11)
+#define SUN8I_HDMI_PHY_ANA_STS_RCALEND2D	BIT(7)
+#define SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK	GENMASK(5, 0)
+
 struct sunxi_dw_hdmi_priv {
 	struct dw_hdmi hdmi;
 	int mux;
+	uint rcal;
 };
 
 struct sunxi_hdmi_phy {
-	u32 pol;
-	u32 res1[3];
+	u32 dbg_ctrl;
+	u32 rext_ctrl;
+	u32 res1[2];
 	u32 read_en;
 	u32 unscramble;
 	u32 res2[2];
-	u32 ctrl;
-	u32 unk1;
-	u32 unk2;
-	u32 pll;
-	u32 clk;
-	u32 unk3;
-	u32 status;
+	u32 ana_cfg1;
+	u32 ana_cfg2;
+	u32 ana_cfg3;
+	u32 pll_cfg1;
+	u32 pll_cfg2;
+	u32 pll_cfg3;
+	u32 ana_sts;
 };
 
 #define HDMI_PHY_OFFS 0x10000
 
-static int sunxi_dw_hdmi_get_divider(uint clock)
-{
-	/*
-	 * Due to missing documentaion of HDMI PHY, we know correct
-	 * settings only for following four PHY dividers. Select one
-	 * based on clock speed.
-	 */
-	if (clock <= 27000000)
-		return 11;
-	else if (clock <= 74250000)
-		return 4;
-	else if (clock <= 148500000)
-		return 2;
-	else
-		return 1;
-}
-
-static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+static void sunxi_dw_hdmi_phy_init(struct sunxi_dw_hdmi_priv *priv)
 {
 	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
+		(struct sunxi_hdmi_phy *)(priv->hdmi.ioaddr + HDMI_PHY_OFFS);
 	unsigned long tmo;
-	u32 tmp;
 
-	/*
-	 * HDMI PHY settings are taken as-is from Allwinner BSP code.
-	 * There is no documentation.
-	 */
-	writel(0, &phy->ctrl);
-	setbits_le32(&phy->ctrl, BIT(0));
+	/* enable read access to HDMI controller */
+	writel(SUN8I_HDMI_PHY_READ_EN_MAGIC, &phy->read_en);
+	/* descramble register offsets */
+	writel(SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC, &phy->unscramble);
+
+	writel(0, &phy->ana_cfg1);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
 	udelay(5);
-	setbits_le32(&phy->ctrl, BIT(16));
-	setbits_le32(&phy->ctrl, BIT(1));
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
 	udelay(10);
-	setbits_le32(&phy->ctrl, BIT(2));
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
 	udelay(5);
-	setbits_le32(&phy->ctrl, BIT(3));
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
 	udelay(40);
-	setbits_le32(&phy->ctrl, BIT(19));
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
 	udelay(100);
-	setbits_le32(&phy->ctrl, BIT(18));
-	setbits_le32(&phy->ctrl, 7 << 4);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
+	setbits_le32(&phy->ana_cfg1,
+		     SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
 
 	/* Note that Allwinner code doesn't fail in case of timeout */
 	tmo = timer_get_us() + 2000;
-	while ((readl(&phy->status) & 0x80) == 0) {
+	while ((readl(&phy->ana_sts) & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D) == 0) {
 		if (timer_get_us() > tmo) {
 			printf("Warning: HDMI PHY init timeout!\n");
 			break;
 		}
 	}
 
-	setbits_le32(&phy->ctrl, 0xf << 8);
-	setbits_le32(&phy->ctrl, BIT(7));
+	setbits_le32(&phy->ana_cfg1,
+		     SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
 
-	writel(0x39dc5040, &phy->pll);
-	writel(0x80084343, &phy->clk);
-	udelay(10000);
-	writel(1, &phy->unk3);
-	setbits_le32(&phy->pll, BIT(25));
-	udelay(100000);
-	tmp = (readl(&phy->status) & 0x1f800) >> 11;
-	setbits_le32(&phy->pll, BIT(31) | BIT(30));
-	setbits_le32(&phy->pll, tmp);
-	writel(0x01FF0F7F, &phy->ctrl);
-	writel(0x80639000, &phy->unk1);
-	writel(0x0F81C405, &phy->unk2);
+	/* enable DDC communication */
+	writel(SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
+	       SUN8I_HDMI_PHY_ANA_CFG3_SDAEN, &phy->ana_cfg3);
 
-	/* enable read access to HDMI controller */
-	writel(0x54524545, &phy->read_en);
-	/* descramble register offsets */
-	writel(0x42494E47, &phy->unscramble);
+	priv->rcal = readl(&phy->ana_sts) & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK;
+	priv->rcal >>= 2;
 }
 
 static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi,
@@ -120,83 +220,130 @@  static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi,
 {
 	struct sunxi_hdmi_phy * const phy =
 		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
-	int div = sunxi_dw_hdmi_get_divider(edid->pixelclock.typ);
-	u32 tmp;
+	struct sunxi_dw_hdmi_priv *priv =
+		container_of(hdmi, struct sunxi_dw_hdmi_priv, hdmi);
+	u32 pll_cfg1, pll_cfg2, ana_cfg1, ana_cfg2, ana_cfg3;
+	u32 tmp, b_offset = 0;
 
-	/*
-	 * Unfortunately, we don't know much about those magic
-	 * numbers. They are taken from Allwinner BSP driver.
-	 */
-	switch (div) {
-	case 1:
-		writel(0x30dc5fc0, &phy->pll);
-		writel(0x800863C0 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(200);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		if (tmp < 0x3d)
-			setbits_le32(&phy->pll, tmp + 2);
-		else
-			setbits_le32(&phy->pll, 0x3f);
-		mdelay(100);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063b000, &phy->unk1);
-		writel(0x0F8246B5, &phy->unk2);
-		break;
-	case 2:
-		writel(0x39dc5040, &phy->pll);
-		writel(0x80084380 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(100);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		setbits_le32(&phy->pll, tmp);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063a800, &phy->unk1);
-		writel(0x0F81C485, &phy->unk2);
-		break;
-	case 4:
-		writel(0x39dc5040, &phy->pll);
-		writel(0x80084340 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(100);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		setbits_le32(&phy->pll, tmp);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063b000, &phy->unk1);
-		writel(0x0F81C405, &phy->unk2);
-		break;
-	case 11:
-		writel(0x39dc5040, &phy->pll);
-		writel(0x80084300 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(100);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		setbits_le32(&phy->pll, tmp);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063b000, &phy->unk1);
-		writel(0x0F81C405, &phy->unk2);
-		break;
+	/* bandwidth / frequency independent settings */
+
+	pll_cfg1 = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
+		   SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
+		   SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
+		   SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
+		   SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
+		   SUN8I_HDMI_PHY_PLL_CFG1_CS |
+		   SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
+		   SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
+		   SUN8I_HDMI_PHY_PLL_CFG1_BWS;
+
+	pll_cfg2 = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
+		   SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
+		   SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
+
+	ana_cfg1 = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
+		   SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
+		   SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
+		   SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
+		   SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
+		   SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
+		   SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
+		   SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
+		   SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
+		   SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
+		   SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
+		   SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
+		   SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
+		   SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
+		   SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
+
+	ana_cfg2 = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
+		   SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
+		   SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
+		   SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
+		   SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
+
+	ana_cfg3 = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
+		   SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
+		   SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
+
+	/* bandwidth / frequency dependent settings */
+	if (edid->pixelclock.typ <= 27000000) {
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+			    SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(4);
+		ana_cfg1 |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(priv->rcal);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
+	} else if (edid->pixelclock.typ <= 74250000) {
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+			    SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(5);
+		ana_cfg1 |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(priv->rcal);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
+	} else if (edid->pixelclock.typ <= 148500000) {
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+			    SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(6);
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
+	} else {
+		b_offset = 2;
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(7);
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3);
 	}
 
+	writel(pll_cfg1, &phy->pll_cfg1);
+	writel(pll_cfg2 | (phy_div - 1), &phy->pll_cfg2);
+	mdelay(10);
+	writel(SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2, &phy->pll_cfg3);
+	setbits_le32(&phy->pll_cfg1, SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
+	mdelay(100);
+	tmp = readl(&phy->ana_sts) & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK;
+	tmp >>= SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
+	tmp = min(tmp + b_offset, (u32)0x3f);
+	setbits_le32(&phy->pll_cfg1,
+		     SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
+		     SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
+	setbits_le32(&phy->pll_cfg1, tmp);
+	mdelay(100);
+	writel(ana_cfg1, &phy->ana_cfg1);
+	writel(ana_cfg2, &phy->ana_cfg2);
+	writel(ana_cfg3, &phy->ana_cfg3);
+
 	if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW)
-		setbits_le32(&phy->pol, 0x200);
+		setbits_le32(&phy->dbg_ctrl,
+			     SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC);
 
 	if (edid->flags & DISPLAY_FLAGS_HSYNC_LOW)
-		setbits_le32(&phy->pol, 0x100);
+		setbits_le32(&phy->dbg_ctrl,
+			     SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC);
 
-	setbits_le32(&phy->ctrl, 0xf << 12);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL);
 }
 
 static void sunxi_dw_hdmi_pll_set(uint clk_khz, int *phy_div)
@@ -363,7 +510,7 @@  static int sunxi_dw_hdmi_probe(struct udevice *dev)
 	/* Clock on */
 	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
 
-	sunxi_dw_hdmi_phy_init(&priv->hdmi);
+	sunxi_dw_hdmi_phy_init(priv);
 
 	priv->mux = uc_plat->source_id;