From 9160c28527fa8c57760c073811859c7bdfac2820 Mon Sep 17 00:00:00 2001
From: chenxing <chenxing@rock-chips.com>
Date: Sat, 4 May 2013 17:08:05 +0800
Subject: [PATCH] rk3188: add gpll instead cpll/dpll support

---
 arch/arm/mach-rk30/board-rk3168-tb.c |   1 +
 arch/arm/mach-rk3188/clock_data.c    | 173 +++++++++++++++++++++++----
 2 files changed, 153 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-rk30/board-rk3168-tb.c b/arch/arm/mach-rk30/board-rk3168-tb.c
index 6608973c67d5..ea2cebf2310d 100644
--- a/arch/arm/mach-rk30/board-rk3168-tb.c
+++ b/arch/arm/mach-rk30/board-rk3168-tb.c
@@ -2568,6 +2568,7 @@ static struct cpufreq_frequency_table dvfs_ddr_table[] = {
 	{.frequency = 200 * 1000 + DDR_FREQ_SUSPEND,    .index = 1000 * 1000},
 	{.frequency = 300 * 1000 + DDR_FREQ_VIDEO,      .index = 1050 * 1000},
 	{.frequency = 400 * 1000 + DDR_FREQ_NORMAL,     .index = 1100 * 1000},
+	{.frequency = 450 * 1000,                       .index = 1150 * 1000},
 	{.frequency = CPUFREQ_TABLE_END},
 };
 #endif
diff --git a/arch/arm/mach-rk3188/clock_data.c b/arch/arm/mach-rk3188/clock_data.c
index 913cbab16a92..ce4b507da794 100755
--- a/arch/arm/mach-rk3188/clock_data.c
+++ b/arch/arm/mach-rk3188/clock_data.c
@@ -188,7 +188,7 @@ void rk30_clkdev_add(struct clk_lookup *cl);
 #define CLKDATA_LOG(fmt, args...) do {} while(0)
 #endif
 #define CLKDATA_ERR(fmt, args...) printk(KERN_ERR "CLKDATA_ERR:\t"fmt, ##args)
-#define CLKDATA_WARNNING(fmt, args...) printk("CLKDATA_WANNING:\t"fmt, ##args)
+#define CLKDATA_WARNING(fmt, args...) printk("CLKDATA_WANING:\t"fmt, ##args)
 
 
 #define get_cru_bits(con,mask,shift)\
@@ -874,7 +874,11 @@ static int cpll_clk_set_rate(struct clk *c, unsigned long rate)
 	struct pll_clk_set temp_clk_set;
 	u32 clk_nr, clk_nf, clk_no;
 
-
+	if(rate == 24 * MHZ) {	
+		cru_writel(PLL_MODE_SLOW(pll_data->id), CRU_MODE_CON);
+		cru_writel((0x1 << (16+1)) | (0x1<<1), PLL_CONS(pll_data->id, 3));
+		return 0;
+	}
 	while(clk_set->rate) {
 		if (clk_set->rate == rate) {
 			break;
@@ -1305,6 +1309,7 @@ static const struct pll_clk_set gpll_clks[] = {
 	_PLL_SET_CLKS(297000,	2,	198,	8),
 	_PLL_SET_CLKS(300000,	1,	50,	4),
 	_PLL_SET_CLKS(594000,	2,	198,	4),
+	_PLL_SET_CLKS(891000,	8,	594,	2),
 	_PLL_SET_CLKS(1188000,	2,	99,	1),
 	_PLL_SET_CLKS(1200000,	1,	50,	1),
 	_PLL_SET_CLKS(0,	0,	 0,	0),
@@ -1318,7 +1323,14 @@ static struct clk general_pll_clk = {
 	.pll 		= &gpll_data
 };
 /********************************clocks***********************************/
-GATE_CLK(ddr_gpll_path, general_pll_clk, DDR_GPLL);
+//GATE_CLK(ddr_gpll_path, general_pll_clk, DDR_GPLL);
+static struct clk clk_ddr_gpll_path = {
+	.name		= "ddr_gpll_path",
+	.parent		= &general_pll_clk,
+	.recalc		= clksel_recalc_parent_rate,
+	.gate_idx	= CLK_GATE_DDR_GPLL,
+	.mode		= gate_mode,
+};
 
 /* core and cpu setting */
 static int ddr_clk_set_rate(struct clk *c, unsigned long rate)
@@ -1335,14 +1347,19 @@ static long ddr_clk_round_rate(struct clk *clk, unsigned long rate)
 static unsigned long ddr_clk_recalc_rate(struct clk *clk)
 {
 	u32 shift = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift);
-	unsigned long rate = clk->parent->recalc(clk->parent) >> shift;
-	//CLKDATA_DBG("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift);
+	unsigned long rate = 0;
+	clk->parent = clk->get_parent(clk);
+	rate = clk->parent->recalc(clk->parent) >> shift;
+	CLKDATA_DBG("%s new clock rate is %lu (shift %u), parent=%s, rate=%lu\n", 
+			clk->name, rate, shift, clk->parent->name, clk->parent->rate);
 	return rate;
 }
 static struct clk *clk_ddr_parents[2] = {&ddr_pll_clk, &clk_ddr_gpll_path};
 static struct clk clk_ddr = {
 	.name		= "ddr",
 	.parent		= &ddr_pll_clk,
+	.get_parent	= clksel_get_parent,
+	.set_parent	= clksel_set_parent,
 	.recalc		= ddr_clk_recalc_rate,
 	.set_rate	= ddr_clk_set_rate,
 	.round_rate	= ddr_clk_round_rate,
@@ -3239,22 +3256,16 @@ static void periph_clk_set_init(void)
 
 	/* general pll */
 	switch (ppll_rate) {
-		case 148500* KHZ:
+		case 148500 * KHZ:
 			aclk_p = 148500 * KHZ;
 			hclk_p = aclk_p >> 1;
 			pclk_p = aclk_p >> 2;
 			break;
-		case 1188*MHZ:
-			aclk_p = aclk_p >> 3; // 0
-			hclk_p = aclk_p >> 1;
-			pclk_p = aclk_p >> 2;
-
 		case 297 * MHZ:
 			aclk_p = ppll_rate >> 1;
 			hclk_p = aclk_p >> 0;
 			pclk_p = aclk_p >> 1;
 			break;
-
 		case 300 * MHZ:
 			aclk_p = ppll_rate >> 1;
 			hclk_p = aclk_p >> 0;
@@ -3265,6 +3276,17 @@ static void periph_clk_set_init(void)
 			hclk_p = aclk_p >> 0;
 			pclk_p = aclk_p >> 1;
 			break;
+		case 891 * MHZ:
+			aclk_p = ppll_rate / 6;
+			hclk_p = aclk_p >> 0;
+			pclk_p = aclk_p >> 1;
+			break;
+		case 1188 * MHZ:
+			aclk_p = ppll_rate >> 3;
+			hclk_p = aclk_p >> 0;
+			pclk_p = aclk_p >> 1;
+			break;
+
 		default:
 			aclk_p = 150 * MHZ;
 			hclk_p = 150 * MHZ;
@@ -3296,6 +3318,21 @@ static void cpu_axi_init(void)
 			hclk_cpu_rate = aclk_cpu_rate >> 1;
 			pclk_cpu_rate = aclk_cpu_rate >> 2;
 			break;
+
+		case 891 * MHZ:
+			cpu_div_rate = gpll_rate / 3;
+			aclk_cpu_rate = cpu_div_rate >> 0;
+			hclk_cpu_rate = aclk_cpu_rate >> 1;
+			pclk_cpu_rate = aclk_cpu_rate >> 2;
+			break;
+
+		case 1188 * MHZ:
+			cpu_div_rate = gpll_rate >> 2;
+			aclk_cpu_rate = cpu_div_rate >> 0;
+			hclk_cpu_rate = aclk_cpu_rate >> 1;
+			pclk_cpu_rate = aclk_cpu_rate >> 2;
+			break;
+
 		default:
 			aclk_cpu_rate = 150 * MHZ;
 			hclk_cpu_rate = 150 * MHZ;
@@ -3340,9 +3377,90 @@ void rk30_clock_common_i2s_init(void)
 	}
 }
 
-static void __init rk30_clock_common_init(unsigned long gpll_rate, unsigned long cpll_rate)
+static void inline clock_set_div(struct clk *clk,u32 div)
 {
+	set_cru_bits_w_msk(div - 1, clk->div_mask, clk->div_shift, clk->clksel_con);
+}
+
+static void inline clock_set_max_div(struct clk *clk)
+{
+	set_cru_bits_w_msk(clk->div_max - 1, clk->div_mask, clk->div_shift, clk->clksel_con);
+}
+
+static void div_clk_for_pll_init(void)
+{
+	clock_set_max_div(&clk_cpu_div);
+	clock_set_max_div(&aclk_vdpu);
+	clock_set_max_div(&aclk_vepu);
+	clock_set_max_div(&aclk_gpu);
+	clock_set_max_div(&aclk_lcdc0_pre);
+	clock_set_max_div(&aclk_lcdc1_pre);
+	clock_set_max_div(&aclk_periph);
+	clock_set_max_div(&dclk_lcdc0);
+	clock_set_max_div(&dclk_lcdc1);
+	clock_set_max_div(&cif0_out_div);
+	clock_set_max_div(&clk_i2s0_div);
+	clock_set_max_div(&clk_spdif_div);
+	clock_set_max_div(&clk_uart0_div);
+	clock_set_max_div(&clk_uart1_div);
+	clock_set_max_div(&clk_uart2_div);
+	clock_set_max_div(&clk_uart3_div);
+	clock_set_max_div(&clk_hsicphy_12m);
+	clock_set_max_div(&clk_hsadc_pll_div);
+	clock_set_max_div(&clk_saradc);
+}
+
+/************************************for cpll runing checking****************************************/
+/* eFuse controller register */
+#define EFUSE_A_SHIFT		(6)
+#define EFUSE_A_MASK		(0xFF)
+//#define EFUSE_PD		(1 << 5)
+//#define EFUSE_PS		(1 << 4)
+#define EFUSE_PGENB		(1 << 3)//active low
+#define EFUSE_LOAD		(1 << 2)
+#define EFUSE_STROBE		(1 << 1)  
+#define EFUSE_CSB		(1 << 0)  //active low
+
+#define REG_EFUSE_CTRL		(0x0000)
+#define REG_EFUSE_DOUT		(0x0004)
+
+#define efuse_readl(offset)		readl_relaxed(RK30_EFUSE_BASE + offset)
+#define efuse_writel(val, offset)	writel_relaxed(val, RK30_EFUSE_BASE + offset)
+int efuse_readregs(u32 addr, u32 length, u8 *pData)
+{
+	efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
+	efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
+	udelay(2);
+	do {
+		efuse_writel(efuse_readl(REG_EFUSE_CTRL) & (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), REG_EFUSE_CTRL);
+		efuse_writel(efuse_readl(REG_EFUSE_CTRL) | ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT), REG_EFUSE_CTRL);
+		udelay(2);
+		efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_STROBE, REG_EFUSE_CTRL);
+		udelay(2);
+		*pData = efuse_readl(REG_EFUSE_DOUT);
+		efuse_writel(efuse_readl(REG_EFUSE_CTRL) & (~EFUSE_STROBE), REG_EFUSE_CTRL);
+		udelay(2);
+		pData++;
+		addr++;
+	} while(--length);
+	udelay(2);
+	efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
+	udelay(1);
+	return 0;
+}
+static u8 pll_flag = 0;
+static int pll_get_flag(void)
+{
+	u8 data_buf[32 + 1];
+	efuse_readregs(0, 32, data_buf);
+
+	printk("pll_flag = 0x%02x\n", data_buf[22]);
+	return data_buf[22] & 0x3;
+}
 
+static void __init rk30_clock_common_init(unsigned long gpll_rate, unsigned long cpll_rate)
+{
+	div_clk_for_pll_init();
 	//general
 	clk_set_rate_nolock(&general_pll_clk, gpll_rate);
 	//code pll
@@ -3361,17 +3479,21 @@ static void __init rk30_clock_common_init(unsigned long gpll_rate, unsigned long
 	clk_set_rate_nolock(&clk_spi1, clk_spi1.parent->rate);
 
 	// uart
-	if(rk30_clock_flags & CLK_FLG_UART_1_3M)
+	if((rk30_clock_flags & CLK_FLG_UART_1_3M) && (cpll_rate != 24 * MHZ))
 		clk_set_parent_nolock(&clk_uart_pll, &codec_pll_clk);
 	else
 		clk_set_parent_nolock(&clk_uart_pll, &general_pll_clk);
 	//mac
-	if(!(gpll_rate % (50 * MHZ)))
+	if(!(gpll_rate % (50 * MHZ))) {
 		clk_set_parent_nolock(&clk_mac_pll_div, &general_pll_clk);
-	else if(!(ddr_pll_clk.rate % (50 * MHZ)))
+
+	} else if((!(ddr_pll_clk.rate % (50 * MHZ))) && (ddr_pll_clk.rate != 24 * MHZ) && ((pll_flag & 0x2) == 0)) {
 		clk_set_parent_nolock(&clk_mac_pll_div, &ddr_pll_clk);
-	else
-		CLKDATA_ERR("mac can't get 50mhz\n");
+
+	} else {
+		CLKDATA_DBG("mac can't get 50mhz, set to gpll\n");
+		clk_set_parent_nolock(&clk_mac_pll_div, &general_pll_clk);
+	}
 
 	//hsadc
 	//auto pll sel
@@ -3397,13 +3519,12 @@ static void __init rk30_clock_common_init(unsigned long gpll_rate, unsigned long
 	clk_set_rate_nolock(&aclk_vepu, 300 * MHZ);
 	clk_set_rate_nolock(&aclk_vdpu, 300 * MHZ);
 	//gpu auto sel
-	clk_set_parent_nolock(&aclk_gpu, &codec_pll_clk);
+	clk_set_parent_nolock(&aclk_gpu, &general_pll_clk);
 	clk_set_rate_nolock(&aclk_gpu, 200 * MHZ);
 	
 	clk_set_rate_nolock(&clk_uart0, 49500000);
 	clk_set_rate_nolock(&clk_sdmmc, 24750000);
 	clk_set_rate_nolock(&clk_sdio, 24750000);
-
 }
 
 static struct clk def_ops_clk = {
@@ -3429,6 +3550,15 @@ void __init _rk30_clock_data_init(unsigned long gpll, unsigned long cpll, int fl
 		codec_pll_clk.set_rate = plus_cpll_clk_set_rate;
 		general_pll_clk.set_rate = plus_gpll_clk_set_rate;
 	}
+
+	pll_flag = pll_get_flag();
+	if (0 != pll_flag) {
+		CLKDATA_DBG("CPLL=%lu, GPLL=%lu;CPLL CAN NOT LOCK, SET CPLL BY PASS, USE GPLL REPLACE CPLL\n",
+				cpll, gpll);
+		cpll = 24 * MHZ;
+		gpll = 891 * MHZ;
+	}
+
 	clk_register_dump_ops(&dump_ops);
 	clk_register_default_ops_clk(&def_ops_clk);
 	rk30_clock_flags = flags;
@@ -3448,6 +3578,7 @@ void __init _rk30_clock_data_init(unsigned long gpll, unsigned long cpll, int fl
 	 * Only enable those clocks we will need, let the drivers
 	 * enable other clocks as necessary
 	 */
+
 	rk30_init_enable_clocks();
 #if 0
 	// print loader config
@@ -3473,7 +3604,7 @@ extern int rk3188_dvfs_init(void);
 
 void __init rk30_clock_data_init(unsigned long gpll, unsigned long cpll, u32 flags)
 {
-	DVFS_DBG("clock: gpll %lu cpll %lu flags 0x%x con2 0x%x/0x%x\n", 
+	CLKDATA_DBG("clock: gpll %lu cpll %lu flags 0x%x con2 0x%x/0x%x\n", 
 			gpll, cpll, flags, cru_readl(PLL_CONS(DPLL_ID, 2)), cru_readl(PLL_CONS(CPLL_ID, 2)));
 	_rk30_clock_data_init(gpll, cpll, flags);
 	rk3188_dvfs_init();
-- 
2.34.1