ARC: HSDK: CGU: Update AXI, TUN, ARC clock options
authorEugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Tue, 16 Jan 2018 17:44:25 +0000 (20:44 +0300)
committerAlexey Brodkin <abrodkin@synopsys.com>
Fri, 19 Jan 2018 14:59:35 +0000 (17:59 +0300)
Update default AXI, TUN, ARC clock set options:
instead of changing only IDIV divider settings adjust also domain PLL
settings.

Add support of TUN_ROM and TUN_PWM clocks (subclocks of TUNN_PLL)

Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
drivers/clk/clk-hsdk-cgu.c
include/dt-bindings/clock/snps,hsdk-cgu.h

index c80f90e..d9da477 100644 (file)
@@ -42,7 +42,9 @@
  *            |-->| TUNNEL PLL |
  *            |   --------------
  *            |        |
- *            |        |-->|CGU_TUN_IDIV|----------->
+ *            |        |-->|CGU_TUN_IDIV_TUN|----------->
+ *            |        |-->|CGU_TUN_IDIV_ROM|----------->
+ *            |        |-->|CGU_TUN_IDIV_PWM|----------->
  *            |
  *            |   ------------
  *            |-->| HDMI PLL |
@@ -60,7 +62,9 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 #define CGU_ARC_IDIV           0x080
-#define CGU_TUN_IDIV           0x380
+#define CGU_TUN_IDIV_TUN       0x380
+#define CGU_TUN_IDIV_ROM       0x390
+#define CGU_TUN_IDIV_PWM       0x3A0
 #define CGU_HDMI_IDIV_APB      0x480
 #define CGU_SYS_IDIV_APB       0x180
 #define CGU_SYS_IDIV_AXI       0x190
@@ -114,8 +118,68 @@ DECLARE_GLOBAL_DATA_PTR;
 #define CREG_CORE_IF_CLK_DIV_1         0x0
 #define CREG_CORE_IF_CLK_DIV_2         0x1
 
+#define MIN_PLL_RATE                   100000000 /* 100 MHz */
 #define PARENT_RATE                    33333333 /* fixed clock - xtal */
-#define CGU_MAX_CLOCKS                 24
+#define CGU_MAX_CLOCKS                 26
+
+#define CGU_SYS_CLOCKS                 16
+#define MAX_AXI_CLOCKS                 4
+
+#define CGU_TUN_CLOCKS                 3
+#define MAX_TUN_CLOCKS                 6
+
+struct hsdk_tun_idiv_cfg {
+       u32 oft;
+       u8  val[MAX_TUN_CLOCKS];
+};
+
+struct hsdk_tun_clk_cfg {
+       const u32 clk_rate[MAX_TUN_CLOCKS];
+       const u32 pll_rate[MAX_TUN_CLOCKS];
+       const struct hsdk_tun_idiv_cfg idiv[CGU_TUN_CLOCKS];
+};
+
+static const struct hsdk_tun_clk_cfg tun_clk_cfg = {
+       { 25000000,  50000000,  75000000,  100000000, 125000000, 150000000 },
+       { 600000000, 600000000, 600000000, 600000000, 700000000, 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 } }
+       }
+};
+
+struct hsdk_sys_idiv_cfg {
+       u32 oft;
+       u8  val[MAX_AXI_CLOCKS];
+};
+
+struct hsdk_axi_clk_cfg {
+       const u32 clk_rate[MAX_AXI_CLOCKS];
+       const u32 pll_rate[MAX_AXI_CLOCKS];
+       const struct hsdk_sys_idiv_cfg idiv[CGU_SYS_CLOCKS];
+};
+
+static const struct hsdk_axi_clk_cfg axi_clk_cfg = {
+       { 200000000,    400000000,      600000000,      800000000 },
+       { 800000000,    800000000,      600000000,      800000000 }, {
+       { CGU_SYS_IDIV_APB,      { 4,   4,      3,      4 } },  /* APB */
+       { CGU_SYS_IDIV_AXI,      { 4,   2,      1,      1 } },  /* AXI */
+       { CGU_SYS_IDIV_ETH,      { 2,   2,      2,      2 } },  /* ETH */
+       { CGU_SYS_IDIV_USB,      { 2,   2,      2,      2 } },  /* USB */
+       { CGU_SYS_IDIV_SDIO,     { 2,   2,      2,      2 } },  /* SDIO */
+       { CGU_SYS_IDIV_HDMI,     { 2,   2,      2,      2 } },  /* HDMI */
+       { CGU_SYS_IDIV_GFX_CORE, { 1,   1,      1,      1 } },  /* GPU-CORE */
+       { CGU_SYS_IDIV_GFX_DMA,  { 2,   2,      2,      2 } },  /* GPU-DMA */
+       { CGU_SYS_IDIV_GFX_CFG,  { 4,   4,      3,      4 } },  /* GPU-CFG */
+       { CGU_SYS_IDIV_DMAC_CORE,{ 2,   2,      2,      2 } },  /* DMAC-CORE */
+       { CGU_SYS_IDIV_DMAC_CFG, { 4,   4,      3,      4 } },  /* DMAC-CFG */
+       { CGU_SYS_IDIV_SDIO_REF, { 8,   8,      6,      8 } },  /* SDIO-REF */
+       { CGU_SYS_IDIV_SPI_REF,  { 24,  24,     18,     24 } }, /* SPI-REF */
+       { CGU_SYS_IDIV_I2C_REF,  { 4,   4,      3,      4 } },  /* I2C-REF */
+       { CGU_SYS_IDIV_UART_REF, { 24,  24,     18,     24 } }, /* UART-REF */
+       { CGU_SYS_IDIV_EBI_REF,  { 16,  16,     12,     16 } }  /* EBI-REF */
+       }
+};
 
 struct hsdk_pll_cfg {
        u32 rate;
@@ -201,6 +265,9 @@ 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 idiv_get(struct clk *);
 static int idiv_off(struct clk *);
 static ulong pll_set(struct clk *, ulong);
@@ -218,11 +285,11 @@ struct hsdk_cgu_clock_map {
 
 static const struct hsdk_cgu_clock_map clock_map[] = {
        { CGU_ARC_PLL, 0, 0, &core_pll_dat, pll_get, pll_set, NULL },
-       { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, idiv_set, idiv_off },
+       { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
        { CGU_DDR_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
        { CGU_SYS_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
-       { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+       { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
@@ -238,7 +305,9 @@ static const struct hsdk_cgu_clock_map clock_map[] = {
        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
        { CGU_SYS_PLL, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
        { CGU_TUN_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
-       { CGU_TUN_PLL, 0, CGU_TUN_IDIV, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+       { CGU_TUN_PLL, 0, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off },
+       { CGU_TUN_PLL, 0, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
+       { CGU_TUN_PLL, 0, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
        { CGU_HDMI_PLL, 0, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
        { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
 };
@@ -453,6 +522,94 @@ static ulong idiv_get(struct clk *sclk)
        return parent_rate / div_factor;
 }
 
+/* Special behavior: wen we set this clock we set both idiv and pll */
+static ulong cpu_clk_set(struct clk *sclk, ulong rate)
+{
+       ulong ret;
+
+       ret = pll_set(sclk, rate);
+       idiv_set(sclk, rate);
+
+       return ret;
+}
+
+/* Special behavior: wen we set this clock we set both idiv and pll and all pll dividers */
+static ulong axi_clk_set(struct clk *sclk, ulong rate)
+{
+       struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+       ulong pll_rate;
+       int i, freq_idx = -1;
+       ulong ret = 0;
+
+       pll_rate = pll_get(sclk);
+
+       for (i = 0; i < MAX_AXI_CLOCKS; i++) {
+               if (axi_clk_cfg.clk_rate[i] == rate) {
+                       freq_idx = i;
+                       break;
+               }
+       }
+
+       if (freq_idx < 0) {
+               pr_err("axi clk: invalid rate=%ld Hz\n", rate);
+               return -EINVAL;
+       }
+
+       /* configure PLL before dividers */
+       if (axi_clk_cfg.pll_rate[freq_idx] < pll_rate)
+               ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
+
+       /* configure SYS dividers */
+       for (i = 0; i < CGU_SYS_CLOCKS; i++) {
+               clk->idiv_regs = clk->cgu_regs + axi_clk_cfg.idiv[i].oft;
+               hsdk_idiv_write(clk, axi_clk_cfg.idiv[i].val[freq_idx]);
+       }
+
+       /* configure PLL after dividers */
+       if (axi_clk_cfg.pll_rate[freq_idx] >= pll_rate)
+               ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]);
+
+       return ret;
+}
+
+static ulong tun_clk_set(struct clk *sclk, ulong rate)
+{
+       struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
+       ulong pll_rate;
+       int i, freq_idx = -1;
+       ulong ret = 0;
+
+       pll_rate = pll_get(sclk);
+
+       for (i = 0; i < MAX_TUN_CLOCKS; i++) {
+               if (tun_clk_cfg.clk_rate[i] == rate) {
+                       freq_idx = i;
+                       break;
+               }
+       }
+
+       if (freq_idx < 0) {
+               pr_err("tun clk: invalid rate=%ld Hz\n", rate);
+               return -EINVAL;
+       }
+
+       /* configure PLL before dividers */
+       if (tun_clk_cfg.pll_rate[freq_idx] < pll_rate)
+               ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
+
+       /* configure SYS dividers */
+       for (i = 0; i < CGU_TUN_CLOCKS; i++) {
+               clk->idiv_regs = clk->cgu_regs + tun_clk_cfg.idiv[i].oft;
+               hsdk_idiv_write(clk, tun_clk_cfg.idiv[i].val[freq_idx]);
+       }
+
+       /* configure PLL after dividers */
+       if (tun_clk_cfg.pll_rate[freq_idx] >= pll_rate)
+               ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]);
+
+       return ret;
+}
+
 static ulong idiv_set(struct clk *sclk, ulong rate)
 {
        struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
index 813ab71..2cfe34e 100644 (file)
 #define CLK_SYS_UART_REF       18
 #define CLK_SYS_EBI_REF                19
 #define CLK_TUN_PLL            20
-#define CLK_TUN                        21
-#define CLK_HDMI_PLL           22
-#define CLK_HDMI               23
+#define CLK_TUN_TUN            21
+#define CLK_TUN_ROM            22
+#define CLK_TUN_PWM            23
+#define CLK_HDMI_PLL           24
+#define CLK_HDMI               25
 
 #endif /* __DT_BINDINGS_CLK_HSDK_CGU_H_ */