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