Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* linux/arch/arm/mach-s3c2410/cpu.c |
2 | * | |
3 | * Copyright (c) 2004-2005 Simtec Electronics | |
4 | * http://www.simtec.co.uk/products/SWLINUX/ | |
5 | * Ben Dooks <ben@simtec.co.uk> | |
6 | * | |
7 | * S3C24XX CPU Support | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | ||
25 | #include <linux/init.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/interrupt.h> | |
28 | #include <linux/ioport.h> | |
d052d1be | 29 | #include <linux/platform_device.h> |
1da177e4 LT |
30 | |
31 | #include <asm/hardware.h> | |
32 | #include <asm/irq.h> | |
33 | #include <asm/io.h> | |
34 | #include <asm/delay.h> | |
35 | ||
36 | #include <asm/mach/arch.h> | |
37 | #include <asm/mach/map.h> | |
38 | ||
39 | #include <asm/arch/regs-gpio.h> | |
40 | ||
41 | #include "cpu.h" | |
42 | #include "clock.h" | |
83f755f5 | 43 | #include "s3c2400.h" |
1da177e4 LT |
44 | #include "s3c2410.h" |
45 | #include "s3c2440.h" | |
46 | ||
47 | struct cpu_table { | |
48 | unsigned long idcode; | |
49 | unsigned long idmask; | |
50 | void (*map_io)(struct map_desc *mach_desc, int size); | |
51 | void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no); | |
52 | void (*init_clocks)(int xtal); | |
53 | int (*init)(void); | |
54 | const char *name; | |
55 | }; | |
56 | ||
57 | /* table of supported CPUs */ | |
58 | ||
83f755f5 | 59 | static const char name_s3c2400[] = "S3C2400"; |
1da177e4 LT |
60 | static const char name_s3c2410[] = "S3C2410"; |
61 | static const char name_s3c2440[] = "S3C2440"; | |
62 | static const char name_s3c2410a[] = "S3C2410A"; | |
63 | static const char name_s3c2440a[] = "S3C2440A"; | |
64 | ||
65 | static struct cpu_table cpu_ids[] __initdata = { | |
66 | { | |
67 | .idcode = 0x32410000, | |
68 | .idmask = 0xffffffff, | |
69 | .map_io = s3c2410_map_io, | |
70 | .init_clocks = s3c2410_init_clocks, | |
71 | .init_uarts = s3c2410_init_uarts, | |
72 | .init = s3c2410_init, | |
73 | .name = name_s3c2410 | |
74 | }, | |
75 | { | |
76 | .idcode = 0x32410002, | |
77 | .idmask = 0xffffffff, | |
78 | .map_io = s3c2410_map_io, | |
79 | .init_clocks = s3c2410_init_clocks, | |
80 | .init_uarts = s3c2410_init_uarts, | |
81 | .init = s3c2410_init, | |
82 | .name = name_s3c2410a | |
83 | }, | |
84 | { | |
85 | .idcode = 0x32440000, | |
86 | .idmask = 0xffffffff, | |
87 | .map_io = s3c2440_map_io, | |
88 | .init_clocks = s3c2440_init_clocks, | |
89 | .init_uarts = s3c2440_init_uarts, | |
90 | .init = s3c2440_init, | |
91 | .name = name_s3c2440 | |
92 | }, | |
93 | { | |
94 | .idcode = 0x32440001, | |
95 | .idmask = 0xffffffff, | |
96 | .map_io = s3c2440_map_io, | |
97 | .init_clocks = s3c2440_init_clocks, | |
98 | .init_uarts = s3c2440_init_uarts, | |
99 | .init = s3c2440_init, | |
100 | .name = name_s3c2440a | |
83f755f5 LCVR |
101 | }, |
102 | { | |
103 | .idcode = 0x0, /* S3C2400 doesn't have an idcode */ | |
104 | .idmask = 0xffffffff, | |
105 | .map_io = s3c2400_map_io, | |
106 | .init_clocks = s3c2400_init_clocks, | |
107 | .init_uarts = s3c2400_init_uarts, | |
108 | .init = s3c2400_init, | |
109 | .name = name_s3c2400 | |
110 | }, | |
1da177e4 LT |
111 | }; |
112 | ||
113 | /* minimal IO mapping */ | |
114 | ||
115 | static struct map_desc s3c_iodesc[] __initdata = { | |
116 | IODESC_ENT(GPIO), | |
117 | IODESC_ENT(IRQ), | |
118 | IODESC_ENT(MEMCTRL), | |
119 | IODESC_ENT(UART) | |
120 | }; | |
121 | ||
122 | ||
123 | static struct cpu_table * | |
124 | s3c_lookup_cpu(unsigned long idcode) | |
125 | { | |
126 | struct cpu_table *tab; | |
127 | int count; | |
128 | ||
129 | tab = cpu_ids; | |
130 | for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) { | |
131 | if ((idcode & tab->idmask) == tab->idcode) | |
132 | return tab; | |
133 | } | |
134 | ||
135 | return NULL; | |
136 | } | |
137 | ||
138 | /* board information */ | |
139 | ||
140 | static struct s3c24xx_board *board; | |
141 | ||
142 | void s3c24xx_set_board(struct s3c24xx_board *b) | |
143 | { | |
144 | int i; | |
145 | ||
146 | board = b; | |
147 | ||
148 | if (b->clocks_count != 0) { | |
53b3531b | 149 | struct clk **ptr = b->clocks; |
1da177e4 LT |
150 | |
151 | for (i = b->clocks_count; i > 0; i--, ptr++) | |
152 | s3c24xx_register_clock(*ptr); | |
153 | } | |
154 | } | |
155 | ||
156 | /* cpu information */ | |
157 | ||
158 | static struct cpu_table *cpu; | |
159 | ||
160 | void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) | |
161 | { | |
83f755f5 | 162 | unsigned long idcode = 0x0; |
1da177e4 LT |
163 | |
164 | /* initialise the io descriptors we need for initialisation */ | |
165 | iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); | |
166 | ||
83f755f5 | 167 | #ifndef CONFIG_CPU_S3C2400 |
1da177e4 | 168 | idcode = __raw_readl(S3C2410_GSTATUS1); |
83f755f5 LCVR |
169 | #endif |
170 | ||
1da177e4 LT |
171 | cpu = s3c_lookup_cpu(idcode); |
172 | ||
173 | if (cpu == NULL) { | |
174 | printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); | |
175 | panic("Unknown S3C24XX CPU"); | |
176 | } | |
177 | ||
178 | if (cpu->map_io == NULL || cpu->init == NULL) { | |
179 | printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); | |
180 | panic("Unsupported S3C24XX CPU"); | |
181 | } | |
182 | ||
183 | printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); | |
184 | ||
185 | (cpu->map_io)(mach_desc, size); | |
186 | } | |
187 | ||
188 | /* s3c24xx_init_clocks | |
189 | * | |
190 | * Initialise the clock subsystem and associated information from the | |
191 | * given master crystal value. | |
192 | * | |
193 | * xtal = 0 -> use default PLL crystal value (normally 12MHz) | |
194 | * != 0 -> PLL crystal value in Hz | |
195 | */ | |
196 | ||
197 | void __init s3c24xx_init_clocks(int xtal) | |
198 | { | |
199 | if (xtal == 0) | |
200 | xtal = 12*1000*1000; | |
201 | ||
202 | if (cpu == NULL) | |
203 | panic("s3c24xx_init_clocks: no cpu setup?\n"); | |
204 | ||
205 | if (cpu->init_clocks == NULL) | |
206 | panic("s3c24xx_init_clocks: cpu has no clock init\n"); | |
207 | else | |
208 | (cpu->init_clocks)(xtal); | |
209 | } | |
210 | ||
211 | void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |
212 | { | |
213 | if (cpu == NULL) | |
214 | return; | |
215 | ||
216 | if (cpu->init_uarts == NULL) { | |
217 | printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n"); | |
218 | } else | |
219 | (cpu->init_uarts)(cfg, no); | |
220 | } | |
221 | ||
222 | static int __init s3c_arch_init(void) | |
223 | { | |
224 | int ret; | |
225 | ||
226 | // do the correct init for cpu | |
227 | ||
228 | if (cpu == NULL) | |
229 | panic("s3c_arch_init: NULL cpu\n"); | |
230 | ||
231 | ret = (cpu->init)(); | |
232 | if (ret != 0) | |
233 | return ret; | |
234 | ||
235 | if (board != NULL) { | |
236 | struct platform_device **ptr = board->devices; | |
237 | int i; | |
238 | ||
239 | for (i = 0; i < board->devices_count; i++, ptr++) { | |
240 | ret = platform_device_register(*ptr); | |
241 | ||
242 | if (ret) { | |
243 | printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret, *ptr); | |
244 | } | |
245 | } | |
246 | ||
247 | /* mask any error, we may not need all these board | |
248 | * devices */ | |
249 | ret = 0; | |
250 | } | |
251 | ||
252 | return ret; | |
253 | } | |
254 | ||
255 | arch_initcall(s3c_arch_init); |