2 * Freescale i.MX23/i.MX28 clock setup code
4 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5 * on behalf of DENX Software Engineering GmbH
7 * Based on code from LTIB:
8 * Copyright (C) 2010 Freescale Semiconductor, Inc.
10 * SPDX-License-Identifier: GPL-2.0+
14 #include <asm/errno.h>
16 #include <asm/arch/clock.h>
17 #include <asm/arch/imx-regs.h>
20 * The PLL frequency is 480MHz and XTAL frequency is 24MHz
21 * iMX23: datasheet section 4.2
22 * iMX28: datasheet section 10.2
24 #define PLL_FREQ_KHZ 480000
25 #define PLL_FREQ_COEF 18
26 #define XTAL_FREQ_KHZ 24000
28 #define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000)
29 #define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000)
31 #if defined(CONFIG_MX23)
32 #define MXC_SSPCLK_MAX MXC_SSPCLK0
33 #elif defined(CONFIG_MX28)
34 #define MXC_SSPCLK_MAX MXC_SSPCLK3
37 static struct mxs_clkctrl_regs *clkctrl_regs = (void *)MXS_CLKCTRL_BASE;
39 static uint32_t get_frac_clk(uint32_t refclk, uint32_t div, uint32_t _mask)
41 uint32_t mask = (_mask + 1) >> 1;
58 return refclk * mult / period;
61 static uint32_t mxs_get_pclk(void)
63 uint32_t clkctrl, clkseq, div;
64 uint8_t clkfrac, frac;
66 clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
68 div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
69 clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
70 frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
71 clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
74 (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
75 uint32_t refclk, mask;
77 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
78 refclk = XTAL_FREQ_MHZ;
79 mask = CLKCTRL_CPU_DIV_XTAL_MASK >>
80 CLKCTRL_CPU_DIV_XTAL_OFFSET;
81 div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
82 CLKCTRL_CPU_DIV_XTAL_OFFSET;
84 refclk = PLL_FREQ_MHZ * PLL_FREQ_COEF / frac;
85 mask = CLKCTRL_CPU_DIV_CPU_MASK;
87 return get_frac_clk(refclk, div, mask);
91 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
92 div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
93 CLKCTRL_CPU_DIV_XTAL_OFFSET;
94 return XTAL_FREQ_MHZ / div;
98 return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
101 static uint32_t mxs_get_hclk(void)
105 uint32_t refclk = mxs_get_pclk();
107 clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
108 div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
110 if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
111 return get_frac_clk(refclk, div, CLKCTRL_HBUS_DIV_MASK);
116 static uint32_t mxs_get_emiclk(void)
118 uint32_t clkctrl, clkseq, div;
119 uint8_t clkfrac, frac;
121 clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
122 clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
125 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
126 div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
127 CLKCTRL_EMI_DIV_XTAL_OFFSET;
128 return XTAL_FREQ_MHZ / div;
132 clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
133 frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
134 div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
135 return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
138 static uint32_t mxs_get_gpmiclk(void)
140 #if defined(CONFIG_MX23)
142 &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
143 #elif defined(CONFIG_MX28)
145 &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
147 uint32_t clkctrl, clkseq, div;
148 uint8_t clkfrac, frac;
150 clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
151 clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
154 if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
155 div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
156 return XTAL_FREQ_MHZ / div;
160 clkfrac = readb(reg);
161 frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
162 div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
163 return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
167 * Set IO clock frequency, in kHz
169 void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
177 if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
180 div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
188 io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
189 writeb(CLKCTRL_FRAC_CLKGATE,
190 &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
191 writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
192 &clkctrl_regs->hw_clkctrl_frac0[io_reg]);
193 writeb(CLKCTRL_FRAC_CLKGATE,
194 &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
198 * Get IO clock, returns IO clock in kHz
200 static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
205 if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) {
206 printf("%s: IO clock selector %u out of range %u..%u\n",
207 __func__, io, MXC_IOCLK0, MXC_IOCLK1);
210 io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
212 ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
213 CLKCTRL_FRAC_FRAC_MASK;
215 return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
219 * Configure SSP clock frequency, in kHz
221 void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
223 uint32_t clk, clkreg;
225 if (ssp > MXC_SSPCLK_MAX)
228 clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
229 (ssp * sizeof(struct mxs_register_32));
231 clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
232 while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
238 clk = mxs_get_ioclk(ssp >> 1);
243 /* Calculate the divider and cap it if necessary */
245 if (clk > CLKCTRL_SSP_DIV_MASK)
246 clk = CLKCTRL_SSP_DIV_MASK;
248 clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
249 while (readl(clkreg) & CLKCTRL_SSP_BUSY)
253 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
254 &clkctrl_regs->hw_clkctrl_clkseq_set);
256 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
257 &clkctrl_regs->hw_clkctrl_clkseq_clr);
261 * Return SSP frequency, in kHz
263 static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
268 if (ssp > MXC_SSPCLK_MAX)
271 tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
272 if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
273 return XTAL_FREQ_KHZ;
275 clkreg = &clkctrl_regs->hw_clkctrl_ssp0 +
276 ssp * sizeof(struct mxs_register_32);
278 tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
282 clk = mxs_get_ioclk(ssp >> 1);
288 * Set SSP/MMC bus frequency, in kHz)
290 void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
292 struct mxs_ssp_regs *ssp_regs;
293 const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
294 const uint32_t sspclk = mxs_get_sspclk(clk);
296 uint32_t divide, rate, tgtclk;
298 ssp_regs = mxs_ssp_regs_by_bus(bus);
301 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
302 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
303 * CLOCK_RATE could be any integer from 0 to 255.
305 for (divide = 2; divide < 254; divide += 2) {
306 rate = sspclk / freq / divide;
311 tgtclk = sspclk / divide / rate;
312 while (tgtclk > freq) {
314 tgtclk = sspclk / divide / rate;
319 /* Always set timeout the maximum */
320 reg = SSP_TIMING_TIMEOUT_MASK |
321 (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
322 ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
323 writel(reg, &ssp_regs->hw_ssp_timing);
325 debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
329 void mxs_set_lcdclk(uint32_t freq)
331 uint32_t fp, x, k_rest, k_best, x_best, tk;
332 int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
337 #if defined(CONFIG_MX23)
338 writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
339 #elif defined(CONFIG_MX28)
340 writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
345 * freq kHz = | 480000000 Hz * -- | * --- * ------
351 * k = -------------------
355 fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
357 for (x = 18; x <= 35; x++) {
359 if ((tk / 1000 == 0) || (tk / 1000 > 255))
364 if (k_rest < (k_best_l % 1000)) {
369 if (k_rest > (k_best_t % 1000)) {
375 if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
385 #if defined(CONFIG_MX23)
386 writeb(CLKCTRL_FRAC_CLKGATE,
387 &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
388 writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
389 &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
390 writeb(CLKCTRL_FRAC_CLKGATE,
391 &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
393 writel(CLKCTRL_PIX_CLKGATE,
394 &clkctrl_regs->hw_clkctrl_pix_set);
395 clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
396 CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
397 k_best << CLKCTRL_PIX_DIV_OFFSET);
399 while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
401 #elif defined(CONFIG_MX28)
402 writeb(CLKCTRL_FRAC_CLKGATE,
403 &clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
404 writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
405 &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
406 writeb(CLKCTRL_FRAC_CLKGATE,
407 &clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
409 writel(CLKCTRL_DIS_LCDIF_CLKGATE,
410 &clkctrl_regs->hw_clkctrl_lcdif_set);
411 clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
412 CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
413 k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
415 while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
420 static uint32_t mxs_get_xbus_clk(void)
424 uint32_t refclk = mxs_get_pclk();
426 clkctrl = readl(&clkctrl_regs->hw_clkctrl_xbus);
427 div = clkctrl & CLKCTRL_XBUS_DIV_MASK;
429 if (clkctrl & CLKCTRL_XBUS_DIV_FRAC_EN)
430 return get_frac_clk(refclk, div, CLKCTRL_XBUS_DIV_MASK);
435 uint32_t mxc_get_clock(enum mxc_clock clk)
439 return mxs_get_pclk() * 1000000;
441 return mxs_get_gpmiclk() * 1000000;
444 return mxs_get_hclk() * 1000000;
446 return mxs_get_emiclk();
448 return mxs_get_ioclk(MXC_IOCLK0);
450 return mxs_get_ioclk(MXC_IOCLK1);
452 return XTAL_FREQ_KHZ * 1000;
454 return mxs_get_sspclk(MXC_SSPCLK0);
457 return mxs_get_sspclk(MXC_SSPCLK1);
459 return mxs_get_sspclk(MXC_SSPCLK2);
461 return mxs_get_sspclk(MXC_SSPCLK3);
464 return mxs_get_xbus_clk() * 1000000;
466 printf("Invalid clock selector %u\n", clk);