Merge https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq
[oweals/u-boot.git] / drivers / clk / clk-hsdk-cgu.c
index 30690b72f3cebd86285b5ad6385f4cd2c7885b45..3eb93a55fc412ff2dadd5e90b2550d0beccede82 100644 (file)
 #include <clk-uclass.h>
 #include <div64.h>
 #include <dm.h>
+#include <log.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
 #include <linux/io.h>
+#include <asm/arcregs.h>
+
+#include <dt-bindings/clock/snps,hsdk-cgu.h>
 
 /*
  * Synopsys ARC HSDK clock tree.
@@ -139,7 +146,7 @@ struct hsdk_div_full_cfg {
        const struct hsdk_idiv_cfg idiv[];
 };
 
-static const struct hsdk_div_full_cfg tun_clk_cfg = {
+static const struct hsdk_div_full_cfg hsdk_4xd_tun_clk_cfg = {
        { 25000000,  50000000,  75000000,  100000000, 125000000, 150000000 },
        { 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
        { CGU_TUN_IDIV_TUN,     { 24,   12,     8,      6,      6,      4 } },
@@ -150,6 +157,16 @@ static const struct hsdk_div_full_cfg tun_clk_cfg = {
        }
 };
 
+static const struct hsdk_div_full_cfg hsdk_tun_clk_cfg = {
+       { 25000000,  50000000,  75000000,  100000000, 125000000, 150000000 },
+       { 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
+       { CGU_TUN_IDIV_TUN,     { 24,   12,     8,      6,      6,      4 } },
+       { CGU_TUN_IDIV_ROM,     { 4,    4,      4,      4,      5,      4 } },
+       { CGU_TUN_IDIV_PWM,     { 8,    8,      8,      8,      10,     8 } },
+       { /* last one */ }
+       }
+};
+
 static const struct hsdk_div_full_cfg axi_clk_cfg = {
        { 200000000,    400000000,      600000000,      800000000 },
        { 800000000,    800000000,      600000000,      800000000 }, {
@@ -214,23 +231,29 @@ static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
        {}
 };
 
-struct hsdk_cgu_clk {
-       /* CGU block register */
-       void __iomem *cgu_regs;
-       /* CREG block register */
-       void __iomem *creg_regs;
-
+struct hsdk_cgu_domain {
        /* PLLs registers */
-       void __iomem *regs;
+       void __iomem *pll_regs;
        /* PLLs special registers */
        void __iomem *spec_regs;
        /* PLLs devdata */
-       const struct hsdk_pll_devdata *pll_devdata;
+       const struct hsdk_pll_devdata *pll;
 
        /* Dividers registers */
        void __iomem *idiv_regs;
 };
 
+struct hsdk_cgu_clk {
+       const struct cgu_clk_map *map;
+       /* CGU block register */
+       void __iomem *cgu_regs;
+       /* CREG block register */
+       void __iomem *creg_regs;
+
+       /* The domain we are working with */
+       struct hsdk_cgu_domain curr_domain;
+};
+
 struct hsdk_pll_devdata {
        const u32 parent_rate;
        const struct hsdk_pll_cfg *const pll_cfg;
@@ -265,13 +288,14 @@ static const struct hsdk_pll_devdata hdmi_pll_dat = {
 static ulong idiv_set(struct clk *, ulong);
 static ulong cpu_clk_set(struct clk *, ulong);
 static ulong axi_clk_set(struct clk *, ulong);
-static ulong tun_clk_set(struct clk *, ulong);
+static ulong tun_hsdk_set(struct clk *, ulong);
+static ulong tun_h4xd_set(struct clk *, ulong);
 static ulong idiv_get(struct clk *);
 static int idiv_off(struct clk *);
 static ulong pll_set(struct clk *, ulong);
 static ulong pll_get(struct clk *);
 
-struct hsdk_cgu_clock_map {
+struct cgu_clk_map {
        const u32 cgu_pll_oft;
        const u32 cgu_div_oft;
        const struct hsdk_pll_devdata *const pll_devdata;
@@ -280,64 +304,94 @@ struct hsdk_cgu_clock_map {
        const int (*const disable)(struct clk *clk);
 };
 
-static const struct hsdk_cgu_clock_map clock_map[] = {
-       { CGU_ARC_PLL, 0, &core_pll_dat, pll_get, pll_set, NULL },
-       { CGU_ARC_PLL, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
-       { CGU_DDR_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
-       { CGU_SYS_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_TUN_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
-       { CGU_TUN_PLL, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off },
-       { CGU_TUN_PLL, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_TUN_PLL, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_TUN_PLL, CGU_TUN_IDIV_TIMER, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_HDMI_PLL, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
-       { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
+static const struct cgu_clk_map hsdk_clk_map[] = {
+       [CLK_ARC_PLL]        = { CGU_ARC_PLL,  0,                      &core_pll_dat, pll_get,  pll_set,      NULL     },
+       [CLK_ARC]            = { CGU_ARC_PLL,  CGU_ARC_IDIV,           &core_pll_dat, idiv_get, cpu_clk_set,  idiv_off },
+       [CLK_DDR_PLL]        = { CGU_DDR_PLL,  0,                      &sdt_pll_dat,  pll_get,  pll_set,      NULL     },
+       [CLK_SYS_PLL]        = { CGU_SYS_PLL,  0,                      &sdt_pll_dat,  pll_get,  pll_set,      NULL     },
+       [CLK_SYS_APB]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_APB,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_AXI]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_AXI,       &sdt_pll_dat,  idiv_get, axi_clk_set,  idiv_off },
+       [CLK_SYS_ETH]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_ETH,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_USB]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_USB,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_SDIO]       = { CGU_SYS_PLL,  CGU_SYS_IDIV_SDIO,      &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_HDMI]       = { CGU_SYS_PLL,  CGU_SYS_IDIV_HDMI,      &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_GFX_CORE]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_GFX_CORE,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_GFX_DMA]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_GFX_DMA,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_GFX_CFG]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_GFX_CFG,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_DMAC_CORE]  = { CGU_SYS_PLL,  CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_DMAC_CFG]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_DMAC_CFG,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_SDIO_REF]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_SDIO_REF,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_SPI_REF]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_SPI_REF,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_I2C_REF]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_I2C_REF,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_UART_REF]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_UART_REF,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_EBI_REF]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_EBI_REF,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_TUN_PLL]        = { CGU_TUN_PLL,  0,                      &sdt_pll_dat,  pll_get,  pll_set,      NULL     },
+       [CLK_TUN_TUN]        = { CGU_TUN_PLL,  CGU_TUN_IDIV_TUN,       &sdt_pll_dat,  idiv_get, tun_hsdk_set, idiv_off },
+       [CLK_TUN_ROM]        = { CGU_TUN_PLL,  CGU_TUN_IDIV_ROM,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_TUN_PWM]        = { CGU_TUN_PLL,  CGU_TUN_IDIV_PWM,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_TUN_TIMER]      = { /* missing in HSDK */ },
+       [CLK_HDMI_PLL]       = { CGU_HDMI_PLL, 0,                      &hdmi_pll_dat, pll_get,  pll_set,      NULL     },
+       [CLK_HDMI]           = { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB,      &hdmi_pll_dat, idiv_get, idiv_set,     idiv_off }
+};
+
+static const struct cgu_clk_map hsdk_4xd_clk_map[] = {
+       [CLK_ARC_PLL]        = { CGU_ARC_PLL,  0,                      &core_pll_dat, pll_get,  pll_set,      NULL     },
+       [CLK_ARC]            = { CGU_ARC_PLL,  CGU_ARC_IDIV,           &core_pll_dat, idiv_get, cpu_clk_set,  idiv_off },
+       [CLK_DDR_PLL]        = { CGU_DDR_PLL,  0,                      &sdt_pll_dat,  pll_get,  pll_set,      NULL     },
+       [CLK_SYS_PLL]        = { CGU_SYS_PLL,  0,                      &sdt_pll_dat,  pll_get,  pll_set,      NULL     },
+       [CLK_SYS_APB]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_APB,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_AXI]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_AXI,       &sdt_pll_dat,  idiv_get, axi_clk_set,  idiv_off },
+       [CLK_SYS_ETH]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_ETH,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_USB]        = { CGU_SYS_PLL,  CGU_SYS_IDIV_USB,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_SDIO]       = { CGU_SYS_PLL,  CGU_SYS_IDIV_SDIO,      &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_HDMI]       = { CGU_SYS_PLL,  CGU_SYS_IDIV_HDMI,      &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_GFX_CORE]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_GFX_CORE,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_GFX_DMA]    = { /* missing in HSDK-4xD */ },
+       [CLK_SYS_GFX_CFG]    = { /* missing in HSDK-4xD */ },
+       [CLK_SYS_DMAC_CORE]  = { CGU_SYS_PLL,  CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_DMAC_CFG]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_DMAC_CFG,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_SDIO_REF]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_SDIO_REF,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_SPI_REF]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_SPI_REF,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_I2C_REF]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_I2C_REF,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_UART_REF]   = { CGU_SYS_PLL,  CGU_SYS_IDIV_UART_REF,  &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_SYS_EBI_REF]    = { CGU_SYS_PLL,  CGU_SYS_IDIV_EBI_REF,   &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_TUN_PLL]        = { CGU_TUN_PLL,  0,                      &sdt_pll_dat,  pll_get,  pll_set,      NULL     },
+       [CLK_TUN_TUN]        = { CGU_TUN_PLL,  CGU_TUN_IDIV_TUN,       &sdt_pll_dat,  idiv_get, tun_h4xd_set, idiv_off },
+       [CLK_TUN_ROM]        = { CGU_TUN_PLL,  CGU_TUN_IDIV_ROM,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_TUN_PWM]        = { CGU_TUN_PLL,  CGU_TUN_IDIV_PWM,       &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_TUN_TIMER]      = { CGU_TUN_PLL,  CGU_TUN_IDIV_TIMER,     &sdt_pll_dat,  idiv_get, idiv_set,     idiv_off },
+       [CLK_HDMI_PLL]       = { CGU_HDMI_PLL, 0,                      &hdmi_pll_dat, pll_get,  pll_set,      NULL     },
+       [CLK_HDMI]           = { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB,      &hdmi_pll_dat, idiv_get, idiv_set,     idiv_off }
 };
 
 static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val)
 {
-       iowrite32(val, clk->idiv_regs);
+       iowrite32(val, clk->curr_domain.idiv_regs);
 }
 
 static inline u32 hsdk_idiv_read(struct hsdk_cgu_clk *clk)
 {
-       return ioread32(clk->idiv_regs);
+       return ioread32(clk->curr_domain.idiv_regs);
 }
 
 static inline void hsdk_pll_write(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
 {
-       iowrite32(val, clk->regs + reg);
+       iowrite32(val, clk->curr_domain.pll_regs + reg);
 }
 
 static inline u32 hsdk_pll_read(struct hsdk_cgu_clk *clk, u32 reg)
 {
-       return ioread32(clk->regs + reg);
+       return ioread32(clk->curr_domain.pll_regs + reg);
 }
 
 static inline void hsdk_pll_spcwrite(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
 {
-       iowrite32(val, clk->spec_regs + reg);
+       iowrite32(val, clk->curr_domain.spec_regs + reg);
 }
 
 static inline u32 hsdk_pll_spcread(struct hsdk_cgu_clk *clk, u32 reg)
 {
-       return ioread32(clk->spec_regs + reg);
+       return ioread32(clk->curr_domain.spec_regs + reg);
 }
 
 static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk,
@@ -372,7 +426,7 @@ static ulong pll_get(struct clk *sclk)
        u64 rate;
        u32 idiv, fbdiv, odiv;
        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
-       u32 parent_rate = clk->pll_devdata->parent_rate;
+       u32 parent_rate = clk->curr_domain.pll->parent_rate;
 
        val = hsdk_pll_read(clk, CGU_PLL_CTRL);
 
@@ -404,7 +458,7 @@ static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate)
        int i;
        unsigned long best_rate;
        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
-       const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+       const struct hsdk_pll_cfg *pll_cfg = clk->curr_domain.pll->pll_cfg;
 
        if (pll_cfg[0].rate == 0)
                return -EINVAL;
@@ -480,19 +534,17 @@ static ulong pll_set(struct clk *sclk, ulong rate)
        int i;
        unsigned long best_rate;
        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
-       const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
+       const struct hsdk_pll_devdata *pll = clk->curr_domain.pll;
+       const struct hsdk_pll_cfg *pll_cfg = pll->pll_cfg;
 
        best_rate = hsdk_pll_round_rate(sclk, rate);
 
-       for (i = 0; pll_cfg[i].rate != 0; i++) {
-               if (pll_cfg[i].rate == best_rate) {
-                       return clk->pll_devdata->update_rate(clk, best_rate,
-                                                            &pll_cfg[i]);
-               }
-       }
+       for (i = 0; pll_cfg[i].rate != 0; i++)
+               if (pll_cfg[i].rate == best_rate)
+                       return pll->update_rate(clk, best_rate, &pll_cfg[i]);
 
        pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate,
-              clk->pll_devdata->parent_rate);
+              pll->parent_rate);
 
        return -EINVAL;
 }
@@ -570,7 +622,7 @@ static ulong common_div_clk_set(struct clk *sclk, ulong rate,
 
        /* configure SYS dividers */
        for (i = 0; cfg->idiv[i].oft != 0; i++) {
-               clk->idiv_regs = clk->cgu_regs + cfg->idiv[i].oft;
+               clk->curr_domain.idiv_regs = clk->cgu_regs + cfg->idiv[i].oft;
                hsdk_idiv_write(clk, cfg->idiv[i].val[freq_idx]);
        }
 
@@ -586,9 +638,14 @@ static ulong axi_clk_set(struct clk *sclk, ulong rate)
        return common_div_clk_set(sclk, rate, &axi_clk_cfg);
 }
 
-static ulong tun_clk_set(struct clk *sclk, ulong rate)
+static ulong tun_hsdk_set(struct clk *sclk, ulong rate)
 {
-       return common_div_clk_set(sclk, rate, &tun_clk_cfg);
+       return common_div_clk_set(sclk, rate, &hsdk_tun_clk_cfg);
+}
+
+static ulong tun_h4xd_set(struct clk *sclk, ulong rate)
+{
+       return common_div_clk_set(sclk, rate, &hsdk_4xd_tun_clk_cfg);
 }
 
 static ulong idiv_set(struct clk *sclk, ulong rate)
@@ -629,37 +686,50 @@ static int hsdk_prepare_clock_tree_branch(struct clk *sclk)
        if (sclk->id >= CGU_MAX_CLOCKS)
                return -EINVAL;
 
-       clk->pll_devdata = clock_map[sclk->id].pll_devdata;
-       clk->regs = clk->cgu_regs + clock_map[sclk->id].cgu_pll_oft;
-       clk->spec_regs = clk->creg_regs;
-       clk->idiv_regs = clk->cgu_regs + clock_map[sclk->id].cgu_div_oft;
+       /* clocks missing in current map have their entry zeroed */
+       if (!clk->map[sclk->id].pll_devdata)
+               return -EINVAL;
+
+       clk->curr_domain.pll = clk->map[sclk->id].pll_devdata;
+       clk->curr_domain.pll_regs = clk->cgu_regs + clk->map[sclk->id].cgu_pll_oft;
+       clk->curr_domain.spec_regs = clk->creg_regs;
+       clk->curr_domain.idiv_regs = clk->cgu_regs + clk->map[sclk->id].cgu_div_oft;
 
        return 0;
 }
 
 static ulong hsdk_cgu_get_rate(struct clk *sclk)
 {
+       struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+
        if (hsdk_prepare_clock_tree_branch(sclk))
                return -EINVAL;
 
-       return clock_map[sclk->id].get_rate(sclk);
+       return clk->map[sclk->id].get_rate(sclk);
 }
 
 static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate)
 {
+       struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+
        if (hsdk_prepare_clock_tree_branch(sclk))
                return -EINVAL;
 
-       return clock_map[sclk->id].set_rate(sclk, rate);
+       if (clk->map[sclk->id].set_rate)
+               return clk->map[sclk->id].set_rate(sclk, rate);
+
+       return -ENOTSUPP;
 }
 
 static int hsdk_cgu_disable(struct clk *sclk)
 {
+       struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+
        if (hsdk_prepare_clock_tree_branch(sclk))
                return -EINVAL;
 
-       if (clock_map[sclk->id].disable)
-               return clock_map[sclk->id].disable(sclk);
+       if (clk->map[sclk->id].disable)
+               return clk->map[sclk->id].disable(sclk);
 
        return -ENOTSUPP;
 }
@@ -672,16 +742,23 @@ static const struct clk_ops hsdk_cgu_ops = {
 
 static int hsdk_cgu_clk_probe(struct udevice *dev)
 {
-       struct hsdk_cgu_clk *pll_clk = dev_get_priv(dev);
+       struct hsdk_cgu_clk *hsdk_clk = dev_get_priv(dev);
+
+       BUILD_BUG_ON(ARRAY_SIZE(hsdk_clk_map) != CGU_MAX_CLOCKS);
+       BUILD_BUG_ON(ARRAY_SIZE(hsdk_4xd_clk_map) != CGU_MAX_CLOCKS);
 
-       BUILD_BUG_ON(ARRAY_SIZE(clock_map) != CGU_MAX_CLOCKS);
+       /* Choose which clock map to use in runtime */
+       if ((read_aux_reg(ARC_AUX_IDENTITY) & 0xFF) == 0x52)
+               hsdk_clk->map = hsdk_clk_map;
+       else
+               hsdk_clk->map = hsdk_4xd_clk_map;
 
-       pll_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0);
-       if (!pll_clk->cgu_regs)
+       hsdk_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0);
+       if (!hsdk_clk->cgu_regs)
                return -EINVAL;
 
-       pll_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1);
-       if (!pll_clk->creg_regs)
+       hsdk_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1);
+       if (!hsdk_clk->creg_regs)
                return -EINVAL;
 
        return 0;