blob: 61a2242b18b86a8bc6174bc06a1fdf2475957a53 [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);
Russell King5ed5fdf2008-09-06 11:23:30 +010064extern void _text, _etext, __data_start, _edata, _end;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static struct meminfo meminfo __initdata = { 0, };
116static const char *cpu_name;
117static const char *machine_name;
Alon Bar-Levcd818992007-02-12 00:54:06 -0800118static char __initdata command_line[COMMAND_LINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
121static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
122#define ENDIANNESS ((char)endian_test.l)
123
124DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
125
126/*
127 * Standard memory resources
128 */
129static struct resource mem_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700130 {
131 .name = "Video RAM",
132 .start = 0,
133 .end = 0,
134 .flags = IORESOURCE_MEM
135 },
136 {
137 .name = "Kernel text",
138 .start = 0,
139 .end = 0,
140 .flags = IORESOURCE_MEM
141 },
142 {
143 .name = "Kernel data",
144 .start = 0,
145 .end = 0,
146 .flags = IORESOURCE_MEM
147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148};
149
150#define video_ram mem_res[0]
151#define kernel_code mem_res[1]
152#define kernel_data mem_res[2]
153
154static struct resource io_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700155 {
156 .name = "reserved",
157 .start = 0x3bc,
158 .end = 0x3be,
159 .flags = IORESOURCE_IO | IORESOURCE_BUSY
160 },
161 {
162 .name = "reserved",
163 .start = 0x378,
164 .end = 0x37f,
165 .flags = IORESOURCE_IO | IORESOURCE_BUSY
166 },
167 {
168 .name = "reserved",
169 .start = 0x278,
170 .end = 0x27f,
171 .flags = IORESOURCE_IO | IORESOURCE_BUSY
172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173};
174
175#define lp0 io_res[0]
176#define lp1 io_res[1]
177#define lp2 io_res[2]
178
179static const char *cache_types[16] = {
180 "write-through",
181 "write-back",
182 "write-back",
183 "undefined 3",
184 "undefined 4",
185 "undefined 5",
186 "write-back",
187 "write-back",
188 "undefined 8",
189 "undefined 9",
190 "undefined 10",
191 "undefined 11",
192 "undefined 12",
193 "undefined 13",
194 "write-back",
195 "undefined 15",
196};
197
198static const char *cache_clean[16] = {
199 "not required",
200 "read-block",
201 "cp15 c7 ops",
202 "undefined 3",
203 "undefined 4",
204 "undefined 5",
205 "cp15 c7 ops",
206 "cp15 c7 ops",
207 "undefined 8",
208 "undefined 9",
209 "undefined 10",
210 "undefined 11",
211 "undefined 12",
212 "undefined 13",
213 "cp15 c7 ops",
214 "undefined 15",
215};
216
217static const char *cache_lockdown[16] = {
218 "not supported",
219 "not supported",
220 "not supported",
221 "undefined 3",
222 "undefined 4",
223 "undefined 5",
224 "format A",
225 "format B",
226 "undefined 8",
227 "undefined 9",
228 "undefined 10",
229 "undefined 11",
230 "undefined 12",
231 "undefined 13",
232 "format C",
233 "undefined 15",
234};
235
236static const char *proc_arch[] = {
237 "undefined/unknown",
238 "3",
239 "4",
240 "4T",
241 "5",
242 "5T",
243 "5TE",
244 "5TEJ",
245 "6TEJ",
Catalin Marinas6b090a22006-01-12 16:28:16 +0000246 "7",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 "?(11)",
248 "?(12)",
249 "?(13)",
250 "?(14)",
251 "?(15)",
252 "?(16)",
253 "?(17)",
254};
255
256#define CACHE_TYPE(x) (((x) >> 25) & 15)
257#define CACHE_S(x) ((x) & (1 << 24))
258#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
259#define CACHE_ISIZE(x) ((x) & 4095)
260
261#define CACHE_SIZE(y) (((y) >> 6) & 7)
262#define CACHE_ASSOC(y) (((y) >> 3) & 7)
263#define CACHE_M(y) ((y) & (1 << 2))
264#define CACHE_LINE(y) ((y) & 3)
265
266static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
267{
268 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
269
270 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
271 cpu, prefix,
272 mult << (8 + CACHE_SIZE(cache)),
273 (mult << CACHE_ASSOC(cache)) >> 1,
274 8 << CACHE_LINE(cache),
275 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
276 CACHE_LINE(cache)));
277}
278
279static void __init dump_cpu_info(int cpu)
280{
Russell King0ba8b9b2008-08-10 18:08:10 +0100281 unsigned int info = read_cpuid_cachetype();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Russell King0ba8b9b2008-08-10 18:08:10 +0100283 if (info != read_cpuid_id()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
285 cache_types[CACHE_TYPE(info)]);
286 if (CACHE_S(info)) {
287 dump_cache("I cache", cpu, CACHE_ISIZE(info));
288 dump_cache("D cache", cpu, CACHE_DSIZE(info));
289 } else {
290 dump_cache("cache", cpu, CACHE_ISIZE(info));
291 }
292 }
Lennert Buytenhek23759dc2006-04-02 00:07:39 +0100293
294 if (arch_is_coherent())
295 printk("Cache coherency enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
298int cpu_architecture(void)
299{
300 int cpu_arch;
301
Russell King0ba8b9b2008-08-10 18:08:10 +0100302 if ((read_cpuid_id() & 0x0008f000) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 cpu_arch = CPU_ARCH_UNKNOWN;
Russell King0ba8b9b2008-08-10 18:08:10 +0100304 } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
305 cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
306 } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
307 cpu_arch = (read_cpuid_id() >> 16) & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 if (cpu_arch)
309 cpu_arch += CPU_ARCH_ARMv3;
Russell King0ba8b9b2008-08-10 18:08:10 +0100310 } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
Catalin Marinas180005c2007-09-25 16:49:45 +0100311 unsigned int mmfr0;
312
313 /* Revised CPUID format. Read the Memory Model Feature
314 * Register 0 and check for VMSAv7 or PMSAv7 */
315 asm("mrc p15, 0, %0, c0, c1, 4"
316 : "=r" (mmfr0));
317 if ((mmfr0 & 0x0000000f) == 0x00000003 ||
318 (mmfr0 & 0x000000f0) == 0x00000030)
319 cpu_arch = CPU_ARCH_ARMv7;
320 else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
321 (mmfr0 & 0x000000f0) == 0x00000020)
322 cpu_arch = CPU_ARCH_ARMv6;
323 else
324 cpu_arch = CPU_ARCH_UNKNOWN;
325 } else
326 cpu_arch = CPU_ARCH_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 return cpu_arch;
329}
330
331/*
332 * These functions re-use the assembly code in head.S, which
333 * already provide the required functionality.
334 */
Russell King0f44ba12006-02-24 21:04:56 +0000335extern struct proc_info_list *lookup_processor_type(unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336extern struct machine_desc *lookup_machine_type(unsigned int);
337
338static void __init setup_processor(void)
339{
340 struct proc_info_list *list;
341
342 /*
343 * locate processor in the list of supported processor
344 * types. The linker builds this table for us from the
345 * entries in arch/arm/mm/proc-*.S
346 */
Russell King0ba8b9b2008-08-10 18:08:10 +0100347 list = lookup_processor_type(read_cpuid_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (!list) {
349 printk("CPU configuration botched (ID %08x), unable "
Russell King0ba8b9b2008-08-10 18:08:10 +0100350 "to continue.\n", read_cpuid_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 while (1);
352 }
353
354 cpu_name = list->cpu_name;
355
356#ifdef MULTI_CPU
357 processor = *list->proc;
358#endif
359#ifdef MULTI_TLB
360 cpu_tlb = *list->tlb;
361#endif
362#ifdef MULTI_USER
363 cpu_user = *list->user;
364#endif
365#ifdef MULTI_CACHE
366 cpu_cache = *list->cache;
367#endif
368
Russell King4e190252006-07-03 13:29:38 +0100369 printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100370 cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
Russell King264edb32006-06-29 15:03:09 +0100371 proc_arch[cpu_architecture()], cr_alignment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700373 sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
375 elf_hwcap = list->elf_hwcap;
Catalin Marinasadeff422006-04-10 21:32:35 +0100376#ifndef CONFIG_ARM_THUMB
377 elf_hwcap &= ~HWCAP_THUMB;
378#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 cpu_proc_init();
381}
382
Russell Kingccea7a12005-05-31 22:22:32 +0100383/*
384 * cpu_init - initialise one CPU.
385 *
386 * cpu_init dumps the cache information, initialises SMP specific
387 * information, and sets up the per-CPU stacks.
388 */
Russell King36c5ed22005-06-19 18:39:33 +0100389void cpu_init(void)
Russell Kingccea7a12005-05-31 22:22:32 +0100390{
391 unsigned int cpu = smp_processor_id();
392 struct stack *stk = &stacks[cpu];
393
394 if (cpu >= NR_CPUS) {
395 printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
396 BUG();
397 }
398
Russell King32f8b972005-11-06 19:49:21 +0000399 if (system_state == SYSTEM_BOOTING)
400 dump_cpu_info(cpu);
Russell Kingccea7a12005-05-31 22:22:32 +0100401
402 /*
403 * setup stacks for re-entrant exception handlers
404 */
405 __asm__ (
406 "msr cpsr_c, %1\n\t"
407 "add sp, %0, %2\n\t"
408 "msr cpsr_c, %3\n\t"
409 "add sp, %0, %4\n\t"
410 "msr cpsr_c, %5\n\t"
411 "add sp, %0, %6\n\t"
412 "msr cpsr_c, %7"
413 :
414 : "r" (stk),
415 "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
416 "I" (offsetof(struct stack, irq[0])),
417 "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
418 "I" (offsetof(struct stack, abt[0])),
419 "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
420 "I" (offsetof(struct stack, und[0])),
Catalin Marinasaaaa3f92005-06-29 15:34:39 +0100421 "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
422 : "r14");
Russell Kingccea7a12005-05-31 22:22:32 +0100423}
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425static struct machine_desc * __init setup_machine(unsigned int nr)
426{
427 struct machine_desc *list;
428
429 /*
430 * locate machine in the list of supported machines.
431 */
432 list = lookup_machine_type(nr);
433 if (!list) {
434 printk("Machine configuration botched (nr %d), unable "
435 "to continue.\n", nr);
436 while (1);
437 }
438
439 printk("Machine: %s\n", list->name);
440
441 return list;
442}
443
Andrew Morton1c97b732006-04-20 21:41:18 +0100444static void __init arm_add_memory(unsigned long start, unsigned long size)
Russell King3a669412005-06-22 21:43:10 +0100445{
Russell King05f96ef2006-11-30 20:44:49 +0000446 struct membank *bank;
447
Russell King3a669412005-06-22 21:43:10 +0100448 /*
449 * Ensure that start/size are aligned to a page boundary.
450 * Size is appropriately rounded down, start is rounded up.
451 */
452 size -= start & ~PAGE_MASK;
453
Russell King05f96ef2006-11-30 20:44:49 +0000454 bank = &meminfo.bank[meminfo.nr_banks++];
455
456 bank->start = PAGE_ALIGN(start);
457 bank->size = size & PAGE_MASK;
458 bank->node = PHYS_TO_NID(start);
Russell King3a669412005-06-22 21:43:10 +0100459}
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461/*
462 * Pick out the memory size. We look for mem=size@start,
463 * where start and size are "size[KkMm]"
464 */
465static void __init early_mem(char **p)
466{
467 static int usermem __initdata = 0;
468 unsigned long size, start;
469
470 /*
471 * If the user specifies memory size, we
472 * blow away any automatically generated
473 * size.
474 */
475 if (usermem == 0) {
476 usermem = 1;
477 meminfo.nr_banks = 0;
478 }
479
480 start = PHYS_OFFSET;
481 size = memparse(*p, p);
482 if (**p == '@')
483 start = memparse(*p + 1, p);
484
Andrew Morton1c97b732006-04-20 21:41:18 +0100485 arm_add_memory(start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487__early_param("mem=", early_mem);
488
489/*
Lennert Buytenhek60296c72008-08-05 01:56:13 +0200490 * vmalloc=size forces the vmalloc area to be exactly 'size'
491 * bytes. This can be used to increase (or decrease) the vmalloc
492 * area - the default is 128m.
493 */
494static void __init early_vmalloc(char **arg)
495{
496 vmalloc_reserve = memparse(*arg, arg);
497}
498__early_param("vmalloc=", early_vmalloc);
499
500/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 * Initial parsing of the command line.
502 */
503static void __init parse_cmdline(char **cmdline_p, char *from)
504{
505 char c = ' ', *to = command_line;
506 int len = 0;
507
508 for (;;) {
509 if (c == ' ') {
510 extern struct early_params __early_begin, __early_end;
511 struct early_params *p;
512
513 for (p = &__early_begin; p < &__early_end; p++) {
Russell King09d9bae2008-09-05 14:08:44 +0100514 int arglen = strlen(p->arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Russell King09d9bae2008-09-05 14:08:44 +0100516 if (memcmp(from, p->arg, arglen) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if (to != command_line)
518 to -= 1;
Russell King09d9bae2008-09-05 14:08:44 +0100519 from += arglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 p->fn(&from);
521
522 while (*from != ' ' && *from != '\0')
523 from++;
524 break;
525 }
526 }
527 }
528 c = *from++;
529 if (!c)
530 break;
531 if (COMMAND_LINE_SIZE <= ++len)
532 break;
533 *to++ = c;
534 }
535 *to = '\0';
536 *cmdline_p = command_line;
537}
538
539static void __init
540setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
541{
542#ifdef CONFIG_BLK_DEV_RAM
543 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
544
545 rd_image_start = image_start;
546 rd_prompt = prompt;
547 rd_doload = doload;
548
549 if (rd_sz)
550 rd_size = rd_sz;
551#endif
552}
553
554static void __init
555request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
556{
557 struct resource *res;
558 int i;
559
560 kernel_code.start = virt_to_phys(&_text);
561 kernel_code.end = virt_to_phys(&_etext - 1);
562 kernel_data.start = virt_to_phys(&__data_start);
563 kernel_data.end = virt_to_phys(&_end - 1);
564
565 for (i = 0; i < mi->nr_banks; i++) {
566 unsigned long virt_start, virt_end;
567
568 if (mi->bank[i].size == 0)
569 continue;
570
571 virt_start = __phys_to_virt(mi->bank[i].start);
572 virt_end = virt_start + mi->bank[i].size - 1;
573
574 res = alloc_bootmem_low(sizeof(*res));
575 res->name = "System RAM";
576 res->start = __virt_to_phys(virt_start);
577 res->end = __virt_to_phys(virt_end);
578 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
579
580 request_resource(&iomem_resource, res);
581
582 if (kernel_code.start >= res->start &&
583 kernel_code.end <= res->end)
584 request_resource(res, &kernel_code);
585 if (kernel_data.start >= res->start &&
586 kernel_data.end <= res->end)
587 request_resource(res, &kernel_data);
588 }
589
590 if (mdesc->video_start) {
591 video_ram.start = mdesc->video_start;
592 video_ram.end = mdesc->video_end;
593 request_resource(&iomem_resource, &video_ram);
594 }
595
596 /*
597 * Some machines don't have the possibility of ever
598 * possessing lp0, lp1 or lp2
599 */
600 if (mdesc->reserve_lp0)
601 request_resource(&ioport_resource, &lp0);
602 if (mdesc->reserve_lp1)
603 request_resource(&ioport_resource, &lp1);
604 if (mdesc->reserve_lp2)
605 request_resource(&ioport_resource, &lp2);
606}
607
608/*
609 * Tag parsing.
610 *
611 * This is the new way of passing data to the kernel at boot time. Rather
612 * than passing a fixed inflexible structure to the kernel, we pass a list
613 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
614 * tag for the list to be recognised (to distinguish the tagged list from
615 * a param_struct). The list is terminated with a zero-length tag (this tag
616 * is not parsed in any way).
617 */
618static int __init parse_tag_core(const struct tag *tag)
619{
620 if (tag->hdr.size > 2) {
621 if ((tag->u.core.flags & 1) == 0)
622 root_mountflags &= ~MS_RDONLY;
623 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
624 }
625 return 0;
626}
627
628__tagtable(ATAG_CORE, parse_tag_core);
629
630static int __init parse_tag_mem32(const struct tag *tag)
631{
632 if (meminfo.nr_banks >= NR_BANKS) {
633 printk(KERN_WARNING
634 "Ignoring memory bank 0x%08x size %dKB\n",
635 tag->u.mem.start, tag->u.mem.size / 1024);
636 return -EINVAL;
637 }
Andrew Morton1c97b732006-04-20 21:41:18 +0100638 arm_add_memory(tag->u.mem.start, tag->u.mem.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
640}
641
642__tagtable(ATAG_MEM, parse_tag_mem32);
643
644#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
645struct screen_info screen_info = {
646 .orig_video_lines = 30,
647 .orig_video_cols = 80,
648 .orig_video_mode = 0,
649 .orig_video_ega_bx = 0,
650 .orig_video_isVGA = 1,
651 .orig_video_points = 8
652};
653
654static int __init parse_tag_videotext(const struct tag *tag)
655{
656 screen_info.orig_x = tag->u.videotext.x;
657 screen_info.orig_y = tag->u.videotext.y;
658 screen_info.orig_video_page = tag->u.videotext.video_page;
659 screen_info.orig_video_mode = tag->u.videotext.video_mode;
660 screen_info.orig_video_cols = tag->u.videotext.video_cols;
661 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
662 screen_info.orig_video_lines = tag->u.videotext.video_lines;
663 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
664 screen_info.orig_video_points = tag->u.videotext.video_points;
665 return 0;
666}
667
668__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
669#endif
670
671static int __init parse_tag_ramdisk(const struct tag *tag)
672{
673 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
674 (tag->u.ramdisk.flags & 2) == 0,
675 tag->u.ramdisk.start, tag->u.ramdisk.size);
676 return 0;
677}
678
679__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681static int __init parse_tag_serialnr(const struct tag *tag)
682{
683 system_serial_low = tag->u.serialnr.low;
684 system_serial_high = tag->u.serialnr.high;
685 return 0;
686}
687
688__tagtable(ATAG_SERIAL, parse_tag_serialnr);
689
690static int __init parse_tag_revision(const struct tag *tag)
691{
692 system_rev = tag->u.revision.rev;
693 return 0;
694}
695
696__tagtable(ATAG_REVISION, parse_tag_revision);
697
698static int __init parse_tag_cmdline(const struct tag *tag)
699{
700 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
701 return 0;
702}
703
704__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
705
706/*
707 * Scan the tag table for this tag, and call its parse function.
708 * The tag table is built by the linker from all the __tagtable
709 * declarations.
710 */
711static int __init parse_tag(const struct tag *tag)
712{
713 extern struct tagtable __tagtable_begin, __tagtable_end;
714 struct tagtable *t;
715
716 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
717 if (tag->hdr.tag == t->tag) {
718 t->parse(tag);
719 break;
720 }
721
722 return t < &__tagtable_end;
723}
724
725/*
726 * Parse all tags in the list, checking both the global and architecture
727 * specific tag tables.
728 */
729static void __init parse_tags(const struct tag *t)
730{
731 for (; t->hdr.size; t = tag_next(t))
732 if (!parse_tag(t))
733 printk(KERN_WARNING
734 "Ignoring unrecognised tag 0x%08x\n",
735 t->hdr.tag);
736}
737
738/*
739 * This holds our defaults.
740 */
741static struct init_tags {
742 struct tag_header hdr1;
743 struct tag_core core;
744 struct tag_header hdr2;
745 struct tag_mem32 mem;
746 struct tag_header hdr3;
747} init_tags __initdata = {
748 { tag_size(tag_core), ATAG_CORE },
749 { 1, PAGE_SIZE, 0xff },
750 { tag_size(tag_mem32), ATAG_MEM },
751 { MEM_SIZE, PHYS_OFFSET },
752 { 0, ATAG_NONE }
753};
754
755static void (*init_machine)(void) __initdata;
756
757static int __init customize_machine(void)
758{
759 /* customizes platform devices, or adds new ones */
760 if (init_machine)
761 init_machine();
762 return 0;
763}
764arch_initcall(customize_machine);
765
766void __init setup_arch(char **cmdline_p)
767{
768 struct tag *tags = (struct tag *)&init_tags;
769 struct machine_desc *mdesc;
770 char *from = default_command_line;
771
772 setup_processor();
773 mdesc = setup_machine(machine_arch_type);
774 machine_name = mdesc->name;
775
776 if (mdesc->soft_reboot)
777 reboot_setup("s");
778
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100779 if (__atags_pointer)
780 tags = phys_to_virt(__atags_pointer);
781 else if (mdesc->boot_params)
Russell Kingf9bd6ea2005-07-04 10:43:36 +0100782 tags = phys_to_virt(mdesc->boot_params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 /*
785 * If we have the old style parameters, convert them to
786 * a tag list.
787 */
788 if (tags->hdr.tag != ATAG_CORE)
789 convert_to_tag_list(tags);
790 if (tags->hdr.tag != ATAG_CORE)
791 tags = (struct tag *)&init_tags;
792
793 if (mdesc->fixup)
794 mdesc->fixup(mdesc, tags, &from, &meminfo);
795
796 if (tags->hdr.tag == ATAG_CORE) {
797 if (meminfo.nr_banks != 0)
798 squash_mem_tags(tags);
Richard Purdie4cd9d6f2008-01-02 00:56:46 +0100799 save_atags(tags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 parse_tags(tags);
801 }
802
803 init_mm.start_code = (unsigned long) &_text;
804 init_mm.end_code = (unsigned long) &_etext;
805 init_mm.end_data = (unsigned long) &_edata;
806 init_mm.brk = (unsigned long) &_end;
807
Alon Bar-Levcd818992007-02-12 00:54:06 -0800808 memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
809 boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 parse_cmdline(cmdline_p, from);
811 paging_init(&meminfo, mdesc);
812 request_standard_resources(&meminfo, mdesc);
813
Russell King7bbb7942006-02-16 11:08:09 +0000814#ifdef CONFIG_SMP
815 smp_init_cpus();
816#endif
817
Russell Kingccea7a12005-05-31 22:22:32 +0100818 cpu_init();
819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 /*
821 * Set up various architecture-specific pointers
822 */
823 init_arch_irq = mdesc->init_irq;
824 system_timer = mdesc->timer;
825 init_machine = mdesc->init_machine;
826
827#ifdef CONFIG_VT
828#if defined(CONFIG_VGA_CONSOLE)
829 conswitchp = &vga_con;
830#elif defined(CONFIG_DUMMY_CONSOLE)
831 conswitchp = &dummy_con;
832#endif
833#endif
Jason Wessel5cbad0e2008-02-20 13:33:40 -0600834 early_trap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835}
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",
Russell King0ba8b9b2008-08-10 18:08:10 +0100889 cpu_name, read_cpuid_id() & 15, elf_platform);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
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
Russell King0ba8b9b2008-08-10 18:08:10 +0100916 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
918
Russell King0ba8b9b2008-08-10 18:08:10 +0100919 if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 /* pre-ARM7 */
Russell King0ba8b9b2008-08-10 18:08:10 +0100921 seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 } else {
Russell King0ba8b9b2008-08-10 18:08:10 +0100923 if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 /* ARM7 */
925 seq_printf(m, "CPU variant\t: 0x%02x\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100926 (read_cpuid_id() >> 16) & 127);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 } else {
928 /* post-ARM7 */
929 seq_printf(m, "CPU variant\t: 0x%x\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100930 (read_cpuid_id() >> 20) & 15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
932 seq_printf(m, "CPU part\t: 0x%03x\n",
Russell King0ba8b9b2008-08-10 18:08:10 +0100933 (read_cpuid_id() >> 4) & 0xfff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 }
Russell King0ba8b9b2008-08-10 18:08:10 +0100935 seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 {
Russell King0ba8b9b2008-08-10 18:08:10 +0100938 unsigned int cache_info = read_cpuid_cachetype();
939 if (cache_info != read_cpuid_id()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 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
Jan Engelhardt2ffd6e12008-01-22 20:41:07 +0100983const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 .start = c_start,
985 .next = c_next,
986 .stop = c_stop,
987 .show = c_show
988};