]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/mx6/clock.c
make mxc_set_clock() actually functional
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx6 / clock.c
1 /*
2  * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 #include <common.h>
24 #include <asm/io.h>
25 #include <asm/errno.h>
26 #include <asm/arch/imx-regs.h>
27 #include <asm/arch/crm_regs.h>
28 #include <asm/arch/clock.h>
29 #include <asm/arch/sys_proto.h>
30
31 enum pll_clocks {
32         PLL_ARM,        /* PLL1: ARM PLL */
33         PLL_BUS,        /* PLL2: System Bus PLL*/
34         PLL_USBOTG,     /* PLL3: OTG USB PLL */
35         PLL_AUDIO,      /* PLL4: Audio PLL */
36         PLL_VIDEO,      /* PLL5: Video PLL */
37         PLL_ENET,       /* PLL6: ENET PLL */
38         PLL_USB2,       /* PLL7: USB2 PLL */
39         PLL_MLB,        /* PLL8: MLB PLL */
40 };
41
42 struct mxc_ccm_reg *const imx_ccm = (void *)CCM_BASE_ADDR;
43 struct anatop_regs *const anatop = (void *)ANATOP_BASE_ADDR;
44
45 int clk_enable(struct clk *clk)
46 {
47         int ret = 0;
48
49         if (!clk)
50                 return 0;
51         if (clk->usecount == 0) {
52 debug("%s: Enabling %s clock\n", __func__, clk->name);
53                 ret = clk->enable(clk);
54                 if (ret)
55                         return ret;
56                 clk->usecount++;
57         }
58         assert(clk->usecount > 0);
59         return ret;
60 }
61
62 void clk_disable(struct clk *clk)
63 {
64         if (!clk)
65                 return;
66
67         assert(clk->usecount > 0);
68         if (!(--clk->usecount)) {
69                 if (clk->disable) {
70 debug("%s: Disabling %s clock\n", __func__, clk->name);
71                         clk->disable(clk);
72                 }
73         }
74 }
75
76 void enable_usboh3_clk(unsigned char enable)
77 {
78         u32 reg;
79
80         reg = __raw_readl(&imx_ccm->CCGR6);
81         if (enable)
82                 reg |= MXC_CCM_CCGR6_USBOH3_MASK;
83         else
84                 reg &= ~(MXC_CCM_CCGR6_USBOH3_MASK);
85         __raw_writel(reg, &imx_ccm->CCGR6);
86
87 }
88
89 #ifdef CONFIG_I2C_MXC
90 /* i2c_num can be from 0 - 2 */
91 int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
92 {
93         u32 reg;
94         u32 mask;
95
96         if (i2c_num > 2)
97                 return -EINVAL;
98
99         mask = MXC_CCM_CCGR_CG_MASK
100                 << (MXC_CCM_CCGR2_I2C1_SERIAL_OFFSET + (i2c_num << 1));
101         reg = __raw_readl(&imx_ccm->CCGR2);
102         if (enable)
103                 reg |= mask;
104         else
105                 reg &= ~mask;
106         __raw_writel(reg, &imx_ccm->CCGR2);
107         return 0;
108 }
109 #endif
110
111 static u32 decode_pll(enum pll_clocks pll, u32 infreq)
112 {
113         u32 div;
114
115         switch (pll) {
116         case PLL_ARM:
117                 div = __raw_readl(&anatop->pll_arm);
118                 if (div & BM_ANADIG_PLL_ARM_BYPASS)
119                         /* Assume the bypass clock is always derived from OSC */
120                         return infreq;
121                 div &= BM_ANADIG_PLL_ARM_DIV_SELECT;
122
123                 return infreq * div / 2;
124         case PLL_BUS:
125                 div = __raw_readl(&anatop->pll_528);
126                 if (div & BM_ANADIG_PLL_SYS_BYPASS)
127                         return infreq;
128                 div &= BM_ANADIG_PLL_SYS_DIV_SELECT;
129
130                 return infreq * (20 + div * 2);
131         case PLL_USBOTG:
132                 div = __raw_readl(&anatop->usb1_pll_480_ctrl);
133                 if (div & BM_ANADIG_USB1_PLL_480_CTRL_BYPASS)
134                         return infreq;
135                 div &= BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT;
136
137                 return infreq * (20 + div * 2);
138         case PLL_AUDIO:
139                 div = __raw_readl(&anatop->pll_audio);
140                 if (div & BM_ANADIG_PLL_AUDIO_BYPASS)
141                         return infreq;
142                 div &= BM_ANADIG_PLL_AUDIO_DIV_SELECT;
143
144                 return infreq * div;
145         case PLL_VIDEO:
146                 div = __raw_readl(&anatop->pll_video);
147                 if (div & BM_ANADIG_PLL_VIDEO_BYPASS)
148                         return infreq;
149                 div &= BM_ANADIG_PLL_VIDEO_DIV_SELECT;
150
151                 return infreq * div;
152         case PLL_ENET:
153                 div = __raw_readl(&anatop->pll_enet);
154                 if (div & BM_ANADIG_PLL_ENET_BYPASS)
155                         return infreq;
156                 div &= BM_ANADIG_PLL_ENET_DIV_SELECT;
157
158                 return (div == 3 ? 125000000 : 25000000 * div * 2);
159         case PLL_USB2:
160                 div = __raw_readl(&anatop->usb2_pll_480_ctrl);
161                 if (div & BM_ANADIG_USB2_PLL_480_CTRL_BYPASS)
162                         return infreq;
163                 div &= BM_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT;
164
165                 return infreq * (20 + div * 2);
166         case PLL_MLB:
167                 div = __raw_readl(&anatop->pll_mlb);
168                 if (div & BM_ANADIG_PLL_MLB_BYPASS)
169                         return infreq;
170                 /* unknown external clock provided on MLB_CLK pin */
171                 return 0;
172         }
173         return 0;
174 }
175
176 static u32 get_mcu_main_clk(void)
177 {
178         u32 reg, freq;
179
180         reg = __raw_readl(&imx_ccm->cacrr);
181         reg &= MXC_CCM_CACRR_ARM_PODF_MASK;
182         reg >>= MXC_CCM_CACRR_ARM_PODF_OFFSET;
183         freq = decode_pll(PLL_ARM, MXC_HCLK);
184
185         return freq / (reg + 1);
186 }
187
188 u32 get_periph_clk(void)
189 {
190         u32 reg, freq = 0;
191
192         reg = __raw_readl(&imx_ccm->cbcdr);
193         if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
194                 reg = __raw_readl(&imx_ccm->cbcmr);
195                 reg &= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK;
196                 reg >>= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET;
197
198                 switch (reg) {
199                 case 0:
200                         freq = decode_pll(PLL_USBOTG, MXC_HCLK);
201                         break;
202                 case 1:
203                 case 2:
204                         freq = MXC_HCLK;
205                         break;
206                 }
207         } else {
208                 reg = __raw_readl(&imx_ccm->cbcmr);
209                 reg &= MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK;
210                 reg >>= MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET;
211
212                 switch (reg) {
213                 case 0:
214                         freq = decode_pll(PLL_BUS, MXC_HCLK);
215                         break;
216                 case 1:
217                         freq = PLL2_PFD2_FREQ;
218                         break;
219                 case 2:
220                         freq = PLL2_PFD0_FREQ;
221                         break;
222                 case 3:
223                         freq = PLL2_PFD2_DIV_FREQ;
224                         break;
225                 }
226         }
227
228         return freq;
229 }
230
231 static u32 get_ipg_clk(void)
232 {
233         u32 reg, ipg_podf;
234
235         reg = __raw_readl(&imx_ccm->cbcdr);
236         reg &= MXC_CCM_CBCDR_IPG_PODF_MASK;
237         ipg_podf = reg >> MXC_CCM_CBCDR_IPG_PODF_OFFSET;
238
239         return get_ahb_clk() / (ipg_podf + 1);
240 }
241
242 static u32 get_ipg_per_clk(void)
243 {
244         u32 reg, perclk_podf;
245
246         reg = __raw_readl(&imx_ccm->cscmr1);
247         perclk_podf = reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK;
248
249         return get_ipg_clk() / (perclk_podf + 1);
250 }
251
252 static u32 get_uart_clk(void)
253 {
254         u32 reg, uart_podf;
255
256         reg = __raw_readl(&imx_ccm->cscdr1);
257         reg &= MXC_CCM_CSCDR1_UART_CLK_PODF_MASK;
258         uart_podf = reg >> MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
259
260         return PLL3_80M / (uart_podf + 1);
261 }
262
263 static u32 get_cspi_clk(void)
264 {
265         u32 reg, cspi_podf;
266
267         reg = __raw_readl(&imx_ccm->cscdr2);
268         reg &= MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK;
269         cspi_podf = reg >> MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET;
270
271         return  PLL3_60M / (cspi_podf + 1);
272 }
273
274 static u32 get_axi_clk(void)
275 {
276         u32 root_freq, axi_podf;
277         u32 cbcdr =  __raw_readl(&imx_ccm->cbcdr);
278
279         axi_podf = cbcdr & MXC_CCM_CBCDR_AXI_PODF_MASK;
280         axi_podf >>= MXC_CCM_CBCDR_AXI_PODF_OFFSET;
281
282         if (cbcdr & MXC_CCM_CBCDR_AXI_SEL) {
283                 if (cbcdr & MXC_CCM_CBCDR_AXI_ALT_SEL)
284                         root_freq = PLL2_PFD2_FREQ;
285                 else
286                         root_freq = PLL3_PFD1_FREQ;
287         } else
288                 root_freq = get_periph_clk();
289
290         return  root_freq / (axi_podf + 1);
291 }
292
293 static u32 get_emi_slow_clk(void)
294 {
295         u32 emi_clk_sel, emi_slow_pof, cscmr1, root_freq = 0;
296
297         cscmr1 =  __raw_readl(&imx_ccm->cscmr1);
298         emi_clk_sel = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK;
299         emi_clk_sel >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET;
300         emi_slow_pof = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK;
301         emi_slow_pof >>= MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET;
302
303         switch (emi_clk_sel) {
304         case 0:
305                 root_freq = get_axi_clk();
306                 break;
307         case 1:
308                 root_freq = decode_pll(PLL_USBOTG, MXC_HCLK);
309                 break;
310         case 2:
311                 root_freq = PLL2_PFD2_FREQ;
312                 break;
313         case 3:
314                 root_freq = PLL2_PFD0_FREQ;
315                 break;
316         }
317
318         return root_freq / (emi_slow_pof + 1);
319 }
320
321 static u32 get_nfc_clk(void)
322 {
323         u32 cs2cdr = __raw_readl(&imx_ccm->cs2cdr);
324         u32 podf = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK) >> MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET;
325         u32 pred = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK) >> MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET;
326         int nfc_clk_sel = (cs2cdr & MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK) >>
327                 MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET;
328         u32 root_freq;
329
330         switch (nfc_clk_sel) {
331         case 0:
332                 root_freq = PLL2_PFD0_FREQ;
333                 break;
334         case 1:
335                 root_freq = decode_pll(PLL_BUS, MXC_HCLK);
336                 break;
337         case 2:
338                 root_freq = decode_pll(PLL_USBOTG, MXC_HCLK);
339                 break;
340         case 3:
341                 root_freq = PLL2_PFD2_FREQ;
342                 break;
343         }
344         debug("root=%d[%u] freq=%u pred=%u podf=%u\n", nfc_clk_sel,
345                 root_freq, root_freq / (pred + 1) / (podf + 1), pred + 1, podf + 1);
346
347         return root_freq / (pred + 1) / (podf + 1);
348 }
349
350 #define CS2CDR_ENFC_MASK        (MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK |    \
351                                 MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK |     \
352                                 MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK)
353
354 static int set_nfc_clk(u32 ref, u32 freq_khz)
355 {
356         u32 cs2cdr = __raw_readl(&imx_ccm->cs2cdr);
357         u32 podf;
358         u32 pred;
359         int nfc_clk_sel;
360         u32 root_freq;
361         u32 min_err = ~0;
362         u32 nfc_val = ~0;
363         u32 freq = freq_khz * 1000;
364
365         for (nfc_clk_sel = 0; nfc_clk_sel < 4; nfc_clk_sel++) {
366                 u32 act_freq;
367                 u32 err;
368
369                 if (ref < 4 && ref != nfc_clk_sel)
370                         continue;
371
372                 switch (nfc_clk_sel) {
373                 case 0:
374                         root_freq = PLL2_PFD0_FREQ;
375                         break;
376                 case 1:
377                         root_freq = decode_pll(PLL_BUS, MXC_HCLK);
378                         break;
379                 case 2:
380                         root_freq = decode_pll(PLL_USBOTG, MXC_HCLK);
381                         break;
382                 case 3:
383                         root_freq = PLL2_PFD2_FREQ;
384                         break;
385                 }
386                 if (root_freq < freq)
387                         continue;
388
389                 podf = min(DIV_ROUND_UP(root_freq, freq), 1 << 6);
390                 pred = min(DIV_ROUND_UP(root_freq / podf, freq), 8);
391                 act_freq = root_freq / pred / podf;
392                 err = (freq - act_freq) * 100 / freq;
393                 debug("root=%d[%u] freq=%u pred=%u podf=%u act=%u err=%d\n",
394                         nfc_clk_sel, root_freq, freq, pred, podf, act_freq, err);
395                 if (act_freq > freq)
396                         continue;
397                 if (err < min_err) {
398                         nfc_val = (podf - 1) << MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET;
399                         nfc_val |= (pred - 1) << MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET;
400                         nfc_val |= nfc_clk_sel << MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET;
401                         min_err = err;
402                         if (err == 0)
403                                 break;
404                 }
405         }
406
407         if (nfc_val == ~0 || min_err > 10)
408                 return -EINVAL;
409
410         if ((cs2cdr & CS2CDR_ENFC_MASK) != nfc_val) {
411                 debug("changing cs2cdr from %08x to %08x\n", cs2cdr,
412                         (cs2cdr & ~CS2CDR_ENFC_MASK) | nfc_val);
413                 __raw_writel((cs2cdr & ~CS2CDR_ENFC_MASK) | nfc_val,
414                         &imx_ccm->cs2cdr);
415         } else {
416                 debug("Leaving cs2cdr unchanged [%08x]\n", cs2cdr);
417         }
418         return 0;
419 }
420
421 static u32 get_mmdc_ch0_clk(void)
422 {
423         u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
424         u32 mmdc_ch0_podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >>
425                                 MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET;
426
427         return get_periph_clk() / (mmdc_ch0_podf + 1);
428 }
429
430 static u32 get_usdhc_clk(u32 port)
431 {
432         u32 root_freq = 0, usdhc_podf = 0, clk_sel = 0;
433         u32 cscmr1 = __raw_readl(&imx_ccm->cscmr1);
434         u32 cscdr1 = __raw_readl(&imx_ccm->cscdr1);
435
436         switch (port) {
437         case 0:
438                 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >>
439                                         MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET;
440                 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC1_CLK_SEL;
441
442                 break;
443         case 1:
444                 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >>
445                                         MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET;
446                 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC2_CLK_SEL;
447
448                 break;
449         case 2:
450                 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >>
451                                         MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET;
452                 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC3_CLK_SEL;
453
454                 break;
455         case 3:
456                 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >>
457                                         MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET;
458                 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC4_CLK_SEL;
459
460                 break;
461         default:
462                 break;
463         }
464
465         if (clk_sel)
466                 root_freq = PLL2_PFD0_FREQ;
467         else
468                 root_freq = PLL2_PFD2_FREQ;
469
470         return root_freq / (usdhc_podf + 1);
471 }
472
473 u32 imx_get_uartclk(void)
474 {
475         return get_uart_clk();
476 }
477
478 u32 imx_get_fecclk(void)
479 {
480         return decode_pll(PLL_ENET, MXC_HCLK);
481 }
482
483 int enable_sata_clock(void)
484 {
485         u32 reg;
486         s32 timeout = 100000;
487
488         /* Enable sata clock */
489         reg = readl(&imx_ccm->CCGR5); /* CCGR5 */
490         reg |= MXC_CCM_CCGR5_SATA_MASK;
491         writel(reg, &imx_ccm->CCGR5);
492
493         /* Enable PLLs */
494         reg = readl(&anatop->pll_enet);
495         reg &= ~BM_ANADIG_PLL_ENET_POWERDOWN;
496         writel(reg, &anatop->pll_enet);
497         reg |= BM_ANADIG_PLL_ENET_ENABLE;
498         while (timeout--) {
499                 if (readl(&anatop->pll_enet) & BM_ANADIG_PLL_ENET_LOCK)
500                         break;
501         }
502         if (timeout <= 0)
503                 return -EIO;
504         reg &= ~BM_ANADIG_PLL_ENET_BYPASS;
505         writel(reg, &anatop->pll_enet);
506         reg |= BM_ANADIG_PLL_ENET_ENABLE_SATA;
507         writel(reg, &anatop->pll_enet);
508
509         return 0 ;
510 }
511
512 void ipu_clk_enable(void)
513 {
514         u32 reg = readl(&imx_ccm->CCGR3);
515         reg |= MXC_CCM_CCGR3_CG0_MASK;
516         writel(reg, &imx_ccm->CCGR3);
517 }
518
519 void ipu_clk_disable(void)
520 {
521         u32 reg = readl(&imx_ccm->CCGR3);
522         reg &= ~MXC_CCM_CCGR3_CG0_MASK;
523         writel(reg, &imx_ccm->CCGR3);
524 }
525
526 void ocotp_clk_enable(void)
527 {
528         u32 reg = readl(&imx_ccm->CCGR2);
529         reg |= MXC_CCM_CCGR2_CG6_MASK;
530         writel(reg, &imx_ccm->CCGR2);
531 }
532
533 void ocotp_clk_disable(void)
534 {
535         u32 reg = readl(&imx_ccm->CCGR2);
536         reg &= ~MXC_CCM_CCGR2_CG6_MASK;
537         writel(reg, &imx_ccm->CCGR2);
538 }
539
540 unsigned int mxc_get_clock(enum mxc_clock clk)
541 {
542         switch (clk) {
543         case MXC_ARM_CLK:
544                 return get_mcu_main_clk();
545         case MXC_PER_CLK:
546                 return get_periph_clk();
547         case MXC_AHB_CLK:
548                 return get_ahb_clk();
549         case MXC_IPG_CLK:
550                 return get_ipg_clk();
551         case MXC_IPG_PERCLK:
552         case MXC_I2C_CLK:
553                 return get_ipg_per_clk();
554         case MXC_UART_CLK:
555                 return get_uart_clk();
556         case MXC_CSPI_CLK:
557                 return get_cspi_clk();
558         case MXC_AXI_CLK:
559                 return get_axi_clk();
560         case MXC_EMI_SLOW_CLK:
561                 return get_emi_slow_clk();
562         case MXC_DDR_CLK:
563                 return get_mmdc_ch0_clk();
564         case MXC_ESDHC_CLK:
565                 return get_usdhc_clk(0);
566         case MXC_ESDHC2_CLK:
567                 return get_usdhc_clk(1);
568         case MXC_ESDHC3_CLK:
569                 return get_usdhc_clk(2);
570         case MXC_ESDHC4_CLK:
571                 return get_usdhc_clk(3);
572         case MXC_SATA_CLK:
573                 return get_ahb_clk();
574         case MXC_NFC_CLK:
575                 return get_nfc_clk();
576         }
577
578         return -1;
579 }
580
581 static inline int gcd(int m, int n)
582 {
583         int t;
584         while (m > 0) {
585                 if (n > m) {
586                         t = m;
587                         m = n;
588                         n = t;
589                 } /* swap */
590                 m -= n;
591         }
592         return n;
593 }
594
595 /* Config CPU clock */
596 static int set_arm_clk(u32 ref, u32 freq_khz)
597 {
598         int d;
599         int div = 0;
600         int mul = 0;
601         u32 min_err = ~0;
602         u32 reg;
603
604         if (freq_khz > ref * 108 / 2000 || freq_khz < ref * 54 / 16000) {
605                 printf("Frequency %u.%03uMHz is out of range: %u.%03u..%u.%03u\n",
606                         freq_khz / 1000, freq_khz % 1000,
607                         54 * ref / 16000000, 54 * ref / 16000 % 1000,
608                         108 * ref / 2000000, 108 * ref / 2000 % 1000);
609                 return -EINVAL;
610         }
611
612         for (d = DIV_ROUND_UP(648000, freq_khz); d <= 8; d++) {
613                 int m = freq_khz * 2 * d / (ref / 1000);
614                 u32 f;
615                 u32 err;
616
617                 if (m > 108 || m < 54) {
618                         debug("%s@%d: d=%d m=%d\n", __func__, __LINE__,
619                                 d, m);
620                         continue;
621                 }
622
623                 f = ref * m / d / 2;
624                 if (f > freq_khz * 1000) {
625                         debug("%s@%d: d=%d m=%d f=%u freq=%u\n", __func__, __LINE__,
626                                 d, m, f, freq_khz);
627                         if (--m < 54)
628                                 return -EINVAL;
629                         f = ref * m / d / 2;
630                 }
631                 err = freq_khz * 1000 - f;
632                 debug("%s@%d: d=%d m=%d f=%u freq=%u err=%d\n", __func__, __LINE__,
633                         d, m, f, freq_khz, err);
634                 if (err < min_err) {
635                         mul = m;
636                         div = d;
637                         min_err = err;
638                         if (err == 0)
639                                 break;
640                 }
641         }
642         if (min_err == ~0)
643                 return -EINVAL;
644         debug("Setting M=%3u D=%2u for %u.%03uMHz (actual: %u.%03uMHz)\n",
645                 mul, div, freq_khz / 1000, freq_khz % 1000,
646                 ref * mul / 2 / div / 1000000, ref * mul / 2 / div / 1000 % 1000);
647
648         reg = readl(&anatop->pll_arm);
649         debug("anadig_pll_arm=%08x -> %08x\n",
650                 reg, (reg & ~0x7f) | mul);
651
652         reg |= 1 << 16;
653         writel(reg, &anatop->pll_arm); /* bypass PLL */
654
655         reg = (reg & ~0x7f) | mul;
656         writel(reg, &anatop->pll_arm);
657
658         writel(div - 1, &imx_ccm->cacrr);
659
660         reg &= ~(1 << 16);
661         writel(reg, &anatop->pll_arm); /* disable PLL bypass */
662
663         return 0;
664 }
665
666 int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk)
667 {
668         int ret;
669
670         freq *= 1000;
671
672         switch (clk) {
673         case MXC_ARM_CLK:
674                 ret = set_arm_clk(ref, freq);
675                 break;
676
677         case MXC_NFC_CLK:
678                 ret = set_nfc_clk(ref, freq);
679                 break;
680
681         default:
682                 printf("Warning: Unsupported or invalid clock type: %d\n",
683                         clk);
684                 return -EINVAL;
685         }
686
687         return ret;
688 }
689
690 /*
691  * Dump some core clocks.
692  */
693 #define print_pll(pll)  {                               \
694         u32 __pll = decode_pll(pll, MXC_HCLK);          \
695         printf("%-12s %4d.%03d MHz\n", #pll,            \
696                 __pll / 1000000, __pll / 1000 % 1000);  \
697         }
698
699 #define MXC_IPG_PER_CLK MXC_IPG_PERCLK
700
701 #define print_clk(clk)  {                               \
702         u32 __clk = mxc_get_clock(MXC_##clk##_CLK);     \
703         printf("%-12s %4d.%03d MHz\n", #clk,            \
704                 __clk / 1000000, __clk / 1000 % 1000);  \
705         }
706
707 static void do_mx6_showclocks(void)
708 {
709         print_pll(PLL_ARM);
710         print_pll(PLL_BUS);
711         print_pll(PLL_USBOTG);
712         print_pll(PLL_AUDIO);
713         print_pll(PLL_VIDEO);
714         print_pll(PLL_ENET);
715         print_pll(PLL_USB2);
716
717         printf("\n");
718         print_clk(IPG);
719         print_clk(UART);
720         print_clk(CSPI);
721         print_clk(AHB);
722         print_clk(AXI);
723         print_clk(DDR);
724         print_clk(ESDHC);
725         print_clk(ESDHC2);
726         print_clk(ESDHC3);
727         print_clk(ESDHC4);
728         print_clk(EMI_SLOW);
729         print_clk(NFC);
730         print_clk(IPG_PER);
731         print_clk(ARM);
732 }
733
734 static struct clk_lookup {
735         const char *name;
736         unsigned int index;
737 } mx6_clk_lookup[] = {
738         { "arm", MXC_ARM_CLK, },
739         { "nfc", MXC_NFC_CLK, },
740 };
741
742 int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
743 {
744         int i;
745         unsigned long freq;
746         unsigned long ref = ~0UL;
747
748         if (argc < 2) {
749                 do_mx6_showclocks();
750                 return CMD_RET_SUCCESS;
751         } else if (argc == 2 || argc > 4) {
752                 return CMD_RET_USAGE;
753         }
754
755         freq = simple_strtoul(argv[2], NULL, 0);
756         if (freq == 0) {
757                 printf("Invalid clock frequency %lu\n", freq);
758                 return CMD_RET_FAILURE;
759         }
760         if (argc > 3) {
761                 ref = simple_strtoul(argv[3], NULL, 0);
762         }
763         for (i = 0; i < ARRAY_SIZE(mx6_clk_lookup); i++) {
764                 if (strcasecmp(argv[1], mx6_clk_lookup[i].name) == 0) {
765                         switch (mx6_clk_lookup[i].index) {
766                         case MXC_ARM_CLK:
767                                 if (argc > 3)
768                                         return CMD_RET_USAGE;
769                                 ref = CONFIG_SYS_MX6_HCLK;
770                                 break;
771
772                         case MXC_NFC_CLK:
773                                 if (argc > 3 && ref > 3) {
774                                         printf("Invalid clock selector value: %lu\n", ref);
775                                         return CMD_RET_FAILURE;
776                                 }
777                                 break;
778                         }
779                         printf("Setting %s clock to %lu MHz\n",
780                                 mx6_clk_lookup[i].name, freq);
781                         if (mxc_set_clock(ref, freq, mx6_clk_lookup[i].index))
782                                 break;
783                         freq = mxc_get_clock(mx6_clk_lookup[i].index);
784                         printf("%s clock set to %lu.%03lu MHz\n",
785                                 mx6_clk_lookup[i].name,
786                                 freq / 1000000, freq / 1000 % 1000);
787                         return CMD_RET_SUCCESS;
788                 }
789         }
790         if (i == ARRAY_SIZE(mx6_clk_lookup)) {
791                 printf("clock %s not found; supported clocks are:\n", argv[1]);
792                 for (i = 0; i < ARRAY_SIZE(mx6_clk_lookup); i++) {
793                         printf("\t%s\n", mx6_clk_lookup[i].name);
794                 }
795         } else {
796                 printf("Failed to set clock %s to %s MHz\n",
797                         argv[1], argv[2]);
798         }
799         return CMD_RET_FAILURE;
800 }
801
802 /***************************************************/
803
804 U_BOOT_CMD(
805         clocks, 4, 0, do_clocks,
806         "display/set clocks",
807         "                    - display clock settings\n"
808         "clocks <clkname> <freq>    - set clock <clkname> to <freq> MHz"
809 );