]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm_cortexa8/mx51/generic.c
applied patches from Freescale and Ka-Ro
[karo-tx-uboot.git] / cpu / arm_cortexa8 / mx51 / generic.c
1 /*
2  * (C) Copyright 2007
3  * Sascha Hauer, Pengutronix
4  *
5  * (C) Copyright 2009-2010 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/arch/mx51.h>
28 #include <asm/errno.h>
29 #ifdef CONFIG_ARCH_CPU_INIT
30 #include <asm/cache-cp15.h>
31 #endif
32 #include "crm_regs.h"
33
34 enum pll_clocks {
35 PLL1_CLK = MXC_DPLL1_BASE,
36 PLL2_CLK = MXC_DPLL2_BASE,
37 PLL3_CLK = MXC_DPLL3_BASE,
38 };
39
40 enum pll_sw_clocks {
41 PLL1_SW_CLK,
42 PLL2_SW_CLK,
43 PLL3_SW_CLK,
44 };
45
46 static u32 __decode_pll(enum pll_clocks pll, u32 infreq)
47 {
48         u32 mfi, mfn, mfd, pd;
49
50         mfn = __REG(pll + MXC_PLL_DP_MFN);
51         mfd = __REG(pll + MXC_PLL_DP_MFD) + 1;
52         mfi = __REG(pll + MXC_PLL_DP_OP);
53         pd = (mfi  & 0xF) + 1;
54         mfi = (mfi >> 4) & 0xF;
55         mfi = (mfi >= 5) ? mfi : 5;
56
57         return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000;
58 }
59
60 static u32 __get_mcu_main_clk(void)
61 {
62         u32 reg, freq;
63         reg = (__REG(MXC_CCM_CACRR) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
64             MXC_CCM_CACRR_ARM_PODF_OFFSET;
65         freq = __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ);
66         return freq / (reg + 1);
67 }
68
69 static u32 __get_periph_clk(void)
70 {
71         u32 reg;
72         reg = __REG(MXC_CCM_CBCDR);
73         if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
74                 reg = __REG(MXC_CCM_CBCMR);
75                 switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
76                         MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
77                 case 0:
78                         return __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ);
79                 case 1:
80                         return __decode_pll(PLL3_CLK, CONFIG_MX51_HCLK_FREQ);
81                 default:
82                         return 0;
83                 }
84         }
85         return __decode_pll(PLL2_CLK, CONFIG_MX51_HCLK_FREQ);
86 }
87
88 static u32 __get_ipg_clk(void)
89 {
90         u32 ahb_podf, ipg_podf;
91
92         ahb_podf = __REG(MXC_CCM_CBCDR);
93         ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
94                         MXC_CCM_CBCDR_IPG_PODF_OFFSET;
95         ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
96                         MXC_CCM_CBCDR_AHB_PODF_OFFSET;
97         return __get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
98 }
99
100 static u32 __get_ipg_per_clk(void)
101 {
102         u32 pred1, pred2, podf;
103         if (__REG(MXC_CCM_CBCMR) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
104                 return __get_ipg_clk();
105         /* Fixme: not handle what about lpm*/
106         podf = __REG(MXC_CCM_CBCDR);
107         pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
108                 MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
109         pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
110                 MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
111         podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
112                 MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
113
114         return __get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
115 }
116
117 static u32 __get_uart_clk(void)
118 {
119         unsigned int freq, reg, pred, podf;
120         reg = __REG(MXC_CCM_CSCMR1);
121         switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
122                 MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
123         case 0x0:
124                 freq = __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ);
125                 break;
126         case 0x1:
127                 freq = __decode_pll(PLL2_CLK, CONFIG_MX51_HCLK_FREQ);
128                 break;
129         case 0x2:
130                 freq = __decode_pll(PLL3_CLK, CONFIG_MX51_HCLK_FREQ);
131                 break;
132         default:
133                 return 66500000;
134         }
135
136         reg = __REG(MXC_CCM_CSCDR1);
137
138         pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
139                 MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
140
141         podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
142                 MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
143         freq /= (pred + 1) * (podf + 1);
144
145         return freq;
146 }
147
148 /*!
149 + * This function returns the low power audio clock.
150 + */
151 u32 get_lp_apm(void)
152 {
153         u32 ret_val = 0;
154         u32 ccsr = __REG(MXC_CCM_CCSR);
155
156         if (((ccsr >> 9) & 1) == 0)
157                 ret_val = CONFIG_MX51_HCLK_FREQ;
158         else
159                 ret_val = ((32768 * 1024));
160
161         return ret_val;
162 }
163
164 static u32 __get_cspi_clk(void)
165 {
166         u32 ret_val = 0, pdf, pre_pdf, clk_sel;
167         u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
168         u32 cscdr2 = __REG(MXC_CCM_CSCDR2);
169
170         pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
171                         >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
172         pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
173                         >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
174         clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
175                         >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
176
177         switch (clk_sel) {
178         case 0:
179                 ret_val = __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ) / ((pre_pdf + 1) * (pdf + 1));
180                 break;
181         case 1:
182                 ret_val = __decode_pll(PLL2_CLK, CONFIG_MX51_HCLK_FREQ) / ((pre_pdf + 1) * (pdf + 1));
183                 break;
184         case 2:
185                 ret_val = __decode_pll(PLL3_CLK, CONFIG_MX51_HCLK_FREQ) / ((pre_pdf + 1) * (pdf + 1));
186                 break;
187         default:
188                 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
189                 break;
190         }
191
192         return ret_val;
193 }
194
195 unsigned int mxc_get_clock(enum mxc_clock clk)
196 {
197         switch (clk) {
198         case MXC_ARM_CLK:
199                 return __get_mcu_main_clk();
200         case MXC_AHB_CLK:
201                 break;
202         case MXC_IPG_CLK:
203                 return __get_ipg_clk();
204         case MXC_IPG_PERCLK:
205                 return __get_ipg_per_clk();
206         case MXC_UART_CLK:
207                 return __get_uart_clk();
208         case MXC_CSPI_CLK:
209                 return __get_cspi_clk();
210         case MXC_FEC_CLK:
211                 return __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ);
212         case MXC_ESDHC_CLK:
213                 return __decode_pll(PLL3_CLK, CONFIG_MX51_HCLK_FREQ);
214         default:
215                 break;
216         }
217         return -1;
218 }
219
220 void mxc_dump_clocks(void)
221 {
222         u32 freq;
223         freq = __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ);
224         printf("mx51 pll1: %dMHz\n", freq / 1000000);
225         freq = __decode_pll(PLL2_CLK, CONFIG_MX51_HCLK_FREQ);
226         printf("mx51 pll2: %dMHz\n", freq / 1000000);
227         freq = __decode_pll(PLL3_CLK, CONFIG_MX51_HCLK_FREQ);
228         printf("mx51 pll3: %dMHz\n", freq / 1000000);
229         printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
230         printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
231         printf("uart clock    : %dHz\n", mxc_get_clock(MXC_UART_CLK));
232         printf("cspi clock    : %dHz\n", mxc_get_clock(MXC_CSPI_CLK));
233 }
234
235 #if defined(CONFIG_DISPLAY_CPUINFO)
236 int print_cpuinfo(void)
237 {
238         printf("CPU:   Freescale i.MX51 family %d.%dV at %d MHz\n",
239                (get_board_rev() & 0xFF) >> 4,
240                (get_board_rev() & 0xF),
241                 __get_mcu_main_clk() / 1000000);
242         mxc_dump_clocks();
243         return 0;
244 }
245 #endif
246
247 /*
248  * Initializes on-chip ethernet controllers.
249  * to override, implement board_eth_init()
250  */
251 #if defined(CONFIG_MXC_FEC)
252 extern int mxc_fec_initialize(bd_t *bis);
253 extern void mxc_fec_set_mac_from_env(char *mac_addr);
254 #endif
255
256 int cpu_eth_init(bd_t *bis)
257 {
258         int rc = -ENODEV;
259
260 #if defined(CONFIG_MXC_FEC)
261         rc = mxc_fec_initialize(bis);
262 #endif
263
264         return rc;
265 }
266
267 #if defined(CONFIG_ARCH_CPU_INIT)
268 int arch_cpu_init(void)
269 {
270         icache_enable();
271         dcache_enable();
272 #ifdef CONFIG_L2_OFF
273         l2_cache_disable();
274 #else
275         l2_cache_enable();
276 #endif
277         return 0;
278 }
279 #endif