]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm926ejs/mx28/generic.c
imported Ka-Ro specific additions to U-Boot 2009.08 for TX28
[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/fec.h>
28
29 static u32 mx28_get_pclk(void)
30 {
31         const u32 xtal = 24, ref = 480;
32         u32 clkfrac, clkseq, clkctrl;
33         u32 frac, div;
34         u32 pclk;
35
36         clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0);
37         clkseq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ);
38         clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CPU);
39
40         if (clkctrl & (BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN |
41                 BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
42                 /* No support of fractional divider calculation */
43                 pclk = 0;
44         } else {
45                 if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) {
46                         /* xtal path */
47                         div = (clkctrl & BM_CLKCTRL_CPU_DIV_XTAL) >>
48                                 BP_CLKCTRL_CPU_DIV_XTAL;
49                         pclk = xtal / div;
50                 } else {
51                         /* ref path */
52                         frac = (clkfrac & BM_CLKCTRL_FRAC0_CPUFRAC) >>
53                                 BP_CLKCTRL_FRAC0_CPUFRAC;
54                         div = (clkctrl & BM_CLKCTRL_CPU_DIV_CPU) >>
55                                 BP_CLKCTRL_CPU_DIV_CPU;
56                         pclk =  (ref * 18 / frac) / div;
57                 }
58         }
59
60         return pclk;
61 }
62
63 static u32 mx28_get_hclk(void)
64 {
65         u32 clkctrl, div, hclk;
66
67         clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_HBUS);
68
69         if (clkctrl & BM_CLKCTRL_HBUS_DIV_FRAC_EN) {
70                 /* No support of fractional divider calculation */
71                 hclk = 0;
72         } else {
73                 div = (clkctrl & BM_CLKCTRL_HBUS_DIV) >>
74                         BP_CLKCTRL_HBUS_DIV;
75                 hclk = mx28_get_pclk() / div;
76         }
77
78         return hclk;
79 }
80
81 static u32 mx28_get_emiclk(void)
82 {
83         const u32 xtal = 24, ref = 480;
84         u32 clkfrac, clkseq, clkctrl;
85         u32 frac, div;
86         u32 emiclk;
87
88         clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0);
89         clkseq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ);
90         clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_EMI);
91
92         if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) {
93                 /* xtal path */
94                 div = (clkctrl & BM_CLKCTRL_EMI_DIV_XTAL) >>
95                         BP_CLKCTRL_EMI_DIV_XTAL;
96                 emiclk = xtal / div;
97         } else {
98                 /* ref path */
99                 frac = (clkfrac & BM_CLKCTRL_FRAC0_EMIFRAC) >>
100                         BP_CLKCTRL_FRAC0_EMIFRAC;
101                 div = (clkctrl & BM_CLKCTRL_EMI_DIV_EMI) >>
102                         BP_CLKCTRL_EMI_DIV_EMI;
103                 emiclk =  (ref * 18 / frac) / div;
104         }
105
106         return emiclk;
107 }
108 static inline void __enable_gpmi_clk(void)
109 {
110         /* Clear bypass bit*/
111         REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ,
112                BM_CLKCTRL_CLKSEQ_BYPASS_GPMI);
113         /* Set gpmi clock to ref_gpmi/12 */
114         REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI,
115               REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI) &
116               (~(BM_CLKCTRL_GPMI_DIV)) &
117               (~(BM_CLKCTRL_GPMI_CLKGATE)) |
118               1);
119 }
120 static u32 mx28_get_gpmiclk(void)
121 {
122         const u32 xtal = 24, ref = 480;
123         u32 clkfrac, clkseq, clkctrl;
124         u32 frac, div;
125         u32 gpmiclk;
126         /* Enable gpmi clock */
127         __enable_gpmi_clk();
128
129         clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC1);
130         clkseq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ);
131         clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_GPMI);
132
133         if (clkseq & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) {
134                 /* xtal path */
135                 div = (clkctrl & BM_CLKCTRL_GPMI_DIV) >>
136                         BP_CLKCTRL_GPMI_DIV;
137                 gpmiclk = xtal / div;
138         } else {
139                 /* ref path */
140                 frac = (clkfrac & BM_CLKCTRL_FRAC1_GPMIFRAC) >>
141                         BP_CLKCTRL_FRAC1_GPMIFRAC;
142                 div = (clkctrl & BM_CLKCTRL_GPMI_DIV) >>
143                         BP_CLKCTRL_GPMI_DIV;
144                 gpmiclk =  (ref * 18 / frac) / div;
145         }
146
147         return gpmiclk;
148 }
149 u32 mxc_get_clock(enum mxc_clock clk)
150 {
151         switch (clk) {
152         case MXC_ARM_CLK:
153                 return mx28_get_pclk() * 1000000;
154         case MXC_GPMI_CLK:
155                 return mx28_get_gpmiclk() * 1000000;
156         case MXC_AHB_CLK:
157         case MXC_IPG_CLK:
158                 return mx28_get_hclk() * 1000000;
159         }
160
161         return 0;
162 }
163
164 #if defined(CONFIG_ARCH_CPU_INIT)
165 int arch_cpu_init(void)
166 {
167         icache_enable();
168         dcache_enable();
169
170         return 0;
171 }
172 #endif
173
174 #if defined(CONFIG_DISPLAY_CPUINFO)
175 int print_cpuinfo(void)
176 {
177         printf("Freescale i.MX28 family\n");
178         printf("CPU:   %d MHz\n", mx28_get_pclk());
179         printf("BUS:   %d MHz\n", mx28_get_hclk());
180         printf("EMI:   %d MHz\n", mx28_get_emiclk());
181         printf("GPMI:   %d MHz\n", mx28_get_gpmiclk());
182         return 0;
183 }
184 #endif
185
186 /*
187  * Initializes on-chip ethernet controllers.
188  */
189 int cpu_eth_init(bd_t *bis)
190 {
191         int rc = ENODEV;
192 #if defined(CONFIG_MXC_FEC)
193         rc = mxc_fec_initialize(bis);
194
195         /* Turn on ENET clocks */
196         REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET,
197                 REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET) &
198                 ~(BM_CLKCTRL_ENET_SLEEP | BM_CLKCTRL_ENET_DISABLE));
199
200         /* Set up ENET PLL for 50 MHz */
201         REG_SET(REGS_CLKCTRL_BASE, HW_CLKCTRL_PLL2CTRL0,
202                 BM_CLKCTRL_PLL2CTRL0_POWER);    /* Power on ENET PLL */
203         udelay(10);                             /* Wait 10 us */
204         REG_CLR(REGS_CLKCTRL_BASE, HW_CLKCTRL_PLL2CTRL0,
205                 BM_CLKCTRL_PLL2CTRL0_CLKGATE);  /* Gate on ENET PLL */
206         REG_WR(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET,
207                 REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_ENET) |
208                 BM_CLKCTRL_ENET_CLK_OUT_EN);    /* Enable pad output */
209
210         /* Board level init */
211         enet_board_init();
212 #endif
213         return rc;
214 }
215