162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
462306a36Sopenharmony_ci * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
562306a36Sopenharmony_ci * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/gcd.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/clkdev.h>
1762306a36Sopenharmony_ci#include <linux/clk.h>
1862306a36Sopenharmony_ci#include <linux/clk-provider.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <asm/addrspace.h>
2162306a36Sopenharmony_ci#include <asm/mach-ar7/ar7.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define BOOT_PLL_SOURCE_MASK	0x3
2462306a36Sopenharmony_ci#define CPU_PLL_SOURCE_SHIFT	16
2562306a36Sopenharmony_ci#define BUS_PLL_SOURCE_SHIFT	14
2662306a36Sopenharmony_ci#define USB_PLL_SOURCE_SHIFT	18
2762306a36Sopenharmony_ci#define DSP_PLL_SOURCE_SHIFT	22
2862306a36Sopenharmony_ci#define BOOT_PLL_SOURCE_AFE	0
2962306a36Sopenharmony_ci#define BOOT_PLL_SOURCE_BUS	0
3062306a36Sopenharmony_ci#define BOOT_PLL_SOURCE_REF	1
3162306a36Sopenharmony_ci#define BOOT_PLL_SOURCE_XTAL	2
3262306a36Sopenharmony_ci#define BOOT_PLL_SOURCE_CPU	3
3362306a36Sopenharmony_ci#define BOOT_PLL_BYPASS		0x00000020
3462306a36Sopenharmony_ci#define BOOT_PLL_ASYNC_MODE	0x02000000
3562306a36Sopenharmony_ci#define BOOT_PLL_2TO1_MODE	0x00008000
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define TNETD7200_CLOCK_ID_CPU	0
3862306a36Sopenharmony_ci#define TNETD7200_CLOCK_ID_DSP	1
3962306a36Sopenharmony_ci#define TNETD7200_CLOCK_ID_USB	2
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define TNETD7200_DEF_CPU_CLK	211000000
4262306a36Sopenharmony_ci#define TNETD7200_DEF_DSP_CLK	125000000
4362306a36Sopenharmony_ci#define TNETD7200_DEF_USB_CLK	48000000
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct tnetd7300_clock {
4662306a36Sopenharmony_ci	u32 ctrl;
4762306a36Sopenharmony_ci#define PREDIV_MASK	0x001f0000
4862306a36Sopenharmony_ci#define PREDIV_SHIFT	16
4962306a36Sopenharmony_ci#define POSTDIV_MASK	0x0000001f
5062306a36Sopenharmony_ci	u32 unused1[3];
5162306a36Sopenharmony_ci	u32 pll;
5262306a36Sopenharmony_ci#define MUL_MASK	0x0000f000
5362306a36Sopenharmony_ci#define MUL_SHIFT	12
5462306a36Sopenharmony_ci#define PLL_MODE_MASK	0x00000001
5562306a36Sopenharmony_ci#define PLL_NDIV	0x00000800
5662306a36Sopenharmony_ci#define PLL_DIV		0x00000002
5762306a36Sopenharmony_ci#define PLL_STATUS	0x00000001
5862306a36Sopenharmony_ci	u32 unused2[3];
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct tnetd7300_clocks {
6262306a36Sopenharmony_ci	struct tnetd7300_clock bus;
6362306a36Sopenharmony_ci	struct tnetd7300_clock cpu;
6462306a36Sopenharmony_ci	struct tnetd7300_clock usb;
6562306a36Sopenharmony_ci	struct tnetd7300_clock dsp;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistruct tnetd7200_clock {
6962306a36Sopenharmony_ci	u32 ctrl;
7062306a36Sopenharmony_ci	u32 unused1[3];
7162306a36Sopenharmony_ci#define DIVISOR_ENABLE_MASK 0x00008000
7262306a36Sopenharmony_ci	u32 mul;
7362306a36Sopenharmony_ci	u32 prediv;
7462306a36Sopenharmony_ci	u32 postdiv;
7562306a36Sopenharmony_ci	u32 postdiv2;
7662306a36Sopenharmony_ci	u32 unused2[6];
7762306a36Sopenharmony_ci	u32 cmd;
7862306a36Sopenharmony_ci	u32 status;
7962306a36Sopenharmony_ci	u32 cmden;
8062306a36Sopenharmony_ci	u32 padding[15];
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct tnetd7200_clocks {
8462306a36Sopenharmony_ci	struct tnetd7200_clock cpu;
8562306a36Sopenharmony_ci	struct tnetd7200_clock dsp;
8662306a36Sopenharmony_ci	struct tnetd7200_clock usb;
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistruct clk_rate {
9062306a36Sopenharmony_ci	u32 rate;
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_cistatic struct clk_rate bus_clk = {
9362306a36Sopenharmony_ci	.rate	= 125000000,
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic struct clk_rate cpu_clk = {
9762306a36Sopenharmony_ci	.rate	= 150000000,
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void approximate(int base, int target, int *prediv,
10162306a36Sopenharmony_ci			int *postdiv, int *mul)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	int i, j, k, freq, res = target;
10462306a36Sopenharmony_ci	for (i = 1; i <= 16; i++)
10562306a36Sopenharmony_ci		for (j = 1; j <= 32; j++)
10662306a36Sopenharmony_ci			for (k = 1; k <= 32; k++) {
10762306a36Sopenharmony_ci				freq = abs(base / j * i / k - target);
10862306a36Sopenharmony_ci				if (freq < res) {
10962306a36Sopenharmony_ci					res = freq;
11062306a36Sopenharmony_ci					*mul = i;
11162306a36Sopenharmony_ci					*prediv = j;
11262306a36Sopenharmony_ci					*postdiv = k;
11362306a36Sopenharmony_ci				}
11462306a36Sopenharmony_ci			}
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic void calculate(int base, int target, int *prediv, int *postdiv,
11862306a36Sopenharmony_ci	int *mul)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	int tmp_gcd, tmp_base, tmp_freq;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	for (*prediv = 1; *prediv <= 32; (*prediv)++) {
12362306a36Sopenharmony_ci		tmp_base = base / *prediv;
12462306a36Sopenharmony_ci		tmp_gcd = gcd(target, tmp_base);
12562306a36Sopenharmony_ci		*mul = target / tmp_gcd;
12662306a36Sopenharmony_ci		*postdiv = tmp_base / tmp_gcd;
12762306a36Sopenharmony_ci		if ((*mul < 1) || (*mul >= 16))
12862306a36Sopenharmony_ci			continue;
12962306a36Sopenharmony_ci		if ((*postdiv > 0) & (*postdiv <= 32))
13062306a36Sopenharmony_ci			break;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (base / *prediv * *mul / *postdiv != target) {
13462306a36Sopenharmony_ci		approximate(base, target, prediv, postdiv, mul);
13562306a36Sopenharmony_ci		tmp_freq = base / *prediv * *mul / *postdiv;
13662306a36Sopenharmony_ci		printk(KERN_WARNING
13762306a36Sopenharmony_ci		       "Adjusted requested frequency %d to %d\n",
13862306a36Sopenharmony_ci		       target, tmp_freq);
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
14262306a36Sopenharmony_ci	       *prediv, *postdiv, *mul);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int tnetd7300_dsp_clock(void)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	u32 didr1, didr2;
14862306a36Sopenharmony_ci	u8 rev = ar7_chip_rev();
14962306a36Sopenharmony_ci	didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
15062306a36Sopenharmony_ci	didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
15162306a36Sopenharmony_ci	if (didr2 & (1 << 23))
15262306a36Sopenharmony_ci		return 0;
15362306a36Sopenharmony_ci	if ((rev >= 0x23) && (rev != 0x57))
15462306a36Sopenharmony_ci		return 250000000;
15562306a36Sopenharmony_ci	if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
15662306a36Sopenharmony_ci	    > 4208000)
15762306a36Sopenharmony_ci		return 250000000;
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
16262306a36Sopenharmony_ci	u32 *bootcr, u32 bus_clock)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int product;
16562306a36Sopenharmony_ci	int base_clock = AR7_REF_CLOCK;
16662306a36Sopenharmony_ci	u32 ctrl = readl(&clock->ctrl);
16762306a36Sopenharmony_ci	u32 pll = readl(&clock->pll);
16862306a36Sopenharmony_ci	int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
16962306a36Sopenharmony_ci	int postdiv = (ctrl & POSTDIV_MASK) + 1;
17062306a36Sopenharmony_ci	int divisor = prediv * postdiv;
17162306a36Sopenharmony_ci	int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
17462306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_BUS:
17562306a36Sopenharmony_ci		base_clock = bus_clock;
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_REF:
17862306a36Sopenharmony_ci		base_clock = AR7_REF_CLOCK;
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_XTAL:
18162306a36Sopenharmony_ci		base_clock = AR7_XTAL_CLOCK;
18262306a36Sopenharmony_ci		break;
18362306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_CPU:
18462306a36Sopenharmony_ci		base_clock = cpu_clk.rate;
18562306a36Sopenharmony_ci		break;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (*bootcr & BOOT_PLL_BYPASS)
18962306a36Sopenharmony_ci		return base_clock / divisor;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if ((pll & PLL_MODE_MASK) == 0)
19262306a36Sopenharmony_ci		return (base_clock >> (mul / 16 + 1)) / divisor;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
19562306a36Sopenharmony_ci		product = (mul & 1) ?
19662306a36Sopenharmony_ci			(base_clock * mul) >> 1 :
19762306a36Sopenharmony_ci			(base_clock * (mul - 1)) >> 2;
19862306a36Sopenharmony_ci		return product / divisor;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (mul == 16)
20262306a36Sopenharmony_ci		return base_clock / divisor;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return base_clock * mul / divisor;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
20862306a36Sopenharmony_ci	u32 *bootcr, u32 frequency)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	int prediv, postdiv, mul;
21162306a36Sopenharmony_ci	int base_clock = bus_clk.rate;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
21462306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_BUS:
21562306a36Sopenharmony_ci		base_clock = bus_clk.rate;
21662306a36Sopenharmony_ci		break;
21762306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_REF:
21862306a36Sopenharmony_ci		base_clock = AR7_REF_CLOCK;
21962306a36Sopenharmony_ci		break;
22062306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_XTAL:
22162306a36Sopenharmony_ci		base_clock = AR7_XTAL_CLOCK;
22262306a36Sopenharmony_ci		break;
22362306a36Sopenharmony_ci	case BOOT_PLL_SOURCE_CPU:
22462306a36Sopenharmony_ci		base_clock = cpu_clk.rate;
22562306a36Sopenharmony_ci		break;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	calculate(base_clock, frequency, &prediv, &postdiv, &mul);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
23162306a36Sopenharmony_ci	mdelay(1);
23262306a36Sopenharmony_ci	writel(4, &clock->pll);
23362306a36Sopenharmony_ci	while (readl(&clock->pll) & PLL_STATUS)
23462306a36Sopenharmony_ci		;
23562306a36Sopenharmony_ci	writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
23662306a36Sopenharmony_ci	mdelay(75);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void __init tnetd7300_init_clocks(void)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4);
24262306a36Sopenharmony_ci	struct tnetd7300_clocks *clocks =
24362306a36Sopenharmony_ci					ioremap(UR8_REGS_CLOCKS,
24462306a36Sopenharmony_ci					sizeof(struct tnetd7300_clocks));
24562306a36Sopenharmony_ci	u32 dsp_clk;
24662306a36Sopenharmony_ci	struct clk *clk;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
24962306a36Sopenharmony_ci		&clocks->bus, bootcr, AR7_AFE_CLOCK);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (*bootcr & BOOT_PLL_ASYNC_MODE)
25262306a36Sopenharmony_ci		cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
25362306a36Sopenharmony_ci			&clocks->cpu, bootcr, AR7_AFE_CLOCK);
25462306a36Sopenharmony_ci	else
25562306a36Sopenharmony_ci		cpu_clk.rate = bus_clk.rate;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	dsp_clk = tnetd7300_dsp_clock();
25862306a36Sopenharmony_ci	if (dsp_clk == 250000000)
25962306a36Sopenharmony_ci		tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
26062306a36Sopenharmony_ci			bootcr, dsp_clk);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	iounmap(clocks);
26362306a36Sopenharmony_ci	iounmap(bootcr);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	clk = clk_register_fixed_rate(NULL, "cpu", NULL, 0, cpu_clk.rate);
26662306a36Sopenharmony_ci	clkdev_create(clk, "cpu", NULL);
26762306a36Sopenharmony_ci	clk = clk_register_fixed_rate(NULL, "dsp", NULL, 0, dsp_clk);
26862306a36Sopenharmony_ci	clkdev_create(clk, "dsp", NULL);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
27262306a36Sopenharmony_ci	int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	printk(KERN_INFO
27562306a36Sopenharmony_ci		"Clocks: base = %d, frequency = %u, prediv = %d, "
27662306a36Sopenharmony_ci		"postdiv = %d, postdiv2 = %d, mul = %d\n",
27762306a36Sopenharmony_ci		base, frequency, prediv, postdiv, postdiv2, mul);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	writel(0, &clock->ctrl);
28062306a36Sopenharmony_ci	writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
28162306a36Sopenharmony_ci	writel((mul - 1) & 0xF, &clock->mul);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	while (readl(&clock->status) & 0x1)
28462306a36Sopenharmony_ci		; /* nop */
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	writel(readl(&clock->cmden) | 1, &clock->cmden);
28962306a36Sopenharmony_ci	writel(readl(&clock->cmd) | 1, &clock->cmd);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	while (readl(&clock->status) & 0x1)
29262306a36Sopenharmony_ci		; /* nop */
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	writel(readl(&clock->cmden) | 1, &clock->cmden);
29762306a36Sopenharmony_ci	writel(readl(&clock->cmd) | 1, &clock->cmd);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	while (readl(&clock->status) & 0x1)
30062306a36Sopenharmony_ci		; /* nop */
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	writel(readl(&clock->ctrl) | 1, &clock->ctrl);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	if (*bootcr & BOOT_PLL_ASYNC_MODE)
30862306a36Sopenharmony_ci		/* Async */
30962306a36Sopenharmony_ci		switch (clock_id) {
31062306a36Sopenharmony_ci		case TNETD7200_CLOCK_ID_DSP:
31162306a36Sopenharmony_ci			return AR7_REF_CLOCK;
31262306a36Sopenharmony_ci		default:
31362306a36Sopenharmony_ci			return AR7_AFE_CLOCK;
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci	else
31662306a36Sopenharmony_ci		/* Sync */
31762306a36Sopenharmony_ci		if (*bootcr & BOOT_PLL_2TO1_MODE)
31862306a36Sopenharmony_ci			/* 2:1 */
31962306a36Sopenharmony_ci			switch (clock_id) {
32062306a36Sopenharmony_ci			case TNETD7200_CLOCK_ID_DSP:
32162306a36Sopenharmony_ci				return AR7_REF_CLOCK;
32262306a36Sopenharmony_ci			default:
32362306a36Sopenharmony_ci				return AR7_AFE_CLOCK;
32462306a36Sopenharmony_ci			}
32562306a36Sopenharmony_ci		else
32662306a36Sopenharmony_ci			/* 1:1 */
32762306a36Sopenharmony_ci			return AR7_REF_CLOCK;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic void __init tnetd7200_init_clocks(void)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4);
33462306a36Sopenharmony_ci	struct tnetd7200_clocks *clocks =
33562306a36Sopenharmony_ci					ioremap(AR7_REGS_CLOCKS,
33662306a36Sopenharmony_ci					sizeof(struct tnetd7200_clocks));
33762306a36Sopenharmony_ci	int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
33862306a36Sopenharmony_ci	int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
33962306a36Sopenharmony_ci	int usb_base, usb_mul, usb_prediv, usb_postdiv;
34062306a36Sopenharmony_ci	struct clk *clk;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
34362306a36Sopenharmony_ci	dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (*bootcr & BOOT_PLL_ASYNC_MODE) {
34662306a36Sopenharmony_ci		printk(KERN_INFO "Clocks: Async mode\n");
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		printk(KERN_INFO "Clocks: Setting DSP clock\n");
34962306a36Sopenharmony_ci		calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
35062306a36Sopenharmony_ci			&dsp_prediv, &dsp_postdiv, &dsp_mul);
35162306a36Sopenharmony_ci		bus_clk.rate =
35262306a36Sopenharmony_ci			((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
35362306a36Sopenharmony_ci		tnetd7200_set_clock(dsp_base, &clocks->dsp,
35462306a36Sopenharmony_ci			dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
35562306a36Sopenharmony_ci			bus_clk.rate);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		printk(KERN_INFO "Clocks: Setting CPU clock\n");
35862306a36Sopenharmony_ci		calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
35962306a36Sopenharmony_ci			&cpu_postdiv, &cpu_mul);
36062306a36Sopenharmony_ci		cpu_clk.rate =
36162306a36Sopenharmony_ci			((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
36262306a36Sopenharmony_ci		tnetd7200_set_clock(cpu_base, &clocks->cpu,
36362306a36Sopenharmony_ci			cpu_prediv, cpu_postdiv, -1, cpu_mul,
36462306a36Sopenharmony_ci			cpu_clk.rate);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	} else
36762306a36Sopenharmony_ci		if (*bootcr & BOOT_PLL_2TO1_MODE) {
36862306a36Sopenharmony_ci			printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci			printk(KERN_INFO "Clocks: Setting CPU clock\n");
37162306a36Sopenharmony_ci			calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
37262306a36Sopenharmony_ci				&cpu_postdiv, &cpu_mul);
37362306a36Sopenharmony_ci			cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul)
37462306a36Sopenharmony_ci								/ cpu_postdiv;
37562306a36Sopenharmony_ci			tnetd7200_set_clock(cpu_base, &clocks->cpu,
37662306a36Sopenharmony_ci				cpu_prediv, cpu_postdiv, -1, cpu_mul,
37762306a36Sopenharmony_ci				cpu_clk.rate);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci			printk(KERN_INFO "Clocks: Setting DSP clock\n");
38062306a36Sopenharmony_ci			calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
38162306a36Sopenharmony_ci				&dsp_postdiv, &dsp_mul);
38262306a36Sopenharmony_ci			bus_clk.rate = cpu_clk.rate / 2;
38362306a36Sopenharmony_ci			tnetd7200_set_clock(dsp_base, &clocks->dsp,
38462306a36Sopenharmony_ci				dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
38562306a36Sopenharmony_ci				dsp_mul * 2, bus_clk.rate);
38662306a36Sopenharmony_ci		} else {
38762306a36Sopenharmony_ci			printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci			printk(KERN_INFO "Clocks: Setting DSP clock\n");
39062306a36Sopenharmony_ci			calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
39162306a36Sopenharmony_ci				&dsp_postdiv, &dsp_mul);
39262306a36Sopenharmony_ci			bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul)
39362306a36Sopenharmony_ci								/ dsp_postdiv;
39462306a36Sopenharmony_ci			tnetd7200_set_clock(dsp_base, &clocks->dsp,
39562306a36Sopenharmony_ci				dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
39662306a36Sopenharmony_ci				dsp_mul * 2, bus_clk.rate);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci			cpu_clk.rate = bus_clk.rate;
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	printk(KERN_INFO "Clocks: Setting USB clock\n");
40262306a36Sopenharmony_ci	usb_base = bus_clk.rate;
40362306a36Sopenharmony_ci	calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
40462306a36Sopenharmony_ci		&usb_postdiv, &usb_mul);
40562306a36Sopenharmony_ci	tnetd7200_set_clock(usb_base, &clocks->usb,
40662306a36Sopenharmony_ci		usb_prediv, usb_postdiv, -1, usb_mul,
40762306a36Sopenharmony_ci		TNETD7200_DEF_USB_CLK);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	iounmap(clocks);
41062306a36Sopenharmony_ci	iounmap(bootcr);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	clk = clk_register_fixed_rate(NULL, "cpu", NULL, 0, cpu_clk.rate);
41362306a36Sopenharmony_ci	clkdev_create(clk, "cpu", NULL);
41462306a36Sopenharmony_ci	clkdev_create(clk, "dsp", NULL);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_civoid __init ar7_init_clocks(void)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	struct clk *clk;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	switch (ar7_chip_id()) {
42262306a36Sopenharmony_ci	case AR7_CHIP_7100:
42362306a36Sopenharmony_ci	case AR7_CHIP_7200:
42462306a36Sopenharmony_ci		tnetd7200_init_clocks();
42562306a36Sopenharmony_ci		break;
42662306a36Sopenharmony_ci	case AR7_CHIP_7300:
42762306a36Sopenharmony_ci		tnetd7300_init_clocks();
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	default:
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	clk = clk_register_fixed_rate(NULL, "bus", NULL, 0, bus_clk.rate);
43362306a36Sopenharmony_ci	clkdev_create(clk, "bus", NULL);
43462306a36Sopenharmony_ci	/* adjust vbus clock rate */
43562306a36Sopenharmony_ci	clk = clk_register_fixed_factor(NULL, "vbus", "bus", 0, 1, 2);
43662306a36Sopenharmony_ci	clkdev_create(clk, "vbus", NULL);
43762306a36Sopenharmony_ci	clkdev_create(clk, "cpmac", "cpmac.1");
43862306a36Sopenharmony_ci	clkdev_create(clk, "cpmac", "cpmac.1");
43962306a36Sopenharmony_ci}
440