rk3368: add support for rk3368 clocks
authordkl <dkl@rock-chips.com>
Wed, 5 Nov 2014 02:02:06 +0000 (10:02 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Mon, 10 Nov 2014 09:31:15 +0000 (17:31 +0800)
1. Add clkops_rate_ddr_div4 ops
2. Add clk_pll_ops_3368_apllb && &clk_pll_ops_3368_aplll ops
3. Add some rk3368 clock macros
4. Add "rkclk_init_special_regs" type clk to handle clock with
   register not in CRU

drivers/clk/rockchip/clk-ops.c
drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/clk-pll.h
drivers/clk/rockchip/clk.c
include/dt-bindings/clock/rockchip,rk3368.h [new file with mode: 0644]
include/dt-bindings/clock/rockchip.h
include/linux/rockchip/cru.h

index 197051dec37edc20afe25f177a9f64d7ed24d632..226541849d31777ad5d7fe4e2ccafee01d5d1fbf 100644 (file)
@@ -494,6 +494,24 @@ const struct clk_ops clkops_rate_ddr_div2 = {
        .determine_rate = clk_ddr_determine_rate,
 };
 
+static unsigned long clk_ddr_div4_recalc_rate(struct clk_hw *hw,
+                                             unsigned long parent_rate)
+{
+       /* Same as clk_core, we should NOT set clk_ddr's parent
+        * (dpll) rate directly as a side effect.
+        */
+       struct clk *parent = __clk_get_parent(hw->clk);
+
+       return clk_divider_recalc_rate(hw, __clk_get_rate(parent))/4;
+}
+
+const struct clk_ops clkops_rate_ddr_div4 = {
+       .recalc_rate    = clk_ddr_div4_recalc_rate,
+       .round_rate     = clk_ddr_round_rate,
+       .set_rate       = clk_ddr_set_rate,
+       .determine_rate = clk_ddr_determine_rate,
+};
+
 static unsigned long clk_3288_i2s_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
 {
@@ -710,7 +728,8 @@ struct clk_ops_table rk_clkops_rate_table[] = {
        {.index = CLKOPS_RATE_RK3288_USB480M,   .clk_ops = &clkops_rate_3288_usb480m},
        {.index = CLKOPS_RATE_RK3288_DCLK_LCDC0,.clk_ops = &clkops_rate_3288_dclk_lcdc0},
        {.index = CLKOPS_RATE_RK3288_DCLK_LCDC1,.clk_ops = &clkops_rate_3288_dclk_lcdc1},
-       {.index = CLKOPS_RATE_DDR_DIV2, .clk_ops = &clkops_rate_ddr_div2},
+       {.index = CLKOPS_RATE_DDR_DIV2,         .clk_ops = &clkops_rate_ddr_div2},
+       {.index = CLKOPS_RATE_DDR_DIV4,         .clk_ops = &clkops_rate_ddr_div4},
        {.index = CLKOPS_RATE_I2S,              .clk_ops = NULL},
        {.index = CLKOPS_RATE_CIFOUT,           .clk_ops = NULL},
        {.index = CLKOPS_RATE_UART,             .clk_ops = NULL},
index ce8496577766b1e043ef13135c95bbef84d92c5e..42dfef3284546cb509032bf460b3b738682cb893 100755 (executable)
@@ -235,6 +235,10 @@ static const struct pll_clk_set rk312xplus_pll_com_table[] = {
        _RK3036_PLL_SET_CLKS(400000, 6, 400, 2, 2, 1, 0),
 };
 
+static const struct apll_clk_set rk3368_apll_table[] = {
+       /* _RK3368_APLL_SET_CLKS(); */
+};
+
 static void pll_wait_lock(struct clk_hw *hw)
 {
        struct clk_pll *pll = to_clk_pll(hw);
@@ -1775,6 +1779,442 @@ static const struct clk_ops clk_pll_ops_312xplus = {
        .set_rate = clk_cpll_set_rate_312xplus,
 };
 
+static long clk_pll_round_rate_3368_apll(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *prate)
+{
+       struct clk *parent = __clk_get_parent(hw->clk);
+
+       if (parent && (rate == __clk_get_rate(parent))) {
+               clk_debug("pll %s round rate=%lu equal to parent rate\n",
+                         __clk_get_name(hw->clk), rate);
+               return rate;
+       }
+
+       return (apll_get_best_set(rate, rk3368_apll_table)->rate);
+}
+
+/* 1: use, 0: no use */
+#define RK3368_APLLB_USE_GPLL  1
+
+/* when define 1, we will set div to make rate change gently, but it will cost
+ more time */
+#define RK3368_APLLB_DIV_MORE  1
+
+static int clk_pll_set_rate_3368_apllb(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct clk_pll *pll = to_clk_pll(hw);
+       struct clk *clk = hw->clk;
+       struct clk *arm_gpll = __clk_lookup("clk_gpll");
+       unsigned long arm_gpll_rate, temp_rate, old_rate;
+       const struct apll_clk_set *ps;
+       u32 temp_div;
+       unsigned long flags;
+       int sel_gpll = 0;
+
+
+#if !RK3368_APLLB_USE_GPLL
+       goto CHANGE_APLL;
+#endif
+
+       /* prepare arm_gpll before reparent clk_core to it */
+       if (!arm_gpll) {
+               clk_err("clk arm_gpll is NULL!\n");
+               goto CHANGE_APLL;
+       }
+
+       arm_gpll_rate = __clk_get_rate(arm_gpll);
+       old_rate = __clk_get_rate(clk);
+
+       temp_rate = (old_rate > rate) ? old_rate : rate;
+       temp_div = DIV_ROUND_UP(arm_gpll_rate, temp_rate);
+
+       if (temp_div > RK3368_CORE_CLK_MAX_DIV) {
+               clk_debug("temp_div %d > max_div %d\n", temp_div,
+                         RK3368_CORE_CLK_MAX_DIV);
+               clk_debug("can't get rate %lu from arm_gpll rate %lu\n",
+                         __clk_get_rate(clk), arm_gpll_rate);
+               goto CHANGE_APLL;
+       }
+
+#if 0
+       if (clk_prepare(arm_gpll)) {
+               clk_err("fail to prepare arm_gpll path\n");
+               clk_unprepare(arm_gpll);
+               goto CHANGE_APLL;
+       }
+
+       if (clk_enable(arm_gpll)) {
+               clk_err("fail to enable arm_gpll path\n");
+               clk_disable(arm_gpll);
+               clk_unprepare(arm_gpll);
+               goto CHANGE_APLL;
+       }
+#endif
+
+       local_irq_save(flags);
+
+       /* select gpll */
+#if RK3368_APLLB_DIV_MORE
+       if (temp_div == 1) {
+               /* when old_rate/2 < (old_rate-arm_gpll_rate),
+                  we can set div to make rate change more gently */
+               if (old_rate > (2*arm_gpll_rate)) {
+                       cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(0));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                                  RK3368_CRU_CLKSELS_CON(0));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
+               } else {
+                       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                                  RK3368_CRU_CLKSELS_CON(0));
+               }
+       } else {
+               cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(0));
+               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                          RK3368_CRU_CLKSELS_CON(0));
+       }
+#else
+       cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(0));
+       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                  RK3368_CRU_CLKSELS_CON(0));
+#endif
+
+       sel_gpll = 1;
+
+       smp_wmb();
+
+       local_irq_restore(flags);
+
+       clk_debug("temp select arm_gpll path, get rate %lu\n",
+                 arm_gpll_rate/temp_div);
+       clk_debug("from arm_gpll rate %lu, temp_div %d\n", arm_gpll_rate,
+                 temp_div);
+
+CHANGE_APLL:
+       ps = apll_get_best_set(rate, rk3368_apll_table);
+       clk_debug("apll will set rate %lu\n", ps->rate);
+       clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n",
+                 ps->pllcon0, ps->pllcon1, ps->pllcon2,
+                 ps->clksel0, ps->clksel1);
+
+       local_irq_save(flags);
+
+       /* If core src don't select gpll, apll need to enter slow mode
+        * before reset
+        */
+       if (!sel_gpll)
+               cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift),
+                          pll->mode_offset);
+
+       /* PLL enter reset */
+       cru_writel(_RK3188PLUS_PLL_RESET_SET(1), pll->reg + RK3188_PLL_CON(3));
+
+       cru_writel(ps->pllcon0, pll->reg + RK3188_PLL_CON(0));
+       cru_writel(ps->pllcon1, pll->reg + RK3188_PLL_CON(1));
+       cru_writel(ps->pllcon2, pll->reg + RK3188_PLL_CON(2));
+
+       udelay(5);
+
+       /* return from rest */
+       cru_writel(_RK3188PLUS_PLL_RESET_SET(0), pll->reg + RK3188_PLL_CON(3));
+
+       /* wating lock state */
+       udelay(ps->rst_dly);
+       pll_wait_lock(hw);
+
+       if (rate >= __clk_get_rate(hw->clk)) {
+               cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(0));
+               cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(1));
+       }
+
+       /* PLL return from slow mode */
+       if (!sel_gpll)
+               cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift),
+                          pll->mode_offset);
+
+       /* reparent to apll, and set div to 1 */
+       if (sel_gpll) {
+#if RK3368_APLLB_DIV_MORE
+               if (temp_div == 1) {
+                       /* when rate/2 < (old_rate-arm_gpll_rate),
+                        we can set div to make rate change more gently */
+                       if (rate > (2*arm_gpll_rate)) {
+                               cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(0));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                                          RK3368_CRU_CLKSELS_CON(0));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(0));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
+                       } else {
+                               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                                          RK3368_CRU_CLKSELS_CON(0));
+                       }
+               } else {
+                       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                                  RK3368_CRU_CLKSELS_CON(0));
+                       cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
+               }
+#else
+               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                          RK3368_CRU_CLKSELS_CON(0));
+               cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(0));
+#endif
+       }
+
+       if (rate < __clk_get_rate(hw->clk)) {
+               cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(0));
+               cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(1));
+       }
+
+       smp_wmb();
+
+       local_irq_restore(flags);
+
+       if (sel_gpll) {
+               sel_gpll = 0;
+               /* clk_disable(arm_gpll);
+               clk_unprepare(arm_gpll); */
+       }
+
+       clk_debug("apll set rate %lu, con(%x,%x,%x,%x), sel(%x,%x)\n",
+                 ps->rate,
+                 cru_readl(pll->reg + RK3188_PLL_CON(0)),
+                 cru_readl(pll->reg + RK3188_PLL_CON(1)),
+                 cru_readl(pll->reg + RK3188_PLL_CON(2)),
+                 cru_readl(pll->reg + RK3188_PLL_CON(3)),
+                 cru_readl(RK3368_CRU_CLKSELS_CON(0)),
+                 cru_readl(RK3368_CRU_CLKSELS_CON(1)));
+
+       return 0;
+}
+
+static const struct clk_ops clk_pll_ops_3368_apllb = {
+       .recalc_rate = clk_pll_recalc_rate_3188plus,
+       .round_rate = clk_pll_round_rate_3368_apll,
+       .set_rate = clk_pll_set_rate_3368_apllb,
+};
+
+/* 1: use, 0: no use */
+#define RK3368_APLLL_USE_GPLL  1
+
+/* when define 1, we will set div to make rate change gently, but it will cost
+ more time */
+#define RK3368_APLLL_DIV_MORE  1
+
+static int clk_pll_set_rate_3368_aplll(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long parent_rate)
+{
+       struct clk_pll *pll = to_clk_pll(hw);
+       struct clk *clk = hw->clk;
+       struct clk *arm_gpll = __clk_lookup("clk_gpll");
+       unsigned long arm_gpll_rate, temp_rate, old_rate;
+       const struct apll_clk_set *ps;
+       u32 temp_div;
+       unsigned long flags;
+       int sel_gpll = 0;
+
+
+#if !RK3368_APLLL_USE_GPLL
+       goto CHANGE_APLL;
+#endif
+
+       /* prepare arm_gpll before reparent clk_core to it */
+       if (!arm_gpll) {
+               clk_err("clk arm_gpll is NULL!\n");
+               goto CHANGE_APLL;
+       }
+
+       arm_gpll_rate = __clk_get_rate(arm_gpll);
+       old_rate = __clk_get_rate(clk);
+
+       temp_rate = (old_rate > rate) ? old_rate : rate;
+       temp_div = DIV_ROUND_UP(arm_gpll_rate, temp_rate);
+
+       if (temp_div > RK3368_CORE_CLK_MAX_DIV) {
+               clk_debug("temp_div %d > max_div %d\n", temp_div,
+                         RK3368_CORE_CLK_MAX_DIV);
+               clk_debug("can't get rate %lu from arm_gpll rate %lu\n",
+                         __clk_get_rate(clk), arm_gpll_rate);
+               goto CHANGE_APLL;
+       }
+
+#if 0
+       if (clk_prepare(arm_gpll)) {
+               clk_err("fail to prepare arm_gpll path\n");
+               clk_unprepare(arm_gpll);
+               goto CHANGE_APLL;
+       }
+
+       if (clk_enable(arm_gpll)) {
+               clk_err("fail to enable arm_gpll path\n");
+               clk_disable(arm_gpll);
+               clk_unprepare(arm_gpll);
+               goto CHANGE_APLL;
+       }
+#endif
+
+       local_irq_save(flags);
+
+       /* select gpll */
+#if RK3368_APLLL_DIV_MORE
+       if (temp_div == 1) {
+               /* when old_rate/2 < (old_rate-arm_gpll_rate),
+                  we can set div to make rate change more gently */
+               if (old_rate > (2*arm_gpll_rate)) {
+                       cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(2));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                                  RK3368_CRU_CLKSELS_CON(2));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
+                       udelay(10);
+                       cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
+               } else {
+                       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                                  RK3368_CRU_CLKSELS_CON(2));
+               }
+       } else {
+               cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(2));
+               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                          RK3368_CRU_CLKSELS_CON(2));
+       }
+#else
+               cru_writel(RK3368_CORE_CLK_DIV(temp_div), RK3368_CRU_CLKSELS_CON(2));
+               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_GPLL,
+                          RK3368_CRU_CLKSELS_CON(2));
+#endif
+
+       sel_gpll = 1;
+
+       smp_wmb();
+
+       local_irq_restore(flags);
+
+       clk_debug("temp select arm_gpll path, get rate %lu\n",
+                 arm_gpll_rate/temp_div);
+       clk_debug("from arm_gpll rate %lu, temp_div %d\n", arm_gpll_rate,
+                 temp_div);
+
+CHANGE_APLL:
+       ps = apll_get_best_set(rate, rk3368_apll_table);
+       clk_debug("apll will set rate %lu\n", ps->rate);
+       clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n",
+                 ps->pllcon0, ps->pllcon1, ps->pllcon2,
+                 ps->clksel0, ps->clksel1);
+
+       local_irq_save(flags);
+
+       /* If core src don't select gpll, apll need to enter slow mode
+        * before reset
+        */
+       if (!sel_gpll)
+               cru_writel(_RK3188_PLL_MODE_SLOW_SET(pll->mode_shift),
+                          pll->mode_offset);
+
+       /* PLL enter reset */
+       cru_writel(_RK3188PLUS_PLL_RESET_SET(1), pll->reg + RK3188_PLL_CON(3));
+
+       cru_writel(ps->pllcon0, pll->reg + RK3188_PLL_CON(0));
+       cru_writel(ps->pllcon1, pll->reg + RK3188_PLL_CON(1));
+       cru_writel(ps->pllcon2, pll->reg + RK3188_PLL_CON(2));
+
+       udelay(5);
+
+       /* return from rest */
+       cru_writel(_RK3188PLUS_PLL_RESET_SET(0), pll->reg + RK3188_PLL_CON(3));
+
+       /* wating lock state */
+       udelay(ps->rst_dly);
+       pll_wait_lock(hw);
+
+       if (rate >= __clk_get_rate(hw->clk)) {
+               cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(2));
+               cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(3));
+       }
+
+       /* PLL return from slow mode */
+       if (!sel_gpll)
+               cru_writel(_RK3188_PLL_MODE_NORM_SET(pll->mode_shift),
+                          pll->mode_offset);
+
+       /* reparent to apll, and set div to 1 */
+       if (sel_gpll) {
+#if RK3368_APLLL_DIV_MORE
+               if (temp_div == 1) {
+                       /* when rate/2 < (old_rate-arm_gpll_rate),
+                        we can set div to make rate change more gently */
+                       if (rate > (2*arm_gpll_rate)) {
+                               cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_CLK_DIV(3), RK3368_CRU_CLKSELS_CON(2));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                                          RK3368_CRU_CLKSELS_CON(2));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_CLK_DIV(2), RK3368_CRU_CLKSELS_CON(2));
+                               udelay(10);
+                               cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
+                       } else {
+                               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                                          RK3368_CRU_CLKSELS_CON(2));
+                       }
+               } else {
+                       cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                                  RK3368_CRU_CLKSELS_CON(2));
+                       cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
+               }
+#else
+               cru_writel(RK3368_CORE_SEL_PLL_W_MSK|RK3368_CORE_SEL_APLL,
+                          RK3368_CRU_CLKSELS_CON(2));
+               cru_writel(RK3368_CORE_CLK_DIV(1), RK3368_CRU_CLKSELS_CON(2));
+#endif
+       }
+
+       if (rate < __clk_get_rate(hw->clk)) {
+               cru_writel(ps->clksel0, RK3368_CRU_CLKSELS_CON(2));
+               cru_writel(ps->clksel1, RK3368_CRU_CLKSELS_CON(3));
+       }
+
+       smp_wmb();
+
+       local_irq_restore(flags);
+
+       if (sel_gpll) {
+               sel_gpll = 0;
+               /* clk_disable(arm_gpll);
+               clk_unprepare(arm_gpll); */
+       }
+
+       clk_debug("apll set rate %lu, con(%x,%x,%x,%x), sel(%x,%x)\n",
+                 ps->rate,
+                 cru_readl(pll->reg + RK3188_PLL_CON(0)),
+                 cru_readl(pll->reg + RK3188_PLL_CON(1)),
+                 cru_readl(pll->reg + RK3188_PLL_CON(2)),
+                 cru_readl(pll->reg + RK3188_PLL_CON(3)),
+                 cru_readl(RK3368_CRU_CLKSELS_CON(2)),
+                 cru_readl(RK3368_CRU_CLKSELS_CON(3)));
+
+       return 0;
+}
+
+static const struct clk_ops clk_pll_ops_3368_aplll = {
+       .recalc_rate = clk_pll_recalc_rate_3188plus,
+       .round_rate = clk_pll_round_rate_3368_apll,
+       .set_rate = clk_pll_set_rate_3368_aplll,
+};
+
 const struct clk_ops *rk_get_pll_ops(u32 pll_flags)
 {
        switch (pll_flags) {
@@ -1805,6 +2245,12 @@ const struct clk_ops *rk_get_pll_ops(u32 pll_flags)
                case CLK_PLL_312XPLUS:
                        return &clk_pll_ops_312xplus;
 
+               case CLK_PLL_3368_APLLB:
+                       return &clk_pll_ops_3368_apllb;
+
+               case CLK_PLL_3368_APLLL:
+                       return &clk_pll_ops_3368_aplll;
+
                default:
                        clk_err("%s: unknown pll_flags!\n", __func__);
                        return NULL;
index df41b57644fe36bb33e20fbd007220d7513f8579..3ecc178a5903d993efac14fe363f693bfb977f51 100755 (executable)
        .pllcon2 = RK3036_PLL_SET_FRAC(_frac),  \
 }
 
+/***************************RK3368 PLL**************************************/
+/*******************CLKSEL0/2 BITS***************************/
+#define RK3368_CORE_SEL_PLL_W_MSK      (1 << 23)
+#define RK3368_CORE_SEL_APLL           (0 << 7)
+#define RK3368_CORE_SEL_GPLL           (1 << 7)
+
+#define RK3368_CORE_CLK_SHIFT          0
+#define RK3368_CORE_CLK_WIDTH          5
+#define RK3368_CORE_CLK_DIV(i) \
+       CLK_DIV_PLUS_ONE_SET(i, RK3368_CORE_CLK_SHIFT, RK3368_CORE_CLK_WIDTH)
+#define RK3368_CORE_CLK_MAX_DIV                (2<<RK3368_CORE_CLK_WIDTH)
+
+#define RK3368_ACLKM_CORE_SHIFT                8
+#define RK3368_ACLKM_CORE_WIDTH                5
+#define RK3368_ACLKM_CORE_DIV(i)       \
+       CLK_DIV_PLUS_ONE_SET(i, RK3368_ACLKM_CORE_SHIFT, RK3368_ACLKM_CORE_WIDTH)
+
+/*******************CLKSEL1/3 BITS***************************/
+#define RK3368_ATCLK_CORE_SHIFT                0
+#define RK3368_ATCLK_CORE_WIDTH                5
+#define RK3368_ATCLK_CORE_DIV(i)       \
+       CLK_DIV_PLUS_ONE_SET(i, RK3368_ATCLK_CORE_SHIFT, RK3368_ATCLK_CORE_WIDTH)
+
+#define RK3368_PCLK_DBG_SHIFT          8
+#define RK3368_PCLK_DBG_WIDTH          5
+#define RK3368_PCLK_DBG_DIV(i) \
+       CLK_DIV_PLUS_ONE_SET(i, RK3368_PCLK_DBG_SHIFT, RK3368_PCLK_DBG_WIDTH)
+
+#define _RK3368_APLL_SET_CLKS(_mhz, nr, nf, no, aclkm_div, atclk_div, pclk_dbg_div) \
+{ \
+       .rate   = _mhz * MHZ, \
+       .pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr) | RK3188PLUS_PLL_CLKOD_SET(no), \
+       .pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf),\
+       .pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nf >> 1),\
+       .rst_dly = ((nr*500)/24+1),\
+       .clksel0 = RK3368_ACLKM_CORE_DIV(aclkm_div),\
+       .clksel1 = RK3368_ATCLK_CORE_DIV(atclk_div) | RK3368_PCLK_DBG_DIV(pclk_dbg_div) \
+}
+
 struct pll_clk_set {
        unsigned long   rate;
        u32     pllcon0;
index aaad37e87a7e3b4412b413c59c4d81e99bab8802..5880b5367efb23169326348bba38f0acd61b63c6 100755 (executable)
@@ -1050,6 +1050,31 @@ out:
        return ret;
 }
 
+static int __init rkclk_init_special_regs(struct device_node *np)
+{
+       struct device_node *node;
+       const char *compatible;
+       void __iomem *reg = 0;
+       int ret = 0;
+
+
+       for_each_available_child_of_node(np, node) {
+               clk_debug("\n");
+               of_property_read_string(node, "compatible", &compatible);
+               if (strcmp(compatible, "rockchip,rk3188-mux-con") == 0) {
+                       reg = of_iomap(node, 0);
+                       ret = rkclk_init_muxinfo(node, reg);
+                       if (ret != 0) {
+                               clk_err("%s: init mux con err\n", __func__);
+                               goto out;
+                       }
+               }
+       }
+
+out:
+       return ret;
+}
+
 static int __init rkclk_init_pd(struct device_node *np)
 {
        struct device_node *node = NULL;
@@ -1839,22 +1864,27 @@ static void __init rk_clk_tree_init(struct device_node *np)
                if (strcmp(compatible, "rockchip,rk-fixed-rate-cons") == 0) {
                        if (rkclk_init_fixed_rate(node) != 0) {
                                clk_err("%s: init fixed_rate err\n", __func__);
-                               return ;
+                               return;
                        }
                } else if (strcmp(compatible, "rockchip,rk-fixed-factor-cons") == 0) {
                        if (rkclk_init_fixed_factor(node) != 0) {
                                clk_err("%s: init fixed_factor err\n", __func__);
-                               return ;
+                               return;
                        }
                } else if (strcmp(compatible, "rockchip,rk-clock-regs") == 0) {
                        if (rkclk_init_regcon(node) != 0) {
                                clk_err("%s: init reg cons err\n", __func__);
-                               return ;
+                               return;
                        }
                } else if (strcmp(compatible, "rockchip,rk-pd-cons") == 0) {
                        if (rkclk_init_pd(node) != 0) {
                                clk_err("%s: init pd err\n", __func__);
-                               return ;
+                               return;
+                       }
+               } else if (strcmp(compatible, "rockchip,rk-clock-special-regs") == 0) {
+                       if (rkclk_init_special_regs(node) != 0) {
+                               clk_err("%s: init special reg err\n", __func__);
+                               return;
                        }
                } else {
                        clk_err("%s: unknown\n", __func__);
diff --git a/include/dt-bindings/clock/rockchip,rk3368.h b/include/dt-bindings/clock/rockchip,rk3368.h
new file mode 100644 (file)
index 0000000..728ec58
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _DT_BINDINGS_CLOCK_ROCKCHIP_RK3368_H
+#define _DT_BINDINGS_CLOCK_ROCKCHIP_RK3368_H
+
+#include "rockchip.h"
+
+/* reset id */
+
+#endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_RK3368_H */
index 5c1234e967e3ab78b0b0ea007b2127c6fdab7744..c6d25f6aca0fce1ae3072e06890d3f5f6b64ed67 100644 (file)
@@ -43,6 +43,8 @@
 #define CLK_PLL_3036_APLL      BIT(6)
 #define CLK_PLL_3036PLUS_AUTO  BIT(7)
 #define CLK_PLL_312XPLUS       BIT(8)
+#define CLK_PLL_3368_APLLB     BIT(9)
+#define CLK_PLL_3368_APLLL     BIT(10)
 
 
 /* rate_ops index */
@@ -64,6 +66,7 @@
 #define CLKOPS_RATE_RK3288_DCLK_LCDC0  16
 #define CLKOPS_RATE_RK3288_DCLK_LCDC1  17
 #define CLKOPS_RATE_DDR_DIV2           18
+#define CLKOPS_RATE_DDR_DIV4           19
 #define CLKOPS_TABLE_END               (~0)
 
 /* pd id */
index 871ba05175f825cf22d9f5b838caeae052401b37..c3e2e63fd64a3e60c875c98e06e0f9ad3b6fd302 100755 (executable)
@@ -241,4 +241,15 @@ enum rk312x_cru_clk_gate {
        RK312X_CLKGATE_PCLK_UART1,
        RK312X_CLKGATE_PCLK_UART2,
 };
+
+/*************************RK3368********************************/
+
+/*******************CRU OFFSET*********************/
+#define RK3368_CRU_CLKSEL_CON          0x100
+#define RK3368_CRU_CLKGATE_CON         0x200
+
+#define RK3368_PLL_CONS(id, i)         ((id) * 0x10 + ((i) * 4))
+#define RK3368_CRU_CLKSELS_CON(i)      (RK3368_CRU_CLKSEL_CON + ((i) * 4))
+#define RK3368_CRU_CLKGATES_CON(i)     (RK3368_CRU_CLKGATE_CON + ((i) * 4))
+
 #endif