From: dkl <dkl@rock-chips.com>
Date: Thu, 9 Jan 2014 07:59:18 +0000 (+0800)
Subject: rk_clk: add common pll and gpll set_rate support
X-Git-Tag: firefly_0821_release~6395
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=a574676e964d464d56e19e6608704394da13a951;p=firefly-linux-kernel-4.4.55.git

rk_clk: add common pll and gpll set_rate support
---

diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 9a53b7245f8f..0254ac85970f 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -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)
 {
diff --git a/drivers/clk/rockchip/clk-pll.h b/drivers/clk/rockchip/clk-pll.h
index 33a73d9c3bdc..e803b7505c62 100644
--- a/drivers/clk/rockchip/clk-pll.h
+++ b/drivers/clk/rockchip/clk-pll.h
@@ -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))
@@ -102,6 +105,10 @@
 	.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;