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