xref: /openbmc/u-boot/arch/arm/cpu/arm926ejs/mxs/clock.c (revision eaaa4f7e)
1 /*
2  * Freescale i.MX23/i.MX28 clock setup code
3  *
4  * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5  * on behalf of DENX Software Engineering GmbH
6  *
7  * Based on code from LTIB:
8  * Copyright (C) 2010 Freescale Semiconductor, Inc.
9  *
10  * SPDX-License-Identifier:	GPL-2.0+
11  */
12 
13 #include <common.h>
14 #include <asm/errno.h>
15 #include <asm/io.h>
16 #include <asm/arch/clock.h>
17 #include <asm/arch/imx-regs.h>
18 
19 /*
20  * The PLL frequency is 480MHz and XTAL frequency is 24MHz
21  *   iMX23: datasheet section 4.2
22  *   iMX28: datasheet section 10.2
23  */
24 #define	PLL_FREQ_KHZ	480000
25 #define	PLL_FREQ_COEF	18
26 #define	XTAL_FREQ_KHZ	24000
27 
28 #define	PLL_FREQ_MHZ	(PLL_FREQ_KHZ / 1000)
29 #define	XTAL_FREQ_MHZ	(XTAL_FREQ_KHZ / 1000)
30 
31 #if defined(CONFIG_MX23)
32 #define MXC_SSPCLK_MAX MXC_SSPCLK0
33 #elif defined(CONFIG_MX28)
34 #define MXC_SSPCLK_MAX MXC_SSPCLK3
35 #endif
36 
37 static uint32_t mxs_get_pclk(void)
38 {
39 	struct mxs_clkctrl_regs *clkctrl_regs =
40 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
41 
42 	uint32_t clkctrl, clkseq, div;
43 	uint8_t clkfrac, frac;
44 
45 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
46 
47 	/* No support of fractional divider calculation */
48 	if (clkctrl &
49 		(CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
50 		return 0;
51 	}
52 
53 	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
54 
55 	/* XTAL Path */
56 	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
57 		div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
58 			CLKCTRL_CPU_DIV_XTAL_OFFSET;
59 		return XTAL_FREQ_MHZ / div;
60 	}
61 
62 	/* REF Path */
63 	clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
64 	frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
65 	div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
66 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
67 }
68 
69 static uint32_t mxs_get_hclk(void)
70 {
71 	struct mxs_clkctrl_regs *clkctrl_regs =
72 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
73 
74 	uint32_t div;
75 	uint32_t clkctrl;
76 
77 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
78 
79 	/* No support of fractional divider calculation */
80 	if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
81 		return 0;
82 
83 	div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
84 	return mxs_get_pclk() / div;
85 }
86 
87 static uint32_t mxs_get_emiclk(void)
88 {
89 	struct mxs_clkctrl_regs *clkctrl_regs =
90 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
91 
92 	uint32_t clkctrl, clkseq, div;
93 	uint8_t clkfrac, frac;
94 
95 	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
96 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
97 
98 	/* XTAL Path */
99 	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
100 		div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
101 			CLKCTRL_EMI_DIV_XTAL_OFFSET;
102 		return XTAL_FREQ_MHZ / div;
103 	}
104 
105 	/* REF Path */
106 	clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
107 	frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
108 	div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
109 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
110 }
111 
112 static uint32_t mxs_get_gpmiclk(void)
113 {
114 	struct mxs_clkctrl_regs *clkctrl_regs =
115 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
116 #if defined(CONFIG_MX23)
117 	uint8_t *reg =
118 		&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
119 #elif defined(CONFIG_MX28)
120 	uint8_t *reg =
121 		&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
122 #endif
123 	uint32_t clkctrl, clkseq, div;
124 	uint8_t clkfrac, frac;
125 
126 	clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
127 	clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
128 
129 	/* XTAL Path */
130 	if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
131 		div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
132 		return XTAL_FREQ_MHZ / div;
133 	}
134 
135 	/* REF Path */
136 	clkfrac = readb(reg);
137 	frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
138 	div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
139 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
140 }
141 
142 /*
143  * Set IO clock frequency, in kHz
144  */
145 void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
146 {
147 	struct mxs_clkctrl_regs *clkctrl_regs =
148 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
149 	uint32_t div;
150 	int io_reg;
151 
152 	if (freq == 0)
153 		return;
154 
155 	if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
156 		return;
157 
158 	div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
159 
160 	if (div < 18)
161 		div = 18;
162 
163 	if (div > 35)
164 		div = 35;
165 
166 	io_reg = CLKCTRL_FRAC0_IO0 - io;	/* Register order is reversed */
167 	writeb(CLKCTRL_FRAC_CLKGATE,
168 		&clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
169 	writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
170 		&clkctrl_regs->hw_clkctrl_frac0[io_reg]);
171 	writeb(CLKCTRL_FRAC_CLKGATE,
172 		&clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
173 }
174 
175 /*
176  * Get IO clock, returns IO clock in kHz
177  */
178 static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
179 {
180 	struct mxs_clkctrl_regs *clkctrl_regs =
181 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
182 	uint8_t ret;
183 	int io_reg;
184 
185 	if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
186 		return 0;
187 
188 	io_reg = CLKCTRL_FRAC0_IO0 - io;	/* Register order is reversed */
189 
190 	ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
191 		CLKCTRL_FRAC_FRAC_MASK;
192 
193 	return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
194 }
195 
196 /*
197  * Configure SSP clock frequency, in kHz
198  */
199 void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
200 {
201 	struct mxs_clkctrl_regs *clkctrl_regs =
202 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
203 	uint32_t clk, clkreg;
204 
205 	if (ssp > MXC_SSPCLK_MAX)
206 		return;
207 
208 	clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
209 			(ssp * sizeof(struct mxs_register_32));
210 
211 	clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
212 	while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
213 		;
214 
215 	if (xtal)
216 		clk = XTAL_FREQ_KHZ;
217 	else
218 		clk = mxs_get_ioclk(ssp >> 1);
219 
220 	if (freq > clk)
221 		return;
222 
223 	/* Calculate the divider and cap it if necessary */
224 	clk /= freq;
225 	if (clk > CLKCTRL_SSP_DIV_MASK)
226 		clk = CLKCTRL_SSP_DIV_MASK;
227 
228 	clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
229 	while (readl(clkreg) & CLKCTRL_SSP_BUSY)
230 		;
231 
232 	if (xtal)
233 		writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
234 			&clkctrl_regs->hw_clkctrl_clkseq_set);
235 	else
236 		writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
237 			&clkctrl_regs->hw_clkctrl_clkseq_clr);
238 }
239 
240 /*
241  * Return SSP frequency, in kHz
242  */
243 static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
244 {
245 	struct mxs_clkctrl_regs *clkctrl_regs =
246 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
247 	uint32_t clkreg;
248 	uint32_t clk, tmp;
249 
250 	if (ssp > MXC_SSPCLK_MAX)
251 		return 0;
252 
253 	tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
254 	if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
255 		return XTAL_FREQ_KHZ;
256 
257 	clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
258 			(ssp * sizeof(struct mxs_register_32));
259 
260 	tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
261 
262 	if (tmp == 0)
263 		return 0;
264 
265 	clk = mxs_get_ioclk(ssp >> 1);
266 
267 	return clk / tmp;
268 }
269 
270 /*
271  * Set SSP/MMC bus frequency, in kHz)
272  */
273 void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
274 {
275 	struct mxs_ssp_regs *ssp_regs;
276 	const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
277 	const uint32_t sspclk = mxs_get_sspclk(clk);
278 	uint32_t reg;
279 	uint32_t divide, rate, tgtclk;
280 
281 	ssp_regs = mxs_ssp_regs_by_bus(bus);
282 
283 	/*
284 	 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
285 	 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
286 	 * CLOCK_RATE could be any integer from 0 to 255.
287 	 */
288 	for (divide = 2; divide < 254; divide += 2) {
289 		rate = sspclk / freq / divide;
290 		if (rate <= 256)
291 			break;
292 	}
293 
294 	tgtclk = sspclk / divide / rate;
295 	while (tgtclk > freq) {
296 		rate++;
297 		tgtclk = sspclk / divide / rate;
298 	}
299 	if (rate > 256)
300 		rate = 256;
301 
302 	/* Always set timeout the maximum */
303 	reg = SSP_TIMING_TIMEOUT_MASK |
304 		(divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
305 		((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
306 	writel(reg, &ssp_regs->hw_ssp_timing);
307 
308 	debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
309 		bus, tgtclk, freq);
310 }
311 
312 void mxs_set_lcdclk(uint32_t freq)
313 {
314 	struct mxs_clkctrl_regs *clkctrl_regs =
315 		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
316 	uint32_t fp, x, k_rest, k_best, x_best, tk;
317 	int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
318 
319 	if (freq == 0)
320 		return;
321 
322 #if defined(CONFIG_MX23)
323 	writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
324 #elif defined(CONFIG_MX28)
325 	writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
326 #endif
327 
328 	/*
329 	 *             /               18 \     1       1
330 	 * freq kHz = | 480000000 Hz * --  | * --- * ------
331 	 *             \                x /     k     1000
332 	 *
333 	 *      480000000 Hz   18
334 	 *      ------------ * --
335 	 *        freq kHz      x
336 	 * k = -------------------
337 	 *             1000
338 	 */
339 
340 	fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
341 
342 	for (x = 18; x <= 35; x++) {
343 		tk = fp / x;
344 		if ((tk / 1000 == 0) || (tk / 1000 > 255))
345 			continue;
346 
347 		k_rest = tk % 1000;
348 
349 		if (k_rest < (k_best_l % 1000)) {
350 			k_best_l = tk;
351 			x_best_l = x;
352 		}
353 
354 		if (k_rest > (k_best_t % 1000)) {
355 			k_best_t = tk;
356 			x_best_t = x;
357 		}
358 	}
359 
360 	if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
361 		k_best = k_best_l;
362 		x_best = x_best_l;
363 	} else {
364 		k_best = k_best_t;
365 		x_best = x_best_t;
366 	}
367 
368 	k_best /= 1000;
369 
370 #if defined(CONFIG_MX23)
371 	writeb(CLKCTRL_FRAC_CLKGATE,
372 		&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
373 	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
374 		&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
375 	writeb(CLKCTRL_FRAC_CLKGATE,
376 		&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
377 
378 	writel(CLKCTRL_PIX_CLKGATE,
379 		&clkctrl_regs->hw_clkctrl_pix_set);
380 	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
381 			CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
382 			k_best << CLKCTRL_PIX_DIV_OFFSET);
383 
384 	while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
385 		;
386 #elif defined(CONFIG_MX28)
387 	writeb(CLKCTRL_FRAC_CLKGATE,
388 		&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
389 	writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
390 		&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
391 	writeb(CLKCTRL_FRAC_CLKGATE,
392 		&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
393 
394 	writel(CLKCTRL_DIS_LCDIF_CLKGATE,
395 		&clkctrl_regs->hw_clkctrl_lcdif_set);
396 	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
397 			CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
398 			k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
399 
400 	while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
401 		;
402 #endif
403 }
404 
405 uint32_t mxc_get_clock(enum mxc_clock clk)
406 {
407 	switch (clk) {
408 	case MXC_ARM_CLK:
409 		return mxs_get_pclk() * 1000000;
410 	case MXC_GPMI_CLK:
411 		return mxs_get_gpmiclk() * 1000000;
412 	case MXC_AHB_CLK:
413 	case MXC_IPG_CLK:
414 		return mxs_get_hclk() * 1000000;
415 	case MXC_EMI_CLK:
416 		return mxs_get_emiclk();
417 	case MXC_IO0_CLK:
418 		return mxs_get_ioclk(MXC_IOCLK0);
419 	case MXC_IO1_CLK:
420 		return mxs_get_ioclk(MXC_IOCLK1);
421 	case MXC_XTAL_CLK:
422 		return XTAL_FREQ_KHZ * 1000;
423 	case MXC_SSP0_CLK:
424 		return mxs_get_sspclk(MXC_SSPCLK0);
425 #ifdef CONFIG_MX28
426 	case MXC_SSP1_CLK:
427 		return mxs_get_sspclk(MXC_SSPCLK1);
428 	case MXC_SSP2_CLK:
429 		return mxs_get_sspclk(MXC_SSPCLK2);
430 	case MXC_SSP3_CLK:
431 		return mxs_get_sspclk(MXC_SSPCLK3);
432 #endif
433 	}
434 
435 	return 0;
436 }
437