rk_clk: add common pll and gpll set_rate support
authordkl <dkl@rock-chips.com>
Thu, 9 Jan 2014 07:59:18 +0000 (15:59 +0800)
committerdkl <dkl@rock-chips.com>
Thu, 9 Jan 2014 07:59:18 +0000 (15:59 +0800)
drivers/clk/rockchip/clk-pll.c
drivers/clk/rockchip/clk-pll.h

index 9a53b7245f8f1017dfab6cc13d88d40f33fff238..0254ac85970fe58f5cc648ae1622b8cd40189e77 100644 (file)
@@ -5,7 +5,7 @@
 #include "clk-pll.h"
 
 
-//static unsigned long lpj_gpll;
+static unsigned long lpj_gpll;
 
 //fixme
 extern void __iomem *reg_start;
@@ -15,12 +15,15 @@ extern void __iomem *reg_start;
 #define cru_writel(v, offset)  do {writel(v, RK30_CRU_BASE + offset); dsb();} \
        while (0)
 
+//fixme
+//#define grf_readl(offset)    readl_relaxed(RK30_GRF_BASE + offset)
+
+
 #define PLLS_IN_NORM(pll_id) (((cru_readl(CRU_MODE_CON)&PLL_MODE_MSK(pll_id))\
                        ==(PLL_MODE_NORM(pll_id)&PLL_MODE_MSK(pll_id)))\
                &&!(cru_readl(PLL_CONS(pll_id,3))&PLL_BYPASS))
 
 
-
 static const struct apll_clk_set apll_table[] = {
 };
 
@@ -39,6 +42,37 @@ static const struct pll_clk_set pll_com_table[] = {
        _PLL_SET_CLKS(0,        0,      0,      0),
 };
 
+
+static void pll_wait_lock(int pll_idx)
+{
+#if 1
+       //fixme
+       udelay(10);
+#else
+       u32 pll_state[4] = {1, 0, 2, 3};
+       u32 bit = 0x20u << pll_state[pll_idx];
+       int delay = 24000000;
+       while (delay > 0) {
+               if (regfile_readl(GRF_SOC_STATUS0) & bit)
+                       break;
+               delay--;
+       }
+       if (delay == 0) {
+               clk_err("PLL_ID=%d\npll_con0=%08x\npll_con1=%08x\n"
+                               "pll_con2=%08x\npll_con3=%08x\n",
+                               pll_idx,
+                               cru_readl(PLL_CONS(pll_idx, 0)),
+                               cru_readl(PLL_CONS(pll_idx, 1)),
+                               cru_readl(PLL_CONS(pll_idx, 2)),
+                               cru_readl(PLL_CONS(pll_idx, 3)));
+
+               clk_err("wait pll bit 0x%x time out!\n", bit);
+               while(1);
+       }
+#endif
+}
+
+
 /*recalc_rate*/
 static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
                unsigned long parent_rate)
@@ -124,30 +158,109 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 }
 
 /*set_rate*/
-static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
-               unsigned long parent_rate)
+static int _pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id,
+               spinlock_t *lock)
 {
+       unsigned long flags = 0;
+
+
+       clk_debug("_pll_clk_set_rate start!\n");
+
+       if(lock)
+               spin_lock_irqsave(lock, flags);
+
+       //enter slowmode
+       cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON);
+       cru_writel((0x1<<(16+1))|(0x1<<1), PLL_CONS(pll_id, 3));
+       dsb();
+       dsb();
+       dsb();
+       dsb();
+       dsb();
+       dsb();
+       cru_writel(clk_set->pllcon0, PLL_CONS(pll_id, 0));
+       cru_writel(clk_set->pllcon1, PLL_CONS(pll_id, 1));
+
+       rk30_clock_udelay(1);
+
+       cru_writel((0x1<<(16+1)), PLL_CONS(pll_id, 3));
+
+       pll_wait_lock(pll_id);
+
+       //return from slow
+       cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON);
+
+       if (lock)
+               spin_unlock_irqrestore(lock, flags);
+
+       clk_debug("pll id=%d, dump reg:\n con0=%x,con1=%x,mode=%x\n", pll_id,
+                       cru_readl(PLL_CONS(pll_id,0)),(PLL_CONS(pll_id,1)),
+                       cru_readl(CRU_MODE_CON));
+
+       clk_debug("_pll_clk_set_rate end!\n");
+
        return 0;
 }
 
-static int clk_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_pll_com_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
-       return 0;
+       struct clk_pll *pll = to_clk_pll(hw);
+       struct pll_clk_set *clk_set = (struct pll_clk_set *)(pll_com_table);
+       int ret = 0;
+
+
+       if(rate == parent_rate) {
+               clk_debug("pll id=%d set rate=%lu equal to parent rate\n",
+                               pll->id, rate);
+               cru_writel(PLL_MODE_SLOW(pll->id), CRU_MODE_CON);
+               cru_writel((0x1 << (16+1)) | (0x1<<1), PLL_CONS(pll->id, 3));
+               clk_debug("pll id=%d enter slow mode, set rate OK!\n", pll->id);
+               return 0;
+       }
+
+       while(clk_set->rate) {
+               if (clk_set->rate == rate) {
+                       break;
+               }
+               clk_set++;
+       }
+
+       if(clk_set->rate == rate) {
+               ret = _pll_clk_set_rate(clk_set, pll->id, pll->lock);
+               clk_debug("pll id=%d set rate=%lu OK!\n", pll->id, rate);
+       } else {
+               clk_err("pll id=%d is no corresponding rate=%lu\n",
+                               pll->id, rate);
+               return -EINVAL;
+       }
+
+       return ret;
 }
 
-static int clk_gpll_set_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
        return 0;
 }
 
-static int clk_pll_com_set_rate(struct clk_hw *hw, unsigned long rate,
+static int clk_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
        return 0;
 }
 
+static int clk_gpll_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
+{
+        int ret = clk_pll_com_set_rate(hw, rate, parent_rate);
+
+        if(!ret)
+                lpj_gpll = CLK_LOOPS_RECALC(clk_pll_recalc_rate(hw, parent_rate));
+
+        return ret;
+}
+
 static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                unsigned long parent_rate)
 {
index 33a73d9c3bdcef62a3d072f67ecdfecb647ee960..e803b7505c6287eb1952ffc28524350954c9c1bd 100644 (file)
@@ -2,12 +2,15 @@
 #define __RK_CLK_PLL_H
 
 #include <linux/clk-provider.h>
-
+#include <linux/delay.h>
 
 
 #define MHZ                    (1000UL * 1000UL)
 #define KHZ                    (1000UL)
-
+#define CLK_LOOPS_JIFFY_REF    (11996091ULL)
+#define CLK_LOOPS_RATE_REF     (1200UL) //Mhz
+#define CLK_LOOPS_RECALC(rate)  \
+       div_u64(CLK_LOOPS_JIFFY_REF*(rate),CLK_LOOPS_RATE_REF*MHZ)
 /*******************cru reg offset***************************/
 #define CRU_MODE_CON           0x40
 #define PLL_CONS(id, i)                ((id) * 0x10 + ((i) * 4))
        .pllcon2 = PLL_CLK_BWADJ_SET(nf >> 1),\
        .rst_dly=((nr*500)/24+1),\
 }
+/*******************OTHERS*********************************/
+#define rk30_clock_udelay(a) udelay(a)
+
+
 
 struct pll_clk_set {
        unsigned long   rate;