]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm926ejs/mx28/generic.c
applied patches from Freescale and Ka-Ro
[karo-tx-uboot.git] / cpu / arm926ejs / mx28 / generic.c
1 /*
2  * Copyright (C) 2010 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/errno.h>
25 #include <asm/arch/regs-clkctrl.h>
26 #include <asm/cache-cp15.h>
27 #include <asm/io.h>
28 #include <asm/fec.h>
29
30 #define MXS_MODULE_SFTRST       (1 << 31)
31 #define MXS_MODULE_CLKGATE      (1 << 30)
32
33 static inline void __mxs_clrl(u32 mask, volatile void *addr)
34 {
35         __raw_writel(mask, addr + MXS_CLR_ADDR);
36 }
37
38 static inline void __mxs_setl(u32 mask, volatile void *addr)
39 {
40         __raw_writel(mask, addr + MXS_SET_ADDR);
41 }
42
43 /*
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
46  * (bit 30).
47  */
48 static int clear_poll_bit(volatile void *addr, u32 mask)
49 {
50         int timeout = 0x400;
51
52         /* clear the bit */
53         __mxs_clrl(mask, addr);
54
55         /*
56          * SFTRST needs 3 GPMI clocks to settle, the reference manual
57          * recommends to wait 1us.
58          */
59         udelay(1);
60
61         /* poll the bit becoming clear */
62         while ((__raw_readl(addr) & mask) && --timeout)
63                 udelay(1);
64
65         return !timeout;
66 }
67
68 int mxs_reset_block(volatile void *reset_addr)
69 {
70         int ret;
71         int timeout = 0x400000;
72
73         /* clear and poll SFTRST */
74         ret = clear_poll_bit(reset_addr, MXS_MODULE_SFTRST);
75         if (ret)
76                 goto error;
77
78         /* clear CLKGATE */
79         __mxs_clrl(MXS_MODULE_CLKGATE, reset_addr);
80
81         /* set SFTRST to reset the block */
82         __mxs_setl(MXS_MODULE_SFTRST, reset_addr);
83         udelay(1);
84
85         /* poll CLKGATE becoming set */
86         while ((!(__raw_readl(reset_addr) & MXS_MODULE_CLKGATE)) && --timeout)
87                 udelay(1);
88
89         if (!timeout)
90                 goto error;
91
92         /* clear and poll SFTRST */
93         ret = clear_poll_bit(reset_addr, MXS_MODULE_SFTRST);
94         if (ret)
95                 goto error;
96
97         /* clear and poll CLKGATE */
98         ret = clear_poll_bit(reset_addr, MXS_MODULE_CLKGATE);
99         if (ret)
100                 goto error;
101
102         return 0;
103
104 error:
105         printf("%s(%p): module reset timeout\n", __func__, reset_addr);
106         return -ETIMEDOUT;
107 }
108
109 static u32 mx28_get_pclk(void)
110 {
111         const u32 xtal = 24, ref = 480;
112         u32 clkfrac, clkseq, clkctrl;
113         u32 frac, div;
114         u32 pclk;
115
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);
119
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 */
123                 pclk = 0;
124         } else {
125                 if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) {
126                         /* xtal path */
127                         div = (clkctrl & BM_CLKCTRL_CPU_DIV_XTAL) >>
128                                 BP_CLKCTRL_CPU_DIV_XTAL;
129                         pclk = xtal / div;
130                 } else {
131                         /* ref path */
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;
137                 }
138         }
139
140         return pclk;
141 }
142
143 static u32 mx28_get_hclk(void)
144 {
145         u32 clkctrl, div, hclk;
146
147         clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_HBUS);
148
149         if (clkctrl & BM_CLKCTRL_HBUS_DIV_FRAC_EN) {
150                 /* No support of fractional divider calculation */
151                 hclk = 0;
152         } else {
153                 div = (clkctrl & BM_CLKCTRL_HBUS_DIV) >>
154                         BP_CLKCTRL_HBUS_DIV;
155                 hclk = mx28_get_pclk() / div;
156         }
157
158         return hclk;
159 }
160
161 static u32 mx28_get_emiclk(void)
162 {
163         const u32 xtal = 24, ref = 480;
164         u32 clkfrac, clkseq, clkctrl;
165         u32 frac, div;
166         u32 emiclk;
167
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);
171
172         if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) {
173                 /* xtal path */
174                 div = (clkctrl & BM_CLKCTRL_EMI_DIV_XTAL) >>
175                         BP_CLKCTRL_EMI_DIV_XTAL;
176                 emiclk = xtal / div;
177         } else {
178                 /* ref path */
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;
184         }
185
186         return emiclk;
187 }
188
189 static inline void __enable_gpmi_clk(void)
190 {
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))) |
199                 1);
200 }
201
202 static u32 mx28_get_gpmiclk(void)
203 {
204         const u32 xtal = 24, ref = 480;
205         u32 clkfrac, clkseq, clkctrl;
206         u32 frac, div;
207         u32 gpmiclk;
208         /* Enable gpmi clock */
209         __enable_gpmi_clk();
210
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);
214
215         if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) {
216                 /* xtal path */
217                 div = (clkctrl & BM_CLKCTRL_GPMI_DIV) >>
218                         BP_CLKCTRL_GPMI_DIV;
219                 gpmiclk = xtal / div;
220         } else {
221                 /* ref path */
222                 frac = (clkfrac & BM_CLKCTRL_FRAC1_GPMIFRAC) >>
223                         BP_CLKCTRL_FRAC1_GPMIFRAC;
224                 div = (clkctrl & BM_CLKCTRL_GPMI_DIV) >>
225                         BP_CLKCTRL_GPMI_DIV;
226                 gpmiclk =  (ref * 18 / frac) / div;
227         }
228
229         return gpmiclk;
230 }
231
232 u32 mxc_get_clock(enum mxc_clock clk)
233 {
234         switch (clk) {
235         case MXC_ARM_CLK:
236                 return mx28_get_pclk() * 1000000;
237         case MXC_GPMI_CLK:
238                 return mx28_get_gpmiclk() * 1000000;
239         case MXC_AHB_CLK:
240         case MXC_IPG_CLK:
241                 return mx28_get_hclk() * 1000000;
242         }
243
244         return 0;
245 }
246
247 #if defined(CONFIG_ARCH_CPU_INIT)
248 int arch_cpu_init(void)
249 {
250         icache_enable();
251         dcache_enable();
252
253         return 0;
254 }
255 #endif
256
257 #if defined(CONFIG_DISPLAY_CPUINFO)
258 int print_cpuinfo(void)
259 {
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());
265         return 0;
266 }
267 #endif
268
269 /*
270  * Initializes on-chip ethernet controllers.
271  */
272 int cpu_eth_init(bd_t *bis)
273 {
274         int rc = ENODEV;
275 #if defined(CONFIG_MXC_FEC)
276         rc = mxc_fec_initialize(bis);
277
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));
282
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 */
292
293         /* Board level init */
294         enet_board_init();
295 #endif
296         return rc;
297 }
298