xref: /OK3568_Linux_fs/u-boot/arch/mips/mach-ath79/ar934x/clk.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2016 Marek Vasut <marex@denx.de>
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <asm/io.h>
9*4882a593Smuzhiyun #include <asm/addrspace.h>
10*4882a593Smuzhiyun #include <asm/types.h>
11*4882a593Smuzhiyun #include <mach/ar71xx_regs.h>
12*4882a593Smuzhiyun #include <mach/ath79.h>
13*4882a593Smuzhiyun #include <wait_bit.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun  * The math for calculating PLL:
19*4882a593Smuzhiyun  *                                       NFRAC * 2^8
20*4882a593Smuzhiyun  *                               NINT + -------------
21*4882a593Smuzhiyun  *                XTAL [MHz]              2^(18 - 1)
22*4882a593Smuzhiyun  *   PLL [MHz] = ------------ * ----------------------
23*4882a593Smuzhiyun  *                  REFDIV              2^OUTDIV
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * Unfortunatelly, there is no way to reliably compute the variables.
26*4882a593Smuzhiyun  * The vendor U-Boot port contains macros for various combinations of
27*4882a593Smuzhiyun  * CPU PLL / DDR PLL / AHB bus speed and there is no obvious pattern
28*4882a593Smuzhiyun  * in those numbers.
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun struct ar934x_pll_config {
31*4882a593Smuzhiyun 	u8	range;
32*4882a593Smuzhiyun 	u8	refdiv;
33*4882a593Smuzhiyun 	u8	outdiv;
34*4882a593Smuzhiyun 	/* Index 0 is for XTAL=25MHz , Index 1 is for XTAL=40MHz */
35*4882a593Smuzhiyun 	u8	nint[2];
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct ar934x_clock_config {
39*4882a593Smuzhiyun 	u16				cpu_freq;
40*4882a593Smuzhiyun 	u16				ddr_freq;
41*4882a593Smuzhiyun 	u16				ahb_freq;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	struct ar934x_pll_config	cpu_pll;
44*4882a593Smuzhiyun 	struct ar934x_pll_config	ddr_pll;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static const struct ar934x_clock_config ar934x_clock_config[] = {
48*4882a593Smuzhiyun 	{ 300, 300, 150, { 1, 1, 1, { 24, 15 } }, { 1, 1, 1, { 24, 15 } } },
49*4882a593Smuzhiyun 	{ 400, 200, 200, { 1, 1, 1, { 32, 20 } }, { 1, 1, 2, { 32, 20 } } },
50*4882a593Smuzhiyun 	{ 400, 400, 200, { 0, 1, 1, { 32, 20 } }, { 0, 1, 1, { 32, 20 } } },
51*4882a593Smuzhiyun 	{ 500, 400, 200, { 1, 1, 0, { 20, 12 } }, { 0, 1, 1, { 32, 20 } } },
52*4882a593Smuzhiyun 	{ 533, 400, 200, { 1, 1, 0, { 21, 13 } }, { 0, 1, 1, { 32, 20 } } },
53*4882a593Smuzhiyun 	{ 533, 500, 250, { 1, 1, 0, { 21, 13 } }, { 0, 1, 0, { 20, 12 } } },
54*4882a593Smuzhiyun 	{ 560, 480, 240, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 12 } } },
55*4882a593Smuzhiyun 	{ 566, 400, 200, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 16, 10 } } },
56*4882a593Smuzhiyun 	{ 566, 450, 225, { 1, 1, 0, { 22, 14 } }, { 0, 1, 1, { 36, 22 } } },
57*4882a593Smuzhiyun 	{ 566, 475, 237, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 11 } } },
58*4882a593Smuzhiyun 	{ 566, 500, 250, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 20, 12 } } },
59*4882a593Smuzhiyun 	{ 566, 525, 262, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 21, 13 } } },
60*4882a593Smuzhiyun 	{ 566, 550, 275, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 22, 13 } } },
61*4882a593Smuzhiyun 	{ 600, 266, 133, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
62*4882a593Smuzhiyun 	{ 600, 266, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
63*4882a593Smuzhiyun 	{ 600, 300, 150, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 24, 15 } } },
64*4882a593Smuzhiyun 	{ 600, 332, 166, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
65*4882a593Smuzhiyun 	{ 600, 332, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
66*4882a593Smuzhiyun 	{ 600, 400, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 32, 20 } } },
67*4882a593Smuzhiyun 	{ 600, 450, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 18, 20 } } },
68*4882a593Smuzhiyun 	{ 600, 500, 250, { 0, 1, 0, { 24, 15 } }, { 1, 1, 0, { 20, 12 } } },
69*4882a593Smuzhiyun 	{ 600, 525, 262, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 21, 20 } } },
70*4882a593Smuzhiyun 	{ 600, 550, 275, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 22, 20 } } },
71*4882a593Smuzhiyun 	{ 600, 575, 287, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 23, 14 } } },
72*4882a593Smuzhiyun 	{ 600, 600, 300, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 24, 20 } } },
73*4882a593Smuzhiyun 	{ 600, 650, 325, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 26, 20 } } },
74*4882a593Smuzhiyun 	{ 650, 600, 300, { 0, 1, 0, { 26, 15 } }, { 0, 1, 0, { 24, 20 } } },
75*4882a593Smuzhiyun 	{ 700, 400, 200, { 3, 1, 0, { 28, 17 } }, { 0, 1, 1, { 32, 20 } } },
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun 
ar934x_srif_pll_cfg(void __iomem * pll_reg_base,const u32 srif_val)78*4882a593Smuzhiyun static void ar934x_srif_pll_cfg(void __iomem *pll_reg_base, const u32 srif_val)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	u32 reg;
81*4882a593Smuzhiyun 	do {
82*4882a593Smuzhiyun 		writel(0x10810f00, pll_reg_base + 0x4);
83*4882a593Smuzhiyun 		writel(srif_val, pll_reg_base + 0x0);
84*4882a593Smuzhiyun 		writel(0xd0810f00, pll_reg_base + 0x4);
85*4882a593Smuzhiyun 		writel(0x03000000, pll_reg_base + 0x8);
86*4882a593Smuzhiyun 		writel(0xd0800f00, pll_reg_base + 0x4);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 		clrbits_be32(pll_reg_base + 0x8, BIT(30));
89*4882a593Smuzhiyun 		udelay(5);
90*4882a593Smuzhiyun 		setbits_be32(pll_reg_base + 0x8, BIT(30));
91*4882a593Smuzhiyun 		udelay(5);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 		wait_for_bit_le32(pll_reg_base + 0xc, BIT(3), 1, 10, 0);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 		clrbits_be32(pll_reg_base + 0x8, BIT(30));
96*4882a593Smuzhiyun 		udelay(5);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 		/* Check if CPU SRIF PLL locked. */
99*4882a593Smuzhiyun 		reg = readl(pll_reg_base + 0x8);
100*4882a593Smuzhiyun 		reg = (reg & 0x7ffff8) >> 3;
101*4882a593Smuzhiyun 	} while (reg >= 0x40000);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
ar934x_pll_init(const u16 cpu_mhz,const u16 ddr_mhz,const u16 ahb_mhz)104*4882a593Smuzhiyun void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	void __iomem *srif_regs = map_physmem(AR934X_SRIF_BASE,
107*4882a593Smuzhiyun 					      AR934X_SRIF_SIZE, MAP_NOCACHE);
108*4882a593Smuzhiyun 	void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE,
109*4882a593Smuzhiyun 					     AR71XX_PLL_SIZE, MAP_NOCACHE);
110*4882a593Smuzhiyun 	const struct ar934x_pll_config *pll_cfg;
111*4882a593Smuzhiyun 	int i, pll_nint, pll_refdiv, xtal_40 = 0;
112*4882a593Smuzhiyun 	u32 reg, cpu_pll, cpu_srif, ddr_pll, ddr_srif;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* Configure SRIF PLL with initial values. */
115*4882a593Smuzhiyun 	writel(0x13210f00, srif_regs + AR934X_SRIF_CPU_DPLL2_REG);
116*4882a593Smuzhiyun 	writel(0x03000000, srif_regs + AR934X_SRIF_CPU_DPLL3_REG);
117*4882a593Smuzhiyun 	writel(0x13210f00, srif_regs + AR934X_SRIF_DDR_DPLL2_REG);
118*4882a593Smuzhiyun 	writel(0x03000000, srif_regs + AR934X_SRIF_DDR_DPLL3_REG);
119*4882a593Smuzhiyun 	writel(0x03000000, srif_regs + 0x188); /* Undocumented reg :-) */
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* Test for 40MHz XTAL */
122*4882a593Smuzhiyun 	reg = ath79_get_bootstrap();
123*4882a593Smuzhiyun 	if (reg & AR934X_BOOTSTRAP_REF_CLK_40) {
124*4882a593Smuzhiyun 		xtal_40 = 1;
125*4882a593Smuzhiyun 		cpu_srif = 0x41c00000;
126*4882a593Smuzhiyun 		ddr_srif = 0x41680000;
127*4882a593Smuzhiyun 	} else {
128*4882a593Smuzhiyun 		xtal_40 = 0;
129*4882a593Smuzhiyun 		cpu_srif = 0x29c00000;
130*4882a593Smuzhiyun 		ddr_srif = 0x29680000;
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	/* Locate CPU/DDR PLL configuration */
134*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ar934x_clock_config); i++) {
135*4882a593Smuzhiyun 		if (cpu_mhz != ar934x_clock_config[i].cpu_freq)
136*4882a593Smuzhiyun 			continue;
137*4882a593Smuzhiyun 		if (ddr_mhz != ar934x_clock_config[i].ddr_freq)
138*4882a593Smuzhiyun 			continue;
139*4882a593Smuzhiyun 		if (ahb_mhz != ar934x_clock_config[i].ahb_freq)
140*4882a593Smuzhiyun 			continue;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 		/* Entry found */
143*4882a593Smuzhiyun 		pll_cfg = &ar934x_clock_config[i].cpu_pll;
144*4882a593Smuzhiyun 		pll_nint = pll_cfg->nint[xtal_40];
145*4882a593Smuzhiyun 		pll_refdiv = pll_cfg->refdiv;
146*4882a593Smuzhiyun 		cpu_pll =
147*4882a593Smuzhiyun 			(pll_nint << AR934X_PLL_CPU_CONFIG_NINT_SHIFT) |
148*4882a593Smuzhiyun 			(pll_refdiv << AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) |
149*4882a593Smuzhiyun 			(pll_cfg->range << AR934X_PLL_CPU_CONFIG_RANGE_SHIFT) |
150*4882a593Smuzhiyun 			(pll_cfg->outdiv << AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		pll_cfg = &ar934x_clock_config[i].ddr_pll;
153*4882a593Smuzhiyun 		pll_nint = pll_cfg->nint[xtal_40];
154*4882a593Smuzhiyun 		pll_refdiv = pll_cfg->refdiv;
155*4882a593Smuzhiyun 		ddr_pll =
156*4882a593Smuzhiyun 			(pll_nint << AR934X_PLL_DDR_CONFIG_NINT_SHIFT) |
157*4882a593Smuzhiyun 			(pll_refdiv << AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) |
158*4882a593Smuzhiyun 			(pll_cfg->range << AR934X_PLL_DDR_CONFIG_RANGE_SHIFT) |
159*4882a593Smuzhiyun 			(pll_cfg->outdiv << AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT);
160*4882a593Smuzhiyun 		break;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	/* PLL configuration not found, hang. */
164*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(ar934x_clock_config))
165*4882a593Smuzhiyun 		hang();
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/* Set PLL Bypass */
168*4882a593Smuzhiyun 	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
169*4882a593Smuzhiyun 		     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
170*4882a593Smuzhiyun 	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
171*4882a593Smuzhiyun 		     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
172*4882a593Smuzhiyun 	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
173*4882a593Smuzhiyun 		     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	/* Configure CPU PLL */
176*4882a593Smuzhiyun 	writel(cpu_pll | AR934X_PLL_CPU_CONFIG_PLLPWD,
177*4882a593Smuzhiyun 	       pll_regs + AR934X_PLL_CPU_CONFIG_REG);
178*4882a593Smuzhiyun 	/* Configure DDR PLL */
179*4882a593Smuzhiyun 	writel(ddr_pll | AR934X_PLL_DDR_CONFIG_PLLPWD,
180*4882a593Smuzhiyun 	       pll_regs + AR934X_PLL_DDR_CONFIG_REG);
181*4882a593Smuzhiyun 	/* Configure PLL routing */
182*4882a593Smuzhiyun 	writel(AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS |
183*4882a593Smuzhiyun 	       AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS |
184*4882a593Smuzhiyun 	       AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS |
185*4882a593Smuzhiyun 	       (0 << AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) |
186*4882a593Smuzhiyun 	       (0 << AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) |
187*4882a593Smuzhiyun 	       (1 << AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) |
188*4882a593Smuzhiyun 	       AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL |
189*4882a593Smuzhiyun 	       AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL |
190*4882a593Smuzhiyun 	       AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL,
191*4882a593Smuzhiyun 	       pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	/* Configure SRIF PLLs, which is completely undocumented :-) */
194*4882a593Smuzhiyun 	ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_CPU_DPLL1_REG, cpu_srif);
195*4882a593Smuzhiyun 	ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_DDR_DPLL1_REG, ddr_srif);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	/* Unset PLL Bypass */
198*4882a593Smuzhiyun 	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
199*4882a593Smuzhiyun 		     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
200*4882a593Smuzhiyun 	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
201*4882a593Smuzhiyun 		     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
202*4882a593Smuzhiyun 	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
203*4882a593Smuzhiyun 		     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	/* Enable PLL dithering */
206*4882a593Smuzhiyun 	writel((1 << AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT) |
207*4882a593Smuzhiyun 	       (0xf << AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT),
208*4882a593Smuzhiyun 	       pll_regs + AR934X_PLL_DDR_DIT_FRAC_REG);
209*4882a593Smuzhiyun 	writel(48 << AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT,
210*4882a593Smuzhiyun 	       pll_regs + AR934X_PLL_CPU_DIT_FRAC_REG);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
ar934x_get_xtal(void)213*4882a593Smuzhiyun static u32 ar934x_get_xtal(void)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	u32 val;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	val = ath79_get_bootstrap();
218*4882a593Smuzhiyun 	if (val & AR934X_BOOTSTRAP_REF_CLK_40)
219*4882a593Smuzhiyun 		return 40000000;
220*4882a593Smuzhiyun 	else
221*4882a593Smuzhiyun 		return 25000000;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
get_serial_clock(void)224*4882a593Smuzhiyun int get_serial_clock(void)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	return ar934x_get_xtal();
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
ar934x_cpupll_to_hz(const u32 regval)229*4882a593Smuzhiyun static u32 ar934x_cpupll_to_hz(const u32 regval)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	const u32 outdiv = (regval >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
232*4882a593Smuzhiyun 			   AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
233*4882a593Smuzhiyun 	const u32 refdiv = (regval >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
234*4882a593Smuzhiyun 			   AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
235*4882a593Smuzhiyun 	const u32 nint = (regval >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
236*4882a593Smuzhiyun 			   AR934X_PLL_CPU_CONFIG_NINT_MASK;
237*4882a593Smuzhiyun 	const u32 nfrac = (regval >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
238*4882a593Smuzhiyun 			   AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
239*4882a593Smuzhiyun 	const u32 xtal = ar934x_get_xtal();
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
ar934x_ddrpll_to_hz(const u32 regval)244*4882a593Smuzhiyun static u32 ar934x_ddrpll_to_hz(const u32 regval)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	const u32 outdiv = (regval >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
247*4882a593Smuzhiyun 			   AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
248*4882a593Smuzhiyun 	const u32 refdiv = (regval >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
249*4882a593Smuzhiyun 			   AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
250*4882a593Smuzhiyun 	const u32 nint = (regval >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
251*4882a593Smuzhiyun 			   AR934X_PLL_DDR_CONFIG_NINT_MASK;
252*4882a593Smuzhiyun 	const u32 nfrac = (regval >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
253*4882a593Smuzhiyun 			   AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
254*4882a593Smuzhiyun 	const u32 xtal = ar934x_get_xtal();
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
ar934x_update_clock(void)259*4882a593Smuzhiyun static void ar934x_update_clock(void)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	void __iomem *regs;
262*4882a593Smuzhiyun 	u32 ctrl, cpu, cpupll, ddr, ddrpll;
263*4882a593Smuzhiyun 	u32 cpudiv, ddrdiv, busdiv;
264*4882a593Smuzhiyun 	u32 cpuclk, ddrclk, busclk;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
267*4882a593Smuzhiyun 			   MAP_NOCACHE);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	cpu = readl(regs + AR934X_PLL_CPU_CONFIG_REG);
270*4882a593Smuzhiyun 	ddr = readl(regs + AR934X_PLL_DDR_CONFIG_REG);
271*4882a593Smuzhiyun 	ctrl = readl(regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	cpupll = ar934x_cpupll_to_hz(cpu);
274*4882a593Smuzhiyun 	ddrpll = ar934x_ddrpll_to_hz(ddr);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	if (ctrl & AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
277*4882a593Smuzhiyun 		cpuclk = ar934x_get_xtal();
278*4882a593Smuzhiyun 	else if (ctrl & AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
279*4882a593Smuzhiyun 		cpuclk = cpupll;
280*4882a593Smuzhiyun 	else
281*4882a593Smuzhiyun 		cpuclk = ddrpll;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (ctrl & AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
284*4882a593Smuzhiyun 		ddrclk = ar934x_get_xtal();
285*4882a593Smuzhiyun 	else if (ctrl & AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
286*4882a593Smuzhiyun 		ddrclk = ddrpll;
287*4882a593Smuzhiyun 	else
288*4882a593Smuzhiyun 		ddrclk = cpupll;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (ctrl & AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
291*4882a593Smuzhiyun 		busclk = ar934x_get_xtal();
292*4882a593Smuzhiyun 	else if (ctrl & AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
293*4882a593Smuzhiyun 		busclk = ddrpll;
294*4882a593Smuzhiyun 	else
295*4882a593Smuzhiyun 		busclk = cpupll;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	cpudiv = (ctrl >> AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
298*4882a593Smuzhiyun 		 AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
299*4882a593Smuzhiyun 	ddrdiv = (ctrl >> AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
300*4882a593Smuzhiyun 		 AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
301*4882a593Smuzhiyun 	busdiv = (ctrl >> AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
302*4882a593Smuzhiyun 		 AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	gd->cpu_clk = cpuclk / (cpudiv + 1);
305*4882a593Smuzhiyun 	gd->mem_clk = ddrclk / (ddrdiv + 1);
306*4882a593Smuzhiyun 	gd->bus_clk = busclk / (busdiv + 1);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
get_bus_freq(ulong dummy)309*4882a593Smuzhiyun ulong get_bus_freq(ulong dummy)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	ar934x_update_clock();
312*4882a593Smuzhiyun 	return gd->bus_clk;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
get_ddr_freq(ulong dummy)315*4882a593Smuzhiyun ulong get_ddr_freq(ulong dummy)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	ar934x_update_clock();
318*4882a593Smuzhiyun 	return gd->mem_clk;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
do_ar934x_showclk(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])321*4882a593Smuzhiyun int do_ar934x_showclk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	ar934x_update_clock();
324*4882a593Smuzhiyun 	printf("CPU:       %8ld MHz\n", gd->cpu_clk / 1000000);
325*4882a593Smuzhiyun 	printf("Memory:    %8ld MHz\n", gd->mem_clk / 1000000);
326*4882a593Smuzhiyun 	printf("AHB:       %8ld MHz\n", gd->bus_clk / 1000000);
327*4882a593Smuzhiyun 	return 0;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun U_BOOT_CMD(
331*4882a593Smuzhiyun 	clocks,	CONFIG_SYS_MAXARGS, 1, do_ar934x_showclk,
332*4882a593Smuzhiyun 	"display clocks",
333*4882a593Smuzhiyun 	""
334*4882a593Smuzhiyun );
335