]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/mx5/clock.c
e92f10623a92bb6e72c2d4c3e947f58dffcce78b
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx5 / clock.c
1 /*
2  * (C) Copyright 2007
3  * Sascha Hauer, Pengutronix
4  *
5  * (C) Copyright 2009 Freescale Semiconductor, Inc.
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 #include <common.h>
27 #include <asm/io.h>
28 #include <asm/errno.h>
29 #include <asm/arch/imx-regs.h>
30 #include <asm/arch/crm_regs.h>
31 #include <asm/arch/clock.h>
32 #include <div64.h>
33
34 enum pll_clocks {
35         PLL1_CLOCK = 0,
36         PLL2_CLOCK,
37         PLL3_CLOCK,
38         PLL4_CLOCK,
39         PLL_CLOCKS,
40 };
41
42 struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
43         [PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
44         [PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
45         [PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
46 #ifdef  CONFIG_MX53
47         [PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
48 #endif
49 };
50
51 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
52
53 void set_usboh3_clk(void)
54 {
55         unsigned int reg;
56
57         reg = readl(&mxc_ccm->cscmr1) &
58                  ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
59         reg |= 1 << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
60         writel(reg, &mxc_ccm->cscmr1);
61
62         reg = readl(&mxc_ccm->cscdr1);
63         reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
64         reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;
65         reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
66         reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
67
68         writel(reg, &mxc_ccm->cscdr1);
69 }
70
71 void enable_usboh3_clk(unsigned char enable)
72 {
73         unsigned int reg;
74
75         reg = readl(&mxc_ccm->CCGR2);
76         if (enable)
77                 reg |= 1 << MXC_CCM_CCGR2_CG14_OFFSET;
78         else
79                 reg &= ~(1 << MXC_CCM_CCGR2_CG14_OFFSET);
80         writel(reg, &mxc_ccm->CCGR2);
81 }
82
83 void set_usb_phy1_clk(void)
84 {
85         unsigned int reg;
86
87         reg = readl(&mxc_ccm->cscmr1);
88         reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
89         writel(reg, &mxc_ccm->cscmr1);
90 }
91
92 void enable_usb_phy1_clk(unsigned char enable)
93 {
94         unsigned int reg;
95
96         reg = readl(&mxc_ccm->CCGR4);
97         if (enable)
98                 reg |= 1 << MXC_CCM_CCGR4_CG5_OFFSET;
99         else
100                 reg &= ~(1 << MXC_CCM_CCGR4_CG5_OFFSET);
101         writel(reg, &mxc_ccm->CCGR4);
102 }
103
104 void set_usb_phy2_clk(void)
105 {
106         unsigned int reg;
107
108         reg = readl(&mxc_ccm->cscmr1);
109         reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
110         writel(reg, &mxc_ccm->cscmr1);
111 }
112
113 void enable_usb_phy2_clk(unsigned char enable)
114 {
115         unsigned int reg;
116
117         reg = readl(&mxc_ccm->CCGR4);
118         if (enable)
119                 reg |= 1 << MXC_CCM_CCGR4_CG6_OFFSET;
120         else
121                 reg &= ~(1 << MXC_CCM_CCGR4_CG6_OFFSET);
122         writel(reg, &mxc_ccm->CCGR4);
123 }
124
125 /*
126  * Calculate the frequency of PLLn.
127  */
128 static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
129 {
130         uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
131         uint64_t refclk, temp;
132         int32_t mfn_abs;
133
134         ctrl = readl(&pll->ctrl);
135
136         if (ctrl & MXC_DPLLC_CTL_HFSM) {
137                 mfn = __raw_readl(&pll->hfs_mfn);
138                 mfd = __raw_readl(&pll->hfs_mfd);
139                 op = __raw_readl(&pll->hfs_op);
140         } else {
141                 mfn = __raw_readl(&pll->mfn);
142                 mfd = __raw_readl(&pll->mfd);
143                 op = __raw_readl(&pll->op);
144         }
145
146         mfd &= MXC_DPLLC_MFD_MFD_MASK;
147         mfn &= MXC_DPLLC_MFN_MFN_MASK;
148         pdf = op & MXC_DPLLC_OP_PDF_MASK;
149         mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET;
150
151         /* 21.2.3 */
152         if (mfi < 5)
153                 mfi = 5;
154
155         /* Sign extend */
156         if (mfn >= 0x04000000) {
157                 mfn |= 0xfc000000;
158                 mfn_abs = -mfn;
159         } else
160                 mfn_abs = mfn;
161
162         refclk = infreq * 2;
163         if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
164                 refclk *= 2;
165
166         do_div(refclk, pdf + 1);
167         temp = refclk * mfn_abs;
168         do_div(temp, mfd + 1);
169         ret = refclk * mfi;
170
171         if ((int)mfn < 0)
172                 ret -= temp;
173         else
174                 ret += temp;
175
176         return ret;
177 }
178
179 /*
180  * Get mcu main rate
181  */
182 u32 get_mcu_main_clk(void)
183 {
184         u32 reg, freq;
185
186         reg = (__raw_readl(&mxc_ccm->cacrr) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
187                 MXC_CCM_CACRR_ARM_PODF_OFFSET;
188         freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
189         return freq / (reg + 1);
190 }
191
192 /*
193  * Get the rate of peripheral's root clock.
194  */
195 static u32 get_periph_clk(void)
196 {
197         u32 reg;
198
199         reg = __raw_readl(&mxc_ccm->cbcdr);
200         if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
201                 return decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
202         reg = __raw_readl(&mxc_ccm->cbcmr);
203         switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
204                 MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
205         case 0:
206                 return decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
207         case 1:
208                 return decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
209         default:
210                 return 0;
211         }
212         /* NOTREACHED */
213 }
214
215 /*
216  * Get the rate of ahb clock.
217  */
218 static u32 get_ahb_clk(void)
219 {
220         uint32_t freq, div, reg;
221
222         freq = get_periph_clk();
223
224         reg = __raw_readl(&mxc_ccm->cbcdr);
225         div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
226                         MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
227
228         return freq / div;
229 }
230
231 /*
232  * Get the rate of ipg clock.
233  */
234 static u32 get_ipg_clk(void)
235 {
236         uint32_t freq, reg, div;
237
238         freq = get_ahb_clk();
239
240         reg = __raw_readl(&mxc_ccm->cbcdr);
241         div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
242                         MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
243
244         return freq / div;
245 }
246
247 /*
248  * Get the rate of ipg_per clock.
249  */
250 static u32 get_ipg_per_clk(void)
251 {
252         u32 pred1, pred2, podf;
253
254         if (__raw_readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
255                 return get_ipg_clk();
256         /* Fixme: not handle what about lpm*/
257         podf = __raw_readl(&mxc_ccm->cbcdr);
258         pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
259                 MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
260         pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
261                 MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
262         podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
263                 MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
264
265         return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
266 }
267
268 /*
269  * Get the rate of uart clk.
270  */
271 static u32 get_uart_clk(void)
272 {
273         unsigned int freq, reg, pred, podf;
274
275         reg = __raw_readl(&mxc_ccm->cscmr1);
276         switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
277                 MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
278         case 0x0:
279                 freq = decode_pll(mxc_plls[PLL1_CLOCK],
280                                     CONFIG_SYS_MX5_HCLK);
281                 break;
282         case 0x1:
283                 freq = decode_pll(mxc_plls[PLL2_CLOCK],
284                                     CONFIG_SYS_MX5_HCLK);
285                 break;
286         case 0x2:
287                 freq = decode_pll(mxc_plls[PLL3_CLOCK],
288                                     CONFIG_SYS_MX5_HCLK);
289                 break;
290         default:
291                 return 66500000;
292         }
293
294         reg = __raw_readl(&mxc_ccm->cscdr1);
295
296         pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
297                 MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
298
299         podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
300                 MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
301         freq /= (pred + 1) * (podf + 1);
302
303         return freq;
304 }
305
306 /*
307  * This function returns the low power audio clock.
308  */
309 u32 get_lp_apm(void)
310 {
311         u32 ret_val = 0;
312         u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
313
314         if (((ccsr >> 9) & 1) == 0)
315                 ret_val = CONFIG_SYS_MX5_HCLK;
316         else
317                 ret_val = ((32768 * 1024));
318
319         return ret_val;
320 }
321
322 /*
323  * get cspi clock rate.
324  */
325 u32 imx_get_cspiclk(void)
326 {
327         u32 ret_val = 0, pdf, pre_pdf, clk_sel;
328         u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
329         u32 cscdr2 = __raw_readl(&mxc_ccm->cscdr2);
330
331         pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
332                         >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
333         pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
334                         >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
335         clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
336                         >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
337
338         switch (clk_sel) {
339         case 0:
340                 ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
341                                         CONFIG_SYS_MX5_HCLK) /
342                                         ((pre_pdf + 1) * (pdf + 1));
343                 break;
344         case 1:
345                 ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
346                                         CONFIG_SYS_MX5_HCLK) /
347                                         ((pre_pdf + 1) * (pdf + 1));
348                 break;
349         case 2:
350                 ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
351                                         CONFIG_SYS_MX5_HCLK) /
352                                         ((pre_pdf + 1) * (pdf + 1));
353                 break;
354         default:
355                 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
356                 break;
357         }
358
359         return ret_val;
360 }
361
362 /*
363  * The API of get mxc clockes.
364  */
365 unsigned int mxc_get_clock(enum mxc_clock clk)
366 {
367         switch (clk) {
368         case MXC_ARM_CLK:
369                 return get_mcu_main_clk();
370         case MXC_AHB_CLK:
371                 return get_ahb_clk();
372         case MXC_IPG_CLK:
373                 return get_ipg_clk();
374         case MXC_IPG_PERCLK:
375                 return get_ipg_per_clk();
376         case MXC_UART_CLK:
377                 return get_uart_clk();
378         case MXC_CSPI_CLK:
379                 return imx_get_cspiclk();
380         case MXC_FEC_CLK:
381                 return decode_pll(mxc_plls[PLL1_CLOCK],
382                                     CONFIG_SYS_MX5_HCLK);
383         default:
384                 break;
385         }
386         return -1;
387 }
388
389 u32 imx_get_uartclk(void)
390 {
391         return get_uart_clk();
392 }
393
394
395 u32 imx_get_fecclk(void)
396 {
397         return mxc_get_clock(MXC_IPG_CLK);
398 }
399
400 /*
401  * Dump some core clockes.
402  */
403 int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
404 {
405         u32 freq;
406
407         freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
408         printf("PLL1       %8d MHz\n", freq / 1000000);
409         freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
410         printf("PLL2       %8d MHz\n", freq / 1000000);
411         freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
412         printf("PLL3       %8d MHz\n", freq / 1000000);
413 #ifdef  CONFIG_MX53
414         freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
415         printf("PLL4       %8d MHz\n", freq / 1000000);
416 #endif
417
418         printf("\n");
419         printf("AHB        %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
420         printf("IPG        %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
421         printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
422
423         return 0;
424 }
425
426 /***************************************************/
427
428 U_BOOT_CMD(
429         clocks, CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,
430         "display clocks",
431         ""
432 );