]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/arm926ejs/mxs/clock.c
mxs: clock: use a single instance of the clkctrl_regs pointer for all functions
[karo-tx-uboot.git] / arch / arm / cpu / arm926ejs / mxs / 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 struct mxs_clkctrl_regs *clkctrl_regs = (void *)MXS_CLKCTRL_BASE;
45
46 static uint32_t mx28_get_pclk(void)
47 {
48         uint32_t clkctrl, clkseq, div;
49         uint8_t clkfrac, frac;
50
51         clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
52
53         /* No support of fractional divider calculation */
54         if (clkctrl &
55                 (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
56                 return 0;
57         }
58
59         clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
60
61         /* XTAL Path */
62         if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
63                 div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
64                         CLKCTRL_CPU_DIV_XTAL_OFFSET;
65                 return XTAL_FREQ_MHZ / div;
66         }
67
68         /* REF Path */
69         clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
70         frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
71         div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
72         return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
73 }
74
75 static uint32_t mx28_get_hclk(void)
76 {
77         uint32_t div;
78         uint32_t clkctrl;
79
80         clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
81
82         /* No support of fractional divider calculation */
83         if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
84                 return 0;
85
86         div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
87         return mx28_get_pclk() / div;
88 }
89
90 static uint32_t mx28_get_emiclk(void)
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 mx28_get_gpmiclk(void)
113 {
114         uint32_t clkctrl, clkseq, div;
115         uint8_t clkfrac, frac;
116
117         clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
118         clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
119
120         /* XTAL Path */
121         if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
122                 div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
123                 return XTAL_FREQ_MHZ / div;
124         }
125
126         /* REF Path */
127         clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]);
128         frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
129         div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
130         return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
131 }
132
133 /*
134  * Set IO clock frequency, in kHz
135  */
136 void mx28_set_ioclk(enum mxs_ioclock io, uint32_t freq)
137 {
138         uint32_t div;
139         int io_reg;
140
141         if (freq == 0)
142                 return;
143
144         if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
145                 return;
146
147         div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
148
149         if (div < 18)
150                 div = 18;
151
152         if (div > 35)
153                 div = 35;
154
155         io_reg = CLKCTRL_FRAC0_IO0 - io;        /* Register order is reversed */
156         writeb(CLKCTRL_FRAC_CLKGATE,
157                 &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
158         writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
159                 &clkctrl_regs->hw_clkctrl_frac0[io_reg]);
160         writeb(CLKCTRL_FRAC_CLKGATE,
161                 &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
162 }
163
164 /*
165  * Get IO clock, returns IO clock in kHz
166  */
167 static uint32_t mx28_get_ioclk(enum mxs_ioclock io)
168 {
169         uint8_t ret;
170         int io_reg;
171
172         if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
173                 return 0;
174
175         io_reg = CLKCTRL_FRAC0_IO0 - io;        /* Register order is reversed */
176
177         ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
178                 CLKCTRL_FRAC_FRAC_MASK;
179
180         return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
181 }
182
183 /*
184  * Configure SSP clock frequency, in kHz
185  */
186 void mx28_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
187 {
188         uint32_t clk, clkreg;
189
190         if (ssp > MXC_SSPCLK3)
191                 return;
192
193         clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
194                         (ssp * sizeof(struct mxs_register_32));
195
196         clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
197         while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
198                 ;
199
200         if (xtal)
201                 clk = XTAL_FREQ_KHZ;
202         else
203                 clk = mx28_get_ioclk(ssp >> 1);
204
205         if (freq > clk)
206                 return;
207
208         /* Calculate the divider and cap it if necessary */
209         clk /= freq;
210         if (clk > CLKCTRL_SSP_DIV_MASK)
211                 clk = CLKCTRL_SSP_DIV_MASK;
212
213         clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
214         while (readl(clkreg) & CLKCTRL_SSP_BUSY)
215                 ;
216
217         if (xtal)
218                 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
219                         &clkctrl_regs->hw_clkctrl_clkseq_set);
220         else
221                 writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
222                         &clkctrl_regs->hw_clkctrl_clkseq_clr);
223 }
224
225 /*
226  * Return SSP frequency, in kHz
227  */
228 static uint32_t mx28_get_sspclk(enum mxs_sspclock ssp)
229 {
230         uint32_t clkreg;
231         uint32_t clk, tmp;
232
233         if (ssp > MXC_SSPCLK3)
234                 return 0;
235
236         tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
237         if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
238                 return XTAL_FREQ_KHZ;
239
240         clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
241                         (ssp * sizeof(struct mxs_register_32));
242
243         tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
244
245         if (tmp == 0)
246                 return 0;
247
248         clk = mx28_get_ioclk(ssp >> 1);
249
250         return clk / tmp;
251 }
252
253 /*
254  * Set SSP/MMC bus frequency, in kHz)
255  */
256 void mx28_set_ssp_busclock(unsigned int bus, uint32_t freq)
257 {
258         struct mxs_ssp_regs *ssp_regs;
259         const uint32_t sspclk = mx28_get_sspclk(bus);
260         uint32_t reg;
261         uint32_t divide, rate, tgtclk;
262
263         ssp_regs = (struct mxs_ssp_regs *)(MXS_SSP0_BASE + (bus * 0x2000));
264
265         /*
266          * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
267          * CLOCK_DIVIDE has to be an even value from 2 to 254, and
268          * CLOCK_RATE could be any integer from 0 to 255.
269          */
270         for (divide = 2; divide < 254; divide += 2) {
271                 rate = sspclk / freq / divide;
272                 if (rate <= 256)
273                         break;
274         }
275
276         tgtclk = sspclk / divide / rate;
277         while (tgtclk > freq) {
278                 rate++;
279                 tgtclk = sspclk / divide / rate;
280         }
281         if (rate > 256)
282                 rate = 256;
283
284         /* Always set timeout the maximum */
285         reg = SSP_TIMING_TIMEOUT_MASK |
286                 (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
287                 ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
288         writel(reg, &ssp_regs->hw_ssp_timing);
289
290         debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
291                 bus, tgtclk, freq);
292 }
293
294 uint32_t mxc_get_clock(enum mxc_clock clk)
295 {
296         switch (clk) {
297         case MXC_ARM_CLK:
298                 return mx28_get_pclk() * 1000000;
299         case MXC_GPMI_CLK:
300                 return mx28_get_gpmiclk() * 1000000;
301         case MXC_AHB_CLK:
302         case MXC_IPG_CLK:
303                 return mx28_get_hclk() * 1000000;
304         case MXC_EMI_CLK:
305                 return mx28_get_emiclk();
306         case MXC_IO0_CLK:
307                 return mx28_get_ioclk(MXC_IOCLK0);
308         case MXC_IO1_CLK:
309                 return mx28_get_ioclk(MXC_IOCLK1);
310         case MXC_SSP0_CLK:
311                 return mx28_get_sspclk(MXC_SSPCLK0);
312         case MXC_SSP1_CLK:
313                 return mx28_get_sspclk(MXC_SSPCLK1);
314         case MXC_SSP2_CLK:
315                 return mx28_get_sspclk(MXC_SSPCLK2);
316         case MXC_SSP3_CLK:
317                 return mx28_get_sspclk(MXC_SSPCLK3);
318         case MXC_XTAL_CLK:
319                 return XTAL_FREQ_KHZ * 1000;
320         }
321
322         return 0;
323 }