blob: 4375284039595f93f2ce9cf91b27abd3fb677375 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/kernel/setup.c
3 *
4 * Copyright (C) 1995-2001 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/config.h>
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/stddef.h>
14#include <linux/ioport.h>
15#include <linux/delay.h>
16#include <linux/utsname.h>
17#include <linux/initrd.h>
18#include <linux/console.h>
19#include <linux/bootmem.h>
20#include <linux/seq_file.h>
21#include <linux/tty.h>
22#include <linux/init.h>
23#include <linux/root_dev.h>
24#include <linux/cpu.h>
25#include <linux/interrupt.h>
Russell King7bbb7942006-02-16 11:08:09 +000026#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/cpu.h>
29#include <asm/elf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/procinfo.h>
31#include <asm/setup.h>
32#include <asm/mach-types.h>
33#include <asm/cacheflush.h>
34#include <asm/tlbflush.h>
35
36#include <asm/mach/arch.h>
37#include <asm/mach/irq.h>
38#include <asm/mach/time.h>
39
Ben Dooks0fc1c832006-03-15 23:17:30 +000040#include "compat.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#ifndef MEM_SIZE
43#define MEM_SIZE (16*1024*1024)
44#endif
45
46#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
47char fpe_type[8];
48
49static int __init fpe_setup(char *line)
50{
51 memcpy(fpe_type, line, 8);
52 return 1;
53}
54
55__setup("fpe=", fpe_setup);
56#endif
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058extern void paging_init(struct meminfo *, struct machine_desc *desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059extern void reboot_setup(char *str);
60extern int root_mountflags;
61extern void _stext, _text, _etext, __data_start, _edata, _end;
62
63unsigned int processor_id;
64unsigned int __machine_arch_type;
65EXPORT_SYMBOL(__machine_arch_type);
66
67unsigned int system_rev;
68EXPORT_SYMBOL(system_rev);
69
70unsigned int system_serial_low;
71EXPORT_SYMBOL(system_serial_low);
72
73unsigned int system_serial_high;
74EXPORT_SYMBOL(system_serial_high);
75
76unsigned int elf_hwcap;
77EXPORT_SYMBOL(elf_hwcap);
78
79
80#ifdef MULTI_CPU
81struct processor processor;
82#endif
83#ifdef MULTI_TLB
84struct cpu_tlb_fns cpu_tlb;
85#endif
86#ifdef MULTI_USER
87struct cpu_user_fns cpu_user;
88#endif
89#ifdef MULTI_CACHE
90struct cpu_cache_fns cpu_cache;
91#endif
92
Russell Kingccea7a12005-05-31 22:22:32 +010093struct stack {
94 u32 irq[3];
95 u32 abt[3];
96 u32 und[3];
97} ____cacheline_aligned;
98
99static struct stack stacks[NR_CPUS];
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101char elf_platform[ELF_PLATFORM_SIZE];
102EXPORT_SYMBOL(elf_platform);
103
104unsigned long phys_initrd_start __initdata = 0;
105unsigned long phys_initrd_size __initdata = 0;
106
107static struct meminfo meminfo __initdata = { 0, };
108static const char *cpu_name;
109static const char *machine_name;
110static char command_line[COMMAND_LINE_SIZE];
111
112static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
113static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
114#define ENDIANNESS ((char)endian_test.l)
115
116DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
117
118/*
119 * Standard memory resources
120 */
121static struct resource mem_res[] = {
122 { "Video RAM", 0, 0, IORESOURCE_MEM },
123 { "Kernel text", 0, 0, IORESOURCE_MEM },
124 { "Kernel data", 0, 0, IORESOURCE_MEM }
125};
126
127#define video_ram mem_res[0]
128#define kernel_code mem_res[1]
129#define kernel_data mem_res[2]
130
131static struct resource io_res[] = {
132 { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
133 { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
134 { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
135};
136
137#define lp0 io_res[0]
138#define lp1 io_res[1]
139#define lp2 io_res[2]
140
141static const char *cache_types[16] = {
142 "write-through",
143 "write-back",
144 "write-back",
145 "undefined 3",
146 "undefined 4",
147 "undefined 5",
148 "write-back",
149 "write-back",
150 "undefined 8",
151 "undefined 9",
152 "undefined 10",
153 "undefined 11",
154 "undefined 12",
155 "undefined 13",
156 "write-back",
157 "undefined 15",
158};
159
160static const char *cache_clean[16] = {
161 "not required",
162 "read-block",
163 "cp15 c7 ops",
164 "undefined 3",
165 "undefined 4",
166 "undefined 5",
167 "cp15 c7 ops",
168 "cp15 c7 ops",
169 "undefined 8",
170 "undefined 9",
171 "undefined 10",
172 "undefined 11",
173 "undefined 12",
174 "undefined 13",
175 "cp15 c7 ops",
176 "undefined 15",
177};
178
179static const char *cache_lockdown[16] = {
180 "not supported",
181 "not supported",
182 "not supported",
183 "undefined 3",
184 "undefined 4",
185 "undefined 5",
186 "format A",
187 "format B",
188 "undefined 8",
189 "undefined 9",
190 "undefined 10",
191 "undefined 11",
192 "undefined 12",
193 "undefined 13",
194 "format C",
195 "undefined 15",
196};
197
198static const char *proc_arch[] = {
199 "undefined/unknown",
200 "3",
201 "4",
202 "4T",
203 "5",
204 "5T",
205 "5TE",
206 "5TEJ",
207 "6TEJ",
Catalin Marinas6b090a22006-01-12 16:28:16 +0000208 "7",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 "?(11)",
210 "?(12)",
211 "?(13)",
212 "?(14)",
213 "?(15)",
214 "?(16)",
215 "?(17)",
216};
217
218#define CACHE_TYPE(x) (((x) >> 25) & 15)
219#define CACHE_S(x) ((x) & (1 << 24))
220#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
221#define CACHE_ISIZE(x) ((x) & 4095)
222
223#define CACHE_SIZE(y) (((y) >> 6) & 7)
224#define CACHE_ASSOC(y) (((y) >> 3) & 7)
225#define CACHE_M(y) ((y) & (1 << 2))
226#define CACHE_LINE(y) ((y) & 3)
227
228static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
229{
230 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
231
232 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
233 cpu, prefix,
234 mult << (8 + CACHE_SIZE(cache)),
235 (mult << CACHE_ASSOC(cache)) >> 1,
236 8 << CACHE_LINE(cache),
237 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
238 CACHE_LINE(cache)));
239}
240
241static void __init dump_cpu_info(int cpu)
242{
243 unsigned int info = read_cpuid(CPUID_CACHETYPE);
244
245 if (info != processor_id) {
246 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
247 cache_types[CACHE_TYPE(info)]);
248 if (CACHE_S(info)) {
249 dump_cache("I cache", cpu, CACHE_ISIZE(info));
250 dump_cache("D cache", cpu, CACHE_DSIZE(info));
251 } else {
252 dump_cache("cache", cpu, CACHE_ISIZE(info));
253 }
254 }
Lennert Buytenhek23759dc2006-04-02 00:07:39 +0100255
256 if (arch_is_coherent())
257 printk("Cache coherency enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
260int cpu_architecture(void)
261{
262 int cpu_arch;
263
Catalin Marinas6b090a22006-01-12 16:28:16 +0000264 if ((processor_id & 0x0008f000) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 cpu_arch = CPU_ARCH_UNKNOWN;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000266 } else if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000268 } else if ((processor_id & 0x00080000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 cpu_arch = (processor_id >> 16) & 7;
270 if (cpu_arch)
271 cpu_arch += CPU_ARCH_ARMv3;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000272 } else {
273 /* the revised CPUID */
274 cpu_arch = ((processor_id >> 12) & 0xf) - 0xb + CPU_ARCH_ARMv6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 }
276
277 return cpu_arch;
278}
279
280/*
281 * These functions re-use the assembly code in head.S, which
282 * already provide the required functionality.
283 */
Russell King0f44ba12006-02-24 21:04:56 +0000284extern struct proc_info_list *lookup_processor_type(unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285extern struct machine_desc *lookup_machine_type(unsigned int);
286
287static void __init setup_processor(void)
288{
289 struct proc_info_list *list;
290
291 /*
292 * locate processor in the list of supported processor
293 * types. The linker builds this table for us from the
294 * entries in arch/arm/mm/proc-*.S
295 */
Russell King0f44ba12006-02-24 21:04:56 +0000296 list = lookup_processor_type(processor_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (!list) {
298 printk("CPU configuration botched (ID %08x), unable "
299 "to continue.\n", processor_id);
300 while (1);
301 }
302
303 cpu_name = list->cpu_name;
304
305#ifdef MULTI_CPU
306 processor = *list->proc;
307#endif
308#ifdef MULTI_TLB
309 cpu_tlb = *list->tlb;
310#endif
311#ifdef MULTI_USER
312 cpu_user = *list->user;
313#endif
314#ifdef MULTI_CACHE
315 cpu_cache = *list->cache;
316#endif
317
318 printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
319 cpu_name, processor_id, (int)processor_id & 15,
320 proc_arch[cpu_architecture()]);
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
323 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
324 elf_hwcap = list->elf_hwcap;
325
326 cpu_proc_init();
327}
328
Russell Kingccea7a12005-05-31 22:22:32 +0100329/*
330 * cpu_init - initialise one CPU.
331 *
332 * cpu_init dumps the cache information, initialises SMP specific
333 * information, and sets up the per-CPU stacks.
334 */
Russell King36c5ed22005-06-19 18:39:33 +0100335void cpu_init(void)
Russell Kingccea7a12005-05-31 22:22:32 +0100336{
337 unsigned int cpu = smp_processor_id();
338 struct stack *stk = &stacks[cpu];
339
340 if (cpu >= NR_CPUS) {
341 printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
342 BUG();
343 }
344
Russell King32f8b972005-11-06 19:49:21 +0000345 if (system_state == SYSTEM_BOOTING)
346 dump_cpu_info(cpu);
Russell Kingccea7a12005-05-31 22:22:32 +0100347
348 /*
349 * setup stacks for re-entrant exception handlers
350 */
351 __asm__ (
352 "msr cpsr_c, %1\n\t"
353 "add sp, %0, %2\n\t"
354 "msr cpsr_c, %3\n\t"
355 "add sp, %0, %4\n\t"
356 "msr cpsr_c, %5\n\t"
357 "add sp, %0, %6\n\t"
358 "msr cpsr_c, %7"
359 :
360 : "r" (stk),
361 "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
362 "I" (offsetof(struct stack, irq[0])),
363 "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
364 "I" (offsetof(struct stack, abt[0])),
365 "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
366 "I" (offsetof(struct stack, und[0])),
Catalin Marinasaaaa3f92005-06-29 15:34:39 +0100367 "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
368 : "r14");
Russell Kingccea7a12005-05-31 22:22:32 +0100369}
370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371static struct machine_desc * __init setup_machine(unsigned int nr)
372{
373 struct machine_desc *list;
374
375 /*
376 * locate machine in the list of supported machines.
377 */
378 list = lookup_machine_type(nr);
379 if (!list) {
380 printk("Machine configuration botched (nr %d), unable "
381 "to continue.\n", nr);
382 while (1);
383 }
384
385 printk("Machine: %s\n", list->name);
386
387 return list;
388}
389
390static void __init early_initrd(char **p)
391{
392 unsigned long start, size;
393
394 start = memparse(*p, p);
395 if (**p == ',') {
396 size = memparse((*p) + 1, p);
397
398 phys_initrd_start = start;
399 phys_initrd_size = size;
400 }
401}
402__early_param("initrd=", early_initrd);
403
Russell King3a669412005-06-22 21:43:10 +0100404static void __init add_memory(unsigned long start, unsigned long size)
405{
406 /*
407 * Ensure that start/size are aligned to a page boundary.
408 * Size is appropriately rounded down, start is rounded up.
409 */
410 size -= start & ~PAGE_MASK;
411
412 meminfo.bank[meminfo.nr_banks].start = PAGE_ALIGN(start);
413 meminfo.bank[meminfo.nr_banks].size = size & PAGE_MASK;
414 meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start);
415 meminfo.nr_banks += 1;
416}
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418/*
419 * Pick out the memory size. We look for mem=size@start,
420 * where start and size are "size[KkMm]"
421 */
422static void __init early_mem(char **p)
423{
424 static int usermem __initdata = 0;
425 unsigned long size, start;
426
427 /*
428 * If the user specifies memory size, we
429 * blow away any automatically generated
430 * size.
431 */
432 if (usermem == 0) {
433 usermem = 1;
434 meminfo.nr_banks = 0;
435 }
436
437 start = PHYS_OFFSET;
438 size = memparse(*p, p);
439 if (**p == '@')
440 start = memparse(*p + 1, p);
441
Russell King3a669412005-06-22 21:43:10 +0100442 add_memory(start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444__early_param("mem=", early_mem);
445
446/*
447 * Initial parsing of the command line.
448 */
449static void __init parse_cmdline(char **cmdline_p, char *from)
450{
451 char c = ' ', *to = command_line;
452 int len = 0;
453
454 for (;;) {
455 if (c == ' ') {
456 extern struct early_params __early_begin, __early_end;
457 struct early_params *p;
458
459 for (p = &__early_begin; p < &__early_end; p++) {
460 int len = strlen(p->arg);
461
462 if (memcmp(from, p->arg, len) == 0) {
463 if (to != command_line)
464 to -= 1;
465 from += len;
466 p->fn(&from);
467
468 while (*from != ' ' && *from != '\0')
469 from++;
470 break;
471 }
472 }
473 }
474 c = *from++;
475 if (!c)
476 break;
477 if (COMMAND_LINE_SIZE <= ++len)
478 break;
479 *to++ = c;
480 }
481 *to = '\0';
482 *cmdline_p = command_line;
483}
484
485static void __init
486setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
487{
488#ifdef CONFIG_BLK_DEV_RAM
489 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
490
491 rd_image_start = image_start;
492 rd_prompt = prompt;
493 rd_doload = doload;
494
495 if (rd_sz)
496 rd_size = rd_sz;
497#endif
498}
499
500static void __init
501request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
502{
503 struct resource *res;
504 int i;
505
506 kernel_code.start = virt_to_phys(&_text);
507 kernel_code.end = virt_to_phys(&_etext - 1);
508 kernel_data.start = virt_to_phys(&__data_start);
509 kernel_data.end = virt_to_phys(&_end - 1);
510
511 for (i = 0; i < mi->nr_banks; i++) {
512 unsigned long virt_start, virt_end;
513
514 if (mi->bank[i].size == 0)
515 continue;
516
517 virt_start = __phys_to_virt(mi->bank[i].start);
518 virt_end = virt_start + mi->bank[i].size - 1;
519
520 res = alloc_bootmem_low(sizeof(*res));
521 res->name = "System RAM";
522 res->start = __virt_to_phys(virt_start);
523 res->end = __virt_to_phys(virt_end);
524 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
525
526 request_resource(&iomem_resource, res);
527
528 if (kernel_code.start >= res->start &&
529 kernel_code.end <= res->end)
530 request_resource(res, &kernel_code);
531 if (kernel_data.start >= res->start &&
532 kernel_data.end <= res->end)
533 request_resource(res, &kernel_data);
534 }
535
536 if (mdesc->video_start) {
537 video_ram.start = mdesc->video_start;
538 video_ram.end = mdesc->video_end;
539 request_resource(&iomem_resource, &video_ram);
540 }
541
542 /*
543 * Some machines don't have the possibility of ever
544 * possessing lp0, lp1 or lp2
545 */
546 if (mdesc->reserve_lp0)
547 request_resource(&ioport_resource, &lp0);
548 if (mdesc->reserve_lp1)
549 request_resource(&ioport_resource, &lp1);
550 if (mdesc->reserve_lp2)
551 request_resource(&ioport_resource, &lp2);
552}
553
554/*
555 * Tag parsing.
556 *
557 * This is the new way of passing data to the kernel at boot time. Rather
558 * than passing a fixed inflexible structure to the kernel, we pass a list
559 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
560 * tag for the list to be recognised (to distinguish the tagged list from
561 * a param_struct). The list is terminated with a zero-length tag (this tag
562 * is not parsed in any way).
563 */
564static int __init parse_tag_core(const struct tag *tag)
565{
566 if (tag->hdr.size > 2) {
567 if ((tag->u.core.flags & 1) == 0)
568 root_mountflags &= ~MS_RDONLY;
569 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
570 }
571 return 0;
572}
573
574__tagtable(ATAG_CORE, parse_tag_core);
575
576static int __init parse_tag_mem32(const struct tag *tag)
577{
578 if (meminfo.nr_banks >= NR_BANKS) {
579 printk(KERN_WARNING
580 "Ignoring memory bank 0x%08x size %dKB\n",
581 tag->u.mem.start, tag->u.mem.size / 1024);
582 return -EINVAL;
583 }
Russell King3a669412005-06-22 21:43:10 +0100584 add_memory(tag->u.mem.start, tag->u.mem.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return 0;
586}
587
588__tagtable(ATAG_MEM, parse_tag_mem32);
589
590#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
591struct screen_info screen_info = {
592 .orig_video_lines = 30,
593 .orig_video_cols = 80,
594 .orig_video_mode = 0,
595 .orig_video_ega_bx = 0,
596 .orig_video_isVGA = 1,
597 .orig_video_points = 8
598};
599
600static int __init parse_tag_videotext(const struct tag *tag)
601{
602 screen_info.orig_x = tag->u.videotext.x;
603 screen_info.orig_y = tag->u.videotext.y;
604 screen_info.orig_video_page = tag->u.videotext.video_page;
605 screen_info.orig_video_mode = tag->u.videotext.video_mode;
606 screen_info.orig_video_cols = tag->u.videotext.video_cols;
607 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
608 screen_info.orig_video_lines = tag->u.videotext.video_lines;
609 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
610 screen_info.orig_video_points = tag->u.videotext.video_points;
611 return 0;
612}
613
614__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
615#endif
616
617static int __init parse_tag_ramdisk(const struct tag *tag)
618{
619 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
620 (tag->u.ramdisk.flags & 2) == 0,
621 tag->u.ramdisk.start, tag->u.ramdisk.size);
622 return 0;
623}
624
625__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
626
627static int __init parse_tag_initrd(const struct tag *tag)
628{
629 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
630 "please update your bootloader.\n");
631 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
632 phys_initrd_size = tag->u.initrd.size;
633 return 0;
634}
635
636__tagtable(ATAG_INITRD, parse_tag_initrd);
637
638static int __init parse_tag_initrd2(const struct tag *tag)
639{
640 phys_initrd_start = tag->u.initrd.start;
641 phys_initrd_size = tag->u.initrd.size;
642 return 0;
643}
644
645__tagtable(ATAG_INITRD2, parse_tag_initrd2);
646
647static int __init parse_tag_serialnr(const struct tag *tag)
648{
649 system_serial_low = tag->u.serialnr.low;
650 system_serial_high = tag->u.serialnr.high;
651 return 0;
652}
653
654__tagtable(ATAG_SERIAL, parse_tag_serialnr);
655
656static int __init parse_tag_revision(const struct tag *tag)
657{
658 system_rev = tag->u.revision.rev;
659 return 0;
660}
661
662__tagtable(ATAG_REVISION, parse_tag_revision);
663
664static int __init parse_tag_cmdline(const struct tag *tag)
665{
666 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
667 return 0;
668}
669
670__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
671
672/*
673 * Scan the tag table for this tag, and call its parse function.
674 * The tag table is built by the linker from all the __tagtable
675 * declarations.
676 */
677static int __init parse_tag(const struct tag *tag)
678{
679 extern struct tagtable __tagtable_begin, __tagtable_end;
680 struct tagtable *t;
681
682 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
683 if (tag->hdr.tag == t->tag) {
684 t->parse(tag);
685 break;
686 }
687
688 return t < &__tagtable_end;
689}
690
691/*
692 * Parse all tags in the list, checking both the global and architecture
693 * specific tag tables.
694 */
695static void __init parse_tags(const struct tag *t)
696{
697 for (; t->hdr.size; t = tag_next(t))
698 if (!parse_tag(t))
699 printk(KERN_WARNING
700 "Ignoring unrecognised tag 0x%08x\n",
701 t->hdr.tag);
702}
703
704/*
705 * This holds our defaults.
706 */
707static struct init_tags {
708 struct tag_header hdr1;
709 struct tag_core core;
710 struct tag_header hdr2;
711 struct tag_mem32 mem;
712 struct tag_header hdr3;
713} init_tags __initdata = {
714 { tag_size(tag_core), ATAG_CORE },
715 { 1, PAGE_SIZE, 0xff },
716 { tag_size(tag_mem32), ATAG_MEM },
717 { MEM_SIZE, PHYS_OFFSET },
718 { 0, ATAG_NONE }
719};
720
721static void (*init_machine)(void) __initdata;
722
723static int __init customize_machine(void)
724{
725 /* customizes platform devices, or adds new ones */
726 if (init_machine)
727 init_machine();
728 return 0;
729}
730arch_initcall(customize_machine);
731
732void __init setup_arch(char **cmdline_p)
733{
734 struct tag *tags = (struct tag *)&init_tags;
735 struct machine_desc *mdesc;
736 char *from = default_command_line;
737
738 setup_processor();
739 mdesc = setup_machine(machine_arch_type);
740 machine_name = mdesc->name;
741
742 if (mdesc->soft_reboot)
743 reboot_setup("s");
744
Russell Kingf9bd6ea2005-07-04 10:43:36 +0100745 if (mdesc->boot_params)
746 tags = phys_to_virt(mdesc->boot_params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 /*
749 * If we have the old style parameters, convert them to
750 * a tag list.
751 */
752 if (tags->hdr.tag != ATAG_CORE)
753 convert_to_tag_list(tags);
754 if (tags->hdr.tag != ATAG_CORE)
755 tags = (struct tag *)&init_tags;
756
757 if (mdesc->fixup)
758 mdesc->fixup(mdesc, tags, &from, &meminfo);
759
760 if (tags->hdr.tag == ATAG_CORE) {
761 if (meminfo.nr_banks != 0)
762 squash_mem_tags(tags);
763 parse_tags(tags);
764 }
765
766 init_mm.start_code = (unsigned long) &_text;
767 init_mm.end_code = (unsigned long) &_etext;
768 init_mm.end_data = (unsigned long) &_edata;
769 init_mm.brk = (unsigned long) &_end;
770
771 memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
772 saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
773 parse_cmdline(cmdline_p, from);
774 paging_init(&meminfo, mdesc);
775 request_standard_resources(&meminfo, mdesc);
776
Russell King7bbb7942006-02-16 11:08:09 +0000777#ifdef CONFIG_SMP
778 smp_init_cpus();
779#endif
780
Russell Kingccea7a12005-05-31 22:22:32 +0100781 cpu_init();
782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 /*
784 * Set up various architecture-specific pointers
785 */
786 init_arch_irq = mdesc->init_irq;
787 system_timer = mdesc->timer;
788 init_machine = mdesc->init_machine;
789
790#ifdef CONFIG_VT
791#if defined(CONFIG_VGA_CONSOLE)
792 conswitchp = &vga_con;
793#elif defined(CONFIG_DUMMY_CONSOLE)
794 conswitchp = &dummy_con;
795#endif
796#endif
797}
798
799
800static int __init topology_init(void)
801{
802 int cpu;
803
804 for_each_cpu(cpu)
805 register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu, NULL);
806
807 return 0;
808}
809
810subsys_initcall(topology_init);
811
812static const char *hwcap_str[] = {
813 "swp",
814 "half",
815 "thumb",
816 "26bit",
817 "fastmult",
818 "fpa",
819 "vfp",
820 "edsp",
821 "java",
822 NULL
823};
824
825static void
826c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
827{
828 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
829
830 seq_printf(m, "%s size\t\t: %d\n"
831 "%s assoc\t\t: %d\n"
832 "%s line length\t: %d\n"
833 "%s sets\t\t: %d\n",
834 type, mult << (8 + CACHE_SIZE(cache)),
835 type, (mult << CACHE_ASSOC(cache)) >> 1,
836 type, 8 << CACHE_LINE(cache),
837 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
838 CACHE_LINE(cache)));
839}
840
841static int c_show(struct seq_file *m, void *v)
842{
843 int i;
844
845 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
846 cpu_name, (int)processor_id & 15, elf_platform);
847
848#if defined(CONFIG_SMP)
849 for_each_online_cpu(i) {
Russell King15559722005-11-06 21:41:08 +0000850 /*
851 * glibc reads /proc/cpuinfo to determine the number of
852 * online processors, looking for lines beginning with
853 * "processor". Give glibc what it expects.
854 */
855 seq_printf(m, "processor\t: %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
857 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
858 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
859 }
860#else /* CONFIG_SMP */
861 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
862 loops_per_jiffy / (500000/HZ),
863 (loops_per_jiffy / (5000/HZ)) % 100);
864#endif
865
866 /* dump out the processor features */
867 seq_puts(m, "Features\t: ");
868
869 for (i = 0; hwcap_str[i]; i++)
870 if (elf_hwcap & (1 << i))
871 seq_printf(m, "%s ", hwcap_str[i]);
872
873 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
874 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
875
Catalin Marinas6b090a22006-01-12 16:28:16 +0000876 if ((processor_id & 0x0008f000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* pre-ARM7 */
878 seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
879 } else {
Catalin Marinas6b090a22006-01-12 16:28:16 +0000880 if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 /* ARM7 */
882 seq_printf(m, "CPU variant\t: 0x%02x\n",
883 (processor_id >> 16) & 127);
884 } else {
885 /* post-ARM7 */
886 seq_printf(m, "CPU variant\t: 0x%x\n",
887 (processor_id >> 20) & 15);
888 }
889 seq_printf(m, "CPU part\t: 0x%03x\n",
890 (processor_id >> 4) & 0xfff);
891 }
892 seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
893
894 {
895 unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
896 if (cache_info != processor_id) {
897 seq_printf(m, "Cache type\t: %s\n"
898 "Cache clean\t: %s\n"
899 "Cache lockdown\t: %s\n"
900 "Cache format\t: %s\n",
901 cache_types[CACHE_TYPE(cache_info)],
902 cache_clean[CACHE_TYPE(cache_info)],
903 cache_lockdown[CACHE_TYPE(cache_info)],
904 CACHE_S(cache_info) ? "Harvard" : "Unified");
905
906 if (CACHE_S(cache_info)) {
907 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
908 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
909 } else {
910 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
911 }
912 }
913 }
914
915 seq_puts(m, "\n");
916
917 seq_printf(m, "Hardware\t: %s\n", machine_name);
918 seq_printf(m, "Revision\t: %04x\n", system_rev);
919 seq_printf(m, "Serial\t\t: %08x%08x\n",
920 system_serial_high, system_serial_low);
921
922 return 0;
923}
924
925static void *c_start(struct seq_file *m, loff_t *pos)
926{
927 return *pos < 1 ? (void *)1 : NULL;
928}
929
930static void *c_next(struct seq_file *m, void *v, loff_t *pos)
931{
932 ++*pos;
933 return NULL;
934}
935
936static void c_stop(struct seq_file *m, void *v)
937{
938}
939
940struct seq_operations cpuinfo_op = {
941 .start = c_start,
942 .next = c_next,
943 .stop = c_stop,
944 .show = c_show
945};