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;
 
