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 uint32_t mxs_get_pclk(void)
39 struct mxs_clkctrl_regs
*clkctrl_regs
=
40 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
42 uint32_t clkctrl
, clkseq
, div
;
43 uint8_t clkfrac
, frac
;
45 clkctrl
= readl(&clkctrl_regs
->hw_clkctrl_cpu
);
47 /* No support of fractional divider calculation */
49 (CLKCTRL_CPU_DIV_XTAL_FRAC_EN
| CLKCTRL_CPU_DIV_CPU_FRAC_EN
)) {
53 clkseq
= readl(&clkctrl_regs
->hw_clkctrl_clkseq
);
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
;
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
;
69 static uint32_t mxs_get_hclk(void)
71 struct mxs_clkctrl_regs
*clkctrl_regs
=
72 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
77 clkctrl
= readl(&clkctrl_regs
->hw_clkctrl_hbus
);
79 /* No support of fractional divider calculation */
80 if (clkctrl
& CLKCTRL_HBUS_DIV_FRAC_EN
)
83 div
= clkctrl
& CLKCTRL_HBUS_DIV_MASK
;
84 return mxs_get_pclk() / div
;
87 static uint32_t mxs_get_emiclk(void)
89 struct mxs_clkctrl_regs
*clkctrl_regs
=
90 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
92 uint32_t clkctrl
, clkseq
, div
;
93 uint8_t clkfrac
, frac
;
95 clkseq
= readl(&clkctrl_regs
->hw_clkctrl_clkseq
);
96 clkctrl
= readl(&clkctrl_regs
->hw_clkctrl_emi
);
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
;
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
;
112 static uint32_t mxs_get_gpmiclk(void)
114 struct mxs_clkctrl_regs
*clkctrl_regs
=
115 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
116 #if defined(CONFIG_MX23)
118 &clkctrl_regs
->hw_clkctrl_frac0
[CLKCTRL_FRAC0_CPU
];
119 #elif defined(CONFIG_MX28)
121 &clkctrl_regs
->hw_clkctrl_frac1
[CLKCTRL_FRAC1_GPMI
];
123 uint32_t clkctrl
, clkseq
, div
;
124 uint8_t clkfrac
, frac
;
126 clkseq
= readl(&clkctrl_regs
->hw_clkctrl_clkseq
);
127 clkctrl
= readl(&clkctrl_regs
->hw_clkctrl_gpmi
);
130 if (clkseq
& CLKCTRL_CLKSEQ_BYPASS_GPMI
) {
131 div
= clkctrl
& CLKCTRL_GPMI_DIV_MASK
;
132 return XTAL_FREQ_MHZ
/ div
;
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
;
143 * Set IO clock frequency, in kHz
145 void mxs_set_ioclk(enum mxs_ioclock io
, uint32_t freq
)
147 struct mxs_clkctrl_regs
*clkctrl_regs
=
148 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
155 if ((io
< MXC_IOCLK0
) || (io
> MXC_IOCLK1
))
158 div
= (PLL_FREQ_KHZ
* PLL_FREQ_COEF
) / freq
;
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
]);
176 * Get IO clock, returns IO clock in kHz
178 static uint32_t mxs_get_ioclk(enum mxs_ioclock io
)
180 struct mxs_clkctrl_regs
*clkctrl_regs
=
181 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
185 if ((io
< MXC_IOCLK0
) || (io
> MXC_IOCLK1
))
188 io_reg
= CLKCTRL_FRAC0_IO0
- io
; /* Register order is reversed */
190 ret
= readb(&clkctrl_regs
->hw_clkctrl_frac0
[io_reg
]) &
191 CLKCTRL_FRAC_FRAC_MASK
;
193 return (PLL_FREQ_KHZ
* PLL_FREQ_COEF
) / ret
;
197 * Configure SSP clock frequency, in kHz
199 void mxs_set_sspclk(enum mxs_sspclock ssp
, uint32_t freq
, int xtal
)
201 struct mxs_clkctrl_regs
*clkctrl_regs
=
202 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
203 uint32_t clk
, clkreg
;
205 if (ssp
> MXC_SSPCLK_MAX
)
208 clkreg
= (uint32_t)(&clkctrl_regs
->hw_clkctrl_ssp0
) +
209 (ssp
* sizeof(struct mxs_register_32
));
211 clrbits_le32(clkreg
, CLKCTRL_SSP_CLKGATE
);
212 while (readl(clkreg
) & CLKCTRL_SSP_CLKGATE
)
218 clk
= mxs_get_ioclk(ssp
>> 1);
223 /* Calculate the divider and cap it if necessary */
225 if (clk
> CLKCTRL_SSP_DIV_MASK
)
226 clk
= CLKCTRL_SSP_DIV_MASK
;
228 clrsetbits_le32(clkreg
, CLKCTRL_SSP_DIV_MASK
, clk
);
229 while (readl(clkreg
) & CLKCTRL_SSP_BUSY
)
233 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0
<< ssp
,
234 &clkctrl_regs
->hw_clkctrl_clkseq_set
);
236 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0
<< ssp
,
237 &clkctrl_regs
->hw_clkctrl_clkseq_clr
);
241 * Return SSP frequency, in kHz
243 static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp
)
245 struct mxs_clkctrl_regs
*clkctrl_regs
=
246 (struct mxs_clkctrl_regs
*)MXS_CLKCTRL_BASE
;
250 if (ssp
> MXC_SSPCLK_MAX
)
253 tmp
= readl(&clkctrl_regs
->hw_clkctrl_clkseq
);
254 if (tmp
& (CLKCTRL_CLKSEQ_BYPASS_SSP0
<< ssp
))
255 return XTAL_FREQ_KHZ
;
257 clkreg
= (uint32_t)(&clkctrl_regs
->hw_clkctrl_ssp0
) +
258 (ssp
* sizeof(struct mxs_register_32
));
260 tmp
= readl(clkreg
) & CLKCTRL_SSP_DIV_MASK
;
265 clk
= mxs_get_ioclk(ssp
>> 1);
271 * Set SSP/MMC bus frequency, in kHz)
273 void mxs_set_ssp_busclock(unsigned int bus
, uint32_t freq
)
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
);
279 uint32_t divide
, rate
, tgtclk
;
281 ssp_regs
= mxs_ssp_regs_by_bus(bus
);
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.
288 for (divide
= 2; divide
< 254; divide
+= 2) {
289 rate
= sspclk
/ freq
/ divide
;
294 tgtclk
= sspclk
/ divide
/ rate
;
295 while (tgtclk
> freq
) {
297 tgtclk
= sspclk
/ divide
/ rate
;
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
);
308 debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
312 void mxs_set_lcdclk(uint32_t freq
)
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;
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
);
330 * freq kHz = | 480000000 Hz * -- | * --- * ------
336 * k = -------------------
340 fp
= ((PLL_FREQ_KHZ
* 1000) / freq
) * 18;
342 for (x
= 18; x
<= 35; x
++) {
344 if ((tk
/ 1000 == 0) || (tk
/ 1000 > 255))
349 if (k_rest
< (k_best_l
% 1000)) {
354 if (k_rest
> (k_best_t
% 1000)) {
360 if (1000 - (k_best_t
% 1000) > (k_best_l
% 1000)) {
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
]);
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
);
384 while (readl(&clkctrl_regs
->hw_clkctrl_pix
) & CLKCTRL_PIX_BUSY
)
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
]);
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
);
400 while (readl(&clkctrl_regs
->hw_clkctrl_lcdif
) & CLKCTRL_DIS_LCDIF_BUSY
)
405 uint32_t mxc_get_clock(enum mxc_clock clk
)
409 return mxs_get_pclk() * 1000000;
411 return mxs_get_gpmiclk() * 1000000;
414 return mxs_get_hclk() * 1000000;
416 return mxs_get_emiclk();
418 return mxs_get_ioclk(MXC_IOCLK0
);
420 return mxs_get_ioclk(MXC_IOCLK1
);
422 return XTAL_FREQ_KHZ
* 1000;
424 return mxs_get_sspclk(MXC_SSPCLK0
);
427 return mxs_get_sspclk(MXC_SSPCLK1
);
429 return mxs_get_sspclk(MXC_SSPCLK2
);
431 return mxs_get_sspclk(MXC_SSPCLK3
);