blob: 38f0e7940a132b1c9e0458bc10e9d1dc3f2401ee [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>
29#include <asm/elf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/procinfo.h>
31#include <asm/setup.h>
32#include <asm/mach-types.h>
33#include <asm/cacheflush.h>
34#include <asm/tlbflush.h>
35
36#include <asm/mach/arch.h>
37#include <asm/mach/irq.h>
38#include <asm/mach/time.h>
Jason Wessel5cbad0e2008-02-20 13:33:40 -060039#include <asm/traps.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Ben Dooks0fc1c832006-03-15 23:17:30 +000041#include "compat.h"
Richard Purdie4cd9d6f2008-01-02 00:56:46 +010042#include "atags.h"
Ben Dooks0fc1c832006-03-15 23:17:30 +000043
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#ifndef MEM_SIZE
45#define MEM_SIZE (16*1024*1024)
46#endif
47
48#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
49char fpe_type[8];
50
51static int __init fpe_setup(char *line)
52{
53 memcpy(fpe_type, line, 8);
54 return 1;
55}
56
57__setup("fpe=", fpe_setup);
58#endif
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060extern void paging_init(struct meminfo *, struct machine_desc *desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061extern void reboot_setup(char *str);
62extern int root_mountflags;
63extern void _stext, _text, _etext, __data_start, _edata, _end;
64
65unsigned int processor_id;
Krzysztof Halasac18f6582007-12-18 03:53:27 +010066EXPORT_SYMBOL(processor_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067unsigned int __machine_arch_type;
68EXPORT_SYMBOL(__machine_arch_type);
69
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010070unsigned int __atags_pointer __initdata;
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072unsigned int system_rev;
73EXPORT_SYMBOL(system_rev);
74
75unsigned int system_serial_low;
76EXPORT_SYMBOL(system_serial_low);
77
78unsigned int system_serial_high;
79EXPORT_SYMBOL(system_serial_high);
80
81unsigned int elf_hwcap;
82EXPORT_SYMBOL(elf_hwcap);
83
84
85#ifdef MULTI_CPU
86struct processor processor;
87#endif
88#ifdef MULTI_TLB
89struct cpu_tlb_fns cpu_tlb;
90#endif
91#ifdef MULTI_USER
92struct cpu_user_fns cpu_user;
93#endif
94#ifdef MULTI_CACHE
95struct cpu_cache_fns cpu_cache;
96#endif
Catalin Marinas953233d2007-02-05 14:48:08 +010097#ifdef CONFIG_OUTER_CACHE
98struct outer_cache_fns outer_cache;
99#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Russell Kingccea7a12005-05-31 22:22:32 +0100101struct stack {
102 u32 irq[3];
103 u32 abt[3];
104 u32 und[3];
105} ____cacheline_aligned;
106
107static struct stack stacks[NR_CPUS];
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109char elf_platform[ELF_PLATFORM_SIZE];
110EXPORT_SYMBOL(elf_platform);
111
112unsigned long phys_initrd_start __initdata = 0;
113unsigned long phys_initrd_size __initdata = 0;
114
115static 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{
281 unsigned int info = read_cpuid(CPUID_CACHETYPE);
282
283 if (info != processor_id) {
284 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
Catalin Marinas6b090a22006-01-12 16:28:16 +0000302 if ((processor_id & 0x0008f000) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 cpu_arch = CPU_ARCH_UNKNOWN;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000304 } else if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000306 } else if ((processor_id & 0x00080000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 cpu_arch = (processor_id >> 16) & 7;
308 if (cpu_arch)
309 cpu_arch += CPU_ARCH_ARMv3;
Catalin Marinas180005c2007-09-25 16:49:45 +0100310 } else if ((processor_id & 0x000f0000) == 0x000f0000) {
311 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 King0f44ba12006-02-24 21:04:56 +0000347 list = lookup_processor_type(processor_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if (!list) {
349 printk("CPU configuration botched (ID %08x), unable "
350 "to continue.\n", processor_id);
351 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",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 cpu_name, processor_id, (int)processor_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
444static void __init early_initrd(char **p)
445{
446 unsigned long start, size;
447
448 start = memparse(*p, p);
449 if (**p == ',') {
450 size = memparse((*p) + 1, p);
451
452 phys_initrd_start = start;
453 phys_initrd_size = size;
454 }
455}
456__early_param("initrd=", early_initrd);
457
Andrew Morton1c97b732006-04-20 21:41:18 +0100458static void __init arm_add_memory(unsigned long start, unsigned long size)
Russell King3a669412005-06-22 21:43:10 +0100459{
Russell King05f96ef2006-11-30 20:44:49 +0000460 struct membank *bank;
461
Russell King3a669412005-06-22 21:43:10 +0100462 /*
463 * Ensure that start/size are aligned to a page boundary.
464 * Size is appropriately rounded down, start is rounded up.
465 */
466 size -= start & ~PAGE_MASK;
467
Russell King05f96ef2006-11-30 20:44:49 +0000468 bank = &meminfo.bank[meminfo.nr_banks++];
469
470 bank->start = PAGE_ALIGN(start);
471 bank->size = size & PAGE_MASK;
472 bank->node = PHYS_TO_NID(start);
Russell King3a669412005-06-22 21:43:10 +0100473}
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475/*
476 * Pick out the memory size. We look for mem=size@start,
477 * where start and size are "size[KkMm]"
478 */
479static void __init early_mem(char **p)
480{
481 static int usermem __initdata = 0;
482 unsigned long size, start;
483
484 /*
485 * If the user specifies memory size, we
486 * blow away any automatically generated
487 * size.
488 */
489 if (usermem == 0) {
490 usermem = 1;
491 meminfo.nr_banks = 0;
492 }
493
494 start = PHYS_OFFSET;
495 size = memparse(*p, p);
496 if (**p == '@')
497 start = memparse(*p + 1, p);
498
Andrew Morton1c97b732006-04-20 21:41:18 +0100499 arm_add_memory(start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501__early_param("mem=", early_mem);
502
503/*
504 * Initial parsing of the command line.
505 */
506static void __init parse_cmdline(char **cmdline_p, char *from)
507{
508 char c = ' ', *to = command_line;
509 int len = 0;
510
511 for (;;) {
512 if (c == ' ') {
513 extern struct early_params __early_begin, __early_end;
514 struct early_params *p;
515
516 for (p = &__early_begin; p < &__early_end; p++) {
517 int len = strlen(p->arg);
518
519 if (memcmp(from, p->arg, len) == 0) {
520 if (to != command_line)
521 to -= 1;
522 from += len;
523 p->fn(&from);
524
525 while (*from != ' ' && *from != '\0')
526 from++;
527 break;
528 }
529 }
530 }
531 c = *from++;
532 if (!c)
533 break;
534 if (COMMAND_LINE_SIZE <= ++len)
535 break;
536 *to++ = c;
537 }
538 *to = '\0';
539 *cmdline_p = command_line;
540}
541
542static void __init
543setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
544{
545#ifdef CONFIG_BLK_DEV_RAM
546 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
547
548 rd_image_start = image_start;
549 rd_prompt = prompt;
550 rd_doload = doload;
551
552 if (rd_sz)
553 rd_size = rd_sz;
554#endif
555}
556
557static void __init
558request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
559{
560 struct resource *res;
561 int i;
562
563 kernel_code.start = virt_to_phys(&_text);
564 kernel_code.end = virt_to_phys(&_etext - 1);
565 kernel_data.start = virt_to_phys(&__data_start);
566 kernel_data.end = virt_to_phys(&_end - 1);
567
568 for (i = 0; i < mi->nr_banks; i++) {
569 unsigned long virt_start, virt_end;
570
571 if (mi->bank[i].size == 0)
572 continue;
573
574 virt_start = __phys_to_virt(mi->bank[i].start);
575 virt_end = virt_start + mi->bank[i].size - 1;
576
577 res = alloc_bootmem_low(sizeof(*res));
578 res->name = "System RAM";
579 res->start = __virt_to_phys(virt_start);
580 res->end = __virt_to_phys(virt_end);
581 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
582
583 request_resource(&iomem_resource, res);
584
585 if (kernel_code.start >= res->start &&
586 kernel_code.end <= res->end)
587 request_resource(res, &kernel_code);
588 if (kernel_data.start >= res->start &&
589 kernel_data.end <= res->end)
590 request_resource(res, &kernel_data);
591 }
592
593 if (mdesc->video_start) {
594 video_ram.start = mdesc->video_start;
595 video_ram.end = mdesc->video_end;
596 request_resource(&iomem_resource, &video_ram);
597 }
598
599 /*
600 * Some machines don't have the possibility of ever
601 * possessing lp0, lp1 or lp2
602 */
603 if (mdesc->reserve_lp0)
604 request_resource(&ioport_resource, &lp0);
605 if (mdesc->reserve_lp1)
606 request_resource(&ioport_resource, &lp1);
607 if (mdesc->reserve_lp2)
608 request_resource(&ioport_resource, &lp2);
609}
610
611/*
612 * Tag parsing.
613 *
614 * This is the new way of passing data to the kernel at boot time. Rather
615 * than passing a fixed inflexible structure to the kernel, we pass a list
616 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
617 * tag for the list to be recognised (to distinguish the tagged list from
618 * a param_struct). The list is terminated with a zero-length tag (this tag
619 * is not parsed in any way).
620 */
621static int __init parse_tag_core(const struct tag *tag)
622{
623 if (tag->hdr.size > 2) {
624 if ((tag->u.core.flags & 1) == 0)
625 root_mountflags &= ~MS_RDONLY;
626 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
627 }
628 return 0;
629}
630
631__tagtable(ATAG_CORE, parse_tag_core);
632
633static int __init parse_tag_mem32(const struct tag *tag)
634{
635 if (meminfo.nr_banks >= NR_BANKS) {
636 printk(KERN_WARNING
637 "Ignoring memory bank 0x%08x size %dKB\n",
638 tag->u.mem.start, tag->u.mem.size / 1024);
639 return -EINVAL;
640 }
Andrew Morton1c97b732006-04-20 21:41:18 +0100641 arm_add_memory(tag->u.mem.start, tag->u.mem.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return 0;
643}
644
645__tagtable(ATAG_MEM, parse_tag_mem32);
646
647#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
648struct screen_info screen_info = {
649 .orig_video_lines = 30,
650 .orig_video_cols = 80,
651 .orig_video_mode = 0,
652 .orig_video_ega_bx = 0,
653 .orig_video_isVGA = 1,
654 .orig_video_points = 8
655};
656
657static int __init parse_tag_videotext(const struct tag *tag)
658{
659 screen_info.orig_x = tag->u.videotext.x;
660 screen_info.orig_y = tag->u.videotext.y;
661 screen_info.orig_video_page = tag->u.videotext.video_page;
662 screen_info.orig_video_mode = tag->u.videotext.video_mode;
663 screen_info.orig_video_cols = tag->u.videotext.video_cols;
664 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
665 screen_info.orig_video_lines = tag->u.videotext.video_lines;
666 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
667 screen_info.orig_video_points = tag->u.videotext.video_points;
668 return 0;
669}
670
671__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
672#endif
673
674static int __init parse_tag_ramdisk(const struct tag *tag)
675{
676 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
677 (tag->u.ramdisk.flags & 2) == 0,
678 tag->u.ramdisk.start, tag->u.ramdisk.size);
679 return 0;
680}
681
682__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
683
684static int __init parse_tag_initrd(const struct tag *tag)
685{
686 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
687 "please update your bootloader.\n");
688 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
689 phys_initrd_size = tag->u.initrd.size;
690 return 0;
691}
692
693__tagtable(ATAG_INITRD, parse_tag_initrd);
694
695static int __init parse_tag_initrd2(const struct tag *tag)
696{
697 phys_initrd_start = tag->u.initrd.start;
698 phys_initrd_size = tag->u.initrd.size;
699 return 0;
700}
701
702__tagtable(ATAG_INITRD2, parse_tag_initrd2);
703
704static int __init parse_tag_serialnr(const struct tag *tag)
705{
706 system_serial_low = tag->u.serialnr.low;
707 system_serial_high = tag->u.serialnr.high;
708 return 0;
709}
710
711__tagtable(ATAG_SERIAL, parse_tag_serialnr);
712
713static int __init parse_tag_revision(const struct tag *tag)
714{
715 system_rev = tag->u.revision.rev;
716 return 0;
717}
718
719__tagtable(ATAG_REVISION, parse_tag_revision);
720
721static int __init parse_tag_cmdline(const struct tag *tag)
722{
723 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
724 return 0;
725}
726
727__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
728
729/*
730 * Scan the tag table for this tag, and call its parse function.
731 * The tag table is built by the linker from all the __tagtable
732 * declarations.
733 */
734static int __init parse_tag(const struct tag *tag)
735{
736 extern struct tagtable __tagtable_begin, __tagtable_end;
737 struct tagtable *t;
738
739 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
740 if (tag->hdr.tag == t->tag) {
741 t->parse(tag);
742 break;
743 }
744
745 return t < &__tagtable_end;
746}
747
748/*
749 * Parse all tags in the list, checking both the global and architecture
750 * specific tag tables.
751 */
752static void __init parse_tags(const struct tag *t)
753{
754 for (; t->hdr.size; t = tag_next(t))
755 if (!parse_tag(t))
756 printk(KERN_WARNING
757 "Ignoring unrecognised tag 0x%08x\n",
758 t->hdr.tag);
759}
760
761/*
762 * This holds our defaults.
763 */
764static struct init_tags {
765 struct tag_header hdr1;
766 struct tag_core core;
767 struct tag_header hdr2;
768 struct tag_mem32 mem;
769 struct tag_header hdr3;
770} init_tags __initdata = {
771 { tag_size(tag_core), ATAG_CORE },
772 { 1, PAGE_SIZE, 0xff },
773 { tag_size(tag_mem32), ATAG_MEM },
774 { MEM_SIZE, PHYS_OFFSET },
775 { 0, ATAG_NONE }
776};
777
778static void (*init_machine)(void) __initdata;
779
780static int __init customize_machine(void)
781{
782 /* customizes platform devices, or adds new ones */
783 if (init_machine)
784 init_machine();
785 return 0;
786}
787arch_initcall(customize_machine);
788
789void __init setup_arch(char **cmdline_p)
790{
791 struct tag *tags = (struct tag *)&init_tags;
792 struct machine_desc *mdesc;
793 char *from = default_command_line;
794
795 setup_processor();
796 mdesc = setup_machine(machine_arch_type);
797 machine_name = mdesc->name;
798
799 if (mdesc->soft_reboot)
800 reboot_setup("s");
801
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100802 if (__atags_pointer)
803 tags = phys_to_virt(__atags_pointer);
804 else if (mdesc->boot_params)
Russell Kingf9bd6ea2005-07-04 10:43:36 +0100805 tags = phys_to_virt(mdesc->boot_params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 /*
808 * If we have the old style parameters, convert them to
809 * a tag list.
810 */
811 if (tags->hdr.tag != ATAG_CORE)
812 convert_to_tag_list(tags);
813 if (tags->hdr.tag != ATAG_CORE)
814 tags = (struct tag *)&init_tags;
815
816 if (mdesc->fixup)
817 mdesc->fixup(mdesc, tags, &from, &meminfo);
818
819 if (tags->hdr.tag == ATAG_CORE) {
820 if (meminfo.nr_banks != 0)
821 squash_mem_tags(tags);
Richard Purdie4cd9d6f2008-01-02 00:56:46 +0100822 save_atags(tags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 parse_tags(tags);
824 }
825
826 init_mm.start_code = (unsigned long) &_text;
827 init_mm.end_code = (unsigned long) &_etext;
828 init_mm.end_data = (unsigned long) &_edata;
829 init_mm.brk = (unsigned long) &_end;
830
Alon Bar-Levcd818992007-02-12 00:54:06 -0800831 memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
832 boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 parse_cmdline(cmdline_p, from);
834 paging_init(&meminfo, mdesc);
835 request_standard_resources(&meminfo, mdesc);
836
Russell King7bbb7942006-02-16 11:08:09 +0000837#ifdef CONFIG_SMP
838 smp_init_cpus();
839#endif
840
Russell Kingccea7a12005-05-31 22:22:32 +0100841 cpu_init();
842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /*
844 * Set up various architecture-specific pointers
845 */
846 init_arch_irq = mdesc->init_irq;
847 system_timer = mdesc->timer;
848 init_machine = mdesc->init_machine;
849
850#ifdef CONFIG_VT
851#if defined(CONFIG_VGA_CONSOLE)
852 conswitchp = &vga_con;
853#elif defined(CONFIG_DUMMY_CONSOLE)
854 conswitchp = &dummy_con;
855#endif
856#endif
Jason Wessel5cbad0e2008-02-20 13:33:40 -0600857 early_trap_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
859
860
861static int __init topology_init(void)
862{
863 int cpu;
864
Russell King66fb8bd2007-03-13 09:54:21 +0000865 for_each_possible_cpu(cpu) {
866 struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
867 cpuinfo->cpu.hotpluggable = 1;
868 register_cpu(&cpuinfo->cpu, cpu);
869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
871 return 0;
872}
873
874subsys_initcall(topology_init);
875
876static const char *hwcap_str[] = {
877 "swp",
878 "half",
879 "thumb",
880 "26bit",
881 "fastmult",
882 "fpa",
883 "vfp",
884 "edsp",
885 "java",
Paul Gortmaker8f7f9432006-10-27 05:13:19 +0100886 "iwmmxt",
Lennert Buytenhek99e4a6d2006-12-18 00:59:10 +0100887 "crunch",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 NULL
889};
890
891static void
892c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
893{
894 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
895
896 seq_printf(m, "%s size\t\t: %d\n"
897 "%s assoc\t\t: %d\n"
898 "%s line length\t: %d\n"
899 "%s sets\t\t: %d\n",
900 type, mult << (8 + CACHE_SIZE(cache)),
901 type, (mult << CACHE_ASSOC(cache)) >> 1,
902 type, 8 << CACHE_LINE(cache),
903 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
904 CACHE_LINE(cache)));
905}
906
907static int c_show(struct seq_file *m, void *v)
908{
909 int i;
910
911 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
912 cpu_name, (int)processor_id & 15, elf_platform);
913
914#if defined(CONFIG_SMP)
915 for_each_online_cpu(i) {
Russell King15559722005-11-06 21:41:08 +0000916 /*
917 * glibc reads /proc/cpuinfo to determine the number of
918 * online processors, looking for lines beginning with
919 * "processor". Give glibc what it expects.
920 */
921 seq_printf(m, "processor\t: %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
923 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
924 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
925 }
926#else /* CONFIG_SMP */
927 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
928 loops_per_jiffy / (500000/HZ),
929 (loops_per_jiffy / (5000/HZ)) % 100);
930#endif
931
932 /* dump out the processor features */
933 seq_puts(m, "Features\t: ");
934
935 for (i = 0; hwcap_str[i]; i++)
936 if (elf_hwcap & (1 << i))
937 seq_printf(m, "%s ", hwcap_str[i]);
938
939 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
940 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
941
Catalin Marinas6b090a22006-01-12 16:28:16 +0000942 if ((processor_id & 0x0008f000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 /* pre-ARM7 */
Greg Ungerer1d28bff2007-05-17 06:12:22 +0100944 seq_printf(m, "CPU part\t: %07x\n", processor_id >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 } else {
Catalin Marinas6b090a22006-01-12 16:28:16 +0000946 if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* ARM7 */
948 seq_printf(m, "CPU variant\t: 0x%02x\n",
949 (processor_id >> 16) & 127);
950 } else {
951 /* post-ARM7 */
952 seq_printf(m, "CPU variant\t: 0x%x\n",
953 (processor_id >> 20) & 15);
954 }
955 seq_printf(m, "CPU part\t: 0x%03x\n",
956 (processor_id >> 4) & 0xfff);
957 }
958 seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
959
960 {
961 unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
962 if (cache_info != processor_id) {
963 seq_printf(m, "Cache type\t: %s\n"
964 "Cache clean\t: %s\n"
965 "Cache lockdown\t: %s\n"
966 "Cache format\t: %s\n",
967 cache_types[CACHE_TYPE(cache_info)],
968 cache_clean[CACHE_TYPE(cache_info)],
969 cache_lockdown[CACHE_TYPE(cache_info)],
970 CACHE_S(cache_info) ? "Harvard" : "Unified");
971
972 if (CACHE_S(cache_info)) {
973 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
974 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
975 } else {
976 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
977 }
978 }
979 }
980
981 seq_puts(m, "\n");
982
983 seq_printf(m, "Hardware\t: %s\n", machine_name);
984 seq_printf(m, "Revision\t: %04x\n", system_rev);
985 seq_printf(m, "Serial\t\t: %08x%08x\n",
986 system_serial_high, system_serial_low);
987
988 return 0;
989}
990
991static void *c_start(struct seq_file *m, loff_t *pos)
992{
993 return *pos < 1 ? (void *)1 : NULL;
994}
995
996static void *c_next(struct seq_file *m, void *v, loff_t *pos)
997{
998 ++*pos;
999 return NULL;
1000}
1001
1002static void c_stop(struct seq_file *m, void *v)
1003{
1004}
1005
Jan Engelhardt2ffd6e12008-01-22 20:41:07 +01001006const struct seq_operations cpuinfo_op = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 .start = c_start,
1008 .next = c_next,
1009 .stop = c_stop,
1010 .show = c_show
1011};