]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/arm926ejs/mx28/clock.c
Merge branch 'master' of git://git.denx.de/u-boot-mpc83xx
[karo-tx-uboot.git] / arch / arm / cpu / arm926ejs / mx28 / clock.c
1 /*
2  * Freescale 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  * See file CREDITS for list of people who contributed to this
11  * project.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation; either version 2 of
16  * the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26  * MA 02111-1307 USA
27  */
28
29 #include <common.h>
30 #include <asm/errno.h>
31 #include <asm/io.h>
32 #include <asm/arch/clock.h>
33 #include <asm/arch/imx-regs.h>
34
35 /* The PLL frequency is always 480MHz, see section 10.2 in iMX28 datasheet. */
36 #define PLL_FREQ_KHZ    480000
37 #define PLL_FREQ_COEF   18
38 /* The XTAL frequency is always 24MHz, see section 10.2 in iMX28 datasheet. */
39 #define XTAL_FREQ_KHZ   24000
40
41 #define PLL_FREQ_MHZ    (PLL_FREQ_KHZ / 1000)
42 #define XTAL_FREQ_MHZ   (XTAL_FREQ_KHZ / 1000)
43
44 static uint32_t mx28_get_pclk(void)
45 {
46         struct mx28_clkctrl_regs *clkctrl_regs =
47                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
48
49         uint32_t clkctrl, clkseq, clkfrac;
50         uint32_t frac, div;
51
52         clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
53
54         /* No support of fractional divider calculation */
55         if (clkctrl &
56                 (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
57                 return 0;
58         }
59
60         clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
61
62         /* XTAL Path */
63         if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
64                 div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
65                         CLKCTRL_CPU_DIV_XTAL_OFFSET;
66                 return XTAL_FREQ_MHZ / div;
67         }
68
69         /* REF Path */
70         clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac0);
71         frac = clkfrac & CLKCTRL_FRAC0_CPUFRAC_MASK;
72         div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
73         return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
74 }
75
76 static uint32_t mx28_get_hclk(void)
77 {
78         struct mx28_clkctrl_regs *clkctrl_regs =
79                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
80
81         uint32_t div;
82         uint32_t clkctrl;
83
84         clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
85
86         /* No support of fractional divider calculation */
87         if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
88                 return 0;
89
90         div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
91         return mx28_get_pclk() / div;
92 }
93
94 static uint32_t mx28_get_emiclk(void)
95 {
96         struct mx28_clkctrl_regs *clkctrl_regs =
97                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
98
99         uint32_t frac, div;
100         uint32_t clkctrl, clkseq, clkfrac;
101
102         clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
103         clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
104
105         /* XTAL Path */
106         if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
107                 div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
108                         CLKCTRL_EMI_DIV_XTAL_OFFSET;
109                 return XTAL_FREQ_MHZ / div;
110         }
111
112         clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac0);
113
114         /* REF Path */
115         frac = (clkfrac & CLKCTRL_FRAC0_EMIFRAC_MASK) >>
116                 CLKCTRL_FRAC0_EMIFRAC_OFFSET;
117         div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
118         return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
119 }
120
121 static uint32_t mx28_get_gpmiclk(void)
122 {
123         struct mx28_clkctrl_regs *clkctrl_regs =
124                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
125
126         uint32_t frac, div;
127         uint32_t clkctrl, clkseq, clkfrac;
128
129         clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
130         clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
131
132         /* XTAL Path */
133         if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
134                 div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
135                 return XTAL_FREQ_MHZ / div;
136         }
137
138         clkfrac = readl(&clkctrl_regs->hw_clkctrl_frac1);
139
140         /* REF Path */
141         frac = (clkfrac & CLKCTRL_FRAC1_GPMIFRAC_MASK) >>
142                 CLKCTRL_FRAC1_GPMIFRAC_OFFSET;
143         div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
144         return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
145 }
146
147 /*
148  * Set IO clock frequency, in kHz
149  */
150 void mx28_set_ioclk(enum mxs_ioclock io, uint32_t freq)
151 {
152         struct mx28_clkctrl_regs *clkctrl_regs =
153                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
154         uint32_t div;
155
156         if (freq == 0)
157                 return;
158
159         if (io > MXC_IOCLK1)
160                 return;
161
162         div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
163
164         if (div < 18)
165                 div = 18;
166
167         if (div > 35)
168                 div = 35;
169
170         if (io == MXC_IOCLK0) {
171                 writel(CLKCTRL_FRAC0_CLKGATEIO0,
172                         &clkctrl_regs->hw_clkctrl_frac0_set);
173                 clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0,
174                                 CLKCTRL_FRAC0_IO0FRAC_MASK,
175                                 div << CLKCTRL_FRAC0_IO0FRAC_OFFSET);
176                 writel(CLKCTRL_FRAC0_CLKGATEIO0,
177                         &clkctrl_regs->hw_clkctrl_frac0_clr);
178         } else {
179                 writel(CLKCTRL_FRAC0_CLKGATEIO1,
180                         &clkctrl_regs->hw_clkctrl_frac0_set);
181                 clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0,
182                                 CLKCTRL_FRAC0_IO1FRAC_MASK,
183                                 div << CLKCTRL_FRAC0_IO1FRAC_OFFSET);
184                 writel(CLKCTRL_FRAC0_CLKGATEIO1,
185                         &clkctrl_regs->hw_clkctrl_frac0_clr);
186         }
187 }
188
189 /*
190  * Get IO clock, returns IO clock in kHz
191  */
192 static uint32_t mx28_get_ioclk(enum mxs_ioclock io)
193 {
194         struct mx28_clkctrl_regs *clkctrl_regs =
195                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
196         uint32_t tmp, ret;
197
198         if (io > MXC_IOCLK1)
199                 return 0;
200
201         tmp = readl(&clkctrl_regs->hw_clkctrl_frac0);
202
203         if (io == MXC_IOCLK0)
204                 ret = (tmp & CLKCTRL_FRAC0_IO0FRAC_MASK) >>
205                         CLKCTRL_FRAC0_IO0FRAC_OFFSET;
206         else
207                 ret = (tmp & CLKCTRL_FRAC0_IO1FRAC_MASK) >>
208                         CLKCTRL_FRAC0_IO1FRAC_OFFSET;
209
210         return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
211 }
212
213 /*
214  * Configure SSP clock frequency, in kHz
215  */
216 void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
217 {
218         struct mx28_clkctrl_regs *clkctrl_regs =
219                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
220         uint32_t clk, clkreg;
221
222         if (ssp > MXC_SSPCLK3)
223                 return;
224
225         clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
226                         (ssp * sizeof(struct mx28_register));
227
228         clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
229         while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
230                 ;
231
232         if (xtal)
233                 clk = XTAL_FREQ_KHZ;
234         else
235                 clk = mx28_get_ioclk(ssp >> 1);
236
237         if (freq > clk)
238                 return;
239
240         /* Calculate the divider and cap it if necessary */
241         clk /= freq;
242         if (clk > CLKCTRL_SSP_DIV_MASK)
243                 clk = CLKCTRL_SSP_DIV_MASK;
244
245         clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
246         while (readl(clkreg) & CLKCTRL_SSP_BUSY)
247                 ;
248
249         if (xtal)
250                 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
251                         &clkctrl_regs->hw_clkctrl_clkseq_set);
252         else
253                 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
254                         &clkctrl_regs->hw_clkctrl_clkseq_clr);
255 }
256
257 /*
258  * Return SSP frequency, in kHz
259  */
260 static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp)
261 {
262         struct mx28_clkctrl_regs *clkctrl_regs =
263                 (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
264         uint32_t clkreg;
265         uint32_t clk, tmp;
266
267         if (ssp > MXC_SSPCLK3)
268                 return 0;
269
270         tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
271         if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
272                 return XTAL_FREQ_KHZ;
273
274         clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
275                         (ssp * sizeof(struct mx28_register));
276
277         tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
278
279         if (tmp == 0)
280                 return 0;
281
282         clk = mx28_get_ioclk(ssp >> 1);
283
284         return clk / tmp;
285 }
286
287 /*
288  * Set SSP/MMC bus frequency, in kHz)
289  */
290 void mx28_set_ssp_busclock(unsigned int bus, uint32_t freq)
291 {
292         struct mx28_ssp_regs *ssp_regs;
293         const uint32_t sspclk = mx28_get_sspclk(bus);
294         uint32_t reg;
295         uint32_t divide, rate, tgtclk;
296
297         ssp_regs = (struct mx28_ssp_regs *)(MXS_SSP0_BASE + (bus * 0x2000));
298
299         /*
300          * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
301          * CLOCK_DIVIDE has to be an even value from 2 to 254, and
302          * CLOCK_RATE could be any integer from 0 to 255.
303          */
304         for (divide = 2; divide < 254; divide += 2) {
305                 rate = sspclk / freq / divide;
306                 if (rate <= 256)
307                         break;
308         }
309
310         tgtclk = sspclk / divide / rate;
311         while (tgtclk > freq) {
312                 rate++;
313                 tgtclk = sspclk / divide / rate;
314         }
315         if (rate > 256)
316                 rate = 256;
317
318         /* Always set timeout the maximum */
319         reg = SSP_TIMING_TIMEOUT_MASK |
320                 (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
321                 ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
322         writel(reg, &ssp_regs->hw_ssp_timing);
323
324         debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
325                 bus, tgtclk, freq);
326 }
327
328 uint32_t mxc_get_clock(enum mxc_clock clk)
329 {
330         switch (clk) {
331         case MXC_ARM_CLK:
332                 return mx28_get_pclk() * 1000000;
333         case MXC_GPMI_CLK:
334                 return mx28_get_gpmiclk() * 1000000;
335         case MXC_AHB_CLK:
336         case MXC_IPG_CLK:
337                 return mx28_get_hclk() * 1000000;
338         case MXC_EMI_CLK:
339                 return mx28_get_emiclk();
340         case MXC_IO0_CLK:
341                 return mx28_get_ioclk(MXC_IOCLK0);
342         case MXC_IO1_CLK:
343                 return mx28_get_ioclk(MXC_IOCLK1);
344         case MXC_SSP0_CLK:
345                 return mx28_get_sspclk(MXC_SSPCLK0);
346         case MXC_SSP1_CLK:
347                 return mx28_get_sspclk(MXC_SSPCLK1);
348         case MXC_SSP2_CLK:
349                 return mx28_get_sspclk(MXC_SSPCLK2);
350         case MXC_SSP3_CLK:
351                 return mx28_get_sspclk(MXC_SSPCLK3);
352         }
353
354         return 0;
355 }