xref: /openbmc/linux/arch/mips/ar7/clock.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1fd534e9bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
27ca5dc14SFlorian Fainelli /*
37ca5dc14SFlorian Fainelli  * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
47ca5dc14SFlorian Fainelli  * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
5780019ddSFlorian Fainelli  * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
67ca5dc14SFlorian Fainelli  */
77ca5dc14SFlorian Fainelli 
87ca5dc14SFlorian Fainelli #include <linux/kernel.h>
97ca5dc14SFlorian Fainelli #include <linux/init.h>
107ca5dc14SFlorian Fainelli #include <linux/types.h>
1126dd3e4fSPaul Gortmaker #include <linux/export.h>
127ca5dc14SFlorian Fainelli #include <linux/delay.h>
137ca5dc14SFlorian Fainelli #include <linux/gcd.h>
147ca5dc14SFlorian Fainelli #include <linux/io.h>
15780019ddSFlorian Fainelli #include <linux/err.h>
164410c423SArnd Bergmann #include <linux/clkdev.h>
17780019ddSFlorian Fainelli #include <linux/clk.h>
18*b408b611SArnd Bergmann #include <linux/clk-provider.h>
197ca5dc14SFlorian Fainelli 
207ca5dc14SFlorian Fainelli #include <asm/addrspace.h>
217ca5dc14SFlorian Fainelli #include <asm/mach-ar7/ar7.h>
227ca5dc14SFlorian Fainelli 
237ca5dc14SFlorian Fainelli #define BOOT_PLL_SOURCE_MASK	0x3
247ca5dc14SFlorian Fainelli #define CPU_PLL_SOURCE_SHIFT	16
257ca5dc14SFlorian Fainelli #define BUS_PLL_SOURCE_SHIFT	14
267ca5dc14SFlorian Fainelli #define USB_PLL_SOURCE_SHIFT	18
277ca5dc14SFlorian Fainelli #define DSP_PLL_SOURCE_SHIFT	22
287ca5dc14SFlorian Fainelli #define BOOT_PLL_SOURCE_AFE	0
297ca5dc14SFlorian Fainelli #define BOOT_PLL_SOURCE_BUS	0
307ca5dc14SFlorian Fainelli #define BOOT_PLL_SOURCE_REF	1
317ca5dc14SFlorian Fainelli #define BOOT_PLL_SOURCE_XTAL	2
327ca5dc14SFlorian Fainelli #define BOOT_PLL_SOURCE_CPU	3
337ca5dc14SFlorian Fainelli #define BOOT_PLL_BYPASS		0x00000020
347ca5dc14SFlorian Fainelli #define BOOT_PLL_ASYNC_MODE	0x02000000
357ca5dc14SFlorian Fainelli #define BOOT_PLL_2TO1_MODE	0x00008000
367ca5dc14SFlorian Fainelli 
377ca5dc14SFlorian Fainelli #define TNETD7200_CLOCK_ID_CPU	0
387ca5dc14SFlorian Fainelli #define TNETD7200_CLOCK_ID_DSP	1
397ca5dc14SFlorian Fainelli #define TNETD7200_CLOCK_ID_USB	2
407ca5dc14SFlorian Fainelli 
417ca5dc14SFlorian Fainelli #define TNETD7200_DEF_CPU_CLK	211000000
427ca5dc14SFlorian Fainelli #define TNETD7200_DEF_DSP_CLK	125000000
437ca5dc14SFlorian Fainelli #define TNETD7200_DEF_USB_CLK	48000000
447ca5dc14SFlorian Fainelli 
457ca5dc14SFlorian Fainelli struct tnetd7300_clock {
467ca5dc14SFlorian Fainelli 	u32 ctrl;
477ca5dc14SFlorian Fainelli #define PREDIV_MASK	0x001f0000
487ca5dc14SFlorian Fainelli #define PREDIV_SHIFT	16
497ca5dc14SFlorian Fainelli #define POSTDIV_MASK	0x0000001f
507ca5dc14SFlorian Fainelli 	u32 unused1[3];
517ca5dc14SFlorian Fainelli 	u32 pll;
527ca5dc14SFlorian Fainelli #define MUL_MASK	0x0000f000
537ca5dc14SFlorian Fainelli #define MUL_SHIFT	12
547ca5dc14SFlorian Fainelli #define PLL_MODE_MASK	0x00000001
557ca5dc14SFlorian Fainelli #define PLL_NDIV	0x00000800
567ca5dc14SFlorian Fainelli #define PLL_DIV		0x00000002
577ca5dc14SFlorian Fainelli #define PLL_STATUS	0x00000001
587ca5dc14SFlorian Fainelli 	u32 unused2[3];
597ca5dc14SFlorian Fainelli };
607ca5dc14SFlorian Fainelli 
617ca5dc14SFlorian Fainelli struct tnetd7300_clocks {
627ca5dc14SFlorian Fainelli 	struct tnetd7300_clock bus;
637ca5dc14SFlorian Fainelli 	struct tnetd7300_clock cpu;
647ca5dc14SFlorian Fainelli 	struct tnetd7300_clock usb;
657ca5dc14SFlorian Fainelli 	struct tnetd7300_clock dsp;
667ca5dc14SFlorian Fainelli };
677ca5dc14SFlorian Fainelli 
687ca5dc14SFlorian Fainelli struct tnetd7200_clock {
697ca5dc14SFlorian Fainelli 	u32 ctrl;
707ca5dc14SFlorian Fainelli 	u32 unused1[3];
717ca5dc14SFlorian Fainelli #define DIVISOR_ENABLE_MASK 0x00008000
727ca5dc14SFlorian Fainelli 	u32 mul;
737ca5dc14SFlorian Fainelli 	u32 prediv;
747ca5dc14SFlorian Fainelli 	u32 postdiv;
757ca5dc14SFlorian Fainelli 	u32 postdiv2;
767ca5dc14SFlorian Fainelli 	u32 unused2[6];
777ca5dc14SFlorian Fainelli 	u32 cmd;
787ca5dc14SFlorian Fainelli 	u32 status;
797ca5dc14SFlorian Fainelli 	u32 cmden;
807ca5dc14SFlorian Fainelli 	u32 padding[15];
817ca5dc14SFlorian Fainelli };
827ca5dc14SFlorian Fainelli 
837ca5dc14SFlorian Fainelli struct tnetd7200_clocks {
847ca5dc14SFlorian Fainelli 	struct tnetd7200_clock cpu;
857ca5dc14SFlorian Fainelli 	struct tnetd7200_clock dsp;
867ca5dc14SFlorian Fainelli 	struct tnetd7200_clock usb;
877ca5dc14SFlorian Fainelli };
887ca5dc14SFlorian Fainelli 
89*b408b611SArnd Bergmann struct clk_rate {
90*b408b611SArnd Bergmann 	u32 rate;
91*b408b611SArnd Bergmann };
92*b408b611SArnd Bergmann static struct clk_rate bus_clk = {
93780019ddSFlorian Fainelli 	.rate	= 125000000,
94780019ddSFlorian Fainelli };
95780019ddSFlorian Fainelli 
96*b408b611SArnd Bergmann static struct clk_rate cpu_clk = {
97780019ddSFlorian Fainelli 	.rate	= 150000000,
98780019ddSFlorian Fainelli };
99780019ddSFlorian Fainelli 
approximate(int base,int target,int * prediv,int * postdiv,int * mul)1007ca5dc14SFlorian Fainelli static void approximate(int base, int target, int *prediv,
1017ca5dc14SFlorian Fainelli 			int *postdiv, int *mul)
1027ca5dc14SFlorian Fainelli {
1037ca5dc14SFlorian Fainelli 	int i, j, k, freq, res = target;
1047ca5dc14SFlorian Fainelli 	for (i = 1; i <= 16; i++)
1057ca5dc14SFlorian Fainelli 		for (j = 1; j <= 32; j++)
1067ca5dc14SFlorian Fainelli 			for (k = 1; k <= 32; k++) {
1077ca5dc14SFlorian Fainelli 				freq = abs(base / j * i / k - target);
1087ca5dc14SFlorian Fainelli 				if (freq < res) {
1097ca5dc14SFlorian Fainelli 					res = freq;
1107ca5dc14SFlorian Fainelli 					*mul = i;
1117ca5dc14SFlorian Fainelli 					*prediv = j;
1127ca5dc14SFlorian Fainelli 					*postdiv = k;
1137ca5dc14SFlorian Fainelli 				}
1147ca5dc14SFlorian Fainelli 			}
1157ca5dc14SFlorian Fainelli }
1167ca5dc14SFlorian Fainelli 
calculate(int base,int target,int * prediv,int * postdiv,int * mul)1177ca5dc14SFlorian Fainelli static void calculate(int base, int target, int *prediv, int *postdiv,
1187ca5dc14SFlorian Fainelli 	int *mul)
1197ca5dc14SFlorian Fainelli {
1207ca5dc14SFlorian Fainelli 	int tmp_gcd, tmp_base, tmp_freq;
1217ca5dc14SFlorian Fainelli 
1227ca5dc14SFlorian Fainelli 	for (*prediv = 1; *prediv <= 32; (*prediv)++) {
1237ca5dc14SFlorian Fainelli 		tmp_base = base / *prediv;
1247ca5dc14SFlorian Fainelli 		tmp_gcd = gcd(target, tmp_base);
1257ca5dc14SFlorian Fainelli 		*mul = target / tmp_gcd;
1267ca5dc14SFlorian Fainelli 		*postdiv = tmp_base / tmp_gcd;
1277ca5dc14SFlorian Fainelli 		if ((*mul < 1) || (*mul >= 16))
1287ca5dc14SFlorian Fainelli 			continue;
1297ca5dc14SFlorian Fainelli 		if ((*postdiv > 0) & (*postdiv <= 32))
1307ca5dc14SFlorian Fainelli 			break;
1317ca5dc14SFlorian Fainelli 	}
1327ca5dc14SFlorian Fainelli 
1337ca5dc14SFlorian Fainelli 	if (base / *prediv * *mul / *postdiv != target) {
1347ca5dc14SFlorian Fainelli 		approximate(base, target, prediv, postdiv, mul);
1357ca5dc14SFlorian Fainelli 		tmp_freq = base / *prediv * *mul / *postdiv;
1367ca5dc14SFlorian Fainelli 		printk(KERN_WARNING
1377ca5dc14SFlorian Fainelli 		       "Adjusted requested frequency %d to %d\n",
1387ca5dc14SFlorian Fainelli 		       target, tmp_freq);
1397ca5dc14SFlorian Fainelli 	}
1407ca5dc14SFlorian Fainelli 
1417ca5dc14SFlorian Fainelli 	printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
1427ca5dc14SFlorian Fainelli 	       *prediv, *postdiv, *mul);
1437ca5dc14SFlorian Fainelli }
1447ca5dc14SFlorian Fainelli 
tnetd7300_dsp_clock(void)1457ca5dc14SFlorian Fainelli static int tnetd7300_dsp_clock(void)
1467ca5dc14SFlorian Fainelli {
1477ca5dc14SFlorian Fainelli 	u32 didr1, didr2;
1487ca5dc14SFlorian Fainelli 	u8 rev = ar7_chip_rev();
1497ca5dc14SFlorian Fainelli 	didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
1507ca5dc14SFlorian Fainelli 	didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
1517ca5dc14SFlorian Fainelli 	if (didr2 & (1 << 23))
1527ca5dc14SFlorian Fainelli 		return 0;
1537ca5dc14SFlorian Fainelli 	if ((rev >= 0x23) && (rev != 0x57))
1547ca5dc14SFlorian Fainelli 		return 250000000;
1557ca5dc14SFlorian Fainelli 	if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
1567ca5dc14SFlorian Fainelli 	    > 4208000)
1577ca5dc14SFlorian Fainelli 		return 250000000;
1587ca5dc14SFlorian Fainelli 	return 0;
1597ca5dc14SFlorian Fainelli }
1607ca5dc14SFlorian Fainelli 
tnetd7300_get_clock(u32 shift,struct tnetd7300_clock * clock,u32 * bootcr,u32 bus_clock)1617ca5dc14SFlorian Fainelli static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
1627ca5dc14SFlorian Fainelli 	u32 *bootcr, u32 bus_clock)
1637ca5dc14SFlorian Fainelli {
1647ca5dc14SFlorian Fainelli 	int product;
1657ca5dc14SFlorian Fainelli 	int base_clock = AR7_REF_CLOCK;
1667ca5dc14SFlorian Fainelli 	u32 ctrl = readl(&clock->ctrl);
1677ca5dc14SFlorian Fainelli 	u32 pll = readl(&clock->pll);
1687ca5dc14SFlorian Fainelli 	int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
1697ca5dc14SFlorian Fainelli 	int postdiv = (ctrl & POSTDIV_MASK) + 1;
1707ca5dc14SFlorian Fainelli 	int divisor = prediv * postdiv;
1717ca5dc14SFlorian Fainelli 	int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
1727ca5dc14SFlorian Fainelli 
1737ca5dc14SFlorian Fainelli 	switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
1747ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_BUS:
1757ca5dc14SFlorian Fainelli 		base_clock = bus_clock;
1767ca5dc14SFlorian Fainelli 		break;
1777ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_REF:
1787ca5dc14SFlorian Fainelli 		base_clock = AR7_REF_CLOCK;
1797ca5dc14SFlorian Fainelli 		break;
1807ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_XTAL:
1817ca5dc14SFlorian Fainelli 		base_clock = AR7_XTAL_CLOCK;
1827ca5dc14SFlorian Fainelli 		break;
1837ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_CPU:
184780019ddSFlorian Fainelli 		base_clock = cpu_clk.rate;
1857ca5dc14SFlorian Fainelli 		break;
1867ca5dc14SFlorian Fainelli 	}
1877ca5dc14SFlorian Fainelli 
1887ca5dc14SFlorian Fainelli 	if (*bootcr & BOOT_PLL_BYPASS)
1897ca5dc14SFlorian Fainelli 		return base_clock / divisor;
1907ca5dc14SFlorian Fainelli 
1917ca5dc14SFlorian Fainelli 	if ((pll & PLL_MODE_MASK) == 0)
1927ca5dc14SFlorian Fainelli 		return (base_clock >> (mul / 16 + 1)) / divisor;
1937ca5dc14SFlorian Fainelli 
1947ca5dc14SFlorian Fainelli 	if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
1957ca5dc14SFlorian Fainelli 		product = (mul & 1) ?
1967ca5dc14SFlorian Fainelli 			(base_clock * mul) >> 1 :
1977ca5dc14SFlorian Fainelli 			(base_clock * (mul - 1)) >> 2;
1987ca5dc14SFlorian Fainelli 		return product / divisor;
1997ca5dc14SFlorian Fainelli 	}
2007ca5dc14SFlorian Fainelli 
2017ca5dc14SFlorian Fainelli 	if (mul == 16)
2027ca5dc14SFlorian Fainelli 		return base_clock / divisor;
2037ca5dc14SFlorian Fainelli 
2047ca5dc14SFlorian Fainelli 	return base_clock * mul / divisor;
2057ca5dc14SFlorian Fainelli }
2067ca5dc14SFlorian Fainelli 
tnetd7300_set_clock(u32 shift,struct tnetd7300_clock * clock,u32 * bootcr,u32 frequency)2077ca5dc14SFlorian Fainelli static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
2087ca5dc14SFlorian Fainelli 	u32 *bootcr, u32 frequency)
2097ca5dc14SFlorian Fainelli {
2107ca5dc14SFlorian Fainelli 	int prediv, postdiv, mul;
211780019ddSFlorian Fainelli 	int base_clock = bus_clk.rate;
2127ca5dc14SFlorian Fainelli 
2137ca5dc14SFlorian Fainelli 	switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
2147ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_BUS:
215780019ddSFlorian Fainelli 		base_clock = bus_clk.rate;
2167ca5dc14SFlorian Fainelli 		break;
2177ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_REF:
2187ca5dc14SFlorian Fainelli 		base_clock = AR7_REF_CLOCK;
2197ca5dc14SFlorian Fainelli 		break;
2207ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_XTAL:
2217ca5dc14SFlorian Fainelli 		base_clock = AR7_XTAL_CLOCK;
2227ca5dc14SFlorian Fainelli 		break;
2237ca5dc14SFlorian Fainelli 	case BOOT_PLL_SOURCE_CPU:
224780019ddSFlorian Fainelli 		base_clock = cpu_clk.rate;
2257ca5dc14SFlorian Fainelli 		break;
2267ca5dc14SFlorian Fainelli 	}
2277ca5dc14SFlorian Fainelli 
2287ca5dc14SFlorian Fainelli 	calculate(base_clock, frequency, &prediv, &postdiv, &mul);
2297ca5dc14SFlorian Fainelli 
2307ca5dc14SFlorian Fainelli 	writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
2310bc67917SFlorian Fainelli 	mdelay(1);
2327ca5dc14SFlorian Fainelli 	writel(4, &clock->pll);
2337ca5dc14SFlorian Fainelli 	while (readl(&clock->pll) & PLL_STATUS)
2347ca5dc14SFlorian Fainelli 		;
2357ca5dc14SFlorian Fainelli 	writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
2360bc67917SFlorian Fainelli 	mdelay(75);
2377ca5dc14SFlorian Fainelli }
2387ca5dc14SFlorian Fainelli 
tnetd7300_init_clocks(void)2397ca5dc14SFlorian Fainelli static void __init tnetd7300_init_clocks(void)
2407ca5dc14SFlorian Fainelli {
2414bdc0d67SChristoph Hellwig 	u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4);
2427ca5dc14SFlorian Fainelli 	struct tnetd7300_clocks *clocks =
2434bdc0d67SChristoph Hellwig 					ioremap(UR8_REGS_CLOCKS,
2447ca5dc14SFlorian Fainelli 					sizeof(struct tnetd7300_clocks));
245*b408b611SArnd Bergmann 	u32 dsp_clk;
246*b408b611SArnd Bergmann 	struct clk *clk;
2477ca5dc14SFlorian Fainelli 
248780019ddSFlorian Fainelli 	bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
2497ca5dc14SFlorian Fainelli 		&clocks->bus, bootcr, AR7_AFE_CLOCK);
2507ca5dc14SFlorian Fainelli 
2517ca5dc14SFlorian Fainelli 	if (*bootcr & BOOT_PLL_ASYNC_MODE)
252780019ddSFlorian Fainelli 		cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
2537ca5dc14SFlorian Fainelli 			&clocks->cpu, bootcr, AR7_AFE_CLOCK);
2547ca5dc14SFlorian Fainelli 	else
255780019ddSFlorian Fainelli 		cpu_clk.rate = bus_clk.rate;
2567ca5dc14SFlorian Fainelli 
257*b408b611SArnd Bergmann 	dsp_clk = tnetd7300_dsp_clock();
258*b408b611SArnd Bergmann 	if (dsp_clk == 250000000)
2597ca5dc14SFlorian Fainelli 		tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
260*b408b611SArnd Bergmann 			bootcr, dsp_clk);
2617ca5dc14SFlorian Fainelli 
2627ca5dc14SFlorian Fainelli 	iounmap(clocks);
2637ca5dc14SFlorian Fainelli 	iounmap(bootcr);
264*b408b611SArnd Bergmann 
265*b408b611SArnd Bergmann 	clk = clk_register_fixed_rate(NULL, "cpu", NULL, 0, cpu_clk.rate);
266*b408b611SArnd Bergmann 	clkdev_create(clk, "cpu", NULL);
267*b408b611SArnd Bergmann 	clk = clk_register_fixed_rate(NULL, "dsp", NULL, 0, dsp_clk);
268*b408b611SArnd Bergmann 	clkdev_create(clk, "dsp", NULL);
2697ca5dc14SFlorian Fainelli }
2707ca5dc14SFlorian Fainelli 
tnetd7200_set_clock(int base,struct tnetd7200_clock * clock,int prediv,int postdiv,int postdiv2,int mul,u32 frequency)2717ca5dc14SFlorian Fainelli static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
2727ca5dc14SFlorian Fainelli 	int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
2737ca5dc14SFlorian Fainelli {
2747ca5dc14SFlorian Fainelli 	printk(KERN_INFO
2757ca5dc14SFlorian Fainelli 		"Clocks: base = %d, frequency = %u, prediv = %d, "
2767ca5dc14SFlorian Fainelli 		"postdiv = %d, postdiv2 = %d, mul = %d\n",
2777ca5dc14SFlorian Fainelli 		base, frequency, prediv, postdiv, postdiv2, mul);
2787ca5dc14SFlorian Fainelli 
2797ca5dc14SFlorian Fainelli 	writel(0, &clock->ctrl);
2807ca5dc14SFlorian Fainelli 	writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
2817ca5dc14SFlorian Fainelli 	writel((mul - 1) & 0xF, &clock->mul);
2827ca5dc14SFlorian Fainelli 
2837ca5dc14SFlorian Fainelli 	while (readl(&clock->status) & 0x1)
2847ca5dc14SFlorian Fainelli 		; /* nop */
2857ca5dc14SFlorian Fainelli 
2867ca5dc14SFlorian Fainelli 	writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
2877ca5dc14SFlorian Fainelli 
2887ca5dc14SFlorian Fainelli 	writel(readl(&clock->cmden) | 1, &clock->cmden);
2897ca5dc14SFlorian Fainelli 	writel(readl(&clock->cmd) | 1, &clock->cmd);
2907ca5dc14SFlorian Fainelli 
2917ca5dc14SFlorian Fainelli 	while (readl(&clock->status) & 0x1)
2927ca5dc14SFlorian Fainelli 		; /* nop */
2937ca5dc14SFlorian Fainelli 
2947ca5dc14SFlorian Fainelli 	writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
2957ca5dc14SFlorian Fainelli 
2967ca5dc14SFlorian Fainelli 	writel(readl(&clock->cmden) | 1, &clock->cmden);
2977ca5dc14SFlorian Fainelli 	writel(readl(&clock->cmd) | 1, &clock->cmd);
2987ca5dc14SFlorian Fainelli 
2997ca5dc14SFlorian Fainelli 	while (readl(&clock->status) & 0x1)
3007ca5dc14SFlorian Fainelli 		; /* nop */
3017ca5dc14SFlorian Fainelli 
3027ca5dc14SFlorian Fainelli 	writel(readl(&clock->ctrl) | 1, &clock->ctrl);
3037ca5dc14SFlorian Fainelli }
3047ca5dc14SFlorian Fainelli 
tnetd7200_get_clock_base(int clock_id,u32 * bootcr)3057ca5dc14SFlorian Fainelli static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
3067ca5dc14SFlorian Fainelli {
3077ca5dc14SFlorian Fainelli 	if (*bootcr & BOOT_PLL_ASYNC_MODE)
3087ca5dc14SFlorian Fainelli 		/* Async */
3097ca5dc14SFlorian Fainelli 		switch (clock_id) {
3107ca5dc14SFlorian Fainelli 		case TNETD7200_CLOCK_ID_DSP:
3117ca5dc14SFlorian Fainelli 			return AR7_REF_CLOCK;
3127ca5dc14SFlorian Fainelli 		default:
3137ca5dc14SFlorian Fainelli 			return AR7_AFE_CLOCK;
3147ca5dc14SFlorian Fainelli 		}
3157ca5dc14SFlorian Fainelli 	else
3167ca5dc14SFlorian Fainelli 		/* Sync */
3177ca5dc14SFlorian Fainelli 		if (*bootcr & BOOT_PLL_2TO1_MODE)
3187ca5dc14SFlorian Fainelli 			/* 2:1 */
3197ca5dc14SFlorian Fainelli 			switch (clock_id) {
3207ca5dc14SFlorian Fainelli 			case TNETD7200_CLOCK_ID_DSP:
3217ca5dc14SFlorian Fainelli 				return AR7_REF_CLOCK;
3227ca5dc14SFlorian Fainelli 			default:
3237ca5dc14SFlorian Fainelli 				return AR7_AFE_CLOCK;
3247ca5dc14SFlorian Fainelli 			}
3257ca5dc14SFlorian Fainelli 		else
3267ca5dc14SFlorian Fainelli 			/* 1:1 */
3277ca5dc14SFlorian Fainelli 			return AR7_REF_CLOCK;
3287ca5dc14SFlorian Fainelli }
3297ca5dc14SFlorian Fainelli 
3307ca5dc14SFlorian Fainelli 
tnetd7200_init_clocks(void)3317ca5dc14SFlorian Fainelli static void __init tnetd7200_init_clocks(void)
3327ca5dc14SFlorian Fainelli {
3334bdc0d67SChristoph Hellwig 	u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4);
3347ca5dc14SFlorian Fainelli 	struct tnetd7200_clocks *clocks =
3354bdc0d67SChristoph Hellwig 					ioremap(AR7_REGS_CLOCKS,
3367ca5dc14SFlorian Fainelli 					sizeof(struct tnetd7200_clocks));
3377ca5dc14SFlorian Fainelli 	int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
3387ca5dc14SFlorian Fainelli 	int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
3397ca5dc14SFlorian Fainelli 	int usb_base, usb_mul, usb_prediv, usb_postdiv;
340*b408b611SArnd Bergmann 	struct clk *clk;
3417ca5dc14SFlorian Fainelli 
3427ca5dc14SFlorian Fainelli 	cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
3437ca5dc14SFlorian Fainelli 	dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
3447ca5dc14SFlorian Fainelli 
3457ca5dc14SFlorian Fainelli 	if (*bootcr & BOOT_PLL_ASYNC_MODE) {
3467ca5dc14SFlorian Fainelli 		printk(KERN_INFO "Clocks: Async mode\n");
3477ca5dc14SFlorian Fainelli 
3487ca5dc14SFlorian Fainelli 		printk(KERN_INFO "Clocks: Setting DSP clock\n");
3497ca5dc14SFlorian Fainelli 		calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
3507ca5dc14SFlorian Fainelli 			&dsp_prediv, &dsp_postdiv, &dsp_mul);
351780019ddSFlorian Fainelli 		bus_clk.rate =
3527ca5dc14SFlorian Fainelli 			((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
3537ca5dc14SFlorian Fainelli 		tnetd7200_set_clock(dsp_base, &clocks->dsp,
3547ca5dc14SFlorian Fainelli 			dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
355780019ddSFlorian Fainelli 			bus_clk.rate);
3567ca5dc14SFlorian Fainelli 
3577ca5dc14SFlorian Fainelli 		printk(KERN_INFO "Clocks: Setting CPU clock\n");
3587ca5dc14SFlorian Fainelli 		calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
3597ca5dc14SFlorian Fainelli 			&cpu_postdiv, &cpu_mul);
360780019ddSFlorian Fainelli 		cpu_clk.rate =
3617ca5dc14SFlorian Fainelli 			((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
3627ca5dc14SFlorian Fainelli 		tnetd7200_set_clock(cpu_base, &clocks->cpu,
3637ca5dc14SFlorian Fainelli 			cpu_prediv, cpu_postdiv, -1, cpu_mul,
364780019ddSFlorian Fainelli 			cpu_clk.rate);
3657ca5dc14SFlorian Fainelli 
3667ca5dc14SFlorian Fainelli 	} else
3677ca5dc14SFlorian Fainelli 		if (*bootcr & BOOT_PLL_2TO1_MODE) {
3687ca5dc14SFlorian Fainelli 			printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
3697ca5dc14SFlorian Fainelli 
3707ca5dc14SFlorian Fainelli 			printk(KERN_INFO "Clocks: Setting CPU clock\n");
3717ca5dc14SFlorian Fainelli 			calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
3727ca5dc14SFlorian Fainelli 				&cpu_postdiv, &cpu_mul);
373780019ddSFlorian Fainelli 			cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul)
3747ca5dc14SFlorian Fainelli 								/ cpu_postdiv;
3757ca5dc14SFlorian Fainelli 			tnetd7200_set_clock(cpu_base, &clocks->cpu,
3767ca5dc14SFlorian Fainelli 				cpu_prediv, cpu_postdiv, -1, cpu_mul,
377780019ddSFlorian Fainelli 				cpu_clk.rate);
3787ca5dc14SFlorian Fainelli 
3797ca5dc14SFlorian Fainelli 			printk(KERN_INFO "Clocks: Setting DSP clock\n");
3807ca5dc14SFlorian Fainelli 			calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
3817ca5dc14SFlorian Fainelli 				&dsp_postdiv, &dsp_mul);
382780019ddSFlorian Fainelli 			bus_clk.rate = cpu_clk.rate / 2;
3837ca5dc14SFlorian Fainelli 			tnetd7200_set_clock(dsp_base, &clocks->dsp,
3847ca5dc14SFlorian Fainelli 				dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
385780019ddSFlorian Fainelli 				dsp_mul * 2, bus_clk.rate);
3867ca5dc14SFlorian Fainelli 		} else {
3877ca5dc14SFlorian Fainelli 			printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
3887ca5dc14SFlorian Fainelli 
3897ca5dc14SFlorian Fainelli 			printk(KERN_INFO "Clocks: Setting DSP clock\n");
3907ca5dc14SFlorian Fainelli 			calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
3917ca5dc14SFlorian Fainelli 				&dsp_postdiv, &dsp_mul);
392780019ddSFlorian Fainelli 			bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul)
3937ca5dc14SFlorian Fainelli 								/ dsp_postdiv;
3947ca5dc14SFlorian Fainelli 			tnetd7200_set_clock(dsp_base, &clocks->dsp,
3957ca5dc14SFlorian Fainelli 				dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
396780019ddSFlorian Fainelli 				dsp_mul * 2, bus_clk.rate);
3977ca5dc14SFlorian Fainelli 
398780019ddSFlorian Fainelli 			cpu_clk.rate = bus_clk.rate;
3997ca5dc14SFlorian Fainelli 		}
4007ca5dc14SFlorian Fainelli 
4017ca5dc14SFlorian Fainelli 	printk(KERN_INFO "Clocks: Setting USB clock\n");
402780019ddSFlorian Fainelli 	usb_base = bus_clk.rate;
4037ca5dc14SFlorian Fainelli 	calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
4047ca5dc14SFlorian Fainelli 		&usb_postdiv, &usb_mul);
4057ca5dc14SFlorian Fainelli 	tnetd7200_set_clock(usb_base, &clocks->usb,
4067ca5dc14SFlorian Fainelli 		usb_prediv, usb_postdiv, -1, usb_mul,
4077ca5dc14SFlorian Fainelli 		TNETD7200_DEF_USB_CLK);
4087ca5dc14SFlorian Fainelli 
4097ca5dc14SFlorian Fainelli 	iounmap(clocks);
4107ca5dc14SFlorian Fainelli 	iounmap(bootcr);
411*b408b611SArnd Bergmann 
412*b408b611SArnd Bergmann 	clk = clk_register_fixed_rate(NULL, "cpu", NULL, 0, cpu_clk.rate);
413*b408b611SArnd Bergmann 	clkdev_create(clk, "cpu", NULL);
414*b408b611SArnd Bergmann 	clkdev_create(clk, "dsp", NULL);
4157ca5dc14SFlorian Fainelli }
4167ca5dc14SFlorian Fainelli 
ar7_init_clocks(void)4170bc67917SFlorian Fainelli void __init ar7_init_clocks(void)
4187ca5dc14SFlorian Fainelli {
419*b408b611SArnd Bergmann 	struct clk *clk;
420*b408b611SArnd Bergmann 
4217ca5dc14SFlorian Fainelli 	switch (ar7_chip_id()) {
4227ca5dc14SFlorian Fainelli 	case AR7_CHIP_7100:
4237ca5dc14SFlorian Fainelli 	case AR7_CHIP_7200:
4247ca5dc14SFlorian Fainelli 		tnetd7200_init_clocks();
4257ca5dc14SFlorian Fainelli 		break;
4267ca5dc14SFlorian Fainelli 	case AR7_CHIP_7300:
4277ca5dc14SFlorian Fainelli 		tnetd7300_init_clocks();
4287ca5dc14SFlorian Fainelli 		break;
4297ca5dc14SFlorian Fainelli 	default:
4307ca5dc14SFlorian Fainelli 		break;
4317ca5dc14SFlorian Fainelli 	}
432*b408b611SArnd Bergmann 	clk = clk_register_fixed_rate(NULL, "bus", NULL, 0, bus_clk.rate);
433*b408b611SArnd Bergmann 	clkdev_create(clk, "bus", NULL);
434780019ddSFlorian Fainelli 	/* adjust vbus clock rate */
435*b408b611SArnd Bergmann 	clk = clk_register_fixed_factor(NULL, "vbus", "bus", 0, 1, 2);
436*b408b611SArnd Bergmann 	clkdev_create(clk, "vbus", NULL);
437*b408b611SArnd Bergmann 	clkdev_create(clk, "cpmac", "cpmac.1");
438*b408b611SArnd Bergmann 	clkdev_create(clk, "cpmac", "cpmac.1");
4397ca5dc14SFlorian Fainelli }
440