18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/export.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/gcd.h>
148c2ecf20Sopenharmony_ci#include <linux/io.h>
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/clk.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/addrspace.h>
198c2ecf20Sopenharmony_ci#include <asm/mach-ar7/ar7.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define BOOT_PLL_SOURCE_MASK	0x3
228c2ecf20Sopenharmony_ci#define CPU_PLL_SOURCE_SHIFT	16
238c2ecf20Sopenharmony_ci#define BUS_PLL_SOURCE_SHIFT	14
248c2ecf20Sopenharmony_ci#define USB_PLL_SOURCE_SHIFT	18
258c2ecf20Sopenharmony_ci#define DSP_PLL_SOURCE_SHIFT	22
268c2ecf20Sopenharmony_ci#define BOOT_PLL_SOURCE_AFE	0
278c2ecf20Sopenharmony_ci#define BOOT_PLL_SOURCE_BUS	0
288c2ecf20Sopenharmony_ci#define BOOT_PLL_SOURCE_REF	1
298c2ecf20Sopenharmony_ci#define BOOT_PLL_SOURCE_XTAL	2
308c2ecf20Sopenharmony_ci#define BOOT_PLL_SOURCE_CPU	3
318c2ecf20Sopenharmony_ci#define BOOT_PLL_BYPASS		0x00000020
328c2ecf20Sopenharmony_ci#define BOOT_PLL_ASYNC_MODE	0x02000000
338c2ecf20Sopenharmony_ci#define BOOT_PLL_2TO1_MODE	0x00008000
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define TNETD7200_CLOCK_ID_CPU	0
368c2ecf20Sopenharmony_ci#define TNETD7200_CLOCK_ID_DSP	1
378c2ecf20Sopenharmony_ci#define TNETD7200_CLOCK_ID_USB	2
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define TNETD7200_DEF_CPU_CLK	211000000
408c2ecf20Sopenharmony_ci#define TNETD7200_DEF_DSP_CLK	125000000
418c2ecf20Sopenharmony_ci#define TNETD7200_DEF_USB_CLK	48000000
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct tnetd7300_clock {
448c2ecf20Sopenharmony_ci	u32 ctrl;
458c2ecf20Sopenharmony_ci#define PREDIV_MASK	0x001f0000
468c2ecf20Sopenharmony_ci#define PREDIV_SHIFT	16
478c2ecf20Sopenharmony_ci#define POSTDIV_MASK	0x0000001f
488c2ecf20Sopenharmony_ci	u32 unused1[3];
498c2ecf20Sopenharmony_ci	u32 pll;
508c2ecf20Sopenharmony_ci#define MUL_MASK	0x0000f000
518c2ecf20Sopenharmony_ci#define MUL_SHIFT	12
528c2ecf20Sopenharmony_ci#define PLL_MODE_MASK	0x00000001
538c2ecf20Sopenharmony_ci#define PLL_NDIV	0x00000800
548c2ecf20Sopenharmony_ci#define PLL_DIV		0x00000002
558c2ecf20Sopenharmony_ci#define PLL_STATUS	0x00000001
568c2ecf20Sopenharmony_ci	u32 unused2[3];
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct tnetd7300_clocks {
608c2ecf20Sopenharmony_ci	struct tnetd7300_clock bus;
618c2ecf20Sopenharmony_ci	struct tnetd7300_clock cpu;
628c2ecf20Sopenharmony_ci	struct tnetd7300_clock usb;
638c2ecf20Sopenharmony_ci	struct tnetd7300_clock dsp;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct tnetd7200_clock {
678c2ecf20Sopenharmony_ci	u32 ctrl;
688c2ecf20Sopenharmony_ci	u32 unused1[3];
698c2ecf20Sopenharmony_ci#define DIVISOR_ENABLE_MASK 0x00008000
708c2ecf20Sopenharmony_ci	u32 mul;
718c2ecf20Sopenharmony_ci	u32 prediv;
728c2ecf20Sopenharmony_ci	u32 postdiv;
738c2ecf20Sopenharmony_ci	u32 postdiv2;
748c2ecf20Sopenharmony_ci	u32 unused2[6];
758c2ecf20Sopenharmony_ci	u32 cmd;
768c2ecf20Sopenharmony_ci	u32 status;
778c2ecf20Sopenharmony_ci	u32 cmden;
788c2ecf20Sopenharmony_ci	u32 padding[15];
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct tnetd7200_clocks {
828c2ecf20Sopenharmony_ci	struct tnetd7200_clock cpu;
838c2ecf20Sopenharmony_ci	struct tnetd7200_clock dsp;
848c2ecf20Sopenharmony_ci	struct tnetd7200_clock usb;
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic struct clk bus_clk = {
888c2ecf20Sopenharmony_ci	.rate	= 125000000,
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic struct clk cpu_clk = {
928c2ecf20Sopenharmony_ci	.rate	= 150000000,
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic struct clk dsp_clk;
968c2ecf20Sopenharmony_cistatic struct clk vbus_clk;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic void approximate(int base, int target, int *prediv,
998c2ecf20Sopenharmony_ci			int *postdiv, int *mul)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	int i, j, k, freq, res = target;
1028c2ecf20Sopenharmony_ci	for (i = 1; i <= 16; i++)
1038c2ecf20Sopenharmony_ci		for (j = 1; j <= 32; j++)
1048c2ecf20Sopenharmony_ci			for (k = 1; k <= 32; k++) {
1058c2ecf20Sopenharmony_ci				freq = abs(base / j * i / k - target);
1068c2ecf20Sopenharmony_ci				if (freq < res) {
1078c2ecf20Sopenharmony_ci					res = freq;
1088c2ecf20Sopenharmony_ci					*mul = i;
1098c2ecf20Sopenharmony_ci					*prediv = j;
1108c2ecf20Sopenharmony_ci					*postdiv = k;
1118c2ecf20Sopenharmony_ci				}
1128c2ecf20Sopenharmony_ci			}
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic void calculate(int base, int target, int *prediv, int *postdiv,
1168c2ecf20Sopenharmony_ci	int *mul)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	int tmp_gcd, tmp_base, tmp_freq;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	for (*prediv = 1; *prediv <= 32; (*prediv)++) {
1218c2ecf20Sopenharmony_ci		tmp_base = base / *prediv;
1228c2ecf20Sopenharmony_ci		tmp_gcd = gcd(target, tmp_base);
1238c2ecf20Sopenharmony_ci		*mul = target / tmp_gcd;
1248c2ecf20Sopenharmony_ci		*postdiv = tmp_base / tmp_gcd;
1258c2ecf20Sopenharmony_ci		if ((*mul < 1) || (*mul >= 16))
1268c2ecf20Sopenharmony_ci			continue;
1278c2ecf20Sopenharmony_ci		if ((*postdiv > 0) & (*postdiv <= 32))
1288c2ecf20Sopenharmony_ci			break;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (base / *prediv * *mul / *postdiv != target) {
1328c2ecf20Sopenharmony_ci		approximate(base, target, prediv, postdiv, mul);
1338c2ecf20Sopenharmony_ci		tmp_freq = base / *prediv * *mul / *postdiv;
1348c2ecf20Sopenharmony_ci		printk(KERN_WARNING
1358c2ecf20Sopenharmony_ci		       "Adjusted requested frequency %d to %d\n",
1368c2ecf20Sopenharmony_ci		       target, tmp_freq);
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
1408c2ecf20Sopenharmony_ci	       *prediv, *postdiv, *mul);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int tnetd7300_dsp_clock(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	u32 didr1, didr2;
1468c2ecf20Sopenharmony_ci	u8 rev = ar7_chip_rev();
1478c2ecf20Sopenharmony_ci	didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
1488c2ecf20Sopenharmony_ci	didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
1498c2ecf20Sopenharmony_ci	if (didr2 & (1 << 23))
1508c2ecf20Sopenharmony_ci		return 0;
1518c2ecf20Sopenharmony_ci	if ((rev >= 0x23) && (rev != 0x57))
1528c2ecf20Sopenharmony_ci		return 250000000;
1538c2ecf20Sopenharmony_ci	if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
1548c2ecf20Sopenharmony_ci	    > 4208000)
1558c2ecf20Sopenharmony_ci		return 250000000;
1568c2ecf20Sopenharmony_ci	return 0;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
1608c2ecf20Sopenharmony_ci	u32 *bootcr, u32 bus_clock)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	int product;
1638c2ecf20Sopenharmony_ci	int base_clock = AR7_REF_CLOCK;
1648c2ecf20Sopenharmony_ci	u32 ctrl = readl(&clock->ctrl);
1658c2ecf20Sopenharmony_ci	u32 pll = readl(&clock->pll);
1668c2ecf20Sopenharmony_ci	int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
1678c2ecf20Sopenharmony_ci	int postdiv = (ctrl & POSTDIV_MASK) + 1;
1688c2ecf20Sopenharmony_ci	int divisor = prediv * postdiv;
1698c2ecf20Sopenharmony_ci	int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
1728c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_BUS:
1738c2ecf20Sopenharmony_ci		base_clock = bus_clock;
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_REF:
1768c2ecf20Sopenharmony_ci		base_clock = AR7_REF_CLOCK;
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_XTAL:
1798c2ecf20Sopenharmony_ci		base_clock = AR7_XTAL_CLOCK;
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_CPU:
1828c2ecf20Sopenharmony_ci		base_clock = cpu_clk.rate;
1838c2ecf20Sopenharmony_ci		break;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (*bootcr & BOOT_PLL_BYPASS)
1878c2ecf20Sopenharmony_ci		return base_clock / divisor;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if ((pll & PLL_MODE_MASK) == 0)
1908c2ecf20Sopenharmony_ci		return (base_clock >> (mul / 16 + 1)) / divisor;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
1938c2ecf20Sopenharmony_ci		product = (mul & 1) ?
1948c2ecf20Sopenharmony_ci			(base_clock * mul) >> 1 :
1958c2ecf20Sopenharmony_ci			(base_clock * (mul - 1)) >> 2;
1968c2ecf20Sopenharmony_ci		return product / divisor;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (mul == 16)
2008c2ecf20Sopenharmony_ci		return base_clock / divisor;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return base_clock * mul / divisor;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
2068c2ecf20Sopenharmony_ci	u32 *bootcr, u32 frequency)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	int prediv, postdiv, mul;
2098c2ecf20Sopenharmony_ci	int base_clock = bus_clk.rate;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
2128c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_BUS:
2138c2ecf20Sopenharmony_ci		base_clock = bus_clk.rate;
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_REF:
2168c2ecf20Sopenharmony_ci		base_clock = AR7_REF_CLOCK;
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_XTAL:
2198c2ecf20Sopenharmony_ci		base_clock = AR7_XTAL_CLOCK;
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	case BOOT_PLL_SOURCE_CPU:
2228c2ecf20Sopenharmony_ci		base_clock = cpu_clk.rate;
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	calculate(base_clock, frequency, &prediv, &postdiv, &mul);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
2298c2ecf20Sopenharmony_ci	mdelay(1);
2308c2ecf20Sopenharmony_ci	writel(4, &clock->pll);
2318c2ecf20Sopenharmony_ci	while (readl(&clock->pll) & PLL_STATUS)
2328c2ecf20Sopenharmony_ci		;
2338c2ecf20Sopenharmony_ci	writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
2348c2ecf20Sopenharmony_ci	mdelay(75);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic void __init tnetd7300_init_clocks(void)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4);
2408c2ecf20Sopenharmony_ci	struct tnetd7300_clocks *clocks =
2418c2ecf20Sopenharmony_ci					ioremap(UR8_REGS_CLOCKS,
2428c2ecf20Sopenharmony_ci					sizeof(struct tnetd7300_clocks));
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
2458c2ecf20Sopenharmony_ci		&clocks->bus, bootcr, AR7_AFE_CLOCK);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (*bootcr & BOOT_PLL_ASYNC_MODE)
2488c2ecf20Sopenharmony_ci		cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
2498c2ecf20Sopenharmony_ci			&clocks->cpu, bootcr, AR7_AFE_CLOCK);
2508c2ecf20Sopenharmony_ci	else
2518c2ecf20Sopenharmony_ci		cpu_clk.rate = bus_clk.rate;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (dsp_clk.rate == 250000000)
2548c2ecf20Sopenharmony_ci		tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
2558c2ecf20Sopenharmony_ci			bootcr, dsp_clk.rate);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	iounmap(clocks);
2588c2ecf20Sopenharmony_ci	iounmap(bootcr);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
2628c2ecf20Sopenharmony_ci	int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	printk(KERN_INFO
2658c2ecf20Sopenharmony_ci		"Clocks: base = %d, frequency = %u, prediv = %d, "
2668c2ecf20Sopenharmony_ci		"postdiv = %d, postdiv2 = %d, mul = %d\n",
2678c2ecf20Sopenharmony_ci		base, frequency, prediv, postdiv, postdiv2, mul);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	writel(0, &clock->ctrl);
2708c2ecf20Sopenharmony_ci	writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
2718c2ecf20Sopenharmony_ci	writel((mul - 1) & 0xF, &clock->mul);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	while (readl(&clock->status) & 0x1)
2748c2ecf20Sopenharmony_ci		; /* nop */
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	writel(readl(&clock->cmden) | 1, &clock->cmden);
2798c2ecf20Sopenharmony_ci	writel(readl(&clock->cmd) | 1, &clock->cmd);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	while (readl(&clock->status) & 0x1)
2828c2ecf20Sopenharmony_ci		; /* nop */
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	writel(readl(&clock->cmden) | 1, &clock->cmden);
2878c2ecf20Sopenharmony_ci	writel(readl(&clock->cmd) | 1, &clock->cmd);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	while (readl(&clock->status) & 0x1)
2908c2ecf20Sopenharmony_ci		; /* nop */
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	writel(readl(&clock->ctrl) | 1, &clock->ctrl);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	if (*bootcr & BOOT_PLL_ASYNC_MODE)
2988c2ecf20Sopenharmony_ci		/* Async */
2998c2ecf20Sopenharmony_ci		switch (clock_id) {
3008c2ecf20Sopenharmony_ci		case TNETD7200_CLOCK_ID_DSP:
3018c2ecf20Sopenharmony_ci			return AR7_REF_CLOCK;
3028c2ecf20Sopenharmony_ci		default:
3038c2ecf20Sopenharmony_ci			return AR7_AFE_CLOCK;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci	else
3068c2ecf20Sopenharmony_ci		/* Sync */
3078c2ecf20Sopenharmony_ci		if (*bootcr & BOOT_PLL_2TO1_MODE)
3088c2ecf20Sopenharmony_ci			/* 2:1 */
3098c2ecf20Sopenharmony_ci			switch (clock_id) {
3108c2ecf20Sopenharmony_ci			case TNETD7200_CLOCK_ID_DSP:
3118c2ecf20Sopenharmony_ci				return AR7_REF_CLOCK;
3128c2ecf20Sopenharmony_ci			default:
3138c2ecf20Sopenharmony_ci				return AR7_AFE_CLOCK;
3148c2ecf20Sopenharmony_ci			}
3158c2ecf20Sopenharmony_ci		else
3168c2ecf20Sopenharmony_ci			/* 1:1 */
3178c2ecf20Sopenharmony_ci			return AR7_REF_CLOCK;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void __init tnetd7200_init_clocks(void)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4);
3248c2ecf20Sopenharmony_ci	struct tnetd7200_clocks *clocks =
3258c2ecf20Sopenharmony_ci					ioremap(AR7_REGS_CLOCKS,
3268c2ecf20Sopenharmony_ci					sizeof(struct tnetd7200_clocks));
3278c2ecf20Sopenharmony_ci	int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
3288c2ecf20Sopenharmony_ci	int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
3298c2ecf20Sopenharmony_ci	int usb_base, usb_mul, usb_prediv, usb_postdiv;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
3328c2ecf20Sopenharmony_ci	dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (*bootcr & BOOT_PLL_ASYNC_MODE) {
3358c2ecf20Sopenharmony_ci		printk(KERN_INFO "Clocks: Async mode\n");
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		printk(KERN_INFO "Clocks: Setting DSP clock\n");
3388c2ecf20Sopenharmony_ci		calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
3398c2ecf20Sopenharmony_ci			&dsp_prediv, &dsp_postdiv, &dsp_mul);
3408c2ecf20Sopenharmony_ci		bus_clk.rate =
3418c2ecf20Sopenharmony_ci			((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
3428c2ecf20Sopenharmony_ci		tnetd7200_set_clock(dsp_base, &clocks->dsp,
3438c2ecf20Sopenharmony_ci			dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
3448c2ecf20Sopenharmony_ci			bus_clk.rate);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		printk(KERN_INFO "Clocks: Setting CPU clock\n");
3478c2ecf20Sopenharmony_ci		calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
3488c2ecf20Sopenharmony_ci			&cpu_postdiv, &cpu_mul);
3498c2ecf20Sopenharmony_ci		cpu_clk.rate =
3508c2ecf20Sopenharmony_ci			((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
3518c2ecf20Sopenharmony_ci		tnetd7200_set_clock(cpu_base, &clocks->cpu,
3528c2ecf20Sopenharmony_ci			cpu_prediv, cpu_postdiv, -1, cpu_mul,
3538c2ecf20Sopenharmony_ci			cpu_clk.rate);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	} else
3568c2ecf20Sopenharmony_ci		if (*bootcr & BOOT_PLL_2TO1_MODE) {
3578c2ecf20Sopenharmony_ci			printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci			printk(KERN_INFO "Clocks: Setting CPU clock\n");
3608c2ecf20Sopenharmony_ci			calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
3618c2ecf20Sopenharmony_ci				&cpu_postdiv, &cpu_mul);
3628c2ecf20Sopenharmony_ci			cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul)
3638c2ecf20Sopenharmony_ci								/ cpu_postdiv;
3648c2ecf20Sopenharmony_ci			tnetd7200_set_clock(cpu_base, &clocks->cpu,
3658c2ecf20Sopenharmony_ci				cpu_prediv, cpu_postdiv, -1, cpu_mul,
3668c2ecf20Sopenharmony_ci				cpu_clk.rate);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci			printk(KERN_INFO "Clocks: Setting DSP clock\n");
3698c2ecf20Sopenharmony_ci			calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
3708c2ecf20Sopenharmony_ci				&dsp_postdiv, &dsp_mul);
3718c2ecf20Sopenharmony_ci			bus_clk.rate = cpu_clk.rate / 2;
3728c2ecf20Sopenharmony_ci			tnetd7200_set_clock(dsp_base, &clocks->dsp,
3738c2ecf20Sopenharmony_ci				dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
3748c2ecf20Sopenharmony_ci				dsp_mul * 2, bus_clk.rate);
3758c2ecf20Sopenharmony_ci		} else {
3768c2ecf20Sopenharmony_ci			printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci			printk(KERN_INFO "Clocks: Setting DSP clock\n");
3798c2ecf20Sopenharmony_ci			calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
3808c2ecf20Sopenharmony_ci				&dsp_postdiv, &dsp_mul);
3818c2ecf20Sopenharmony_ci			bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul)
3828c2ecf20Sopenharmony_ci								/ dsp_postdiv;
3838c2ecf20Sopenharmony_ci			tnetd7200_set_clock(dsp_base, &clocks->dsp,
3848c2ecf20Sopenharmony_ci				dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
3858c2ecf20Sopenharmony_ci				dsp_mul * 2, bus_clk.rate);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci			cpu_clk.rate = bus_clk.rate;
3888c2ecf20Sopenharmony_ci		}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	printk(KERN_INFO "Clocks: Setting USB clock\n");
3918c2ecf20Sopenharmony_ci	usb_base = bus_clk.rate;
3928c2ecf20Sopenharmony_ci	calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
3938c2ecf20Sopenharmony_ci		&usb_postdiv, &usb_mul);
3948c2ecf20Sopenharmony_ci	tnetd7200_set_clock(usb_base, &clocks->usb,
3958c2ecf20Sopenharmony_ci		usb_prediv, usb_postdiv, -1, usb_mul,
3968c2ecf20Sopenharmony_ci		TNETD7200_DEF_USB_CLK);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	dsp_clk.rate = cpu_clk.rate;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	iounmap(clocks);
4018c2ecf20Sopenharmony_ci	iounmap(bootcr);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci/*
4058c2ecf20Sopenharmony_ci * Linux clock API
4068c2ecf20Sopenharmony_ci */
4078c2ecf20Sopenharmony_ciint clk_enable(struct clk *clk)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	return 0;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_enable);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_civoid clk_disable(struct clk *clk)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_disable);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ciunsigned long clk_get_rate(struct clk *clk)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	if (!clk)
4218c2ecf20Sopenharmony_ci		return 0;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return clk->rate;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get_rate);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistruct clk *clk_get(struct device *dev, const char *id)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	if (!strcmp(id, "bus"))
4308c2ecf20Sopenharmony_ci		return &bus_clk;
4318c2ecf20Sopenharmony_ci	/* cpmac and vbus share the same rate */
4328c2ecf20Sopenharmony_ci	if (!strcmp(id, "cpmac"))
4338c2ecf20Sopenharmony_ci		return &vbus_clk;
4348c2ecf20Sopenharmony_ci	if (!strcmp(id, "cpu"))
4358c2ecf20Sopenharmony_ci		return &cpu_clk;
4368c2ecf20Sopenharmony_ci	if (!strcmp(id, "dsp"))
4378c2ecf20Sopenharmony_ci		return &dsp_clk;
4388c2ecf20Sopenharmony_ci	if (!strcmp(id, "vbus"))
4398c2ecf20Sopenharmony_ci		return &vbus_clk;
4408c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOENT);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_civoid clk_put(struct clk *clk)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_put);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_civoid __init ar7_init_clocks(void)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	switch (ar7_chip_id()) {
4528c2ecf20Sopenharmony_ci	case AR7_CHIP_7100:
4538c2ecf20Sopenharmony_ci	case AR7_CHIP_7200:
4548c2ecf20Sopenharmony_ci		tnetd7200_init_clocks();
4558c2ecf20Sopenharmony_ci		break;
4568c2ecf20Sopenharmony_ci	case AR7_CHIP_7300:
4578c2ecf20Sopenharmony_ci		dsp_clk.rate = tnetd7300_dsp_clock();
4588c2ecf20Sopenharmony_ci		tnetd7300_init_clocks();
4598c2ecf20Sopenharmony_ci		break;
4608c2ecf20Sopenharmony_ci	default:
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci	/* adjust vbus clock rate */
4648c2ecf20Sopenharmony_ci	vbus_clk.rate = bus_clk.rate / 2;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci/* dummy functions, should not be called */
4688c2ecf20Sopenharmony_cilong clk_round_rate(struct clk *clk, unsigned long rate)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	WARN_ON(clk);
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_round_rate);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciint clk_set_rate(struct clk *clk, unsigned long rate)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	WARN_ON(clk);
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_set_rate);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciint clk_set_parent(struct clk *clk, struct clk *parent)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	WARN_ON(clk);
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_set_parent);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistruct clk *clk_get_parent(struct clk *clk)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	WARN_ON(clk);
4928c2ecf20Sopenharmony_ci	return NULL;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get_parent);
495