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