blob: efac7df72d6563cb85048a2cb4b1680b38b96c3d [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>
39
Ben Dooks0fc1c832006-03-15 23:17:30 +000040#include "compat.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#ifndef MEM_SIZE
43#define MEM_SIZE (16*1024*1024)
44#endif
45
46#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
47char fpe_type[8];
48
49static int __init fpe_setup(char *line)
50{
51 memcpy(fpe_type, line, 8);
52 return 1;
53}
54
55__setup("fpe=", fpe_setup);
56#endif
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058extern void paging_init(struct meminfo *, struct machine_desc *desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059extern void reboot_setup(char *str);
60extern int root_mountflags;
61extern void _stext, _text, _etext, __data_start, _edata, _end;
62
63unsigned int processor_id;
64unsigned int __machine_arch_type;
65EXPORT_SYMBOL(__machine_arch_type);
66
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010067unsigned int __atags_pointer __initdata;
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069unsigned int system_rev;
70EXPORT_SYMBOL(system_rev);
71
72unsigned int system_serial_low;
73EXPORT_SYMBOL(system_serial_low);
74
75unsigned int system_serial_high;
76EXPORT_SYMBOL(system_serial_high);
77
78unsigned int elf_hwcap;
79EXPORT_SYMBOL(elf_hwcap);
80
81
82#ifdef MULTI_CPU
83struct processor processor;
84#endif
85#ifdef MULTI_TLB
86struct cpu_tlb_fns cpu_tlb;
87#endif
88#ifdef MULTI_USER
89struct cpu_user_fns cpu_user;
90#endif
91#ifdef MULTI_CACHE
92struct cpu_cache_fns cpu_cache;
93#endif
Catalin Marinas953233d2007-02-05 14:48:08 +010094#ifdef CONFIG_OUTER_CACHE
95struct outer_cache_fns outer_cache;
96#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Russell Kingccea7a12005-05-31 22:22:32 +010098struct stack {
99 u32 irq[3];
100 u32 abt[3];
101 u32 und[3];
102} ____cacheline_aligned;
103
104static struct stack stacks[NR_CPUS];
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106char elf_platform[ELF_PLATFORM_SIZE];
107EXPORT_SYMBOL(elf_platform);
108
109unsigned long phys_initrd_start __initdata = 0;
110unsigned long phys_initrd_size __initdata = 0;
111
112static struct meminfo meminfo __initdata = { 0, };
113static const char *cpu_name;
114static const char *machine_name;
Alon Bar-Levcd818992007-02-12 00:54:06 -0800115static char __initdata command_line[COMMAND_LINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
118static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
119#define ENDIANNESS ((char)endian_test.l)
120
121DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
122
123/*
124 * Standard memory resources
125 */
126static struct resource mem_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700127 {
128 .name = "Video RAM",
129 .start = 0,
130 .end = 0,
131 .flags = IORESOURCE_MEM
132 },
133 {
134 .name = "Kernel text",
135 .start = 0,
136 .end = 0,
137 .flags = IORESOURCE_MEM
138 },
139 {
140 .name = "Kernel data",
141 .start = 0,
142 .end = 0,
143 .flags = IORESOURCE_MEM
144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145};
146
147#define video_ram mem_res[0]
148#define kernel_code mem_res[1]
149#define kernel_data mem_res[2]
150
151static struct resource io_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700152 {
153 .name = "reserved",
154 .start = 0x3bc,
155 .end = 0x3be,
156 .flags = IORESOURCE_IO | IORESOURCE_BUSY
157 },
158 {
159 .name = "reserved",
160 .start = 0x378,
161 .end = 0x37f,
162 .flags = IORESOURCE_IO | IORESOURCE_BUSY
163 },
164 {
165 .name = "reserved",
166 .start = 0x278,
167 .end = 0x27f,
168 .flags = IORESOURCE_IO | IORESOURCE_BUSY
169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170};
171
172#define lp0 io_res[0]
173#define lp1 io_res[1]
174#define lp2 io_res[2]
175
176static const char *cache_types[16] = {
177 "write-through",
178 "write-back",
179 "write-back",
180 "undefined 3",
181 "undefined 4",
182 "undefined 5",
183 "write-back",
184 "write-back",
185 "undefined 8",
186 "undefined 9",
187 "undefined 10",
188 "undefined 11",
189 "undefined 12",
190 "undefined 13",
191 "write-back",
192 "undefined 15",
193};
194
195static const char *cache_clean[16] = {
196 "not required",
197 "read-block",
198 "cp15 c7 ops",
199 "undefined 3",
200 "undefined 4",
201 "undefined 5",
202 "cp15 c7 ops",
203 "cp15 c7 ops",
204 "undefined 8",
205 "undefined 9",
206 "undefined 10",
207 "undefined 11",
208 "undefined 12",
209 "undefined 13",
210 "cp15 c7 ops",
211 "undefined 15",
212};
213
214static const char *cache_lockdown[16] = {
215 "not supported",
216 "not supported",
217 "not supported",
218 "undefined 3",
219 "undefined 4",
220 "undefined 5",
221 "format A",
222 "format B",
223 "undefined 8",
224 "undefined 9",
225 "undefined 10",
226 "undefined 11",
227 "undefined 12",
228 "undefined 13",
229 "format C",
230 "undefined 15",
231};
232
233static const char *proc_arch[] = {
234 "undefined/unknown",
235 "3",
236 "4",
237 "4T",
238 "5",
239 "5T",
240 "5TE",
241 "5TEJ",
242 "6TEJ",
Catalin Marinas6b090a22006-01-12 16:28:16 +0000243 "7",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 "?(11)",
245 "?(12)",
246 "?(13)",
247 "?(14)",
248 "?(15)",
249 "?(16)",
250 "?(17)",
251};
252
253#define CACHE_TYPE(x) (((x) >> 25) & 15)
254#define CACHE_S(x) ((x) & (1 << 24))
255#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
256#define CACHE_ISIZE(x) ((x) & 4095)
257
258#define CACHE_SIZE(y) (((y) >> 6) & 7)
259#define CACHE_ASSOC(y) (((y) >> 3) & 7)
260#define CACHE_M(y) ((y) & (1 << 2))
261#define CACHE_LINE(y) ((y) & 3)
262
263static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
264{
265 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
266
267 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
268 cpu, prefix,
269 mult << (8 + CACHE_SIZE(cache)),
270 (mult << CACHE_ASSOC(cache)) >> 1,
271 8 << CACHE_LINE(cache),
272 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
273 CACHE_LINE(cache)));
274}
275
276static void __init dump_cpu_info(int cpu)
277{
278 unsigned int info = read_cpuid(CPUID_CACHETYPE);
279
280 if (info != processor_id) {
281 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
282 cache_types[CACHE_TYPE(info)]);
283 if (CACHE_S(info)) {
284 dump_cache("I cache", cpu, CACHE_ISIZE(info));
285 dump_cache("D cache", cpu, CACHE_DSIZE(info));
286 } else {
287 dump_cache("cache", cpu, CACHE_ISIZE(info));
288 }
289 }
Lennert Buytenhek23759dc2006-04-02 00:07:39 +0100290
291 if (arch_is_coherent())
292 printk("Cache coherency enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
295int cpu_architecture(void)
296{
297 int cpu_arch;
298
Catalin Marinas6b090a22006-01-12 16:28:16 +0000299 if ((processor_id & 0x0008f000) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 cpu_arch = CPU_ARCH_UNKNOWN;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000301 } else if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000303 } else if ((processor_id & 0x00080000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 cpu_arch = (processor_id >> 16) & 7;
305 if (cpu_arch)
306 cpu_arch += CPU_ARCH_ARMv3;
Catalin Marinas180005c2007-09-25 16:49:45 +0100307 } else if ((processor_id & 0x000f0000) == 0x000f0000) {
308 unsigned int mmfr0;
309
310 /* Revised CPUID format. Read the Memory Model Feature
311 * Register 0 and check for VMSAv7 or PMSAv7 */
312 asm("mrc p15, 0, %0, c0, c1, 4"
313 : "=r" (mmfr0));
314 if ((mmfr0 & 0x0000000f) == 0x00000003 ||
315 (mmfr0 & 0x000000f0) == 0x00000030)
316 cpu_arch = CPU_ARCH_ARMv7;
317 else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
318 (mmfr0 & 0x000000f0) == 0x00000020)
319 cpu_arch = CPU_ARCH_ARMv6;
320 else
321 cpu_arch = CPU_ARCH_UNKNOWN;
322 } else
323 cpu_arch = CPU_ARCH_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 return cpu_arch;
326}
327
328/*
329 * These functions re-use the assembly code in head.S, which
330 * already provide the required functionality.
331 */
Russell King0f44ba12006-02-24 21:04:56 +0000332extern struct proc_info_list *lookup_processor_type(unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333extern struct machine_desc *lookup_machine_type(unsigned int);
334
335static void __init setup_processor(void)
336{
337 struct proc_info_list *list;
338
339 /*
340 * locate processor in the list of supported processor
341 * types. The linker builds this table for us from the
342 * entries in arch/arm/mm/proc-*.S
343 */
Russell King0f44ba12006-02-24 21:04:56 +0000344 list = lookup_processor_type(processor_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 if (!list) {
346 printk("CPU configuration botched (ID %08x), unable "
347 "to continue.\n", processor_id);
348 while (1);
349 }
350
351 cpu_name = list->cpu_name;
352
353#ifdef MULTI_CPU
354 processor = *list->proc;
355#endif
356#ifdef MULTI_TLB
357 cpu_tlb = *list->tlb;
358#endif
359#ifdef MULTI_USER
360 cpu_user = *list->user;
361#endif
362#ifdef MULTI_CACHE
363 cpu_cache = *list->cache;
364#endif
365
Russell King4e190252006-07-03 13:29:38 +0100366 printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 cpu_name, processor_id, (int)processor_id & 15,
Russell King264edb32006-06-29 15:03:09 +0100368 proc_arch[cpu_architecture()], cr_alignment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700370 sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
372 elf_hwcap = list->elf_hwcap;
Catalin Marinasadeff422006-04-10 21:32:35 +0100373#ifndef CONFIG_ARM_THUMB
374 elf_hwcap &= ~HWCAP_THUMB;
375#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 cpu_proc_init();
378}
379
Russell Kingccea7a12005-05-31 22:22:32 +0100380/*
381 * cpu_init - initialise one CPU.
382 *
383 * cpu_init dumps the cache information, initialises SMP specific
384 * information, and sets up the per-CPU stacks.
385 */
Russell King36c5ed22005-06-19 18:39:33 +0100386void cpu_init(void)
Russell Kingccea7a12005-05-31 22:22:32 +0100387{
388 unsigned int cpu = smp_processor_id();
389 struct stack *stk = &stacks[cpu];
390
391 if (cpu >= NR_CPUS) {
392 printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
393 BUG();
394 }
395
Russell King32f8b972005-11-06 19:49:21 +0000396 if (system_state == SYSTEM_BOOTING)
397 dump_cpu_info(cpu);
Russell Kingccea7a12005-05-31 22:22:32 +0100398
399 /*
400 * setup stacks for re-entrant exception handlers
401 */
402 __asm__ (
403 "msr cpsr_c, %1\n\t"
404 "add sp, %0, %2\n\t"
405 "msr cpsr_c, %3\n\t"
406 "add sp, %0, %4\n\t"
407 "msr cpsr_c, %5\n\t"
408 "add sp, %0, %6\n\t"
409 "msr cpsr_c, %7"
410 :
411 : "r" (stk),
412 "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
413 "I" (offsetof(struct stack, irq[0])),
414 "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
415 "I" (offsetof(struct stack, abt[0])),
416 "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
417 "I" (offsetof(struct stack, und[0])),
Catalin Marinasaaaa3f92005-06-29 15:34:39 +0100418 "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
419 : "r14");
Russell Kingccea7a12005-05-31 22:22:32 +0100420}
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422static struct machine_desc * __init setup_machine(unsigned int nr)
423{
424 struct machine_desc *list;
425
426 /*
427 * locate machine in the list of supported machines.
428 */
429 list = lookup_machine_type(nr);
430 if (!list) {
431 printk("Machine configuration botched (nr %d), unable "
432 "to continue.\n", nr);
433 while (1);
434 }
435
436 printk("Machine: %s\n", list->name);
437
438 return list;
439}
440
441static void __init early_initrd(char **p)
442{
443 unsigned long start, size;
444
445 start = memparse(*p, p);
446 if (**p == ',') {
447 size = memparse((*p) + 1, p);
448
449 phys_initrd_start = start;
450 phys_initrd_size = size;
451 }
452}
453__early_param("initrd=", early_initrd);
454
Andrew Morton1c97b732006-04-20 21:41:18 +0100455static void __init arm_add_memory(unsigned long start, unsigned long size)
Russell King3a669412005-06-22 21:43:10 +0100456{
Russell King05f96ef2006-11-30 20:44:49 +0000457 struct membank *bank;
458
Russell King3a669412005-06-22 21:43:10 +0100459 /*
460 * Ensure that start/size are aligned to a page boundary.
461 * Size is appropriately rounded down, start is rounded up.
462 */
463 size -= start & ~PAGE_MASK;
464
Russell King05f96ef2006-11-30 20:44:49 +0000465 bank = &meminfo.bank[meminfo.nr_banks++];
466
467 bank->start = PAGE_ALIGN(start);
468 bank->size = size & PAGE_MASK;
469 bank->node = PHYS_TO_NID(start);
Russell King3a669412005-06-22 21:43:10 +0100470}
471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472/*
473 * Pick out the memory size. We look for mem=size@start,
474 * where start and size are "size[KkMm]"
475 */
476static void __init early_mem(char **p)
477{
478 static int usermem __initdata = 0;
479 unsigned long size, start;
480
481 /*
482 * If the user specifies memory size, we
483 * blow away any automatically generated
484 * size.
485 */
486 if (usermem == 0) {
487 usermem = 1;
488 meminfo.nr_banks = 0;
489 }
490
491 start = PHYS_OFFSET;
492 size = memparse(*p, p);
493 if (**p == '@')
494 start = memparse(*p + 1, p);
495
Andrew Morton1c97b732006-04-20 21:41:18 +0100496 arm_add_memory(start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498__early_param("mem=", early_mem);
499
500/*
501 * 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++) {
514 int len = strlen(p->arg);
515
516 if (memcmp(from, p->arg, len) == 0) {
517 if (to != command_line)
518 to -= 1;
519 from += len;
520 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
681static int __init parse_tag_initrd(const struct tag *tag)
682{
683 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
684 "please update your bootloader.\n");
685 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
686 phys_initrd_size = tag->u.initrd.size;
687 return 0;
688}
689
690__tagtable(ATAG_INITRD, parse_tag_initrd);
691
692static int __init parse_tag_initrd2(const struct tag *tag)
693{
694 phys_initrd_start = tag->u.initrd.start;
695 phys_initrd_size = tag->u.initrd.size;
696 return 0;
697}
698
699__tagtable(ATAG_INITRD2, parse_tag_initrd2);
700
701static int __init parse_tag_serialnr(const struct tag *tag)
702{
703 system_serial_low = tag->u.serialnr.low;
704 system_serial_high = tag->u.serialnr.high;
705 return 0;
706}
707
708__tagtable(ATAG_SERIAL, parse_tag_serialnr);
709
710static int __init parse_tag_revision(const struct tag *tag)
711{
712 system_rev = tag->u.revision.rev;
713 return 0;
714}
715
716__tagtable(ATAG_REVISION, parse_tag_revision);
717
718static int __init parse_tag_cmdline(const struct tag *tag)
719{
720 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
721 return 0;
722}
723
724__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
725
726/*
727 * Scan the tag table for this tag, and call its parse function.
728 * The tag table is built by the linker from all the __tagtable
729 * declarations.
730 */
731static int __init parse_tag(const struct tag *tag)
732{
733 extern struct tagtable __tagtable_begin, __tagtable_end;
734 struct tagtable *t;
735
736 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
737 if (tag->hdr.tag == t->tag) {
738 t->parse(tag);
739 break;
740 }
741
742 return t < &__tagtable_end;
743}
744
745/*
746 * Parse all tags in the list, checking both the global and architecture
747 * specific tag tables.
748 */
749static void __init parse_tags(const struct tag *t)
750{
751 for (; t->hdr.size; t = tag_next(t))
752 if (!parse_tag(t))
753 printk(KERN_WARNING
754 "Ignoring unrecognised tag 0x%08x\n",
755 t->hdr.tag);
756}
757
758/*
759 * This holds our defaults.
760 */
761static struct init_tags {
762 struct tag_header hdr1;
763 struct tag_core core;
764 struct tag_header hdr2;
765 struct tag_mem32 mem;
766 struct tag_header hdr3;
767} init_tags __initdata = {
768 { tag_size(tag_core), ATAG_CORE },
769 { 1, PAGE_SIZE, 0xff },
770 { tag_size(tag_mem32), ATAG_MEM },
771 { MEM_SIZE, PHYS_OFFSET },
772 { 0, ATAG_NONE }
773};
774
775static void (*init_machine)(void) __initdata;
776
777static int __init customize_machine(void)
778{
779 /* customizes platform devices, or adds new ones */
780 if (init_machine)
781 init_machine();
782 return 0;
783}
784arch_initcall(customize_machine);
785
786void __init setup_arch(char **cmdline_p)
787{
788 struct tag *tags = (struct tag *)&init_tags;
789 struct machine_desc *mdesc;
790 char *from = default_command_line;
791
792 setup_processor();
793 mdesc = setup_machine(machine_arch_type);
794 machine_name = mdesc->name;
795
796 if (mdesc->soft_reboot)
797 reboot_setup("s");
798
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100799 if (__atags_pointer)
800 tags = phys_to_virt(__atags_pointer);
801 else if (mdesc->boot_params)
Russell Kingf9bd6ea2005-07-04 10:43:36 +0100802 tags = phys_to_virt(mdesc->boot_params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804 /*
805 * If we have the old style parameters, convert them to
806 * a tag list.
807 */
808 if (tags->hdr.tag != ATAG_CORE)
809 convert_to_tag_list(tags);
810 if (tags->hdr.tag != ATAG_CORE)
811 tags = (struct tag *)&init_tags;
812
813 if (mdesc->fixup)
814 mdesc->fixup(mdesc, tags, &from, &meminfo);
815
816 if (tags->hdr.tag == ATAG_CORE) {
817 if (meminfo.nr_banks != 0)
818 squash_mem_tags(tags);
819 parse_tags(tags);
820 }
821
822 init_mm.start_code = (unsigned long) &_text;
823 init_mm.end_code = (unsigned long) &_etext;
824 init_mm.end_data = (unsigned long) &_edata;
825 init_mm.brk = (unsigned long) &_end;
826
Alon Bar-Levcd818992007-02-12 00:54:06 -0800827 memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
828 boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 parse_cmdline(cmdline_p, from);
830 paging_init(&meminfo, mdesc);
831 request_standard_resources(&meminfo, mdesc);
832
Russell King7bbb7942006-02-16 11:08:09 +0000833#ifdef CONFIG_SMP
834 smp_init_cpus();
835#endif
836
Russell Kingccea7a12005-05-31 22:22:32 +0100837 cpu_init();
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 /*
840 * Set up various architecture-specific pointers
841 */
842 init_arch_irq = mdesc->init_irq;
843 system_timer = mdesc->timer;
844 init_machine = mdesc->init_machine;
845
846#ifdef CONFIG_VT
847#if defined(CONFIG_VGA_CONSOLE)
848 conswitchp = &vga_con;
849#elif defined(CONFIG_DUMMY_CONSOLE)
850 conswitchp = &dummy_con;
851#endif
852#endif
853}
854
855
856static int __init topology_init(void)
857{
858 int cpu;
859
Russell King66fb8bd2007-03-13 09:54:21 +0000860 for_each_possible_cpu(cpu) {
861 struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
862 cpuinfo->cpu.hotpluggable = 1;
863 register_cpu(&cpuinfo->cpu, cpu);
864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866 return 0;
867}
868
869subsys_initcall(topology_init);
870
871static const char *hwcap_str[] = {
872 "swp",
873 "half",
874 "thumb",
875 "26bit",
876 "fastmult",
877 "fpa",
878 "vfp",
879 "edsp",
880 "java",
Paul Gortmaker8f7f9432006-10-27 05:13:19 +0100881 "iwmmxt",
Lennert Buytenhek99e4a6d2006-12-18 00:59:10 +0100882 "crunch",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 NULL
884};
885
886static void
887c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
888{
889 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
890
891 seq_printf(m, "%s size\t\t: %d\n"
892 "%s assoc\t\t: %d\n"
893 "%s line length\t: %d\n"
894 "%s sets\t\t: %d\n",
895 type, mult << (8 + CACHE_SIZE(cache)),
896 type, (mult << CACHE_ASSOC(cache)) >> 1,
897 type, 8 << CACHE_LINE(cache),
898 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
899 CACHE_LINE(cache)));
900}
901
902static int c_show(struct seq_file *m, void *v)
903{
904 int i;
905
906 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
907 cpu_name, (int)processor_id & 15, elf_platform);
908
909#if defined(CONFIG_SMP)
910 for_each_online_cpu(i) {
Russell King15559722005-11-06 21:41:08 +0000911 /*
912 * glibc reads /proc/cpuinfo to determine the number of
913 * online processors, looking for lines beginning with
914 * "processor". Give glibc what it expects.
915 */
916 seq_printf(m, "processor\t: %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
918 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
919 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
920 }
921#else /* CONFIG_SMP */
922 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
923 loops_per_jiffy / (500000/HZ),
924 (loops_per_jiffy / (5000/HZ)) % 100);
925#endif
926
927 /* dump out the processor features */
928 seq_puts(m, "Features\t: ");
929
930 for (i = 0; hwcap_str[i]; i++)
931 if (elf_hwcap & (1 << i))
932 seq_printf(m, "%s ", hwcap_str[i]);
933
934 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
935 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
936
Catalin Marinas6b090a22006-01-12 16:28:16 +0000937 if ((processor_id & 0x0008f000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /* pre-ARM7 */
Greg Ungerer1d28bff2007-05-17 06:12:22 +0100939 seq_printf(m, "CPU part\t: %07x\n", processor_id >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 } else {
Catalin Marinas6b090a22006-01-12 16:28:16 +0000941 if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 /* ARM7 */
943 seq_printf(m, "CPU variant\t: 0x%02x\n",
944 (processor_id >> 16) & 127);
945 } else {
946 /* post-ARM7 */
947 seq_printf(m, "CPU variant\t: 0x%x\n",
948 (processor_id >> 20) & 15);
949 }
950 seq_printf(m, "CPU part\t: 0x%03x\n",
951 (processor_id >> 4) & 0xfff);
952 }
953 seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
954
955 {
956 unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
957 if (cache_info != processor_id) {
958 seq_printf(m, "Cache type\t: %s\n"
959 "Cache clean\t: %s\n"
960 "Cache lockdown\t: %s\n"
961 "Cache format\t: %s\n",
962 cache_types[CACHE_TYPE(cache_info)],
963 cache_clean[CACHE_TYPE(cache_info)],
964 cache_lockdown[CACHE_TYPE(cache_info)],
965 CACHE_S(cache_info) ? "Harvard" : "Unified");
966
967 if (CACHE_S(cache_info)) {
968 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
969 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
970 } else {
971 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
972 }
973 }
974 }
975
976 seq_puts(m, "\n");
977
978 seq_printf(m, "Hardware\t: %s\n", machine_name);
979 seq_printf(m, "Revision\t: %04x\n", system_rev);
980 seq_printf(m, "Serial\t\t: %08x%08x\n",
981 system_serial_high, system_serial_low);
982
983 return 0;
984}
985
986static void *c_start(struct seq_file *m, loff_t *pos)
987{
988 return *pos < 1 ? (void *)1 : NULL;
989}
990
991static void *c_next(struct seq_file *m, void *v, loff_t *pos)
992{
993 ++*pos;
994 return NULL;
995}
996
997static void c_stop(struct seq_file *m, void *v)
998{
999}
1000
1001struct seq_operations cpuinfo_op = {
1002 .start = c_start,
1003 .next = c_next,
1004 .stop = c_stop,
1005 .show = c_show
1006};