diff options
author | Chris Zankel <czankel@tensilica.com> | 2005-06-24 01:01:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:05:21 -0400 |
commit | 5a0015d62668e64c8b6e02e360fbbea121bfd5e6 (patch) | |
tree | ed879f8cbe0efee21ad861f38c4024bdcf25df9b /arch/xtensa/kernel/setup.c | |
parent | 4bedea94545165364618d403d03b61d797acba0b (diff) |
[PATCH] xtensa: Architecture support for Tensilica Xtensa Part 3
The attached patches provides part 3 of an architecture implementation for the
Tensilica Xtensa CPU series.
Signed-off-by: Chris Zankel <chris@zankel.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/xtensa/kernel/setup.c')
-rw-r--r-- | arch/xtensa/kernel/setup.c | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c new file mode 100644 index 000000000000..1f5bf5d624e4 --- /dev/null +++ b/arch/xtensa/kernel/setup.c | |||
@@ -0,0 +1,520 @@ | |||
1 | /* | ||
2 | * arch/xtensa/setup.c | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 1995 Linus Torvalds | ||
9 | * Copyright (C) 2001 - 2005 Tensilica Inc. | ||
10 | * | ||
11 | * Chris Zankel <chris@zankel.net> | ||
12 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> | ||
13 | * Kevin Chea | ||
14 | * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca> | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/tty.h> | ||
22 | #include <linux/bootmem.h> | ||
23 | #include <linux/kernel.h> | ||
24 | |||
25 | #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) | ||
26 | # include <linux/console.h> | ||
27 | #endif | ||
28 | |||
29 | #ifdef CONFIG_RTC | ||
30 | # include <linux/timex.h> | ||
31 | #endif | ||
32 | |||
33 | #ifdef CONFIG_PROC_FS | ||
34 | # include <linux/seq_file.h> | ||
35 | #endif | ||
36 | |||
37 | #include <asm/system.h> | ||
38 | #include <asm/bootparam.h> | ||
39 | #include <asm/pgtable.h> | ||
40 | #include <asm/processor.h> | ||
41 | #include <asm/timex.h> | ||
42 | #include <asm/platform.h> | ||
43 | #include <asm/page.h> | ||
44 | #include <asm/setup.h> | ||
45 | |||
46 | #include <xtensa/config/system.h> | ||
47 | |||
48 | #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) | ||
49 | struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16}; | ||
50 | #endif | ||
51 | |||
52 | #ifdef CONFIG_BLK_DEV_FD | ||
53 | extern struct fd_ops no_fd_ops; | ||
54 | struct fd_ops *fd_ops; | ||
55 | #endif | ||
56 | |||
57 | #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) | ||
58 | extern struct ide_ops no_ide_ops; | ||
59 | struct ide_ops *ide_ops; | ||
60 | #endif | ||
61 | |||
62 | extern struct rtc_ops no_rtc_ops; | ||
63 | struct rtc_ops *rtc_ops; | ||
64 | |||
65 | #ifdef CONFIG_PC_KEYB | ||
66 | extern struct kbd_ops no_kbd_ops; | ||
67 | struct kbd_ops *kbd_ops; | ||
68 | #endif | ||
69 | |||
70 | #ifdef CONFIG_BLK_DEV_INITRD | ||
71 | extern void *initrd_start; | ||
72 | extern void *initrd_end; | ||
73 | extern void *__initrd_start; | ||
74 | extern void *__initrd_end; | ||
75 | int initrd_is_mapped = 0; | ||
76 | extern int initrd_below_start_ok; | ||
77 | #endif | ||
78 | |||
79 | unsigned char aux_device_present; | ||
80 | extern unsigned long loops_per_jiffy; | ||
81 | |||
82 | /* Command line specified as configuration option. */ | ||
83 | |||
84 | static char command_line[COMMAND_LINE_SIZE]; | ||
85 | |||
86 | #ifdef CONFIG_CMDLINE_BOOL | ||
87 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; | ||
88 | #endif | ||
89 | |||
90 | sysmem_info_t __initdata sysmem; | ||
91 | |||
92 | #ifdef CONFIG_BLK_DEV_INITRD | ||
93 | int initrd_is_mapped; | ||
94 | #endif | ||
95 | |||
96 | extern void init_mmu(void); | ||
97 | |||
98 | /* | ||
99 | * Boot parameter parsing. | ||
100 | * | ||
101 | * The Xtensa port uses a list of variable-sized tags to pass data to | ||
102 | * the kernel. The first tag must be a BP_TAG_FIRST tag for the list | ||
103 | * to be recognised. The list is terminated with a zero-sized | ||
104 | * BP_TAG_LAST tag. | ||
105 | */ | ||
106 | |||
107 | typedef struct tagtable { | ||
108 | u32 tag; | ||
109 | int (*parse)(const bp_tag_t*); | ||
110 | } tagtable_t; | ||
111 | |||
112 | #define __tagtable(tag, fn) static tagtable_t __tagtable_##fn \ | ||
113 | __attribute__((unused, __section__(".taglist"))) = { tag, fn } | ||
114 | |||
115 | /* parse current tag */ | ||
116 | |||
117 | static int __init parse_tag_mem(const bp_tag_t *tag) | ||
118 | { | ||
119 | meminfo_t *mi = (meminfo_t*)(tag->data); | ||
120 | |||
121 | if (mi->type != MEMORY_TYPE_CONVENTIONAL) | ||
122 | return -1; | ||
123 | |||
124 | if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) { | ||
125 | printk(KERN_WARNING | ||
126 | "Ignoring memory bank 0x%08lx size %ldKB\n", | ||
127 | (unsigned long)mi->start, | ||
128 | (unsigned long)mi->end - (unsigned long)mi->start); | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | sysmem.bank[sysmem.nr_banks].type = mi->type; | ||
132 | sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start); | ||
133 | sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_SIZE; | ||
134 | sysmem.nr_banks++; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | __tagtable(BP_TAG_MEMORY, parse_tag_mem); | ||
140 | |||
141 | #ifdef CONFIG_BLK_DEV_INITRD | ||
142 | |||
143 | static int __init parse_tag_initrd(const bp_tag_t* tag) | ||
144 | { | ||
145 | meminfo_t* mi; | ||
146 | mi = (meminfo_t*)(tag->data); | ||
147 | initrd_start = (void*)(mi->start); | ||
148 | initrd_end = (void*)(mi->end); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | __tagtable(BP_TAG_INITRD, parse_tag_initrd); | ||
154 | |||
155 | #endif /* CONFIG_BLK_DEV_INITRD */ | ||
156 | |||
157 | static int __init parse_tag_cmdline(const bp_tag_t* tag) | ||
158 | { | ||
159 | strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE); | ||
160 | command_line[COMMAND_LINE_SIZE - 1] = '\0'; | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | __tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline); | ||
165 | |||
166 | static int __init parse_bootparam(const bp_tag_t* tag) | ||
167 | { | ||
168 | extern tagtable_t __tagtable_begin, __tagtable_end; | ||
169 | tagtable_t *t; | ||
170 | |||
171 | /* Boot parameters must start with a BP_TAG_FIRST tag. */ | ||
172 | |||
173 | if (tag->id != BP_TAG_FIRST) { | ||
174 | printk(KERN_WARNING "Invalid boot parameters!\n"); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size); | ||
179 | |||
180 | /* Parse all tags. */ | ||
181 | |||
182 | while (tag != NULL && tag->id != BP_TAG_LAST) { | ||
183 | for (t = &__tagtable_begin; t < &__tagtable_end; t++) { | ||
184 | if (tag->id == t->tag) { | ||
185 | t->parse(tag); | ||
186 | break; | ||
187 | } | ||
188 | } | ||
189 | if (t == &__tagtable_end) | ||
190 | printk(KERN_WARNING "Ignoring tag " | ||
191 | "0x%08x\n", tag->id); | ||
192 | tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size); | ||
193 | } | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Initialize architecture. (Early stage) | ||
200 | */ | ||
201 | |||
202 | void __init init_arch(bp_tag_t *bp_start) | ||
203 | { | ||
204 | |||
205 | #ifdef CONFIG_BLK_DEV_INITRD | ||
206 | initrd_start = &__initrd_start; | ||
207 | initrd_end = &__initrd_end; | ||
208 | #endif | ||
209 | |||
210 | sysmem.nr_banks = 0; | ||
211 | |||
212 | #ifdef CONFIG_CMDLINE_BOOL | ||
213 | strcpy(command_line, default_command_line); | ||
214 | #endif | ||
215 | |||
216 | /* Parse boot parameters */ | ||
217 | |||
218 | if (bp_start) | ||
219 | parse_bootparam(bp_start); | ||
220 | |||
221 | if (sysmem.nr_banks == 0) { | ||
222 | sysmem.nr_banks = 1; | ||
223 | sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START; | ||
224 | sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START | ||
225 | + PLATFORM_DEFAULT_MEM_SIZE; | ||
226 | } | ||
227 | |||
228 | /* Early hook for platforms */ | ||
229 | |||
230 | platform_init(bp_start); | ||
231 | |||
232 | /* Initialize MMU. */ | ||
233 | |||
234 | init_mmu(); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Initialize system. Setup memory and reserve regions. | ||
239 | */ | ||
240 | |||
241 | extern char _end; | ||
242 | extern char _stext; | ||
243 | extern char _WindowVectors_text_start; | ||
244 | extern char _WindowVectors_text_end; | ||
245 | extern char _DebugInterruptVector_literal_start; | ||
246 | extern char _DebugInterruptVector_text_end; | ||
247 | extern char _KernelExceptionVector_literal_start; | ||
248 | extern char _KernelExceptionVector_text_end; | ||
249 | extern char _UserExceptionVector_literal_start; | ||
250 | extern char _UserExceptionVector_text_end; | ||
251 | extern char _DoubleExceptionVector_literal_start; | ||
252 | extern char _DoubleExceptionVector_text_end; | ||
253 | |||
254 | void __init setup_arch(char **cmdline_p) | ||
255 | { | ||
256 | extern int mem_reserve(unsigned long, unsigned long, int); | ||
257 | extern void bootmem_init(void); | ||
258 | |||
259 | memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); | ||
260 | saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; | ||
261 | *cmdline_p = command_line; | ||
262 | |||
263 | /* Reserve some memory regions */ | ||
264 | |||
265 | #ifdef CONFIG_BLK_DEV_INITRD | ||
266 | if (initrd_start < initrd_end) { | ||
267 | initrd_is_mapped = mem_reserve(__pa(initrd_start), | ||
268 | __pa(initrd_end), 0); | ||
269 | initrd_below_start_ok = 1; | ||
270 | } else { | ||
271 | initrd_start = 0; | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | mem_reserve(__pa(&_stext),__pa(&_end), 1); | ||
276 | |||
277 | mem_reserve(__pa(&_WindowVectors_text_start), | ||
278 | __pa(&_WindowVectors_text_end), 0); | ||
279 | |||
280 | mem_reserve(__pa(&_DebugInterruptVector_literal_start), | ||
281 | __pa(&_DebugInterruptVector_text_end), 0); | ||
282 | |||
283 | mem_reserve(__pa(&_KernelExceptionVector_literal_start), | ||
284 | __pa(&_KernelExceptionVector_text_end), 0); | ||
285 | |||
286 | mem_reserve(__pa(&_UserExceptionVector_literal_start), | ||
287 | __pa(&_UserExceptionVector_text_end), 0); | ||
288 | |||
289 | mem_reserve(__pa(&_DoubleExceptionVector_literal_start), | ||
290 | __pa(&_DoubleExceptionVector_text_end), 0); | ||
291 | |||
292 | bootmem_init(); | ||
293 | |||
294 | platform_setup(cmdline_p); | ||
295 | |||
296 | |||
297 | paging_init(); | ||
298 | |||
299 | #ifdef CONFIG_VT | ||
300 | # if defined(CONFIG_VGA_CONSOLE) | ||
301 | conswitchp = &vga_con; | ||
302 | # elif defined(CONFIG_DUMMY_CONSOLE) | ||
303 | conswitchp = &dummy_con; | ||
304 | # endif | ||
305 | #endif | ||
306 | |||
307 | #if CONFIG_PCI | ||
308 | platform_pcibios_init(); | ||
309 | #endif | ||
310 | } | ||
311 | |||
312 | void machine_restart(char * cmd) | ||
313 | { | ||
314 | platform_restart(); | ||
315 | } | ||
316 | |||
317 | void machine_halt(void) | ||
318 | { | ||
319 | platform_halt(); | ||
320 | while (1); | ||
321 | } | ||
322 | |||
323 | void machine_power_off(void) | ||
324 | { | ||
325 | platform_power_off(); | ||
326 | while (1); | ||
327 | } | ||
328 | #ifdef CONFIG_PROC_FS | ||
329 | |||
330 | /* | ||
331 | * Display some core information through /proc/cpuinfo. | ||
332 | */ | ||
333 | |||
334 | static int | ||
335 | c_show(struct seq_file *f, void *slot) | ||
336 | { | ||
337 | /* high-level stuff */ | ||
338 | seq_printf(f,"processor\t: 0\n" | ||
339 | "vendor_id\t: Tensilica\n" | ||
340 | "model\t\t: Xtensa " XCHAL_HW_RELEASE_NAME "\n" | ||
341 | "core ID\t\t: " XCHAL_CORE_ID "\n" | ||
342 | "build ID\t: 0x%x\n" | ||
343 | "byte order\t: %s\n" | ||
344 | "cpu MHz\t\t: %lu.%02lu\n" | ||
345 | "bogomips\t: %lu.%02lu\n", | ||
346 | XCHAL_BUILD_UNIQUE_ID, | ||
347 | XCHAL_HAVE_BE ? "big" : "little", | ||
348 | CCOUNT_PER_JIFFY/(1000000/HZ), | ||
349 | (CCOUNT_PER_JIFFY/(10000/HZ)) % 100, | ||
350 | loops_per_jiffy/(500000/HZ), | ||
351 | (loops_per_jiffy/(5000/HZ)) % 100); | ||
352 | |||
353 | seq_printf(f,"flags\t\t: " | ||
354 | #if XCHAL_HAVE_NMI | ||
355 | "nmi " | ||
356 | #endif | ||
357 | #if XCHAL_HAVE_DEBUG | ||
358 | "debug " | ||
359 | # if XCHAL_HAVE_OCD | ||
360 | "ocd " | ||
361 | # endif | ||
362 | #endif | ||
363 | #if XCHAL_HAVE_DENSITY | ||
364 | "density " | ||
365 | #endif | ||
366 | #if XCHAL_HAVE_BOOLEANS | ||
367 | "boolean " | ||
368 | #endif | ||
369 | #if XCHAL_HAVE_LOOPS | ||
370 | "loop " | ||
371 | #endif | ||
372 | #if XCHAL_HAVE_NSA | ||
373 | "nsa " | ||
374 | #endif | ||
375 | #if XCHAL_HAVE_MINMAX | ||
376 | "minmax " | ||
377 | #endif | ||
378 | #if XCHAL_HAVE_SEXT | ||
379 | "sext " | ||
380 | #endif | ||
381 | #if XCHAL_HAVE_CLAMPS | ||
382 | "clamps " | ||
383 | #endif | ||
384 | #if XCHAL_HAVE_MAC16 | ||
385 | "mac16 " | ||
386 | #endif | ||
387 | #if XCHAL_HAVE_MUL16 | ||
388 | "mul16 " | ||
389 | #endif | ||
390 | #if XCHAL_HAVE_MUL32 | ||
391 | "mul32 " | ||
392 | #endif | ||
393 | #if XCHAL_HAVE_MUL32_HIGH | ||
394 | "mul32h " | ||
395 | #endif | ||
396 | #if XCHAL_HAVE_FP | ||
397 | "fpu " | ||
398 | #endif | ||
399 | "\n"); | ||
400 | |||
401 | /* Registers. */ | ||
402 | seq_printf(f,"physical aregs\t: %d\n" | ||
403 | "misc regs\t: %d\n" | ||
404 | "ibreak\t\t: %d\n" | ||
405 | "dbreak\t\t: %d\n", | ||
406 | XCHAL_NUM_AREGS, | ||
407 | XCHAL_NUM_MISC_REGS, | ||
408 | XCHAL_NUM_IBREAK, | ||
409 | XCHAL_NUM_DBREAK); | ||
410 | |||
411 | |||
412 | /* Interrupt. */ | ||
413 | seq_printf(f,"num ints\t: %d\n" | ||
414 | "ext ints\t: %d\n" | ||
415 | "int levels\t: %d\n" | ||
416 | "timers\t\t: %d\n" | ||
417 | "debug level\t: %d\n", | ||
418 | XCHAL_NUM_INTERRUPTS, | ||
419 | XCHAL_NUM_EXTINTERRUPTS, | ||
420 | XCHAL_NUM_INTLEVELS, | ||
421 | XCHAL_NUM_TIMERS, | ||
422 | XCHAL_DEBUGLEVEL); | ||
423 | |||
424 | /* Coprocessors */ | ||
425 | #if XCHAL_HAVE_CP | ||
426 | seq_printf(f, "coprocessors\t: %d\n", XCHAL_CP_NUM); | ||
427 | #else | ||
428 | seq_printf(f, "coprocessors\t: none\n"); | ||
429 | #endif | ||
430 | |||
431 | /* {I,D}{RAM,ROM} and XLMI */ | ||
432 | seq_printf(f,"inst ROMs\t: %d\n" | ||
433 | "inst RAMs\t: %d\n" | ||
434 | "data ROMs\t: %d\n" | ||
435 | "data RAMs\t: %d\n" | ||
436 | "XLMI ports\t: %d\n", | ||
437 | XCHAL_NUM_IROM, | ||
438 | XCHAL_NUM_IRAM, | ||
439 | XCHAL_NUM_DROM, | ||
440 | XCHAL_NUM_DRAM, | ||
441 | XCHAL_NUM_XLMI); | ||
442 | |||
443 | /* Cache */ | ||
444 | seq_printf(f,"icache line size: %d\n" | ||
445 | "icache ways\t: %d\n" | ||
446 | "icache size\t: %d\n" | ||
447 | "icache flags\t: " | ||
448 | #if XCHAL_ICACHE_LINE_LOCKABLE | ||
449 | "lock" | ||
450 | #endif | ||
451 | "\n" | ||
452 | "dcache line size: %d\n" | ||
453 | "dcache ways\t: %d\n" | ||
454 | "dcache size\t: %d\n" | ||
455 | "dcache flags\t: " | ||
456 | #if XCHAL_DCACHE_IS_WRITEBACK | ||
457 | "writeback" | ||
458 | #endif | ||
459 | #if XCHAL_DCACHE_LINE_LOCKABLE | ||
460 | "lock" | ||
461 | #endif | ||
462 | "\n", | ||
463 | XCHAL_ICACHE_LINESIZE, | ||
464 | XCHAL_ICACHE_WAYS, | ||
465 | XCHAL_ICACHE_SIZE, | ||
466 | XCHAL_DCACHE_LINESIZE, | ||
467 | XCHAL_DCACHE_WAYS, | ||
468 | XCHAL_DCACHE_SIZE); | ||
469 | |||
470 | /* MMU */ | ||
471 | seq_printf(f,"ASID bits\t: %d\n" | ||
472 | "ASID invalid\t: %d\n" | ||
473 | "ASID kernel\t: %d\n" | ||
474 | "rings\t\t: %d\n" | ||
475 | "itlb ways\t: %d\n" | ||
476 | "itlb AR ways\t: %d\n" | ||
477 | "dtlb ways\t: %d\n" | ||
478 | "dtlb AR ways\t: %d\n", | ||
479 | XCHAL_MMU_ASID_BITS, | ||
480 | XCHAL_MMU_ASID_INVALID, | ||
481 | XCHAL_MMU_ASID_KERNEL, | ||
482 | XCHAL_MMU_RINGS, | ||
483 | XCHAL_ITLB_WAYS, | ||
484 | XCHAL_ITLB_ARF_WAYS, | ||
485 | XCHAL_DTLB_WAYS, | ||
486 | XCHAL_DTLB_ARF_WAYS); | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | * We show only CPU #0 info. | ||
493 | */ | ||
494 | static void * | ||
495 | c_start(struct seq_file *f, loff_t *pos) | ||
496 | { | ||
497 | return (void *) ((*pos == 0) ? (void *)1 : NULL); | ||
498 | } | ||
499 | |||
500 | static void * | ||
501 | c_next(struct seq_file *f, void *v, loff_t *pos) | ||
502 | { | ||
503 | return NULL; | ||
504 | } | ||
505 | |||
506 | static void | ||
507 | c_stop(struct seq_file *f, void *v) | ||
508 | { | ||
509 | } | ||
510 | |||
511 | struct seq_operations cpuinfo_op = | ||
512 | { | ||
513 | start: c_start, | ||
514 | next: c_next, | ||
515 | stop: c_stop, | ||
516 | show: c_show | ||
517 | }; | ||
518 | |||
519 | #endif /* CONFIG_PROC_FS */ | ||
520 | |||