blob: ae3712d39ab71c624d12a8acdfd6088dc420d427 [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"
Richard Purdie4cd9d6f2008-01-02 00:56:46 +010041#include "atags.h"
Ben Dooks0fc1c832006-03-15 23:17:30 +000042
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#ifndef MEM_SIZE
44#define MEM_SIZE (16*1024*1024)
45#endif
46
47#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
48char fpe_type[8];
49
50static int __init fpe_setup(char *line)
51{
52 memcpy(fpe_type, line, 8);
53 return 1;
54}
55
56__setup("fpe=", fpe_setup);
57#endif
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059extern void paging_init(struct meminfo *, struct machine_desc *desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060extern void reboot_setup(char *str);
61extern int root_mountflags;
62extern void _stext, _text, _etext, __data_start, _edata, _end;
63
64unsigned int processor_id;
65unsigned int __machine_arch_type;
66EXPORT_SYMBOL(__machine_arch_type);
67
Bill Gatliff9d20fdd2007-05-31 22:02:22 +010068unsigned int __atags_pointer __initdata;
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070unsigned int system_rev;
71EXPORT_SYMBOL(system_rev);
72
73unsigned int system_serial_low;
74EXPORT_SYMBOL(system_serial_low);
75
76unsigned int system_serial_high;
77EXPORT_SYMBOL(system_serial_high);
78
79unsigned int elf_hwcap;
80EXPORT_SYMBOL(elf_hwcap);
81
82
83#ifdef MULTI_CPU
84struct processor processor;
85#endif
86#ifdef MULTI_TLB
87struct cpu_tlb_fns cpu_tlb;
88#endif
89#ifdef MULTI_USER
90struct cpu_user_fns cpu_user;
91#endif
92#ifdef MULTI_CACHE
93struct cpu_cache_fns cpu_cache;
94#endif
Catalin Marinas953233d2007-02-05 14:48:08 +010095#ifdef CONFIG_OUTER_CACHE
96struct outer_cache_fns outer_cache;
97#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Russell Kingccea7a12005-05-31 22:22:32 +010099struct stack {
100 u32 irq[3];
101 u32 abt[3];
102 u32 und[3];
103} ____cacheline_aligned;
104
105static struct stack stacks[NR_CPUS];
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107char elf_platform[ELF_PLATFORM_SIZE];
108EXPORT_SYMBOL(elf_platform);
109
110unsigned long phys_initrd_start __initdata = 0;
111unsigned long phys_initrd_size __initdata = 0;
112
113static struct meminfo meminfo __initdata = { 0, };
114static const char *cpu_name;
115static const char *machine_name;
Alon Bar-Levcd818992007-02-12 00:54:06 -0800116static char __initdata command_line[COMMAND_LINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
119static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
120#define ENDIANNESS ((char)endian_test.l)
121
122DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
123
124/*
125 * Standard memory resources
126 */
127static struct resource mem_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700128 {
129 .name = "Video RAM",
130 .start = 0,
131 .end = 0,
132 .flags = IORESOURCE_MEM
133 },
134 {
135 .name = "Kernel text",
136 .start = 0,
137 .end = 0,
138 .flags = IORESOURCE_MEM
139 },
140 {
141 .name = "Kernel data",
142 .start = 0,
143 .end = 0,
144 .flags = IORESOURCE_MEM
145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146};
147
148#define video_ram mem_res[0]
149#define kernel_code mem_res[1]
150#define kernel_data mem_res[2]
151
152static struct resource io_res[] = {
Greg Kroah-Hartman740e5182006-06-12 14:47:06 -0700153 {
154 .name = "reserved",
155 .start = 0x3bc,
156 .end = 0x3be,
157 .flags = IORESOURCE_IO | IORESOURCE_BUSY
158 },
159 {
160 .name = "reserved",
161 .start = 0x378,
162 .end = 0x37f,
163 .flags = IORESOURCE_IO | IORESOURCE_BUSY
164 },
165 {
166 .name = "reserved",
167 .start = 0x278,
168 .end = 0x27f,
169 .flags = IORESOURCE_IO | IORESOURCE_BUSY
170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171};
172
173#define lp0 io_res[0]
174#define lp1 io_res[1]
175#define lp2 io_res[2]
176
177static const char *cache_types[16] = {
178 "write-through",
179 "write-back",
180 "write-back",
181 "undefined 3",
182 "undefined 4",
183 "undefined 5",
184 "write-back",
185 "write-back",
186 "undefined 8",
187 "undefined 9",
188 "undefined 10",
189 "undefined 11",
190 "undefined 12",
191 "undefined 13",
192 "write-back",
193 "undefined 15",
194};
195
196static const char *cache_clean[16] = {
197 "not required",
198 "read-block",
199 "cp15 c7 ops",
200 "undefined 3",
201 "undefined 4",
202 "undefined 5",
203 "cp15 c7 ops",
204 "cp15 c7 ops",
205 "undefined 8",
206 "undefined 9",
207 "undefined 10",
208 "undefined 11",
209 "undefined 12",
210 "undefined 13",
211 "cp15 c7 ops",
212 "undefined 15",
213};
214
215static const char *cache_lockdown[16] = {
216 "not supported",
217 "not supported",
218 "not supported",
219 "undefined 3",
220 "undefined 4",
221 "undefined 5",
222 "format A",
223 "format B",
224 "undefined 8",
225 "undefined 9",
226 "undefined 10",
227 "undefined 11",
228 "undefined 12",
229 "undefined 13",
230 "format C",
231 "undefined 15",
232};
233
234static const char *proc_arch[] = {
235 "undefined/unknown",
236 "3",
237 "4",
238 "4T",
239 "5",
240 "5T",
241 "5TE",
242 "5TEJ",
243 "6TEJ",
Catalin Marinas6b090a22006-01-12 16:28:16 +0000244 "7",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 "?(11)",
246 "?(12)",
247 "?(13)",
248 "?(14)",
249 "?(15)",
250 "?(16)",
251 "?(17)",
252};
253
254#define CACHE_TYPE(x) (((x) >> 25) & 15)
255#define CACHE_S(x) ((x) & (1 << 24))
256#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */
257#define CACHE_ISIZE(x) ((x) & 4095)
258
259#define CACHE_SIZE(y) (((y) >> 6) & 7)
260#define CACHE_ASSOC(y) (((y) >> 3) & 7)
261#define CACHE_M(y) ((y) & (1 << 2))
262#define CACHE_LINE(y) ((y) & 3)
263
264static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
265{
266 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
267
268 printk("CPU%u: %s: %d bytes, associativity %d, %d byte lines, %d sets\n",
269 cpu, prefix,
270 mult << (8 + CACHE_SIZE(cache)),
271 (mult << CACHE_ASSOC(cache)) >> 1,
272 8 << CACHE_LINE(cache),
273 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
274 CACHE_LINE(cache)));
275}
276
277static void __init dump_cpu_info(int cpu)
278{
279 unsigned int info = read_cpuid(CPUID_CACHETYPE);
280
281 if (info != processor_id) {
282 printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
283 cache_types[CACHE_TYPE(info)]);
284 if (CACHE_S(info)) {
285 dump_cache("I cache", cpu, CACHE_ISIZE(info));
286 dump_cache("D cache", cpu, CACHE_DSIZE(info));
287 } else {
288 dump_cache("cache", cpu, CACHE_ISIZE(info));
289 }
290 }
Lennert Buytenhek23759dc2006-04-02 00:07:39 +0100291
292 if (arch_is_coherent())
293 printk("Cache coherency enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
296int cpu_architecture(void)
297{
298 int cpu_arch;
299
Catalin Marinas6b090a22006-01-12 16:28:16 +0000300 if ((processor_id & 0x0008f000) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 cpu_arch = CPU_ARCH_UNKNOWN;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000302 } else if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
Catalin Marinas6b090a22006-01-12 16:28:16 +0000304 } else if ((processor_id & 0x00080000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 cpu_arch = (processor_id >> 16) & 7;
306 if (cpu_arch)
307 cpu_arch += CPU_ARCH_ARMv3;
Catalin Marinas180005c2007-09-25 16:49:45 +0100308 } else if ((processor_id & 0x000f0000) == 0x000f0000) {
309 unsigned int mmfr0;
310
311 /* Revised CPUID format. Read the Memory Model Feature
312 * Register 0 and check for VMSAv7 or PMSAv7 */
313 asm("mrc p15, 0, %0, c0, c1, 4"
314 : "=r" (mmfr0));
315 if ((mmfr0 & 0x0000000f) == 0x00000003 ||
316 (mmfr0 & 0x000000f0) == 0x00000030)
317 cpu_arch = CPU_ARCH_ARMv7;
318 else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
319 (mmfr0 & 0x000000f0) == 0x00000020)
320 cpu_arch = CPU_ARCH_ARMv6;
321 else
322 cpu_arch = CPU_ARCH_UNKNOWN;
323 } else
324 cpu_arch = CPU_ARCH_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 return cpu_arch;
327}
328
329/*
330 * These functions re-use the assembly code in head.S, which
331 * already provide the required functionality.
332 */
Russell King0f44ba12006-02-24 21:04:56 +0000333extern struct proc_info_list *lookup_processor_type(unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334extern struct machine_desc *lookup_machine_type(unsigned int);
335
336static void __init setup_processor(void)
337{
338 struct proc_info_list *list;
339
340 /*
341 * locate processor in the list of supported processor
342 * types. The linker builds this table for us from the
343 * entries in arch/arm/mm/proc-*.S
344 */
Russell King0f44ba12006-02-24 21:04:56 +0000345 list = lookup_processor_type(processor_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 if (!list) {
347 printk("CPU configuration botched (ID %08x), unable "
348 "to continue.\n", processor_id);
349 while (1);
350 }
351
352 cpu_name = list->cpu_name;
353
354#ifdef MULTI_CPU
355 processor = *list->proc;
356#endif
357#ifdef MULTI_TLB
358 cpu_tlb = *list->tlb;
359#endif
360#ifdef MULTI_USER
361 cpu_user = *list->user;
362#endif
363#ifdef MULTI_CACHE
364 cpu_cache = *list->cache;
365#endif
366
Russell King4e190252006-07-03 13:29:38 +0100367 printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 cpu_name, processor_id, (int)processor_id & 15,
Russell King264edb32006-06-29 15:03:09 +0100369 proc_arch[cpu_architecture()], cr_alignment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Serge E. Hallyn96b644b2006-10-02 02:18:13 -0700371 sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
373 elf_hwcap = list->elf_hwcap;
Catalin Marinasadeff422006-04-10 21:32:35 +0100374#ifndef CONFIG_ARM_THUMB
375 elf_hwcap &= ~HWCAP_THUMB;
376#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 cpu_proc_init();
379}
380
Russell Kingccea7a12005-05-31 22:22:32 +0100381/*
382 * cpu_init - initialise one CPU.
383 *
384 * cpu_init dumps the cache information, initialises SMP specific
385 * information, and sets up the per-CPU stacks.
386 */
Russell King36c5ed22005-06-19 18:39:33 +0100387void cpu_init(void)
Russell Kingccea7a12005-05-31 22:22:32 +0100388{
389 unsigned int cpu = smp_processor_id();
390 struct stack *stk = &stacks[cpu];
391
392 if (cpu >= NR_CPUS) {
393 printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
394 BUG();
395 }
396
Russell King32f8b972005-11-06 19:49:21 +0000397 if (system_state == SYSTEM_BOOTING)
398 dump_cpu_info(cpu);
Russell Kingccea7a12005-05-31 22:22:32 +0100399
400 /*
401 * setup stacks for re-entrant exception handlers
402 */
403 __asm__ (
404 "msr cpsr_c, %1\n\t"
405 "add sp, %0, %2\n\t"
406 "msr cpsr_c, %3\n\t"
407 "add sp, %0, %4\n\t"
408 "msr cpsr_c, %5\n\t"
409 "add sp, %0, %6\n\t"
410 "msr cpsr_c, %7"
411 :
412 : "r" (stk),
413 "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
414 "I" (offsetof(struct stack, irq[0])),
415 "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
416 "I" (offsetof(struct stack, abt[0])),
417 "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
418 "I" (offsetof(struct stack, und[0])),
Catalin Marinasaaaa3f92005-06-29 15:34:39 +0100419 "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
420 : "r14");
Russell Kingccea7a12005-05-31 22:22:32 +0100421}
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423static struct machine_desc * __init setup_machine(unsigned int nr)
424{
425 struct machine_desc *list;
426
427 /*
428 * locate machine in the list of supported machines.
429 */
430 list = lookup_machine_type(nr);
431 if (!list) {
432 printk("Machine configuration botched (nr %d), unable "
433 "to continue.\n", nr);
434 while (1);
435 }
436
437 printk("Machine: %s\n", list->name);
438
439 return list;
440}
441
442static void __init early_initrd(char **p)
443{
444 unsigned long start, size;
445
446 start = memparse(*p, p);
447 if (**p == ',') {
448 size = memparse((*p) + 1, p);
449
450 phys_initrd_start = start;
451 phys_initrd_size = size;
452 }
453}
454__early_param("initrd=", early_initrd);
455
Andrew Morton1c97b732006-04-20 21:41:18 +0100456static void __init arm_add_memory(unsigned long start, unsigned long size)
Russell King3a669412005-06-22 21:43:10 +0100457{
Russell King05f96ef2006-11-30 20:44:49 +0000458 struct membank *bank;
459
Russell King3a669412005-06-22 21:43:10 +0100460 /*
461 * Ensure that start/size are aligned to a page boundary.
462 * Size is appropriately rounded down, start is rounded up.
463 */
464 size -= start & ~PAGE_MASK;
465
Russell King05f96ef2006-11-30 20:44:49 +0000466 bank = &meminfo.bank[meminfo.nr_banks++];
467
468 bank->start = PAGE_ALIGN(start);
469 bank->size = size & PAGE_MASK;
470 bank->node = PHYS_TO_NID(start);
Russell King3a669412005-06-22 21:43:10 +0100471}
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/*
474 * Pick out the memory size. We look for mem=size@start,
475 * where start and size are "size[KkMm]"
476 */
477static void __init early_mem(char **p)
478{
479 static int usermem __initdata = 0;
480 unsigned long size, start;
481
482 /*
483 * If the user specifies memory size, we
484 * blow away any automatically generated
485 * size.
486 */
487 if (usermem == 0) {
488 usermem = 1;
489 meminfo.nr_banks = 0;
490 }
491
492 start = PHYS_OFFSET;
493 size = memparse(*p, p);
494 if (**p == '@')
495 start = memparse(*p + 1, p);
496
Andrew Morton1c97b732006-04-20 21:41:18 +0100497 arm_add_memory(start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499__early_param("mem=", early_mem);
500
501/*
502 * Initial parsing of the command line.
503 */
504static void __init parse_cmdline(char **cmdline_p, char *from)
505{
506 char c = ' ', *to = command_line;
507 int len = 0;
508
509 for (;;) {
510 if (c == ' ') {
511 extern struct early_params __early_begin, __early_end;
512 struct early_params *p;
513
514 for (p = &__early_begin; p < &__early_end; p++) {
515 int len = strlen(p->arg);
516
517 if (memcmp(from, p->arg, len) == 0) {
518 if (to != command_line)
519 to -= 1;
520 from += len;
521 p->fn(&from);
522
523 while (*from != ' ' && *from != '\0')
524 from++;
525 break;
526 }
527 }
528 }
529 c = *from++;
530 if (!c)
531 break;
532 if (COMMAND_LINE_SIZE <= ++len)
533 break;
534 *to++ = c;
535 }
536 *to = '\0';
537 *cmdline_p = command_line;
538}
539
540static void __init
541setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
542{
543#ifdef CONFIG_BLK_DEV_RAM
544 extern int rd_size, rd_image_start, rd_prompt, rd_doload;
545
546 rd_image_start = image_start;
547 rd_prompt = prompt;
548 rd_doload = doload;
549
550 if (rd_sz)
551 rd_size = rd_sz;
552#endif
553}
554
555static void __init
556request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
557{
558 struct resource *res;
559 int i;
560
561 kernel_code.start = virt_to_phys(&_text);
562 kernel_code.end = virt_to_phys(&_etext - 1);
563 kernel_data.start = virt_to_phys(&__data_start);
564 kernel_data.end = virt_to_phys(&_end - 1);
565
566 for (i = 0; i < mi->nr_banks; i++) {
567 unsigned long virt_start, virt_end;
568
569 if (mi->bank[i].size == 0)
570 continue;
571
572 virt_start = __phys_to_virt(mi->bank[i].start);
573 virt_end = virt_start + mi->bank[i].size - 1;
574
575 res = alloc_bootmem_low(sizeof(*res));
576 res->name = "System RAM";
577 res->start = __virt_to_phys(virt_start);
578 res->end = __virt_to_phys(virt_end);
579 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
580
581 request_resource(&iomem_resource, res);
582
583 if (kernel_code.start >= res->start &&
584 kernel_code.end <= res->end)
585 request_resource(res, &kernel_code);
586 if (kernel_data.start >= res->start &&
587 kernel_data.end <= res->end)
588 request_resource(res, &kernel_data);
589 }
590
591 if (mdesc->video_start) {
592 video_ram.start = mdesc->video_start;
593 video_ram.end = mdesc->video_end;
594 request_resource(&iomem_resource, &video_ram);
595 }
596
597 /*
598 * Some machines don't have the possibility of ever
599 * possessing lp0, lp1 or lp2
600 */
601 if (mdesc->reserve_lp0)
602 request_resource(&ioport_resource, &lp0);
603 if (mdesc->reserve_lp1)
604 request_resource(&ioport_resource, &lp1);
605 if (mdesc->reserve_lp2)
606 request_resource(&ioport_resource, &lp2);
607}
608
609/*
610 * Tag parsing.
611 *
612 * This is the new way of passing data to the kernel at boot time. Rather
613 * than passing a fixed inflexible structure to the kernel, we pass a list
614 * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
615 * tag for the list to be recognised (to distinguish the tagged list from
616 * a param_struct). The list is terminated with a zero-length tag (this tag
617 * is not parsed in any way).
618 */
619static int __init parse_tag_core(const struct tag *tag)
620{
621 if (tag->hdr.size > 2) {
622 if ((tag->u.core.flags & 1) == 0)
623 root_mountflags &= ~MS_RDONLY;
624 ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
625 }
626 return 0;
627}
628
629__tagtable(ATAG_CORE, parse_tag_core);
630
631static int __init parse_tag_mem32(const struct tag *tag)
632{
633 if (meminfo.nr_banks >= NR_BANKS) {
634 printk(KERN_WARNING
635 "Ignoring memory bank 0x%08x size %dKB\n",
636 tag->u.mem.start, tag->u.mem.size / 1024);
637 return -EINVAL;
638 }
Andrew Morton1c97b732006-04-20 21:41:18 +0100639 arm_add_memory(tag->u.mem.start, tag->u.mem.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return 0;
641}
642
643__tagtable(ATAG_MEM, parse_tag_mem32);
644
645#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
646struct screen_info screen_info = {
647 .orig_video_lines = 30,
648 .orig_video_cols = 80,
649 .orig_video_mode = 0,
650 .orig_video_ega_bx = 0,
651 .orig_video_isVGA = 1,
652 .orig_video_points = 8
653};
654
655static int __init parse_tag_videotext(const struct tag *tag)
656{
657 screen_info.orig_x = tag->u.videotext.x;
658 screen_info.orig_y = tag->u.videotext.y;
659 screen_info.orig_video_page = tag->u.videotext.video_page;
660 screen_info.orig_video_mode = tag->u.videotext.video_mode;
661 screen_info.orig_video_cols = tag->u.videotext.video_cols;
662 screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
663 screen_info.orig_video_lines = tag->u.videotext.video_lines;
664 screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
665 screen_info.orig_video_points = tag->u.videotext.video_points;
666 return 0;
667}
668
669__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
670#endif
671
672static int __init parse_tag_ramdisk(const struct tag *tag)
673{
674 setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
675 (tag->u.ramdisk.flags & 2) == 0,
676 tag->u.ramdisk.start, tag->u.ramdisk.size);
677 return 0;
678}
679
680__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
681
682static int __init parse_tag_initrd(const struct tag *tag)
683{
684 printk(KERN_WARNING "ATAG_INITRD is deprecated; "
685 "please update your bootloader.\n");
686 phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
687 phys_initrd_size = tag->u.initrd.size;
688 return 0;
689}
690
691__tagtable(ATAG_INITRD, parse_tag_initrd);
692
693static int __init parse_tag_initrd2(const struct tag *tag)
694{
695 phys_initrd_start = tag->u.initrd.start;
696 phys_initrd_size = tag->u.initrd.size;
697 return 0;
698}
699
700__tagtable(ATAG_INITRD2, parse_tag_initrd2);
701
702static int __init parse_tag_serialnr(const struct tag *tag)
703{
704 system_serial_low = tag->u.serialnr.low;
705 system_serial_high = tag->u.serialnr.high;
706 return 0;
707}
708
709__tagtable(ATAG_SERIAL, parse_tag_serialnr);
710
711static int __init parse_tag_revision(const struct tag *tag)
712{
713 system_rev = tag->u.revision.rev;
714 return 0;
715}
716
717__tagtable(ATAG_REVISION, parse_tag_revision);
718
719static int __init parse_tag_cmdline(const struct tag *tag)
720{
721 strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
722 return 0;
723}
724
725__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
726
727/*
728 * Scan the tag table for this tag, and call its parse function.
729 * The tag table is built by the linker from all the __tagtable
730 * declarations.
731 */
732static int __init parse_tag(const struct tag *tag)
733{
734 extern struct tagtable __tagtable_begin, __tagtable_end;
735 struct tagtable *t;
736
737 for (t = &__tagtable_begin; t < &__tagtable_end; t++)
738 if (tag->hdr.tag == t->tag) {
739 t->parse(tag);
740 break;
741 }
742
743 return t < &__tagtable_end;
744}
745
746/*
747 * Parse all tags in the list, checking both the global and architecture
748 * specific tag tables.
749 */
750static void __init parse_tags(const struct tag *t)
751{
752 for (; t->hdr.size; t = tag_next(t))
753 if (!parse_tag(t))
754 printk(KERN_WARNING
755 "Ignoring unrecognised tag 0x%08x\n",
756 t->hdr.tag);
757}
758
759/*
760 * This holds our defaults.
761 */
762static struct init_tags {
763 struct tag_header hdr1;
764 struct tag_core core;
765 struct tag_header hdr2;
766 struct tag_mem32 mem;
767 struct tag_header hdr3;
768} init_tags __initdata = {
769 { tag_size(tag_core), ATAG_CORE },
770 { 1, PAGE_SIZE, 0xff },
771 { tag_size(tag_mem32), ATAG_MEM },
772 { MEM_SIZE, PHYS_OFFSET },
773 { 0, ATAG_NONE }
774};
775
776static void (*init_machine)(void) __initdata;
777
778static int __init customize_machine(void)
779{
780 /* customizes platform devices, or adds new ones */
781 if (init_machine)
782 init_machine();
783 return 0;
784}
785arch_initcall(customize_machine);
786
787void __init setup_arch(char **cmdline_p)
788{
789 struct tag *tags = (struct tag *)&init_tags;
790 struct machine_desc *mdesc;
791 char *from = default_command_line;
792
793 setup_processor();
794 mdesc = setup_machine(machine_arch_type);
795 machine_name = mdesc->name;
796
797 if (mdesc->soft_reboot)
798 reboot_setup("s");
799
Bill Gatliff9d20fdd2007-05-31 22:02:22 +0100800 if (__atags_pointer)
801 tags = phys_to_virt(__atags_pointer);
802 else if (mdesc->boot_params)
Russell Kingf9bd6ea2005-07-04 10:43:36 +0100803 tags = phys_to_virt(mdesc->boot_params);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 /*
806 * If we have the old style parameters, convert them to
807 * a tag list.
808 */
809 if (tags->hdr.tag != ATAG_CORE)
810 convert_to_tag_list(tags);
811 if (tags->hdr.tag != ATAG_CORE)
812 tags = (struct tag *)&init_tags;
813
814 if (mdesc->fixup)
815 mdesc->fixup(mdesc, tags, &from, &meminfo);
816
817 if (tags->hdr.tag == ATAG_CORE) {
818 if (meminfo.nr_banks != 0)
819 squash_mem_tags(tags);
Richard Purdie4cd9d6f2008-01-02 00:56:46 +0100820 save_atags(tags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 parse_tags(tags);
822 }
823
824 init_mm.start_code = (unsigned long) &_text;
825 init_mm.end_code = (unsigned long) &_etext;
826 init_mm.end_data = (unsigned long) &_edata;
827 init_mm.brk = (unsigned long) &_end;
828
Alon Bar-Levcd818992007-02-12 00:54:06 -0800829 memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
830 boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 parse_cmdline(cmdline_p, from);
832 paging_init(&meminfo, mdesc);
833 request_standard_resources(&meminfo, mdesc);
834
Russell King7bbb7942006-02-16 11:08:09 +0000835#ifdef CONFIG_SMP
836 smp_init_cpus();
837#endif
838
Russell Kingccea7a12005-05-31 22:22:32 +0100839 cpu_init();
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 /*
842 * Set up various architecture-specific pointers
843 */
844 init_arch_irq = mdesc->init_irq;
845 system_timer = mdesc->timer;
846 init_machine = mdesc->init_machine;
847
848#ifdef CONFIG_VT
849#if defined(CONFIG_VGA_CONSOLE)
850 conswitchp = &vga_con;
851#elif defined(CONFIG_DUMMY_CONSOLE)
852 conswitchp = &dummy_con;
853#endif
854#endif
855}
856
857
858static int __init topology_init(void)
859{
860 int cpu;
861
Russell King66fb8bd2007-03-13 09:54:21 +0000862 for_each_possible_cpu(cpu) {
863 struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
864 cpuinfo->cpu.hotpluggable = 1;
865 register_cpu(&cpuinfo->cpu, cpu);
866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 return 0;
869}
870
871subsys_initcall(topology_init);
872
873static const char *hwcap_str[] = {
874 "swp",
875 "half",
876 "thumb",
877 "26bit",
878 "fastmult",
879 "fpa",
880 "vfp",
881 "edsp",
882 "java",
Paul Gortmaker8f7f9432006-10-27 05:13:19 +0100883 "iwmmxt",
Lennert Buytenhek99e4a6d2006-12-18 00:59:10 +0100884 "crunch",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 NULL
886};
887
888static void
889c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
890{
891 unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
892
893 seq_printf(m, "%s size\t\t: %d\n"
894 "%s assoc\t\t: %d\n"
895 "%s line length\t: %d\n"
896 "%s sets\t\t: %d\n",
897 type, mult << (8 + CACHE_SIZE(cache)),
898 type, (mult << CACHE_ASSOC(cache)) >> 1,
899 type, 8 << CACHE_LINE(cache),
900 type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
901 CACHE_LINE(cache)));
902}
903
904static int c_show(struct seq_file *m, void *v)
905{
906 int i;
907
908 seq_printf(m, "Processor\t: %s rev %d (%s)\n",
909 cpu_name, (int)processor_id & 15, elf_platform);
910
911#if defined(CONFIG_SMP)
912 for_each_online_cpu(i) {
Russell King15559722005-11-06 21:41:08 +0000913 /*
914 * glibc reads /proc/cpuinfo to determine the number of
915 * online processors, looking for lines beginning with
916 * "processor". Give glibc what it expects.
917 */
918 seq_printf(m, "processor\t: %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
920 per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
921 (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
922 }
923#else /* CONFIG_SMP */
924 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
925 loops_per_jiffy / (500000/HZ),
926 (loops_per_jiffy / (5000/HZ)) % 100);
927#endif
928
929 /* dump out the processor features */
930 seq_puts(m, "Features\t: ");
931
932 for (i = 0; hwcap_str[i]; i++)
933 if (elf_hwcap & (1 << i))
934 seq_printf(m, "%s ", hwcap_str[i]);
935
936 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24);
937 seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
938
Catalin Marinas6b090a22006-01-12 16:28:16 +0000939 if ((processor_id & 0x0008f000) == 0x00000000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* pre-ARM7 */
Greg Ungerer1d28bff2007-05-17 06:12:22 +0100941 seq_printf(m, "CPU part\t: %07x\n", processor_id >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 } else {
Catalin Marinas6b090a22006-01-12 16:28:16 +0000943 if ((processor_id & 0x0008f000) == 0x00007000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 /* ARM7 */
945 seq_printf(m, "CPU variant\t: 0x%02x\n",
946 (processor_id >> 16) & 127);
947 } else {
948 /* post-ARM7 */
949 seq_printf(m, "CPU variant\t: 0x%x\n",
950 (processor_id >> 20) & 15);
951 }
952 seq_printf(m, "CPU part\t: 0x%03x\n",
953 (processor_id >> 4) & 0xfff);
954 }
955 seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
956
957 {
958 unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
959 if (cache_info != processor_id) {
960 seq_printf(m, "Cache type\t: %s\n"
961 "Cache clean\t: %s\n"
962 "Cache lockdown\t: %s\n"
963 "Cache format\t: %s\n",
964 cache_types[CACHE_TYPE(cache_info)],
965 cache_clean[CACHE_TYPE(cache_info)],
966 cache_lockdown[CACHE_TYPE(cache_info)],
967 CACHE_S(cache_info) ? "Harvard" : "Unified");
968
969 if (CACHE_S(cache_info)) {
970 c_show_cache(m, "I", CACHE_ISIZE(cache_info));
971 c_show_cache(m, "D", CACHE_DSIZE(cache_info));
972 } else {
973 c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
974 }
975 }
976 }
977
978 seq_puts(m, "\n");
979
980 seq_printf(m, "Hardware\t: %s\n", machine_name);
981 seq_printf(m, "Revision\t: %04x\n", system_rev);
982 seq_printf(m, "Serial\t\t: %08x%08x\n",
983 system_serial_high, system_serial_low);
984
985 return 0;
986}
987
988static void *c_start(struct seq_file *m, loff_t *pos)
989{
990 return *pos < 1 ? (void *)1 : NULL;
991}
992
993static void *c_next(struct seq_file *m, void *v, loff_t *pos)
994{
995 ++*pos;
996 return NULL;
997}
998
999static void c_stop(struct seq_file *m, void *v)
1000{
1001}
1002
1003struct seq_operations cpuinfo_op = {
1004 .start = c_start,
1005 .next = c_next,
1006 .stop = c_stop,
1007 .show = c_show
1008};