blob: fb04703f2a8c1303b4b57dd71e20f7791d06cae7 [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>
Alexey Dobriyan4e950f62007-07-30 02:36:13 +040026#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/cpu.h>
Russell King0ba8b9b2008-08-10 18:08:10 +010029#include <asm/cputype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/elf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/procinfo.h>
32#include <asm/setup.h>
33#include <asm/mach-types.h>
34#include <asm/cacheflush.h>
35#include <asm/tlbflush.h>
36
37#include <asm/mach/arch.h>
38#include <asm/mach/irq.h>
39#include <asm/mach/time.h>
Jason Wessel5cbad0e2008-02-20 13:33:40 -060040#include <asm/traps.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Ben Dooks0fc1c832006-03-15 23:17:30 +000042#include "compat.h"
Richard Purdie4cd9d6f2008-01-02 00:56:46 +010043#include "atags.h"
Ben Dooks0fc1c832006-03-15 23:17:30 +000044
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#ifndef MEM_SIZE
46#define MEM_SIZE (16*1024*1024)
47#endif
48
49#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
50char fpe_type[8];
51
52static int __init fpe_setup(char *line)
53{
54 memcpy(fpe_type, line, 8);
55 return 1;
56}
57
58__setup("fpe=", fpe_setup);
59#endif
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061extern void paging_init(struct meminfo *, struct machine_desc *desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062extern void reboot_setup(char *str);
63extern int root_mountflags;
64extern void _stext, _text, _etext, __data_start, _edata, _end;
65
66unsigned int processor_id;
Krzysztof Halasac18f6582007-12-18 03:53:27 +010067EXPORT_SYMBOL(processor_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068unsigned int __machine_arch_type;
69EXPORT_SYMBOL(__machine_arch_type);
70
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010071unsigned int __atags_pointer __initdata;
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073unsigned int system_rev;
74EXPORT_SYMBOL(system_rev);
75
76unsigned int system_serial_low;
77EXPORT_SYMBOL(system_serial_low);
78
79unsigned int system_serial_high;
80EXPORT_SYMBOL(system_serial_high);
81
82unsigned int elf_hwcap;
83EXPORT_SYMBOL(elf_hwcap);
84
Lennert Buytenhek60296c72008-08-05 01:56:13 +020085unsigned long __initdata vmalloc_reserve = 128 << 20;
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88#ifdef MULTI_CPU
89struct processor processor;
90#endif
91#ifdef MULTI_TLB
92struct cpu_tlb_fns cpu_tlb;
93#endif
94#ifdef MULTI_USER
95struct cpu_user_fns cpu_user;
96#endif
97#ifdef MULTI_CACHE
98struct cpu_cache_fns cpu_cache;
99#endif
Catalin Marinas953233d2007-02-05 14:48:08 +0100100#ifdef CONFIG_OUTER_CACHE
101struct outer_cache_fns outer_cache;
102#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Russell Kingccea7a12005-05-31 22:22:32 +0100104struct stack {
105 u32 irq[3];
106 u32 abt[3];
107 u32 und[3];
108} ____cacheline_aligned;
109
110static struct stack stacks[NR_CPUS];
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112char elf_platform[ELF_PLATFORM_SIZE];
113EXPORT_SYMBOL(elf_platform);
114
115unsigned long phys_initrd_start __initdata = 0;
116unsigned long phys_initrd_size __initdata = 0;
117
118static struct meminfo meminfo __initdata = { 0, };
119static const char *cpu_name;
120static const char *machine_name;
Alon Bar-Levcd818992007-02-12 00:54:06 -0800121static char __initdata command_line[COMMAND_LINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
124static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
125#define ENDIANNESS ((char)endian_test.l)
126
127DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
128
129/*
130 * Standard memory resources
131 */
132static struct resource mem_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700133 {
134 .name = "Video RAM",
135 .start = 0,
136 .end = 0,
137 .flags = IORESOURCE_MEM
138 },
139 {
140 .name = "Kernel text",
141 .start = 0,
142 .end = 0,
143 .flags = IORESOURCE_MEM
144 },
145 {
146 .name = "Kernel data",
147 .start = 0,
148 .end = 0,
149 .flags = IORESOURCE_MEM
150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151};
152
153#define video_ram mem_res[0]
154#define kernel_code mem_res[1]
155#define kernel_data mem_res[2]
156
157static struct resource io_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700158 {
159 .name = "reserved",
160 .start = 0x3bc,
161 .end = 0x3be,
162 .flags = IORESOURCE_IO | IORESOURCE_BUSY
163 },
164 {
165 .name = "reserved",
166 .start = 0x378,
167 .end = 0x37f,
168 .flags = IORESOURCE_IO | IORESOURCE_BUSY
169 },
170 {
171 .name = "reserved",
172 .start = 0x278,
173 .end = 0x27f,
174 .flags = IORESOURCE_IO | IORESOURCE_BUSY
175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176};
177
178#define lp0 io_res[0]
179#define lp1 io_res[1]
180#define lp2 io_res[2]
181
182static const char *cache_types[16] = {
183 "write-through",
184 "write-back",
185 "write-back",
186 "undefined 3",
187 "undefined 4",
188 "undefined 5",
189 "write-back",
190 "write-back",
191 "undefined 8",
192 "undefined 9",
193 "undefined 10",
194 "undefined 11",
195 "undefined 12",
196 "undefined 13",
197 "write-back",
198 "undefined 15",
199};
200
201static const char *cache_clean[16] = {
202 "not required",
203 "read-block",
204 "cp15 c7 ops",
205 "undefined 3",
206 "undefined 4",
207 "undefined 5",
208 "cp15 c7 ops",
209 "cp15 c7 ops",
210 "undefined 8",
211 "undefined 9",
212 "undefined 10",
213 "undefined 11",
214 "undefined 12",
215 "undefined 13",
216 "cp15 c7 ops",
217 "undefined 15",
218};
219
220static const char *cache_lockdown[16] = {
221 "not supported",
222 "not supported",
223 "not supported",
224 "undefined 3",
225 "undefined 4",
226 "undefined 5",
227 "format A",
228 "format B",
229 "undefined 8",
230 "undefined 9",
231 "undefined 10",
232 "undefined 11",
233 "undefined 12",
234 "undefined 13",
235 "format C",
236 "undefined 15",
237};
238
239static const char *proc_arch[] = {
240 "undefined/unknown",
241 "3",
242 "4",
243 "4T",
244 "5",
245 "5T",
246 "5TE",
247 "5TEJ",
248 "6TEJ",
Catalin Marinas6b090a22006-01-12 16:28:16 +0000249 "7",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 "?(11)",
251 "?(12)",
252 "?(13)",
253 "?(14)",
254 "?(15)",
255 "?(16)",
256 "?(17)",
257};
258
259#define CACHE_TYPE(x) (((x) >> 25) & 15)
260#define CACHE_S(x) ((x) & (1 << 24))
261#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
262#define CACHE_ISIZE(x) ((x) & 4095)
263
264#define CACHE_SIZE(y) (((y) >> 6) & 7)
265#define CACHE_ASSOC(y) (((y) >> 3) & 7)
266#define CACHE_M(y) ((y) & (1 << 2))
267#define CACHE_LINE(y) ((y) & 3)
268
269static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
270{
271 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
272
273 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
274 cpu, prefix,
275 mult << (8 + CACHE_SIZE(cache)),
276 (mult << CACHE_ASSOC(cache)) >> 1,
277 8 << CACHE_LINE(cache),
278 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
279 CACHE_LINE(cache)));
280}
281
282static void __init dump_cpu_info(int cpu)
283{
Russell King0ba8b9b2008-08-10 18:08:10 +0100284 unsigned int info = read_cpuid_cachetype();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Russell King0ba8b9b2008-08-10 18:08:10 +0100286 if (info != read_cpuid_id()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
288 cache_types[CACHE_TYPE(info)]);
289 if (CACHE_S(info)) {
290 dump_cache("I cache", cpu, CACHE_ISIZE(info));
291 dump_cache("D cache", cpu, CACHE_DSIZE(info));
292 } else {
293 dump_cache("cache", cpu, CACHE_ISIZE(info));
294 }
295 }
Lennert Buytenhek23759dc2006-04-02 00:07:39 +0100296
297 if (arch_is_coherent())
298 printk("Cache coherency enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
301int cpu_architecture(void)
302{
303 int cpu_arch;
304
Russell King0ba8b9b2008-08-10 18:08:10 +0100305 if ((read_cpuid_id() & 0x0008f000) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 cpu_arch = CPU_ARCH_UNKNOWN;
Russell King0ba8b9b2008-08-10 18:08:10 +0100307 } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
308 cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
309 } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
310 cpu_arch = (read_cpuid_id() >> 16) & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (cpu_arch)
312 cpu_arch += CPU_ARCH_ARMv3;
Russell King0ba8b9b2008-08-10 18:08:10 +0100313 } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
Catalin Marinas180005c2007-09-25 16:49:45 +0100314 unsigned int mmfr0;
315
316 /* Revised CPUID format. Read the Memory Model Feature
317 * Register 0 and check for VMSAv7 or PMSAv7 */
318 asm("mrc p15, 0, %0, c0, c1, 4"
319 : "=r" (mmfr0));
320 if ((mmfr0 & 0x0000000f) == 0x00000003 ||
321 (mmfr0 & 0x000000f0) == 0x00000030)
322 cpu_arch = CPU_ARCH_ARMv7;
323 else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
324 (mmfr0 & 0x000000f0) == 0x00000020)
325 cpu_arch = CPU_ARCH_ARMv6;
326 else
327 cpu_arch = CPU_ARCH_UNKNOWN;
328 } else
329 cpu_arch = CPU_ARCH_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 return cpu_arch;
332}
333
334/*
335 * These functions re-use the assembly code in head.S, which
336 * already provide the required functionality.
337 */
Russell King0f44ba12006-02-24 21:04:56 +0000338extern struct proc_info_list *lookup_processor_type(unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339extern struct machine_desc *lookup_machine_type(unsigned int);
340
341static void __init setup_processor(void)
342{
343 struct proc_info_list *list;
344
345 /*
346 * locate processor in the list of supported processor
347 * types. The linker builds this table for us from the
348 * entries in arch/arm/mm/proc-*.S
349 */
Russell King0ba8b9b2008-08-10 18:08:10 +0100350 list = lookup_processor_type(read_cpuid_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (!list) {
352 printk("CPU configuration botched (ID %08x), unable "
Russell King0ba8b9b2008-08-10 18:08:10 +0100353 "to continue.\n", read_cpuid_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 while (1);
355 }
356
357 cpu_name = list->cpu_name;
358
359#ifdef MULTI_CPU
360 processor = *list->proc;
361#endif
362#ifdef MULTI_TLB
363 cpu_tlb = *list->tlb;
364#endif
365#ifdef MULTI_USER
366 cpu_user = *list->user;
367#endif
368#ifdef MULTI_CACHE
369 cpu_cache = *list->cache;
370#endif
371
Russell King4e190252006-07-03 13:29:38 +0100372 printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100373 cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
Russell King264edb32006-06-29 15:03:09 +0100374 proc_arch[cpu_architecture()], cr_alignment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700376 sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
378 elf_hwcap = list->elf_hwcap;
Catalin Marinasadeff422006-04-10 21:32:35 +0100379#ifndef CONFIG_ARM_THUMB
380 elf_hwcap &= ~HWCAP_THUMB;
381#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 cpu_proc_init();
384}
385
Russell Kingccea7a12005-05-31 22:22:32 +0100386/*
387 * cpu_init - initialise one CPU.
388 *
389 * cpu_init dumps the cache information, initialises SMP specific
390 * information, and sets up the per-CPU stacks.
391 */
Russell King36c5ed22005-06-19 18:39:33 +0100392void cpu_init(void)
Russell Kingccea7a12005-05-31 22:22:32 +0100393{
394 unsigned int cpu = smp_processor_id();
395 struct stack *stk = &stacks[cpu];
396
397 if (cpu >= NR_CPUS) {
398 printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
399 BUG();
400 }
401
Russell King32f8b972005-11-06 19:49:21 +0000402 if (system_state == SYSTEM_BOOTING)
403 dump_cpu_info(cpu);
Russell Kingccea7a12005-05-31 22:22:32 +0100404
405 /*
406 * setup stacks for re-entrant exception handlers
407 */
408 __asm__ (
409 "msr cpsr_c, %1\n\t"
410 "add sp, %0, %2\n\t"
411 "msr cpsr_c, %3\n\t"
412 "add sp, %0, %4\n\t"
413 "msr cpsr_c, %5\n\t"
414 "add sp, %0, %6\n\t"
415 "msr cpsr_c, %7"
416 :
417 : "r" (stk),
418 "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
419 "I" (offsetof(struct stack, irq[0])),
420 "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
421 "I" (offsetof(struct stack, abt[0])),
422 "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
423 "I" (offsetof(struct stack, und[0])),
Catalin Marinasaaaa3f92005-06-29 15:34:39 +0100424 "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
425 : "r14");
Russell Kingccea7a12005-05-31 22:22:32 +0100426}
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428static struct machine_desc * __init setup_machine(unsigned int nr)
429{
430 struct machine_desc *list;
431
432 /*
433 * locate machine in the list of supported machines.
434 */
435 list = lookup_machine_type(nr);
436 if (!list) {
437 printk("Machine configuration botched (nr %d), unable "
438 "to continue.\n", nr);
439 while (1);
440 }
441
442 printk("Machine: %s\n", list->name);
443
444 return list;
445}
446
447static void __init early_initrd(char **p)
448{
449 unsigned long start, size;
450
451 start = memparse(*p, p);
452 if (**p == ',') {
453 size = memparse((*p) + 1, p);
454
455 phys_initrd_start = start;
456 phys_initrd_size = size;
457 }
458}
459__early_param("initrd=", early_initrd);
460
Andrew Morton1c97b732006-04-20 21:41:18 +0100461static void __init arm_add_memory(unsigned long start, unsigned long size)
Russell King3a669412005-06-22 21:43:10 +0100462{
Russell King05f96ef2006-11-30 20:44:49 +0000463 struct membank *bank;
464
Russell King3a669412005-06-22 21:43:10 +0100465 /*
466 * Ensure that start/size are aligned to a page boundary.
467 * Size is appropriately rounded down, start is rounded up.
468 */
469 size -= start & ~PAGE_MASK;
470
Russell King05f96ef2006-11-30 20:44:49 +0000471 bank = &meminfo.bank[meminfo.nr_banks++];
472
473 bank->start = PAGE_ALIGN(start);
474 bank->size = size & PAGE_MASK;
475 bank->node = PHYS_TO_NID(start);
Russell King3a669412005-06-22 21:43:10 +0100476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478/*
479 * Pick out the memory size. We look for mem=size@start,
480 * where start and size are "size[KkMm]"
481 */
482static void __init early_mem(char **p)
483{
484 static int usermem __initdata = 0;
485 unsigned long size, start;
486
487 /*
488 * If the user specifies memory size, we
489 * blow away any automatically generated
490 * size.
491 */
492 if (usermem == 0) {
493 usermem = 1;
494 meminfo.nr_banks = 0;
495 }
496
497 start = PHYS_OFFSET;
498 size = memparse(*p, p);
499 if (**p == '@')
500 start = memparse(*p + 1, p);
501
Andrew Morton1c97b732006-04-20 21:41:18 +0100502 arm_add_memory(start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503}
504__early_param("mem=", early_mem);
505
506/*
Lennert Buytenhek60296c72008-08-05 01:56:13 +0200507 * vmalloc=size forces the vmalloc area to be exactly 'size'
508 * bytes. This can be used to increase (or decrease) the vmalloc
509 * area - the default is 128m.
510 */
511static void __init early_vmalloc(char **arg)
512{
513 vmalloc_reserve = memparse(*arg, arg);
514}
515__early_param("vmalloc=", early_vmalloc);
516
517/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 * Initial parsing of the command line.
519 */
520static void __init parse_cmdline(char **cmdline_p, char *from)
521{
522 char c = ' ', *to = command_line;
523 int len = 0;
524
525 for (;;) {
526 if (c == ' ') {
527 extern struct early_params __early_begin, __early_end;
528 struct early_params *p;
529
530 for (p = &__early_begin; p < &__early_end; p++) {
531 int len = strlen(p->arg);
532
533 if (memcmp(from, p->arg, len) == 0) {
534 if (to != command_line)
535 to -= 1;
536 from += len;
537 p->fn(&from);
538
539 while (*from != ' ' && *from != '\0')
540 from++;
541 break;
542 }
543 }
544 }
545 c = *from++;
546 if (!c)
547 break;
548 if (COMMAND_LINE_SIZE <= ++len)
549 break;
550 *to++ = c;
551 }
552 *to = '\0';
553 *cmdline_p = command_line;
554}
555
556static void __init
557setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
558{
559#ifdef CONFIG_BLK_DEV_RAM
560 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
561
562 rd_image_start = image_start;
563 rd_prompt = prompt;
564 rd_doload = doload;
565
566 if (rd_sz)
567 rd_size = rd_sz;
568#endif
569}
570
571static void __init
572request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
573{
574 struct resource *res;
575 int i;
576
577 kernel_code.start = virt_to_phys(&_text);
578 kernel_code.end = virt_to_phys(&_etext - 1);
579 kernel_data.start = virt_to_phys(&__data_start);
580 kernel_data.end = virt_to_phys(&_end - 1);
581
582 for (i = 0; i < mi->nr_banks; i++) {
583 unsigned long virt_start, virt_end;
584
585 if (mi->bank[i].size == 0)
586 continue;
587
588 virt_start = __phys_to_virt(mi->bank[i].start);
589 virt_end = virt_start + mi->bank[i].size - 1;
590
591 res = alloc_bootmem_low(sizeof(*res));
592 res->name = "System RAM";
593 res->start = __virt_to_phys(virt_start);
594 res->end = __virt_to_phys(virt_end);
595 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
596
597 request_resource(&iomem_resource, res);
598
599 if (kernel_code.start >= res->start &&
600 kernel_code.end <= res->end)
601 request_resource(res, &kernel_code);
602 if (kernel_data.start >= res->start &&
603 kernel_data.end <= res->end)
604 request_resource(res, &kernel_data);
605 }
606
607 if (mdesc->video_start) {
608 video_ram.start = mdesc->video_start;
609 video_ram.end = mdesc->video_end;
610 request_resource(&iomem_resource, &video_ram);
611 }
612
613 /*
614 * Some machines don't have the possibility of ever
615 * possessing lp0, lp1 or lp2
616 */
617 if (mdesc->reserve_lp0)
618 request_resource(&ioport_resource, &lp0);
619 if (mdesc->reserve_lp1)
620 request_resource(&ioport_resource, &lp1);
621 if (mdesc->reserve_lp2)
622 request_resource(&ioport_resource, &lp2);
623}
624
625/*
626 * Tag parsing.
627 *
628 * This is the new way of passing data to the kernel at boot time. Rather
629 * than passing a fixed inflexible structure to the kernel, we pass a list
630 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
631 * tag for the list to be recognised (to distinguish the tagged list from
632 * a param_struct). The list is terminated with a zero-length tag (this tag
633 * is not parsed in any way).
634 */
635static int __init parse_tag_core(const struct tag *tag)
636{
637 if (tag->hdr.size > 2) {
638 if ((tag->u.core.flags & 1) == 0)
639 root_mountflags &= ~MS_RDONLY;
640 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
641 }
642 return 0;
643}
644
645__tagtable(ATAG_CORE, parse_tag_core);
646
647static int __init parse_tag_mem32(const struct tag *tag)
648{
649 if (meminfo.nr_banks >= NR_BANKS) {
650 printk(KERN_WARNING
651 "Ignoring memory bank 0x%08x size %dKB\n",
652 tag->u.mem.start, tag->u.mem.size / 1024);
653 return -EINVAL;
654 }
Andrew Morton1c97b732006-04-20 21:41:18 +0100655 arm_add_memory(tag->u.mem.start, tag->u.mem.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return 0;
657}
658
659__tagtable(ATAG_MEM, parse_tag_mem32);
660
661#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
662struct screen_info screen_info = {
663 .orig_video_lines = 30,
664 .orig_video_cols = 80,
665 .orig_video_mode = 0,
666 .orig_video_ega_bx = 0,
667 .orig_video_isVGA = 1,
668 .orig_video_points = 8
669};
670
671static int __init parse_tag_videotext(const struct tag *tag)
672{
673 screen_info.orig_x = tag->u.videotext.x;
674 screen_info.orig_y = tag->u.videotext.y;
675 screen_info.orig_video_page = tag->u.videotext.video_page;
676 screen_info.orig_video_mode = tag->u.videotext.video_mode;
677 screen_info.orig_video_cols = tag->u.videotext.video_cols;
678 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
679 screen_info.orig_video_lines = tag->u.videotext.video_lines;
680 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
681 screen_info.orig_video_points = tag->u.videotext.video_points;
682 return 0;
683}
684
685__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
686#endif
687
688static int __init parse_tag_ramdisk(const struct tag *tag)
689{
690 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
691 (tag->u.ramdisk.flags & 2) == 0,
692 tag->u.ramdisk.start, tag->u.ramdisk.size);
693 return 0;
694}
695
696__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
697
698static int __init parse_tag_initrd(const struct tag *tag)
699{
700 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
701 "please update your bootloader.\n");
702 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
703 phys_initrd_size = tag->u.initrd.size;
704 return 0;
705}
706
707__tagtable(ATAG_INITRD, parse_tag_initrd);
708
709static int __init parse_tag_initrd2(const struct tag *tag)
710{
711 phys_initrd_start = tag->u.initrd.start;
712 phys_initrd_size = tag->u.initrd.size;
713 return 0;
714}
715
716__tagtable(ATAG_INITRD2, parse_tag_initrd2);
717
718static int __init parse_tag_serialnr(const struct tag *tag)
719{
720 system_serial_low = tag->u.serialnr.low;
721 system_serial_high = tag->u.serialnr.high;
722 return 0;
723}
724
725__tagtable(ATAG_SERIAL, parse_tag_serialnr);
726
727static int __init parse_tag_revision(const struct tag *tag)
728{
729 system_rev = tag->u.revision.rev;
730 return 0;
731}
732
733__tagtable(ATAG_REVISION, parse_tag_revision);
734
735static int __init parse_tag_cmdline(const struct tag *tag)
736{
737 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
738 return 0;
739}
740
741__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
742
743/*
744 * Scan the tag table for this tag, and call its parse function.
745 * The tag table is built by the linker from all the __tagtable
746 * declarations.
747 */
748static int __init parse_tag(const struct tag *tag)
749{
750 extern struct tagtable __tagtable_begin, __tagtable_end;
751 struct tagtable *t;
752
753 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
754 if (tag->hdr.tag == t->tag) {
755 t->parse(tag);
756 break;
757 }
758
759 return t < &__tagtable_end;
760}
761
762/*
763 * Parse all tags in the list, checking both the global and architecture
764 * specific tag tables.
765 */
766static void __init parse_tags(const struct tag *t)
767{
768 for (; t->hdr.size; t = tag_next(t))
769 if (!parse_tag(t))
770 printk(KERN_WARNING
771 "Ignoring unrecognised tag 0x%08x\n",
772 t->hdr.tag);
773}
774
775/*
776 * This holds our defaults.
777 */
778static struct init_tags {
779 struct tag_header hdr1;
780 struct tag_core core;
781 struct tag_header hdr2;
782 struct tag_mem32 mem;
783 struct tag_header hdr3;
784} init_tags __initdata = {
785 { tag_size(tag_core), ATAG_CORE },
786 { 1, PAGE_SIZE, 0xff },
787 { tag_size(tag_mem32), ATAG_MEM },
788 { MEM_SIZE, PHYS_OFFSET },
789 { 0, ATAG_NONE }
790};
791
792static void (*init_machine)(void) __initdata;
793
794static int __init customize_machine(void)
795{
796 /* customizes platform devices, or adds new ones */
797 if (init_machine)
798 init_machine();
799 return 0;
800}
801arch_initcall(customize_machine);
802
803void __init setup_arch(char **cmdline_p)
804{
805 struct tag *tags = (struct tag *)&init_tags;
806 struct machine_desc *mdesc;
807 char *from = default_command_line;
808
809 setup_processor();
810 mdesc = setup_machine(machine_arch_type);
811 machine_name = mdesc->name;
812
813 if (mdesc->soft_reboot)
814 reboot_setup("s");
815
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100816 if (__atags_pointer)
817 tags = phys_to_virt(__atags_pointer);
818 else if (mdesc->boot_params)
Russell Kingf9bd6ea2005-07-04 10:43:36 +0100819 tags = phys_to_virt(mdesc->boot_params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 /*
822 * If we have the old style parameters, convert them to
823 * a tag list.
824 */
825 if (tags->hdr.tag != ATAG_CORE)
826 convert_to_tag_list(tags);
827 if (tags->hdr.tag != ATAG_CORE)
828 tags = (struct tag *)&init_tags;
829
830 if (mdesc->fixup)
831 mdesc->fixup(mdesc, tags, &from, &meminfo);
832
833 if (tags->hdr.tag == ATAG_CORE) {
834 if (meminfo.nr_banks != 0)
835 squash_mem_tags(tags);
Richard Purdie4cd9d6f2008-01-02 00:56:46 +0100836 save_atags(tags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 parse_tags(tags);
838 }
839
840 init_mm.start_code = (unsigned long) &_text;
841 init_mm.end_code = (unsigned long) &_etext;
842 init_mm.end_data = (unsigned long) &_edata;
843 init_mm.brk = (unsigned long) &_end;
844
Alon Bar-Levcd818992007-02-12 00:54:06 -0800845 memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
846 boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 parse_cmdline(cmdline_p, from);
848 paging_init(&meminfo, mdesc);
849 request_standard_resources(&meminfo, mdesc);
850
Russell King7bbb7942006-02-16 11:08:09 +0000851#ifdef CONFIG_SMP
852 smp_init_cpus();
853#endif
854
Russell Kingccea7a12005-05-31 22:22:32 +0100855 cpu_init();
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 /*
858 * Set up various architecture-specific pointers
859 */
860 init_arch_irq = mdesc->init_irq;
861 system_timer = mdesc->timer;
862 init_machine = mdesc->init_machine;
863
864#ifdef CONFIG_VT
865#if defined(CONFIG_VGA_CONSOLE)
866 conswitchp = &vga_con;
867#elif defined(CONFIG_DUMMY_CONSOLE)
868 conswitchp = &dummy_con;
869#endif
870#endif
Jason Wessel5cbad0e2008-02-20 13:33:40 -0600871 early_trap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872}
873
874
875static int __init topology_init(void)
876{
877 int cpu;
878
Russell King66fb8bd2007-03-13 09:54:21 +0000879 for_each_possible_cpu(cpu) {
880 struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
881 cpuinfo->cpu.hotpluggable = 1;
882 register_cpu(&cpuinfo->cpu, cpu);
883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 return 0;
886}
887
888subsys_initcall(topology_init);
889
890static const char *hwcap_str[] = {
891 "swp",
892 "half",
893 "thumb",
894 "26bit",
895 "fastmult",
896 "fpa",
897 "vfp",
898 "edsp",
899 "java",
Paul Gortmaker8f7f9432006-10-27 05:13:19 +0100900 "iwmmxt",
Lennert Buytenhek99e4a6d2006-12-18 00:59:10 +0100901 "crunch",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 NULL
903};
904
905static void
906c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
907{
908 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
909
910 seq_printf(m, "%s size\t\t: %d\n"
911 "%s assoc\t\t: %d\n"
912 "%s line length\t: %d\n"
913 "%s sets\t\t: %d\n",
914 type, mult << (8 + CACHE_SIZE(cache)),
915 type, (mult << CACHE_ASSOC(cache)) >> 1,
916 type, 8 << CACHE_LINE(cache),
917 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
918 CACHE_LINE(cache)));
919}
920
921static int c_show(struct seq_file *m, void *v)
922{
923 int i;
924
925 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100926 cpu_name, read_cpuid_id() & 15, elf_platform);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928#if defined(CONFIG_SMP)
929 for_each_online_cpu(i) {
Russell King15559722005-11-06 21:41:08 +0000930 /*
931 * glibc reads /proc/cpuinfo to determine the number of
932 * online processors, looking for lines beginning with
933 * "processor". Give glibc what it expects.
934 */
935 seq_printf(m, "processor\t: %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
937 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
938 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
939 }
940#else /* CONFIG_SMP */
941 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
942 loops_per_jiffy / (500000/HZ),
943 (loops_per_jiffy / (5000/HZ)) % 100);
944#endif
945
946 /* dump out the processor features */
947 seq_puts(m, "Features\t: ");
948
949 for (i = 0; hwcap_str[i]; i++)
950 if (elf_hwcap & (1 << i))
951 seq_printf(m, "%s ", hwcap_str[i]);
952
Russell King0ba8b9b2008-08-10 18:08:10 +0100953 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
955
Russell King0ba8b9b2008-08-10 18:08:10 +0100956 if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 /* pre-ARM7 */
Russell King0ba8b9b2008-08-10 18:08:10 +0100958 seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 } else {
Russell King0ba8b9b2008-08-10 18:08:10 +0100960 if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /* ARM7 */
962 seq_printf(m, "CPU variant\t: 0x%02x\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100963 (read_cpuid_id() >> 16) & 127);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 } else {
965 /* post-ARM7 */
966 seq_printf(m, "CPU variant\t: 0x%x\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100967 (read_cpuid_id() >> 20) & 15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 }
969 seq_printf(m, "CPU part\t: 0x%03x\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100970 (read_cpuid_id() >> 4) & 0xfff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 }
Russell King0ba8b9b2008-08-10 18:08:10 +0100972 seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 {
Russell King0ba8b9b2008-08-10 18:08:10 +0100975 unsigned int cache_info = read_cpuid_cachetype();
976 if (cache_info != read_cpuid_id()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 seq_printf(m, "Cache type\t: %s\n"
978 "Cache clean\t: %s\n"
979 "Cache lockdown\t: %s\n"
980 "Cache format\t: %s\n",
981 cache_types[CACHE_TYPE(cache_info)],
982 cache_clean[CACHE_TYPE(cache_info)],
983 cache_lockdown[CACHE_TYPE(cache_info)],
984 CACHE_S(cache_info) ? "Harvard" : "Unified");
985
986 if (CACHE_S(cache_info)) {
987 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
988 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
989 } else {
990 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
991 }
992 }
993 }
994
995 seq_puts(m, "\n");
996
997 seq_printf(m, "Hardware\t: %s\n", machine_name);
998 seq_printf(m, "Revision\t: %04x\n", system_rev);
999 seq_printf(m, "Serial\t\t: %08x%08x\n",
1000 system_serial_high, system_serial_low);
1001
1002 return 0;
1003}
1004
1005static void *c_start(struct seq_file *m, loff_t *pos)
1006{
1007 return *pos < 1 ? (void *)1 : NULL;
1008}
1009
1010static void *c_next(struct seq_file *m, void *v, loff_t *pos)
1011{
1012 ++*pos;
1013 return NULL;
1014}
1015
1016static void c_stop(struct seq_file *m, void *v)
1017{
1018}
1019
Jan Engelhardt2ffd6e12008-01-22 20:41:07 +01001020const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 .start = c_start,
1022 .next = c_next,
1023 .stop = c_stop,
1024 .show = c_show
1025};