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