3 * Sascha Hauer, Pengutronix
5 * (C) Copyright 2009 Freescale Semiconductor, Inc.
7 * See file CREDITS for list of people who contributed to this
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.
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.
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,
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>
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,
47 [PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
51 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
53 void set_usboh3_clk(void)
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);
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;
68 writel(reg, &mxc_ccm->cscdr1);
71 void enable_usboh3_clk(unsigned char enable)
75 reg = readl(&mxc_ccm->CCGR2);
77 reg |= 1 << MXC_CCM_CCGR2_CG14_OFFSET;
79 reg &= ~(1 << MXC_CCM_CCGR2_CG14_OFFSET);
80 writel(reg, &mxc_ccm->CCGR2);
83 void set_usb_phy1_clk(void)
87 reg = readl(&mxc_ccm->cscmr1);
88 reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
89 writel(reg, &mxc_ccm->cscmr1);
92 void enable_usb_phy1_clk(unsigned char enable)
96 reg = readl(&mxc_ccm->CCGR4);
98 reg |= 1 << MXC_CCM_CCGR4_CG5_OFFSET;
100 reg &= ~(1 << MXC_CCM_CCGR4_CG5_OFFSET);
101 writel(reg, &mxc_ccm->CCGR4);
104 void set_usb_phy2_clk(void)
108 reg = readl(&mxc_ccm->cscmr1);
109 reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
110 writel(reg, &mxc_ccm->cscmr1);
113 void enable_usb_phy2_clk(unsigned char enable)
117 reg = readl(&mxc_ccm->CCGR4);
119 reg |= 1 << MXC_CCM_CCGR4_CG6_OFFSET;
121 reg &= ~(1 << MXC_CCM_CCGR4_CG6_OFFSET);
122 writel(reg, &mxc_ccm->CCGR4);
126 * Calculate the frequency of PLLn.
128 static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
130 uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
131 uint64_t refclk, temp;
134 ctrl = readl(&pll->ctrl);
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);
141 mfn = __raw_readl(&pll->mfn);
142 mfd = __raw_readl(&pll->mfd);
143 op = __raw_readl(&pll->op);
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;
156 if (mfn >= 0x04000000) {
163 if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
166 do_div(refclk, pdf + 1);
167 temp = refclk * mfn_abs;
168 do_div(temp, mfd + 1);
182 u32 get_mcu_main_clk(void)
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);
193 * Get the rate of peripheral's root clock.
195 static u32 get_periph_clk(void)
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) {
206 return decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
208 return decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
216 * Get the rate of ahb clock.
218 static u32 get_ahb_clk(void)
220 uint32_t freq, div, reg;
222 freq = get_periph_clk();
224 reg = __raw_readl(&mxc_ccm->cbcdr);
225 div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
226 MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
232 * Get the rate of ipg clock.
234 static u32 get_ipg_clk(void)
236 uint32_t freq, reg, div;
238 freq = get_ahb_clk();
240 reg = __raw_readl(&mxc_ccm->cbcdr);
241 div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
242 MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
248 * Get the rate of ipg_per clock.
250 static u32 get_ipg_per_clk(void)
252 u32 pred1, pred2, podf;
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;
265 return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
269 * Get the rate of uart clk.
271 static u32 get_uart_clk(void)
273 unsigned int freq, reg, pred, podf;
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) {
279 freq = decode_pll(mxc_plls[PLL1_CLOCK],
280 CONFIG_SYS_MX5_HCLK);
283 freq = decode_pll(mxc_plls[PLL2_CLOCK],
284 CONFIG_SYS_MX5_HCLK);
287 freq = decode_pll(mxc_plls[PLL3_CLOCK],
288 CONFIG_SYS_MX5_HCLK);
294 reg = __raw_readl(&mxc_ccm->cscdr1);
296 pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
297 MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
299 podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
300 MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
301 freq /= (pred + 1) * (podf + 1);
307 * This function returns the low power audio clock.
312 u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
314 if (((ccsr >> 9) & 1) == 0)
315 ret_val = CONFIG_SYS_MX5_HCLK;
317 ret_val = ((32768 * 1024));
323 * get cspi clock rate.
325 u32 imx_get_cspiclk(void)
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);
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;
340 ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
341 CONFIG_SYS_MX5_HCLK) /
342 ((pre_pdf + 1) * (pdf + 1));
345 ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
346 CONFIG_SYS_MX5_HCLK) /
347 ((pre_pdf + 1) * (pdf + 1));
350 ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
351 CONFIG_SYS_MX5_HCLK) /
352 ((pre_pdf + 1) * (pdf + 1));
355 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
363 * The API of get mxc clockes.
365 unsigned int mxc_get_clock(enum mxc_clock clk)
369 return get_mcu_main_clk();
371 return get_ahb_clk();
373 return get_ipg_clk();
375 return get_ipg_per_clk();
377 return get_uart_clk();
379 return imx_get_cspiclk();
381 return decode_pll(mxc_plls[PLL1_CLOCK],
382 CONFIG_SYS_MX5_HCLK);
389 u32 imx_get_uartclk(void)
391 return get_uart_clk();
395 u32 imx_get_fecclk(void)
397 return mxc_get_clock(MXC_IPG_CLK);
401 * Dump some core clockes.
403 int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
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);
414 freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
415 printf("PLL4 %8d MHz\n", freq / 1000000);
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);
426 /***************************************************/
429 clocks, CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,