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