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