xref: /linux/arch/mips/ath79/clock.c (revision 626a0695a6d98338063c528d113d9ee4ba00cd78)
1d4a67d9dSGabor Juhos /*
2d4a67d9dSGabor Juhos  *  Atheros AR71XX/AR724X/AR913X common routines
3d4a67d9dSGabor Juhos  *
48889612bSGabor Juhos  *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
5d4a67d9dSGabor Juhos  *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
6d4a67d9dSGabor Juhos  *
78889612bSGabor Juhos  *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
88889612bSGabor Juhos  *
9d4a67d9dSGabor Juhos  *  This program is free software; you can redistribute it and/or modify it
10d4a67d9dSGabor Juhos  *  under the terms of the GNU General Public License version 2 as published
11d4a67d9dSGabor Juhos  *  by the Free Software Foundation.
12d4a67d9dSGabor Juhos  */
13d4a67d9dSGabor Juhos 
14d4a67d9dSGabor Juhos #include <linux/kernel.h>
15d4a67d9dSGabor Juhos #include <linux/module.h>
16d4a67d9dSGabor Juhos #include <linux/init.h>
17d4a67d9dSGabor Juhos #include <linux/err.h>
18d4a67d9dSGabor Juhos #include <linux/clk.h>
192c4f1ac5SGabor Juhos #include <linux/clkdev.h>
20d4a67d9dSGabor Juhos 
2197541ccfSGabor Juhos #include <asm/div64.h>
2297541ccfSGabor Juhos 
23d4a67d9dSGabor Juhos #include <asm/mach-ath79/ath79.h>
24d4a67d9dSGabor Juhos #include <asm/mach-ath79/ar71xx_regs.h>
25d4a67d9dSGabor Juhos #include "common.h"
26d4a67d9dSGabor Juhos 
27d4a67d9dSGabor Juhos #define AR71XX_BASE_FREQ	40000000
28d4a67d9dSGabor Juhos #define AR724X_BASE_FREQ	5000000
29d4a67d9dSGabor Juhos #define AR913X_BASE_FREQ	5000000
30d4a67d9dSGabor Juhos 
31d4a67d9dSGabor Juhos struct clk {
32d4a67d9dSGabor Juhos 	unsigned long rate;
33d4a67d9dSGabor Juhos };
34d4a67d9dSGabor Juhos 
352c4f1ac5SGabor Juhos static void __init ath79_add_sys_clkdev(const char *id, unsigned long rate)
362c4f1ac5SGabor Juhos {
372c4f1ac5SGabor Juhos 	struct clk *clk;
382c4f1ac5SGabor Juhos 	int err;
392c4f1ac5SGabor Juhos 
402c4f1ac5SGabor Juhos 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
412c4f1ac5SGabor Juhos 	if (!clk)
422c4f1ac5SGabor Juhos 		panic("failed to allocate %s clock structure", id);
432c4f1ac5SGabor Juhos 
442c4f1ac5SGabor Juhos 	clk->rate = rate;
452c4f1ac5SGabor Juhos 
462c4f1ac5SGabor Juhos 	err = clk_register_clkdev(clk, id, NULL);
472c4f1ac5SGabor Juhos 	if (err)
482c4f1ac5SGabor Juhos 		panic("unable to register %s clock device", id);
492c4f1ac5SGabor Juhos }
50d4a67d9dSGabor Juhos 
51d4a67d9dSGabor Juhos static void __init ar71xx_clocks_init(void)
52d4a67d9dSGabor Juhos {
536612a688SGabor Juhos 	unsigned long ref_rate;
546612a688SGabor Juhos 	unsigned long cpu_rate;
556612a688SGabor Juhos 	unsigned long ddr_rate;
566612a688SGabor Juhos 	unsigned long ahb_rate;
57d4a67d9dSGabor Juhos 	u32 pll;
58d4a67d9dSGabor Juhos 	u32 freq;
59d4a67d9dSGabor Juhos 	u32 div;
60d4a67d9dSGabor Juhos 
616612a688SGabor Juhos 	ref_rate = AR71XX_BASE_FREQ;
62d4a67d9dSGabor Juhos 
63d4a67d9dSGabor Juhos 	pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
64d4a67d9dSGabor Juhos 
65*626a0695SAlban Bedel 	div = ((pll >> AR71XX_PLL_FB_SHIFT) & AR71XX_PLL_FB_MASK) + 1;
666612a688SGabor Juhos 	freq = div * ref_rate;
67d4a67d9dSGabor Juhos 
68d4a67d9dSGabor Juhos 	div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
696612a688SGabor Juhos 	cpu_rate = freq / div;
70d4a67d9dSGabor Juhos 
71d4a67d9dSGabor Juhos 	div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
726612a688SGabor Juhos 	ddr_rate = freq / div;
73d4a67d9dSGabor Juhos 
74d4a67d9dSGabor Juhos 	div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
756612a688SGabor Juhos 	ahb_rate = cpu_rate / div;
766612a688SGabor Juhos 
772c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ref", ref_rate);
782c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("cpu", cpu_rate);
792c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ddr", ddr_rate);
802c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ahb", ahb_rate);
81d4a67d9dSGabor Juhos 
822c4f1ac5SGabor Juhos 	clk_add_alias("wdt", NULL, "ahb", NULL);
832c4f1ac5SGabor Juhos 	clk_add_alias("uart", NULL, "ahb", NULL);
84d4a67d9dSGabor Juhos }
85d4a67d9dSGabor Juhos 
86d4a67d9dSGabor Juhos static void __init ar724x_clocks_init(void)
87d4a67d9dSGabor Juhos {
886612a688SGabor Juhos 	unsigned long ref_rate;
896612a688SGabor Juhos 	unsigned long cpu_rate;
906612a688SGabor Juhos 	unsigned long ddr_rate;
916612a688SGabor Juhos 	unsigned long ahb_rate;
92d4a67d9dSGabor Juhos 	u32 pll;
93d4a67d9dSGabor Juhos 	u32 freq;
94d4a67d9dSGabor Juhos 	u32 div;
95d4a67d9dSGabor Juhos 
966612a688SGabor Juhos 	ref_rate = AR724X_BASE_FREQ;
97d4a67d9dSGabor Juhos 	pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
98d4a67d9dSGabor Juhos 
99*626a0695SAlban Bedel 	div = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK);
1006612a688SGabor Juhos 	freq = div * ref_rate;
101d4a67d9dSGabor Juhos 
102d4a67d9dSGabor Juhos 	div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
103d4a67d9dSGabor Juhos 	freq *= div;
104d4a67d9dSGabor Juhos 
1056612a688SGabor Juhos 	cpu_rate = freq;
106d4a67d9dSGabor Juhos 
107d4a67d9dSGabor Juhos 	div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
1086612a688SGabor Juhos 	ddr_rate = freq / div;
109d4a67d9dSGabor Juhos 
110d4a67d9dSGabor Juhos 	div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
1116612a688SGabor Juhos 	ahb_rate = cpu_rate / div;
1126612a688SGabor Juhos 
1132c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ref", ref_rate);
1142c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("cpu", cpu_rate);
1152c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ddr", ddr_rate);
1162c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ahb", ahb_rate);
117d4a67d9dSGabor Juhos 
1182c4f1ac5SGabor Juhos 	clk_add_alias("wdt", NULL, "ahb", NULL);
1192c4f1ac5SGabor Juhos 	clk_add_alias("uart", NULL, "ahb", NULL);
120d4a67d9dSGabor Juhos }
121d4a67d9dSGabor Juhos 
122d4a67d9dSGabor Juhos static void __init ar913x_clocks_init(void)
123d4a67d9dSGabor Juhos {
1246612a688SGabor Juhos 	unsigned long ref_rate;
1256612a688SGabor Juhos 	unsigned long cpu_rate;
1266612a688SGabor Juhos 	unsigned long ddr_rate;
1276612a688SGabor Juhos 	unsigned long ahb_rate;
128d4a67d9dSGabor Juhos 	u32 pll;
129d4a67d9dSGabor Juhos 	u32 freq;
130d4a67d9dSGabor Juhos 	u32 div;
131d4a67d9dSGabor Juhos 
1326612a688SGabor Juhos 	ref_rate = AR913X_BASE_FREQ;
133d4a67d9dSGabor Juhos 	pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
134d4a67d9dSGabor Juhos 
135*626a0695SAlban Bedel 	div = ((pll >> AR913X_PLL_FB_SHIFT) & AR913X_PLL_FB_MASK);
1366612a688SGabor Juhos 	freq = div * ref_rate;
137d4a67d9dSGabor Juhos 
1386612a688SGabor Juhos 	cpu_rate = freq;
139d4a67d9dSGabor Juhos 
140d4a67d9dSGabor Juhos 	div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
1416612a688SGabor Juhos 	ddr_rate = freq / div;
142d4a67d9dSGabor Juhos 
143d4a67d9dSGabor Juhos 	div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
1446612a688SGabor Juhos 	ahb_rate = cpu_rate / div;
1456612a688SGabor Juhos 
1462c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ref", ref_rate);
1472c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("cpu", cpu_rate);
1482c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ddr", ddr_rate);
1492c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ahb", ahb_rate);
150d4a67d9dSGabor Juhos 
1512c4f1ac5SGabor Juhos 	clk_add_alias("wdt", NULL, "ahb", NULL);
1522c4f1ac5SGabor Juhos 	clk_add_alias("uart", NULL, "ahb", NULL);
153d4a67d9dSGabor Juhos }
154d4a67d9dSGabor Juhos 
15504225e1dSGabor Juhos static void __init ar933x_clocks_init(void)
15604225e1dSGabor Juhos {
1576612a688SGabor Juhos 	unsigned long ref_rate;
1586612a688SGabor Juhos 	unsigned long cpu_rate;
1596612a688SGabor Juhos 	unsigned long ddr_rate;
1606612a688SGabor Juhos 	unsigned long ahb_rate;
16104225e1dSGabor Juhos 	u32 clock_ctrl;
16204225e1dSGabor Juhos 	u32 cpu_config;
16304225e1dSGabor Juhos 	u32 freq;
16404225e1dSGabor Juhos 	u32 t;
16504225e1dSGabor Juhos 
16604225e1dSGabor Juhos 	t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
16704225e1dSGabor Juhos 	if (t & AR933X_BOOTSTRAP_REF_CLK_40)
1686612a688SGabor Juhos 		ref_rate = (40 * 1000 * 1000);
16904225e1dSGabor Juhos 	else
1706612a688SGabor Juhos 		ref_rate = (25 * 1000 * 1000);
17104225e1dSGabor Juhos 
17204225e1dSGabor Juhos 	clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG);
17304225e1dSGabor Juhos 	if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
1746612a688SGabor Juhos 		cpu_rate = ref_rate;
1756612a688SGabor Juhos 		ahb_rate = ref_rate;
1766612a688SGabor Juhos 		ddr_rate = ref_rate;
17704225e1dSGabor Juhos 	} else {
17804225e1dSGabor Juhos 		cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG);
17904225e1dSGabor Juhos 
18004225e1dSGabor Juhos 		t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
18104225e1dSGabor Juhos 		    AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
1826612a688SGabor Juhos 		freq = ref_rate / t;
18304225e1dSGabor Juhos 
18404225e1dSGabor Juhos 		t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
18504225e1dSGabor Juhos 		    AR933X_PLL_CPU_CONFIG_NINT_MASK;
18604225e1dSGabor Juhos 		freq *= t;
18704225e1dSGabor Juhos 
18804225e1dSGabor Juhos 		t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
18904225e1dSGabor Juhos 		    AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
19004225e1dSGabor Juhos 		if (t == 0)
19104225e1dSGabor Juhos 			t = 1;
19204225e1dSGabor Juhos 
19304225e1dSGabor Juhos 		freq >>= t;
19404225e1dSGabor Juhos 
19504225e1dSGabor Juhos 		t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
19604225e1dSGabor Juhos 		     AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1;
1976612a688SGabor Juhos 		cpu_rate = freq / t;
19804225e1dSGabor Juhos 
19904225e1dSGabor Juhos 		t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
20004225e1dSGabor Juhos 		      AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1;
2016612a688SGabor Juhos 		ddr_rate = freq / t;
20204225e1dSGabor Juhos 
20304225e1dSGabor Juhos 		t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
20404225e1dSGabor Juhos 		     AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1;
2056612a688SGabor Juhos 		ahb_rate = freq / t;
20604225e1dSGabor Juhos 	}
20704225e1dSGabor Juhos 
2082c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ref", ref_rate);
2092c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("cpu", cpu_rate);
2102c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ddr", ddr_rate);
2112c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ahb", ahb_rate);
2126612a688SGabor Juhos 
2132c4f1ac5SGabor Juhos 	clk_add_alias("wdt", NULL, "ahb", NULL);
2142c4f1ac5SGabor Juhos 	clk_add_alias("uart", NULL, "ref", NULL);
21504225e1dSGabor Juhos }
21604225e1dSGabor Juhos 
21797541ccfSGabor Juhos static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
21897541ccfSGabor Juhos 				      u32 frac, u32 out_div)
21997541ccfSGabor Juhos {
22097541ccfSGabor Juhos 	u64 t;
22197541ccfSGabor Juhos 	u32 ret;
22297541ccfSGabor Juhos 
223837f036cSGabor Juhos 	t = ref;
22497541ccfSGabor Juhos 	t *= nint;
22597541ccfSGabor Juhos 	do_div(t, ref_div);
22697541ccfSGabor Juhos 	ret = t;
22797541ccfSGabor Juhos 
228837f036cSGabor Juhos 	t = ref;
22997541ccfSGabor Juhos 	t *= nfrac;
23097541ccfSGabor Juhos 	do_div(t, ref_div * frac);
23197541ccfSGabor Juhos 	ret += t;
23297541ccfSGabor Juhos 
23397541ccfSGabor Juhos 	ret /= (1 << out_div);
23497541ccfSGabor Juhos 	return ret;
23597541ccfSGabor Juhos }
23697541ccfSGabor Juhos 
2378889612bSGabor Juhos static void __init ar934x_clocks_init(void)
2388889612bSGabor Juhos {
2396612a688SGabor Juhos 	unsigned long ref_rate;
2406612a688SGabor Juhos 	unsigned long cpu_rate;
2416612a688SGabor Juhos 	unsigned long ddr_rate;
2426612a688SGabor Juhos 	unsigned long ahb_rate;
24397541ccfSGabor Juhos 	u32 pll, out_div, ref_div, nint, nfrac, frac, clk_ctrl, postdiv;
2448889612bSGabor Juhos 	u32 cpu_pll, ddr_pll;
2458889612bSGabor Juhos 	u32 bootstrap;
24697541ccfSGabor Juhos 	void __iomem *dpll_base;
24797541ccfSGabor Juhos 
24897541ccfSGabor Juhos 	dpll_base = ioremap(AR934X_SRIF_BASE, AR934X_SRIF_SIZE);
2498889612bSGabor Juhos 
2508889612bSGabor Juhos 	bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
2518889612bSGabor Juhos 	if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40)
2526612a688SGabor Juhos 		ref_rate = 40 * 1000 * 1000;
2538889612bSGabor Juhos 	else
2546612a688SGabor Juhos 		ref_rate = 25 * 1000 * 1000;
2558889612bSGabor Juhos 
25697541ccfSGabor Juhos 	pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL2_REG);
25797541ccfSGabor Juhos 	if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
25897541ccfSGabor Juhos 		out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) &
25997541ccfSGabor Juhos 			  AR934X_SRIF_DPLL2_OUTDIV_MASK;
26097541ccfSGabor Juhos 		pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL1_REG);
26197541ccfSGabor Juhos 		nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) &
26297541ccfSGabor Juhos 		       AR934X_SRIF_DPLL1_NINT_MASK;
26397541ccfSGabor Juhos 		nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK;
26497541ccfSGabor Juhos 		ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) &
26597541ccfSGabor Juhos 			  AR934X_SRIF_DPLL1_REFDIV_MASK;
26697541ccfSGabor Juhos 		frac = 1 << 18;
26797541ccfSGabor Juhos 	} else {
2688889612bSGabor Juhos 		pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG);
2698889612bSGabor Juhos 		out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
2708889612bSGabor Juhos 			AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
2718889612bSGabor Juhos 		ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
2728889612bSGabor Juhos 			  AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
2738889612bSGabor Juhos 		nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
2748889612bSGabor Juhos 		       AR934X_PLL_CPU_CONFIG_NINT_MASK;
27597541ccfSGabor Juhos 		nfrac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
2768889612bSGabor Juhos 			AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
27797541ccfSGabor Juhos 		frac = 1 << 6;
27897541ccfSGabor Juhos 	}
2798889612bSGabor Juhos 
2806612a688SGabor Juhos 	cpu_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
28197541ccfSGabor Juhos 				      nfrac, frac, out_div);
2828889612bSGabor Juhos 
28397541ccfSGabor Juhos 	pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL2_REG);
28497541ccfSGabor Juhos 	if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
28597541ccfSGabor Juhos 		out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) &
28697541ccfSGabor Juhos 			  AR934X_SRIF_DPLL2_OUTDIV_MASK;
28797541ccfSGabor Juhos 		pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL1_REG);
28897541ccfSGabor Juhos 		nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) &
28997541ccfSGabor Juhos 		       AR934X_SRIF_DPLL1_NINT_MASK;
29097541ccfSGabor Juhos 		nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK;
29197541ccfSGabor Juhos 		ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) &
29297541ccfSGabor Juhos 			  AR934X_SRIF_DPLL1_REFDIV_MASK;
29397541ccfSGabor Juhos 		frac = 1 << 18;
29497541ccfSGabor Juhos 	} else {
2958889612bSGabor Juhos 		pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG);
2968889612bSGabor Juhos 		out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
2978889612bSGabor Juhos 			  AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
2988889612bSGabor Juhos 		ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
2998889612bSGabor Juhos 			   AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
3008889612bSGabor Juhos 		nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
3018889612bSGabor Juhos 		       AR934X_PLL_DDR_CONFIG_NINT_MASK;
30297541ccfSGabor Juhos 		nfrac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
3038889612bSGabor Juhos 			AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
30497541ccfSGabor Juhos 		frac = 1 << 10;
30597541ccfSGabor Juhos 	}
3068889612bSGabor Juhos 
3076612a688SGabor Juhos 	ddr_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
30897541ccfSGabor Juhos 				      nfrac, frac, out_div);
3098889612bSGabor Juhos 
3108889612bSGabor Juhos 	clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
3118889612bSGabor Juhos 
3128889612bSGabor Juhos 	postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) &
3138889612bSGabor Juhos 		  AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK;
3148889612bSGabor Juhos 
3158889612bSGabor Juhos 	if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS)
3166612a688SGabor Juhos 		cpu_rate = ref_rate;
3178889612bSGabor Juhos 	else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL)
3186612a688SGabor Juhos 		cpu_rate = cpu_pll / (postdiv + 1);
3198889612bSGabor Juhos 	else
3206612a688SGabor Juhos 		cpu_rate = ddr_pll / (postdiv + 1);
3218889612bSGabor Juhos 
3228889612bSGabor Juhos 	postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) &
3238889612bSGabor Juhos 		  AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK;
3248889612bSGabor Juhos 
3258889612bSGabor Juhos 	if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS)
3266612a688SGabor Juhos 		ddr_rate = ref_rate;
3278889612bSGabor Juhos 	else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL)
3286612a688SGabor Juhos 		ddr_rate = ddr_pll / (postdiv + 1);
3298889612bSGabor Juhos 	else
3306612a688SGabor Juhos 		ddr_rate = cpu_pll / (postdiv + 1);
3318889612bSGabor Juhos 
3328889612bSGabor Juhos 	postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) &
3338889612bSGabor Juhos 		  AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK;
3348889612bSGabor Juhos 
3358889612bSGabor Juhos 	if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS)
3366612a688SGabor Juhos 		ahb_rate = ref_rate;
3378889612bSGabor Juhos 	else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL)
3386612a688SGabor Juhos 		ahb_rate = ddr_pll / (postdiv + 1);
3398889612bSGabor Juhos 	else
3406612a688SGabor Juhos 		ahb_rate = cpu_pll / (postdiv + 1);
3416612a688SGabor Juhos 
3422c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ref", ref_rate);
3432c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("cpu", cpu_rate);
3442c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ddr", ddr_rate);
3452c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ahb", ahb_rate);
3468889612bSGabor Juhos 
3472c4f1ac5SGabor Juhos 	clk_add_alias("wdt", NULL, "ref", NULL);
3482c4f1ac5SGabor Juhos 	clk_add_alias("uart", NULL, "ref", NULL);
34997541ccfSGabor Juhos 
35097541ccfSGabor Juhos 	iounmap(dpll_base);
3518889612bSGabor Juhos }
3528889612bSGabor Juhos 
35341583c05SGabor Juhos static void __init qca955x_clocks_init(void)
35441583c05SGabor Juhos {
3556612a688SGabor Juhos 	unsigned long ref_rate;
3566612a688SGabor Juhos 	unsigned long cpu_rate;
3576612a688SGabor Juhos 	unsigned long ddr_rate;
3586612a688SGabor Juhos 	unsigned long ahb_rate;
35941583c05SGabor Juhos 	u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
36041583c05SGabor Juhos 	u32 cpu_pll, ddr_pll;
36141583c05SGabor Juhos 	u32 bootstrap;
36241583c05SGabor Juhos 
36341583c05SGabor Juhos 	bootstrap = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP);
36441583c05SGabor Juhos 	if (bootstrap &	QCA955X_BOOTSTRAP_REF_CLK_40)
3656612a688SGabor Juhos 		ref_rate = 40 * 1000 * 1000;
36641583c05SGabor Juhos 	else
3676612a688SGabor Juhos 		ref_rate = 25 * 1000 * 1000;
36841583c05SGabor Juhos 
36941583c05SGabor Juhos 	pll = ath79_pll_rr(QCA955X_PLL_CPU_CONFIG_REG);
37041583c05SGabor Juhos 	out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
37141583c05SGabor Juhos 		  QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK;
37241583c05SGabor Juhos 	ref_div = (pll >> QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
37341583c05SGabor Juhos 		  QCA955X_PLL_CPU_CONFIG_REFDIV_MASK;
37441583c05SGabor Juhos 	nint = (pll >> QCA955X_PLL_CPU_CONFIG_NINT_SHIFT) &
37541583c05SGabor Juhos 	       QCA955X_PLL_CPU_CONFIG_NINT_MASK;
37641583c05SGabor Juhos 	frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
37741583c05SGabor Juhos 	       QCA955X_PLL_CPU_CONFIG_NFRAC_MASK;
37841583c05SGabor Juhos 
3796612a688SGabor Juhos 	cpu_pll = nint * ref_rate / ref_div;
3806612a688SGabor Juhos 	cpu_pll += frac * ref_rate / (ref_div * (1 << 6));
38141583c05SGabor Juhos 	cpu_pll /= (1 << out_div);
38241583c05SGabor Juhos 
38341583c05SGabor Juhos 	pll = ath79_pll_rr(QCA955X_PLL_DDR_CONFIG_REG);
38441583c05SGabor Juhos 	out_div = (pll >> QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
38541583c05SGabor Juhos 		  QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK;
38641583c05SGabor Juhos 	ref_div = (pll >> QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
38741583c05SGabor Juhos 		  QCA955X_PLL_DDR_CONFIG_REFDIV_MASK;
38841583c05SGabor Juhos 	nint = (pll >> QCA955X_PLL_DDR_CONFIG_NINT_SHIFT) &
38941583c05SGabor Juhos 	       QCA955X_PLL_DDR_CONFIG_NINT_MASK;
39041583c05SGabor Juhos 	frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
39141583c05SGabor Juhos 	       QCA955X_PLL_DDR_CONFIG_NFRAC_MASK;
39241583c05SGabor Juhos 
3936612a688SGabor Juhos 	ddr_pll = nint * ref_rate / ref_div;
3946612a688SGabor Juhos 	ddr_pll += frac * ref_rate / (ref_div * (1 << 10));
39541583c05SGabor Juhos 	ddr_pll /= (1 << out_div);
39641583c05SGabor Juhos 
39741583c05SGabor Juhos 	clk_ctrl = ath79_pll_rr(QCA955X_PLL_CLK_CTRL_REG);
39841583c05SGabor Juhos 
39941583c05SGabor Juhos 	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
40041583c05SGabor Juhos 		  QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
40141583c05SGabor Juhos 
40241583c05SGabor Juhos 	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
4036612a688SGabor Juhos 		cpu_rate = ref_rate;
40441583c05SGabor Juhos 	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
4056612a688SGabor Juhos 		cpu_rate = ddr_pll / (postdiv + 1);
40641583c05SGabor Juhos 	else
4076612a688SGabor Juhos 		cpu_rate = cpu_pll / (postdiv + 1);
40841583c05SGabor Juhos 
40941583c05SGabor Juhos 	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
41041583c05SGabor Juhos 		  QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
41141583c05SGabor Juhos 
41241583c05SGabor Juhos 	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
4136612a688SGabor Juhos 		ddr_rate = ref_rate;
41441583c05SGabor Juhos 	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
4156612a688SGabor Juhos 		ddr_rate = cpu_pll / (postdiv + 1);
41641583c05SGabor Juhos 	else
4176612a688SGabor Juhos 		ddr_rate = ddr_pll / (postdiv + 1);
41841583c05SGabor Juhos 
41941583c05SGabor Juhos 	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
42041583c05SGabor Juhos 		  QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
42141583c05SGabor Juhos 
42241583c05SGabor Juhos 	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
4236612a688SGabor Juhos 		ahb_rate = ref_rate;
42441583c05SGabor Juhos 	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
4256612a688SGabor Juhos 		ahb_rate = ddr_pll / (postdiv + 1);
42641583c05SGabor Juhos 	else
4276612a688SGabor Juhos 		ahb_rate = cpu_pll / (postdiv + 1);
4286612a688SGabor Juhos 
4292c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ref", ref_rate);
4302c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("cpu", cpu_rate);
4312c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ddr", ddr_rate);
4322c4f1ac5SGabor Juhos 	ath79_add_sys_clkdev("ahb", ahb_rate);
43341583c05SGabor Juhos 
4342c4f1ac5SGabor Juhos 	clk_add_alias("wdt", NULL, "ref", NULL);
4352c4f1ac5SGabor Juhos 	clk_add_alias("uart", NULL, "ref", NULL);
43641583c05SGabor Juhos }
43741583c05SGabor Juhos 
438d4a67d9dSGabor Juhos void __init ath79_clocks_init(void)
439d4a67d9dSGabor Juhos {
440d4a67d9dSGabor Juhos 	if (soc_is_ar71xx())
441d4a67d9dSGabor Juhos 		ar71xx_clocks_init();
442d4a67d9dSGabor Juhos 	else if (soc_is_ar724x())
443d4a67d9dSGabor Juhos 		ar724x_clocks_init();
444d4a67d9dSGabor Juhos 	else if (soc_is_ar913x())
445d4a67d9dSGabor Juhos 		ar913x_clocks_init();
44604225e1dSGabor Juhos 	else if (soc_is_ar933x())
44704225e1dSGabor Juhos 		ar933x_clocks_init();
4488889612bSGabor Juhos 	else if (soc_is_ar934x())
4498889612bSGabor Juhos 		ar934x_clocks_init();
45041583c05SGabor Juhos 	else if (soc_is_qca955x())
45141583c05SGabor Juhos 		qca955x_clocks_init();
452d4a67d9dSGabor Juhos 	else
453d4a67d9dSGabor Juhos 		BUG();
454d4a67d9dSGabor Juhos }
455d4a67d9dSGabor Juhos 
45623107802SGabor Juhos unsigned long __init
45723107802SGabor Juhos ath79_get_sys_clk_rate(const char *id)
45823107802SGabor Juhos {
45923107802SGabor Juhos 	struct clk *clk;
46023107802SGabor Juhos 	unsigned long rate;
46123107802SGabor Juhos 
46223107802SGabor Juhos 	clk = clk_get(NULL, id);
46323107802SGabor Juhos 	if (IS_ERR(clk))
46423107802SGabor Juhos 		panic("unable to get %s clock, err=%d", id, (int) PTR_ERR(clk));
46523107802SGabor Juhos 
46623107802SGabor Juhos 	rate = clk_get_rate(clk);
46723107802SGabor Juhos 	clk_put(clk);
46823107802SGabor Juhos 
46923107802SGabor Juhos 	return rate;
47023107802SGabor Juhos }
47123107802SGabor Juhos 
472d4a67d9dSGabor Juhos /*
473d4a67d9dSGabor Juhos  * Linux clock API
474d4a67d9dSGabor Juhos  */
475d4a67d9dSGabor Juhos int clk_enable(struct clk *clk)
476d4a67d9dSGabor Juhos {
477d4a67d9dSGabor Juhos 	return 0;
478d4a67d9dSGabor Juhos }
479d4a67d9dSGabor Juhos EXPORT_SYMBOL(clk_enable);
480d4a67d9dSGabor Juhos 
481d4a67d9dSGabor Juhos void clk_disable(struct clk *clk)
482d4a67d9dSGabor Juhos {
483d4a67d9dSGabor Juhos }
484d4a67d9dSGabor Juhos EXPORT_SYMBOL(clk_disable);
485d4a67d9dSGabor Juhos 
486d4a67d9dSGabor Juhos unsigned long clk_get_rate(struct clk *clk)
487d4a67d9dSGabor Juhos {
488d4a67d9dSGabor Juhos 	return clk->rate;
489d4a67d9dSGabor Juhos }
490d4a67d9dSGabor Juhos EXPORT_SYMBOL(clk_get_rate);
491