2 * Copyright (C) 2010 Freescale Semiconductor, Inc.
4 * See file CREDITS for list of people who contributed to this
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.
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.
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,
24 #include <asm/errno.h>
25 #include <asm/arch/regs-clkctrl.h>
26 #include <asm/cache-cp15.h>
30 #define MXS_MODULE_SFTRST (1 << 31)
31 #define MXS_MODULE_CLKGATE (1 << 30)
33 static inline void __mxs_clrl(u32 mask, volatile void *addr)
35 __raw_writel(mask, addr + MXS_CLR_ADDR);
38 static inline void __mxs_setl(u32 mask, volatile void *addr)
40 __raw_writel(mask, addr + MXS_SET_ADDR);
44 * Clear the bit and poll it cleared. This is usually called with
45 * a reset address and mask being either SFTRST(bit 31) or CLKGATE
48 static int clear_poll_bit(volatile void *addr, u32 mask)
53 __mxs_clrl(mask, addr);
56 * SFTRST needs 3 GPMI clocks to settle, the reference manual
57 * recommends to wait 1us.
61 /* poll the bit becoming clear */
62 while ((__raw_readl(addr) & mask) && --timeout)
68 int mxs_reset_block(volatile void *reset_addr)
71 int timeout = 0x400000;
73 /* clear and poll SFTRST */
74 ret = clear_poll_bit(reset_addr, MXS_MODULE_SFTRST);
79 __mxs_clrl(MXS_MODULE_CLKGATE, reset_addr);
81 /* set SFTRST to reset the block */
82 __mxs_setl(MXS_MODULE_SFTRST, reset_addr);
85 /* poll CLKGATE becoming set */
86 while ((!(__raw_readl(reset_addr) & MXS_MODULE_CLKGATE)) && --timeout)
92 /* clear and poll SFTRST */
93 ret = clear_poll_bit(reset_addr, MXS_MODULE_SFTRST);
97 /* clear and poll CLKGATE */
98 ret = clear_poll_bit(reset_addr, MXS_MODULE_CLKGATE);
105 printf("%s(%p): module reset timeout\n", __func__, reset_addr);
109 static u32 mx28_get_pclk(void)
111 const u32 xtal = 24, ref = 480;
112 u32 clkfrac, clkseq, clkctrl;
116 clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0);
117 clkseq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ);
118 clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CPU);
120 if (clkctrl & (BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN |
121 BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
122 /* No support of fractional divider calculation */
125 if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) {
127 div = (clkctrl & BM_CLKCTRL_CPU_DIV_XTAL) >>
128 BP_CLKCTRL_CPU_DIV_XTAL;
132 frac = (clkfrac & BM_CLKCTRL_FRAC0_CPUFRAC) >>
133 BP_CLKCTRL_FRAC0_CPUFRAC;
134 div = (clkctrl & BM_CLKCTRL_CPU_DIV_CPU) >>
135 BP_CLKCTRL_CPU_DIV_CPU;
136 pclk = (ref * 18 / frac) / div;
143 static u32 mx28_get_hclk(void)
145 u32 clkctrl, div, hclk;
147 clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_HBUS);
149 if (clkctrl & BM_CLKCTRL_HBUS_DIV_FRAC_EN) {
150 /* No support of fractional divider calculation */
153 div = (clkctrl & BM_CLKCTRL_HBUS_DIV) >>
155 hclk = mx28_get_pclk() / div;
161 static u32 mx28_get_emiclk(void)
163 const u32 xtal = 24, ref = 480;
164 u32 clkfrac, clkseq, clkctrl;
168 clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0);
169 clkseq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ);
170 clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_EMI);
172 if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) {
174 div = (clkctrl & BM_CLKCTRL_EMI_DIV_XTAL) >>
175 BP_CLKCTRL_EMI_DIV_XTAL;
179 frac = (clkfrac & BM_CLKCTRL_FRAC0_EMIFRAC) >>
180 BP_CLKCTRL_FRAC0_EMIFRAC;
181 div = (clkctrl & BM_CLKCTRL_EMI_DIV_EMI) >>
182 BP_CLKCTRL_EMI_DIV_EMI;
183 emiclk = (ref * 18 / frac) / div;
189 static inline void __enable_gpmi_clk(void)
191 /* Clear bypass bit*/
192 REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
193 BM_CLKCTRL_CLKSEQ_BYPASS_GPMI);
194 /* Set gpmi clock to ref_gpmi/12 */
195 REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI,
196 (REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) &
197 (~(BM_CLKCTRL_GPMI_DIV |
198 ~BM_CLKCTRL_GPMI_CLKGATE))) |
202 static u32 mx28_get_gpmiclk(void)
204 const u32 xtal = 24, ref = 480;
205 u32 clkfrac, clkseq, clkctrl;
208 /* Enable gpmi clock */
211 clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1);
212 clkseq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ);
213 clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI);
215 if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) {
217 div = (clkctrl & BM_CLKCTRL_GPMI_DIV) >>
219 gpmiclk = xtal / div;
222 frac = (clkfrac & BM_CLKCTRL_FRAC1_GPMIFRAC) >>
223 BP_CLKCTRL_FRAC1_GPMIFRAC;
224 div = (clkctrl & BM_CLKCTRL_GPMI_DIV) >>
226 gpmiclk = (ref * 18 / frac) / div;
232 u32 mxc_get_clock(enum mxc_clock clk)
236 return mx28_get_pclk() * 1000000;
238 return mx28_get_gpmiclk() * 1000000;
241 return mx28_get_hclk() * 1000000;
247 #if defined(CONFIG_ARCH_CPU_INIT)
248 int arch_cpu_init(void)
257 #if defined(CONFIG_DISPLAY_CPUINFO)
258 int print_cpuinfo(void)
260 printf("Freescale i.MX28 family\n");
261 printf("CPU: %d MHz\n", mx28_get_pclk());
262 printf("BUS: %d MHz\n", mx28_get_hclk());
263 printf("EMI: %d MHz\n", mx28_get_emiclk());
264 printf("GPMI: %d MHz\n", mx28_get_gpmiclk());
270 * Initializes on-chip ethernet controllers.
272 int cpu_eth_init(bd_t *bis)
275 #if defined(CONFIG_MXC_FEC)
276 rc = mxc_fec_initialize(bis);
278 /* Turn on ENET clocks */
279 REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET,
280 REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET) &
281 ~(BM_CLKCTRL_ENET_SLEEP | BM_CLKCTRL_ENET_DISABLE));
283 /* Set up ENET PLL for 50 MHz */
284 REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_PLL2CTRL0,
285 BM_CLKCTRL_PLL2CTRL0_POWER); /* Power on ENET PLL */
286 udelay(10); /* Wait 10 us */
287 REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_PLL2CTRL0,
288 BM_CLKCTRL_PLL2CTRL0_CLKGATE); /* Gate on ENET PLL */
289 REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET,
290 REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET) |
291 BM_CLKCTRL_ENET_CLK_OUT_EN); /* Enable pad output */
293 /* Board level init */