From: Ao Xu <ao...@amlogic.com>

The S4-series splits the HIU into `sys_ctrl`, `pwr_ctrl`, and `clk_ctrl`.
Introduce VPU clock settings specific to the Amlogic S4 SoC,
which differ from the configurations used for G12.

Signed-off-by: Ao Xu <ao...@amlogic.com>
---
 drivers/gpu/drm/meson/meson_vclk.c | 1018 +++++++++++++++++++++++++-----------
 1 file changed, 720 insertions(+), 298 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_vclk.c 
b/drivers/gpu/drm/meson/meson_vclk.c
index 
2a942dc6a6dc23561ec26a54139b27acf8009ccb..b2707af2a5283874936658d2749cecb4ef86beb5
 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -87,8 +87,11 @@
 #define CTS_VDAC_EN            BIT(4)
 #define HDMI_TX_PIXEL_EN       BIT(5)
 #define HHI_HDMI_CLK_CNTL      0x1cc /* 0x73 offset in data sheet */
-#define HDMI_TX_PIXEL_SEL_MASK (0xf << 16)
+#define HDMI_TX_PIXEL_SEL_MASK GENMASK(19, 16)
 #define HDMI_TX_PIXEL_SEL_SHIFT        16
+
+#define HDMI_TX_FE_SEL_MASK    GENMASK(23, 20)
+#define HDMI_TX_FE_SEL_SHIFT   20
 #define CTS_HDMI_SYS_SEL_MASK  (0x7 << 9)
 #define CTS_HDMI_SYS_DIV_MASK  (0x7f)
 #define CTS_HDMI_SYS_EN                BIT(8)
@@ -110,6 +113,30 @@
 #define HDMI_PLL_LOCK          BIT(31)
 #define HDMI_PLL_LOCK_G12A     (3 << 30)
 
+/* ANA Registers */
+/* REG_BASE:  REGISTER_BASE_ADDR = 0xfe000000 */
+#define CLKCTRL_VID_CLK_CTRL   0x0c0 /* 0x30 offset in data sheet */
+#define CLKCTRL_VID_CLK_CTRL2  0x0c4 /* 0x31 offset in data sheet */
+#define CLKCTRL_VID_CLK_DIV    0x0c8 /* 0x32 offset in data sheet */
+#define CLKCTRL_VIID_CLK_DIV   0x0cc /* 0x33 offset in data sheet */
+#define CLKCTRL_VIID_CLK_CTRL  0x0d0 /* 0x34 offset in data sheet */
+
+#define CLKCTRL_VID_PLL_CLK_DIV        0x0e4 /* 0x39 offset in data sheet */
+#define CLKCTRL_HDMI_CLK_CTRL  0x0e0  /* 0x38 */
+
+/* REG_BASE:  REGISTER_BASE_ADDR = 0xfe008000 */
+#define ANACTRL_HDMIPLL_CTRL0  0x1c0 /* 0x70 offset in data sheet */
+#define ANACTRL_HDMIPLL_CTRL1  0x1c4 /* 0x71 offset in data sheet */
+#define ANACTRL_HDMIPLL_CTRL2  0x1c8 /* 0x72 offset in data sheet */
+#define ANACTRL_HDMIPLL_CTRL3  0x1cc /* 0x73 offset in data sheet */
+#define ANACTRL_HDMIPLL_CTRL4  0x1d0 /* 0x74 offset in data sheet */
+#define ANACTRL_HDMIPLL_CTRL5  0x1d4 /* 0x75 offset in data sheet */
+#define ANACTRL_HDMIPLL_CTRL6  0x1d8 /* 0x76 offset in data sheet */
+#define ANACTRL_HDMIPLL_STS    0x1dc /* 0x77 offset in data sheet */
+#define ANACTRL_HDMIPLL_VLOCK  0x1e4 /* 0x79 offset in data sheet */
+#define HDMI_PLL_RESET_S4      BIT(29)
+#define HDMI_PLL_LOCK_S4       (3 << 30)
+
 #define FREQ_1000_1001(_freq)  DIV_ROUND_CLOSEST(_freq * 1000, 1001)
 
 /* VID PLL Dividers */
@@ -137,8 +164,13 @@ static void meson_vid_pll_set(struct meson_drm *priv, 
unsigned int div)
        unsigned int shift_sel = 0;
 
        /* Disable vid_pll output clock */
-       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
-       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_PLL_CLK_DIV, 
VID_PLL_EN, 0);
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_PLL_CLK_DIV, 
VID_PLL_PRESET, 0);
+       } else {
+               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 
0);
+               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, 
VID_PLL_PRESET, 0);
+       }
 
        switch (div) {
        case VID_PLL_DIV_2:
@@ -199,37 +231,71 @@ static void meson_vid_pll_set(struct meson_drm *priv, 
unsigned int div)
                break;
        }
 
-       if (div == VID_PLL_DIV_1)
-               /* Enable vid_pll bypass to HDMI pll */
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  VID_PLL_BYPASS, VID_PLL_BYPASS);
-       else {
-               /* Disable Bypass */
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  VID_PLL_BYPASS, 0);
-               /* Clear sel */
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  3 << 16, 0);
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  VID_PLL_PRESET, 0);
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  0x7fff, 0);
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               if (div == VID_PLL_DIV_1) {
+                       /* Enable vid_pll bypass to HDMI pll */
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          VID_PLL_BYPASS, VID_PLL_BYPASS);
+               } else {
+                       /* Disable Bypass */
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          VID_PLL_BYPASS, 0);
+                       /* Clear sel */
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          3 << 16, 0);
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          VID_PLL_PRESET, 0);
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          0x7fff, 0);
+
+                       /* Setup sel and val */
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          3 << 16, shift_sel << 16);
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          VID_PLL_PRESET, VID_PLL_PRESET);
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          0x7fff, shift_val);
+
+                       regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_PLL_CLK_DIV,
+                                          VID_PLL_PRESET, 0);
+               }
 
-               /* Setup sel and val */
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  3 << 16, shift_sel << 16);
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  VID_PLL_PRESET, VID_PLL_PRESET);
-               regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  0x7fff, shift_val);
+               /* Enable the vid_pll output clock */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_PLL_CLK_DIV,
+                                       VID_PLL_EN, VID_PLL_EN);
+       } else {
+               if (div == VID_PLL_DIV_1) {
+                       /* Enable vid_pll bypass to HDMI pll */
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          VID_PLL_BYPASS, VID_PLL_BYPASS);
+               } else {
+                       /* Disable Bypass */
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          VID_PLL_BYPASS, 0);
+                       /* Clear sel */
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          3 << 16, 0);
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          VID_PLL_PRESET, 0);
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          0x7fff, 0);
+
+                       /* Setup sel and val */
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          3 << 16, shift_sel << 16);
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          VID_PLL_PRESET, VID_PLL_PRESET);
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          0x7fff, shift_val);
+
+                       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+                                          VID_PLL_PRESET, 0);
+               }
 
+               /* Enable the vid_pll output clock */
                regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                                  VID_PLL_PRESET, 0);
+                                       VID_PLL_EN, VID_PLL_EN);
        }
-
-       /* Enable the vid_pll output clock */
-       regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-                               VID_PLL_EN, VID_PLL_EN);
 }
 
 /*
@@ -287,56 +353,117 @@ static void meson_venci_cvbs_clock_config(struct 
meson_drm *priv)
                regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
                        ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A),
                        10, 0);
+       } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL0, 0x3b01047b);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL1, 0x00018000);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL2, 0x00000000);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL3, 0x0a691c00);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL4, 0x33771290);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL5, 0x39270000);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL6, 0x50540000);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL0, 0x1b01047b);
+
+               /* Poll for lock bit */
+               regmap_read_poll_timeout(priv->hhi, ANACTRL_HDMIPLL_CTRL0, val,
+                       ((val & HDMI_PLL_LOCK) == HDMI_PLL_LOCK),
+                       10, 0);
        }
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               /* Disable VCLK2 */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_CTRL, 
VCLK2_EN, 0);
 
-       /* Disable VCLK2 */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
+               /* Setup vid_pll to /1 */
+               meson_vid_pll_set(priv, VID_PLL_DIV_1);
 
-       /* Setup vid_pll to /1 */
-       meson_vid_pll_set(priv, VID_PLL_DIV_1);
+               /* Setup the VCLK2 divider value to achieve 27MHz */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_DIV,
+                                       VCLK2_DIV_MASK, (55 - 1));
 
-       /* Setup the VCLK2 divider value to achieve 27MHz */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
-                               VCLK2_DIV_MASK, (55 - 1));
+               /* select vid_pll for vclk2 */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_CTRL,
+                                       VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT));
 
-       /* select vid_pll for vclk2 */
-       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+               /* enable vclk2 gate */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_CTRL, 
VCLK2_EN, VCLK2_EN);
+
+               /* select vclk_div1 for enci */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCI_SEL_MASK, (8 << 
CTS_ENCI_SEL_SHIFT));
+               /* select vclk_div1 for vdac */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_DIV,
+                                       CTS_VDAC_SEL_MASK, (8 << 
CTS_VDAC_SEL_SHIFT));
+
+               /* release vclk2_div_reset and enable vclk2_div */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_DIV,
+                                       VCLK2_DIV_EN | VCLK2_DIV_RESET, 
VCLK2_DIV_EN);
+
+               /* enable vclk2_div1 gate */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_CTRL,
+                                       VCLK2_DIV1_EN, VCLK2_DIV1_EN);
+
+               /* reset vclk2 */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_CTRL,
+                                       VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VIID_CLK_CTRL,
+                                       VCLK2_SOFT_RESET, 0);
+
+               /* enable enci_clk */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL2,
+                                       CTS_ENCI_EN, CTS_ENCI_EN);
+               /* enable vdac_clk */
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL2,
+                                       CTS_VDAC_EN, CTS_VDAC_EN);
+
+       } else {
+               /* Disable VCLK2 */
+               regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
+
+               /* Setup vid_pll to /1 */
+               meson_vid_pll_set(priv, VID_PLL_DIV_1);
+
+               /* Setup the VCLK2 divider value to achieve 27MHz */
+               regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
+                                       VCLK2_DIV_MASK, (55 - 1));
+
+               /* select vid_pll for vclk2 */
+               if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+                       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+                                               VCLK2_SEL_MASK, (0 << 
VCLK2_SEL_SHIFT));
+               else
+                       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+                                               VCLK2_SEL_MASK, (4 << 
VCLK2_SEL_SHIFT));
+
+               /* enable vclk2 gate */
+               regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 
VCLK2_EN);
+
+               /* select vclk_div1 for enci */
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                       CTS_ENCI_SEL_MASK, (8 << 
CTS_ENCI_SEL_SHIFT));
+               /* select vclk_div1 for vdac */
+               regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
+                                       CTS_VDAC_SEL_MASK, (8 << 
CTS_VDAC_SEL_SHIFT));
+
+               /* release vclk2_div_reset and enable vclk2_div */
+               regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
+                                       VCLK2_DIV_EN | VCLK2_DIV_RESET, 
VCLK2_DIV_EN);
+
+               /* enable vclk2_div1 gate */
                regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
-                                       VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT));
-       else
+                                       VCLK2_DIV1_EN, VCLK2_DIV1_EN);
+
+               /* reset vclk2 */
+               regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
+                                       VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
                regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
-                                       VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
-
-       /* enable vclk2 gate */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
-
-       /* select vclk_div1 for enci */
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCI_SEL_MASK, (8 << CTS_ENCI_SEL_SHIFT));
-       /* select vclk_div1 for vdac */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
-                               CTS_VDAC_SEL_MASK, (8 << CTS_VDAC_SEL_SHIFT));
-
-       /* release vclk2_div_reset and enable vclk2_div */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
-                               VCLK2_DIV_EN | VCLK2_DIV_RESET, VCLK2_DIV_EN);
-
-       /* enable vclk2_div1 gate */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
-                               VCLK2_DIV1_EN, VCLK2_DIV1_EN);
-
-       /* reset vclk2 */
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
-                               VCLK2_SOFT_RESET, VCLK2_SOFT_RESET);
-       regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
-                               VCLK2_SOFT_RESET, 0);
-
-       /* enable enci_clk */
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
-                               CTS_ENCI_EN, CTS_ENCI_EN);
-       /* enable vdac_clk */
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
-                               CTS_VDAC_EN, CTS_VDAC_EN);
+                                       VCLK2_SOFT_RESET, 0);
+
+               /* enable enci_clk */
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+                                       CTS_ENCI_EN, CTS_ENCI_EN);
+               /* enable vdac_clk */
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+                                       CTS_VDAC_EN, CTS_VDAC_EN);
+       }
 }
 
 enum {
@@ -357,6 +484,8 @@ enum {
        MESON_VCLK_HDMI_594000,
 /* 2970 /1 /1 /1 /5 /1  => /1 /2 */
        MESON_VCLK_HDMI_594000_YUV420,
+/* 4320 /4 /4 /1 /5 /1  => /2 /2 */
+       MESON_VCLK_HDMI_27000,
 };
 
 struct meson_vclk_params {
@@ -467,6 +596,18 @@ struct meson_vclk_params {
                .vid_pll_div = VID_PLL_DIV_5,
                .vclk_div = 1,
        },
+       [MESON_VCLK_HDMI_27000] = {
+               .pll_freq = 4320000,
+               .phy_freq = 270000,
+               .vclk_freq = 54000,
+               .venc_freq = 27000,
+               .pixel_freq = 27000,
+               .pll_od1 = 4,
+               .pll_od2 = 4,
+               .pll_od3 = 1,
+               .vid_pll_div = VID_PLL_DIV_5,
+               .vclk_div = 1,
+       },
        { /* sentinel */ },
 };
 
@@ -487,136 +628,226 @@ static inline unsigned int pll_od_to_reg(unsigned int 
od)
        return 0;
 }
 
-static void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
+static void gxbb_pll_set_params(struct meson_drm *priv, unsigned int m,
                                      unsigned int frac, unsigned int od1,
                                      unsigned int od2, unsigned int od3)
 {
        unsigned int val;
 
-       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
-               if (frac)
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
-                                    0x00004000 | frac);
-               else
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
-                                    0x00000000);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
+       if (frac)
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                            0x00004000 | frac);
+       else
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                            0x00000000);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+       /* Enable and unreset */
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                          0x7 << 28, HHI_HDMI_PLL_CNTL_EN);
+
+       /* Poll for lock bit */
+       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                val, (val & HDMI_PLL_LOCK), 10, 0);
+
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                               3 << 16, pll_od_to_reg(od1) << 16);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                               3 << 22, pll_od_to_reg(od2) << 22);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+                               3 << 18, pll_od_to_reg(od3) << 18);
+}
 
-               /* Enable and unreset */
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                                  0x7 << 28, HHI_HDMI_PLL_CNTL_EN);
+static void gxm_pll_set_params(struct meson_drm *priv, unsigned int m,
+                                     unsigned int frac, unsigned int od1,
+                                     unsigned int od2, unsigned int od3)
+{
+       unsigned int val;
 
-               /* Poll for lock bit */
-               regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-                                        val, (val & HDMI_PLL_LOCK), 10, 0);
-       } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
-                  meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
 
-               /* Reset PLL */
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                               HDMI_PLL_RESET, HDMI_PLL_RESET);
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                               HDMI_PLL_RESET, 0);
+       /* Reset PLL */
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                       HDMI_PLL_RESET, HDMI_PLL_RESET);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                       HDMI_PLL_RESET, 0);
 
-               /* Poll for lock bit */
-               regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
-                               (val & HDMI_PLL_LOCK), 10, 0);
-       } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m);
+       /* Poll for lock bit */
+       regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
+                       (val & HDMI_PLL_LOCK), 10, 0);
 
-               /* Enable and reset */
-               /* TODO: add specific macro for g12a here */
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                                  0x3 << 28, 0x3 << 28);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
+                               3 << 21, pll_od_to_reg(od1) << 21);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
+                               3 << 23, pll_od_to_reg(od2) << 23);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
+                               3 << 19, pll_od_to_reg(od3) << 19);
+}
 
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac);
-               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
+static void g12a_pll_set_params(struct meson_drm *priv, unsigned int m,
+                                     unsigned int frac, unsigned int od1,
+                                     unsigned int od2, unsigned int od3)
+{
+       unsigned int val;
+
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m);
+
+       /* Enable and reset */
+       /* TODO: add specific macro for g12a here */
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                          0x3 << 28, 0x3 << 28);
 
-               /* G12A HDMI PLL Needs specific parameters for 5.4GHz */
-               if (m >= 0xf7) {
-                       if (frac < 0x10000) {
-                               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4,
-                                                       0x6a685c00);
-                               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5,
-                                                       0x11551293);
-                       } else {
-                               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4,
-                                                       0xea68dc00);
-                               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5,
-                                                       0x65771290);
-                       }
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000);
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac);
+       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
+
+       /* G12A HDMI PLL Needs specific parameters for 5.4GHz */
+       if (m >= 0xf7) {
+               if (frac < 0x10000) {
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4,
+                                               0x6a685c00);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5,
+                                               0x11551293);
                } else {
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00);
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290);
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000);
-                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4,
+                                               0xea68dc00);
+                       regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5,
+                                               0x65771290);
                }
-
-               do {
-                       /* Reset PLL */
-                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                                       HDMI_PLL_RESET_G12A, 
HDMI_PLL_RESET_G12A);
-
-                       /* UN-Reset PLL */
-                       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                                       HDMI_PLL_RESET_G12A, 0);
-
-                       /* Poll for lock bits */
-                       if (!regmap_read_poll_timeout(priv->hhi,
-                                                     HHI_HDMI_PLL_CNTL, val,
-                                                     ((val & 
HDMI_PLL_LOCK_G12A)
-                                                       == HDMI_PLL_LOCK_G12A),
-                                                     10, 100))
-                               break;
-               } while(1);
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000);
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000);
+       } else {
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00);
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290);
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000);
+               regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000);
        }
 
-       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-                               3 << 16, pll_od_to_reg(od1) << 16);
-       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
-                meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
-                               3 << 21, pll_od_to_reg(od1) << 21);
-       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+       do {
+               /* Reset PLL */
                regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                               3 << 16, pll_od_to_reg(od1) << 16);
+                               HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A);
 
-       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-                               3 << 22, pll_od_to_reg(od2) << 22);
-       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
-                meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
-                               3 << 23, pll_od_to_reg(od2) << 23);
-       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+               /* UN-Reset PLL */
                regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-                               3 << 18, pll_od_to_reg(od2) << 18);
+                               HDMI_PLL_RESET_G12A, 0);
+
+               /* Poll for lock bits */
+               if (!regmap_read_poll_timeout(priv->hhi,
+                                             HHI_HDMI_PLL_CNTL, val,
+                                             ((val & HDMI_PLL_LOCK_G12A)
+                                             == HDMI_PLL_LOCK_G12A),
+                                             10, 100))
+                       break;
+       } while (1);
 
-       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-                               3 << 18, pll_od_to_reg(od3) << 18);
-       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
-                meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
-                               3 << 19, pll_od_to_reg(od3) << 19);
-       else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
-               regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                               3 << 16, pll_od_to_reg(od1) << 16);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                                       3 << 18, pll_od_to_reg(od2) << 18);
+       regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+                               3 << 20, pll_od_to_reg(od3) << 20);
+}
+
+static void s4_pll_set_params(struct meson_drm *priv, unsigned int m,
+                                     unsigned int frac, unsigned int od1,
+                                     unsigned int od2, unsigned int od3)
+{
+       unsigned int val;
+
+       DRM_DEBUG_DRIVER("%s: m = %d, frac = %d, od1 = %d, od2 = %d, od3 = 
%d\n",
+                       __func__, m, frac, od1, od2, od3);
+
+       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL0, 0x0b3a0400 | m);
+
+       /* Enable and reset */
+       /* TODO: add specific macro for g12a here */
+       regmap_update_bits(priv->hhi, ANACTRL_HDMIPLL_CTRL0,
+                          0x3 << 28, 0x3 << 28);
+
+       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL1, frac);
+       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL2, 0x00000000);
+
+       /* S4 HDMI PLL Needs specific parameters for 5.4GHz */
+       if (m >= 0xf7) {
+               if (frac < 0x10000) {
+                       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL3,
+                                               0x6a685c00);
+                       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL4,
+                                               0x11551293);
+               } else {
+                       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL3,
+                                               0x6a685c00);
+                       regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL4,
+                                               0x44331290);
+               }
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL5, 0x39272008);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL6, 0x56540000);
+       } else {
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL3, 0x6a68dc00);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL4, 0x65771290);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL5, 0x39272008);
+               regmap_write(priv->hhi, ANACTRL_HDMIPLL_CTRL6, 0x56540000);
+       }
+
+       do {
+               //todo, need confir rst and lock bit
+               /* Reset PLL */
+               regmap_update_bits(priv->hhi, ANACTRL_HDMIPLL_CTRL0,
+                               HDMI_PLL_RESET_S4, HDMI_PLL_RESET_S4);
+
+               /* UN-Reset PLL */
+               regmap_update_bits(priv->hhi, ANACTRL_HDMIPLL_CTRL0,
+                               HDMI_PLL_RESET_S4, 0);
+
+               /* Poll for lock bits */
+               if (!regmap_read_poll_timeout(priv->hhi,
+                                             ANACTRL_HDMIPLL_CTRL0, val,
+                                             ((val & HDMI_PLL_LOCK_S4)
+                                             == HDMI_PLL_LOCK_S4),
+                                             10, 100))
+                       break;
+       } while (1);
+
+       regmap_update_bits(priv->hhi, ANACTRL_HDMIPLL_CTRL0,
+                               3 << 16, pll_od_to_reg(od1) << 16);
+       regmap_update_bits(priv->hhi, ANACTRL_HDMIPLL_CTRL0,
+                                       3 << 18, pll_od_to_reg(od2) << 18);
+       regmap_update_bits(priv->hhi, ANACTRL_HDMIPLL_CTRL0,
                                3 << 20, pll_od_to_reg(od3) << 20);
 }
 
+static void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
+                                     unsigned int frac, unsigned int od1,
+                                     unsigned int od2, unsigned int od3)
+{
+       switch (priv->compat) {
+       case VPU_COMPATIBLE_GXBB:
+               gxbb_pll_set_params(priv, m, frac, od1, od2, od3);
+               break;
+       case VPU_COMPATIBLE_GXM:
+       case VPU_COMPATIBLE_GXL:
+               gxm_pll_set_params(priv, m, frac, od1, od2, od3);
+               break;
+       case VPU_COMPATIBLE_G12A:
+               g12a_pll_set_params(priv, m, frac, od1, od2, od3);
+               break;
+       case VPU_COMPATIBLE_S4:
+               s4_pll_set_params(priv, m, frac, od1, od2, od3);
+               break;
+       default:
+               break;
+       }
+}
+
 #define XTAL_FREQ 24000
 
 static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv,
@@ -632,6 +863,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm 
*priv,
 #define HDMI_FRAC_MAX_GXBB     4096
 #define HDMI_FRAC_MAX_GXL      1024
 #define HDMI_FRAC_MAX_G12A     131072
+#define HDMI_FRAC_MAX_S4       131072
 
 static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv,
                                            unsigned int m,
@@ -651,6 +883,9 @@ static unsigned int meson_hdmi_pll_get_frac(struct 
meson_drm *priv,
        if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
                frac_max = HDMI_FRAC_MAX_G12A;
 
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4))
+               frac_max = HDMI_FRAC_MAX_S4;
+
        /* We can have a perfect match !*/
        if (pll_freq / m == parent_freq &&
            pll_freq % m == 0)
@@ -688,6 +923,12 @@ static bool meson_hdmi_pll_validate_params(struct 
meson_drm *priv,
                        return false;
                if (frac >= HDMI_FRAC_MAX_G12A)
                        return false;
+       } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               /* Empiric supported min/max dividers */
+               if (m < 106 || m > 247)
+                       return false;
+               if (frac >= HDMI_FRAC_MAX_S4)
+                       return false;
        }
 
        return true;
@@ -813,14 +1054,22 @@ static void meson_vclk_set(struct meson_drm *priv, 
unsigned int pll_base_freq,
 {
        unsigned int m = 0, frac = 0;
 
-       /* Set HDMI-TX sys clock */
-       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                          CTS_HDMI_SYS_SEL_MASK, 0);
-       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                          CTS_HDMI_SYS_DIV_MASK, 0);
-       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                          CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
-
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               CTS_HDMI_SYS_SEL_MASK, 0);
+               regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                                  CTS_HDMI_SYS_DIV_MASK, 0);
+               regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                                  CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
+       } else {
+               /* Set HDMI-TX sys clock */
+               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                                  CTS_HDMI_SYS_SEL_MASK, 0);
+               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                                  CTS_HDMI_SYS_DIV_MASK, 0);
+               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                                  CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
+       }
        /* Set HDMI PLL rate */
        if (!od1 && !od2 && !od3) {
                meson_hdmi_pll_generic_set(priv, pll_base_freq);
@@ -875,6 +1124,22 @@ static void meson_vclk_set(struct meson_drm *priv, 
unsigned int pll_base_freq,
                        break;
                }
 
+               meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
+       } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               switch (pll_base_freq) {
+               case 2970000:
+                       m = 0x7b;
+                       frac = vic_alternate_clock ? 0x140b4 : 0x18000;
+                       break;
+               case 4320000:
+                       m = vic_alternate_clock ? 0xb3 : 0xb4;
+                       frac = vic_alternate_clock ? 0x1a3ee : 0;
+                       break;
+               case 5940000:
+                       m = 0xf7;
+                       frac = vic_alternate_clock ? 0x8148 : 0x10000;
+                       break;
+               }
                meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
        }
 
@@ -882,146 +1147,303 @@ static void meson_vclk_set(struct meson_drm *priv, 
unsigned int pll_base_freq,
        meson_vid_pll_set(priv, vid_pll_div);
 
        /* Set VCLK div */
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                          VCLK_SEL_MASK, 0);
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                          VCLK_DIV_MASK, vclk_div - 1);
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                  VCLK_SEL_MASK, 0);
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_DIV,
+                                  VCLK_DIV_MASK, vclk_div - 1);
+       } else {
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                  VCLK_SEL_MASK, 0);
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                  VCLK_DIV_MASK, vclk_div - 1);
+       }
 
        /* Set HDMI-TX source */
        switch (hdmi_tx_div) {
        case 1:
-               /* enable vclk_div1 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV1_EN, VCLK_DIV1_EN);
+               if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+                       /* enable vclk_div1 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV1_EN, VCLK_DIV1_EN);
+
+                       /* select vclk_div1 for HDMI-TX */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                                          HDMI_TX_PIXEL_SEL_MASK, 0);
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                                               HDMI_TX_FE_SEL_MASK, 0);
+               } else {
+                       /* enable vclk_div1 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV1_EN, VCLK_DIV1_EN);
 
-               /* select vclk_div1 for HDMI-TX */
-               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                                  HDMI_TX_PIXEL_SEL_MASK, 0);
+                       /* select vclk_div1 for HDMI-TX */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                                          HDMI_TX_PIXEL_SEL_MASK, 0);
+               }
                break;
        case 2:
-               /* enable vclk_div2 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV2_EN, VCLK_DIV2_EN);
+               if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+                       /* enable vclk_div2 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV2_EN, VCLK_DIV2_EN);
+
+                       /* select vclk_div2 for HDMI-TX */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_PIXEL_SEL_MASK, 1 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_FE_SEL_MASK, 1 << HDMI_TX_FE_SEL_SHIFT);
+               } else {
+                       /* enable vclk_div2 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV2_EN, VCLK_DIV2_EN);
 
-               /* select vclk_div2 for HDMI-TX */
-               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                       HDMI_TX_PIXEL_SEL_MASK, 1 << HDMI_TX_PIXEL_SEL_SHIFT);
+                       /* select vclk_div2 for HDMI-TX */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                               HDMI_TX_PIXEL_SEL_MASK, 1 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+               }
                break;
        case 4:
-               /* enable vclk_div4 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV4_EN, VCLK_DIV4_EN);
+               if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+                       /* enable vclk_div4 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV4_EN, VCLK_DIV4_EN);
+
+                       /* select vclk_div4 for HDMI-TX */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_PIXEL_SEL_MASK, 2 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_FE_SEL_MASK, 2 << HDMI_TX_FE_SEL_SHIFT);
+               } else {
+                       /* enable vclk_div4 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV4_EN, VCLK_DIV4_EN);
 
-               /* select vclk_div4 for HDMI-TX */
-               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                       HDMI_TX_PIXEL_SEL_MASK, 2 << HDMI_TX_PIXEL_SEL_SHIFT);
+                       /* select vclk_div4 for HDMI-TX */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                               HDMI_TX_PIXEL_SEL_MASK, 2 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+               }
                break;
        case 6:
-               /* enable vclk_div6 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV6_EN, VCLK_DIV6_EN);
+               if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+                       /* enable vclk_div6 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV6_EN, VCLK_DIV6_EN);
+
+                       /* select vclk_div6 for HDMI-TX */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_PIXEL_SEL_MASK, 3 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_FE_SEL_MASK, 3 << HDMI_TX_FE_SEL_SHIFT);
+               } else {
+                       /* enable vclk_div6 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV6_EN, VCLK_DIV6_EN);
 
-               /* select vclk_div6 for HDMI-TX */
-               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                       HDMI_TX_PIXEL_SEL_MASK, 3 << HDMI_TX_PIXEL_SEL_SHIFT);
+                       /* select vclk_div6 for HDMI-TX */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                               HDMI_TX_PIXEL_SEL_MASK, 3 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+               }
                break;
        case 12:
-               /* enable vclk_div12 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV12_EN, VCLK_DIV12_EN);
+               if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+                       /* enable vclk_div12 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV12_EN, VCLK_DIV12_EN);
+
+                       /* select vclk_div12 for HDMI-TX */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_PIXEL_SEL_MASK, 4 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_HDMI_CLK_CTRL,
+                               HDMI_TX_FE_SEL_MASK, 4 << HDMI_TX_FE_SEL_SHIFT);
+               } else {
+                       /* enable vclk_div12 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV12_EN, VCLK_DIV12_EN);
 
-               /* select vclk_div12 for HDMI-TX */
-               regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
-                       HDMI_TX_PIXEL_SEL_MASK, 4 << HDMI_TX_PIXEL_SEL_SHIFT);
+                       /* select vclk_div12 for HDMI-TX */
+                       regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+                               HDMI_TX_PIXEL_SEL_MASK, 4 << 
HDMI_TX_PIXEL_SEL_SHIFT);
+               }
                break;
        }
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4))
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL2,
+                                  HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
+       else
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
                                   HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
 
        /* Set ENCI/ENCP Source */
-       switch (venc_div) {
-       case 1:
-               /* enable vclk_div1 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV1_EN, VCLK_DIV1_EN);
-
-               if (hdmi_use_enci)
-                       /* select vclk_div1 for enci */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                                          CTS_ENCI_SEL_MASK, 0);
-               else
-                       /* select vclk_div1 for encp */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                                          CTS_ENCP_SEL_MASK, 0);
-               break;
-       case 2:
-               /* enable vclk_div2 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV2_EN, VCLK_DIV2_EN);
-
-               if (hdmi_use_enci)
-                       /* select vclk_div2 for enci */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCI_SEL_MASK, 1 << CTS_ENCI_SEL_SHIFT);
-               else
-                       /* select vclk_div2 for encp */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCP_SEL_MASK, 1 << CTS_ENCP_SEL_SHIFT);
-               break;
-       case 4:
-               /* enable vclk_div4 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV4_EN, VCLK_DIV4_EN);
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+               switch (venc_div) {
+               case 1:
+                       /* enable vclk_div1 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV1_EN, VCLK_DIV1_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div1 for enci */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                                  CTS_ENCI_SEL_MASK, 0);
+                       else
+                               /* select vclk_div1 for encp */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                                  CTS_ENCP_SEL_MASK, 0);
+                       break;
+               case 2:
+                       /* enable vclk_div2 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV2_EN, VCLK_DIV2_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div2 for enci */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCI_SEL_MASK, 1 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div2 for encp */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCP_SEL_MASK, 1 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               case 4:
+                       /* enable vclk_div4 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV4_EN, VCLK_DIV4_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div4 for enci */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCI_SEL_MASK, 2 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div4 for encp */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCP_SEL_MASK, 2 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               case 6:
+                       /* enable vclk_div6 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV6_EN, VCLK_DIV6_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div6 for enci */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCI_SEL_MASK, 3 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div6 for encp */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCP_SEL_MASK, 3 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               case 12:
+                       /* enable vclk_div12 gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL,
+                                          VCLK_DIV12_EN, VCLK_DIV12_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div12 for enci */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCI_SEL_MASK, 4 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div12 for encp */
+                               regmap_update_bits(priv->clkctrl, 
CLKCTRL_VID_CLK_DIV,
+                                       CTS_ENCP_SEL_MASK, 4 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               }
 
                if (hdmi_use_enci)
-                       /* select vclk_div4 for enci */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCI_SEL_MASK, 2 << CTS_ENCI_SEL_SHIFT);
+                       /* Enable ENCI clock gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL2,
+                                          CTS_ENCI_EN, CTS_ENCI_EN);
                else
-                       /* select vclk_div4 for encp */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCP_SEL_MASK, 2 << CTS_ENCP_SEL_SHIFT);
-               break;
-       case 6:
-               /* enable vclk_div6 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV6_EN, VCLK_DIV6_EN);
+                       /* Enable ENCP clock gate */
+                       regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL2,
+                                          CTS_ENCP_EN, CTS_ENCP_EN);
+
+               regmap_update_bits(priv->clkctrl, CLKCTRL_VID_CLK_CTRL, 
VCLK_EN, VCLK_EN);
+       } else {
+               switch (venc_div) {
+               case 1:
+                       /* enable vclk_div1 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV1_EN, VCLK_DIV1_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div1 for enci */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                                  CTS_ENCI_SEL_MASK, 0);
+                       else
+                               /* select vclk_div1 for encp */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                                  CTS_ENCP_SEL_MASK, 0);
+                       break;
+               case 2:
+                       /* enable vclk_div2 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV2_EN, VCLK_DIV2_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div2 for enci */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCI_SEL_MASK, 1 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div2 for encp */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCP_SEL_MASK, 1 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               case 4:
+                       /* enable vclk_div4 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV4_EN, VCLK_DIV4_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div4 for enci */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCI_SEL_MASK, 2 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div4 for encp */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCP_SEL_MASK, 2 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               case 6:
+                       /* enable vclk_div6 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV6_EN, VCLK_DIV6_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div6 for enci */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCI_SEL_MASK, 3 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div6 for encp */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCP_SEL_MASK, 3 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               case 12:
+                       /* enable vclk_div12 gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+                                          VCLK_DIV12_EN, VCLK_DIV12_EN);
+
+                       if (hdmi_use_enci)
+                               /* select vclk_div12 for enci */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCI_SEL_MASK, 4 << 
CTS_ENCI_SEL_SHIFT);
+                       else
+                               /* select vclk_div12 for encp */
+                               regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+                                               CTS_ENCP_SEL_MASK, 4 << 
CTS_ENCP_SEL_SHIFT);
+                       break;
+               }
 
                if (hdmi_use_enci)
-                       /* select vclk_div6 for enci */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCI_SEL_MASK, 3 << CTS_ENCI_SEL_SHIFT);
+                       /* Enable ENCI clock gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+                                          CTS_ENCI_EN, CTS_ENCI_EN);
                else
-                       /* select vclk_div6 for encp */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCP_SEL_MASK, 3 << CTS_ENCP_SEL_SHIFT);
-               break;
-       case 12:
-               /* enable vclk_div12 gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
-                                  VCLK_DIV12_EN, VCLK_DIV12_EN);
+                       /* Enable ENCP clock gate */
+                       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+                                          CTS_ENCP_EN, CTS_ENCP_EN);
 
-               if (hdmi_use_enci)
-                       /* select vclk_div12 for enci */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCI_SEL_MASK, 4 << CTS_ENCI_SEL_SHIFT);
-               else
-                       /* select vclk_div12 for encp */
-                       regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-                               CTS_ENCP_SEL_MASK, 4 << CTS_ENCP_SEL_SHIFT);
-               break;
+               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, 
VCLK_EN);
        }
-
-       if (hdmi_use_enci)
-               /* Enable ENCI clock gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
-                                  CTS_ENCI_EN, CTS_ENCI_EN);
-       else
-               /* Enable ENCP clock gate */
-               regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
-                                  CTS_ENCP_EN, CTS_ENCP_EN);
-
-       regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
 }
 
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,

-- 
2.43.0



Reply via email to