xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 354e6f72)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/arm/kernel/setup.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1995-2001 Russell King
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
71da177e4SLinus Torvalds  * it under the terms of the GNU General Public License version 2 as
81da177e4SLinus Torvalds  * published by the Free Software Foundation.
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds #include <linux/module.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/stddef.h>
131da177e4SLinus Torvalds #include <linux/ioport.h>
141da177e4SLinus Torvalds #include <linux/delay.h>
151da177e4SLinus Torvalds #include <linux/utsname.h>
161da177e4SLinus Torvalds #include <linux/initrd.h>
171da177e4SLinus Torvalds #include <linux/console.h>
181da177e4SLinus Torvalds #include <linux/bootmem.h>
191da177e4SLinus Torvalds #include <linux/seq_file.h>
20894673eeSJon Smirl #include <linux/screen_info.h>
211da177e4SLinus Torvalds #include <linux/init.h>
221da177e4SLinus Torvalds #include <linux/root_dev.h>
231da177e4SLinus Torvalds #include <linux/cpu.h>
241da177e4SLinus Torvalds #include <linux/interrupt.h>
257bbb7940SRussell King #include <linux/smp.h>
264e950f6fSAlexey Dobriyan #include <linux/fs.h>
27e119bfffSRussell King #include <linux/proc_fs.h>
281da177e4SLinus Torvalds 
29b86040a5SCatalin Marinas #include <asm/unified.h>
301da177e4SLinus Torvalds #include <asm/cpu.h>
310ba8b9b2SRussell King #include <asm/cputype.h>
321da177e4SLinus Torvalds #include <asm/elf.h>
331da177e4SLinus Torvalds #include <asm/procinfo.h>
3437efe642SRussell King #include <asm/sections.h>
351da177e4SLinus Torvalds #include <asm/setup.h>
361da177e4SLinus Torvalds #include <asm/mach-types.h>
371da177e4SLinus Torvalds #include <asm/cacheflush.h>
3846097c7dSRussell King #include <asm/cachetype.h>
391da177e4SLinus Torvalds #include <asm/tlbflush.h>
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #include <asm/mach/arch.h>
421da177e4SLinus Torvalds #include <asm/mach/irq.h>
431da177e4SLinus Torvalds #include <asm/mach/time.h>
445cbad0ebSJason Wessel #include <asm/traps.h>
45bff595c1SCatalin Marinas #include <asm/unwind.h>
461da177e4SLinus Torvalds 
470fc1c832SBen Dooks #include "compat.h"
484cd9d6f7SRichard Purdie #include "atags.h"
49bc581770SLinus Walleij #include "tcm.h"
500fc1c832SBen Dooks 
511da177e4SLinus Torvalds #ifndef MEM_SIZE
521da177e4SLinus Torvalds #define MEM_SIZE	(16*1024*1024)
531da177e4SLinus Torvalds #endif
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
561da177e4SLinus Torvalds char fpe_type[8];
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds static int __init fpe_setup(char *line)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
611da177e4SLinus Torvalds 	return 1;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
651da177e4SLinus Torvalds #endif
661da177e4SLinus Torvalds 
674b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
681da177e4SLinus Torvalds extern void reboot_setup(char *str);
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds unsigned int processor_id;
71c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
721da177e4SLinus Torvalds unsigned int __machine_arch_type;
731da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
74c0e95878SRussell King unsigned int cacheid;
75c0e95878SRussell King EXPORT_SYMBOL(cacheid);
761da177e4SLinus Torvalds 
779d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
789d20fdd5SBill Gatliff 
791da177e4SLinus Torvalds unsigned int system_rev;
801da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds unsigned int system_serial_low;
831da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds unsigned int system_serial_high;
861da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds unsigned int elf_hwcap;
891da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds #ifdef MULTI_CPU
931da177e4SLinus Torvalds struct processor processor;
941da177e4SLinus Torvalds #endif
951da177e4SLinus Torvalds #ifdef MULTI_TLB
961da177e4SLinus Torvalds struct cpu_tlb_fns cpu_tlb;
971da177e4SLinus Torvalds #endif
981da177e4SLinus Torvalds #ifdef MULTI_USER
991da177e4SLinus Torvalds struct cpu_user_fns cpu_user;
1001da177e4SLinus Torvalds #endif
1011da177e4SLinus Torvalds #ifdef MULTI_CACHE
1021da177e4SLinus Torvalds struct cpu_cache_fns cpu_cache;
1031da177e4SLinus Torvalds #endif
104953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
105953233dcSCatalin Marinas struct outer_cache_fns outer_cache;
1066c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
107953233dcSCatalin Marinas #endif
1081da177e4SLinus Torvalds 
109ccea7a19SRussell King struct stack {
110ccea7a19SRussell King 	u32 irq[3];
111ccea7a19SRussell King 	u32 abt[3];
112ccea7a19SRussell King 	u32 und[3];
113ccea7a19SRussell King } ____cacheline_aligned;
114ccea7a19SRussell King 
115ccea7a19SRussell King static struct stack stacks[NR_CPUS];
116ccea7a19SRussell King 
1171da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1181da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds static const char *cpu_name;
1211da177e4SLinus Torvalds static const char *machine_name;
12248ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
1251da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1261da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds /*
1311da177e4SLinus Torvalds  * Standard memory resources
1321da177e4SLinus Torvalds  */
1331da177e4SLinus Torvalds static struct resource mem_res[] = {
134740e518eSGreg Kroah-Hartman 	{
135740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
136740e518eSGreg Kroah-Hartman 		.start = 0,
137740e518eSGreg Kroah-Hartman 		.end = 0,
138740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
139740e518eSGreg Kroah-Hartman 	},
140740e518eSGreg Kroah-Hartman 	{
141740e518eSGreg Kroah-Hartman 		.name = "Kernel text",
142740e518eSGreg Kroah-Hartman 		.start = 0,
143740e518eSGreg Kroah-Hartman 		.end = 0,
144740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
145740e518eSGreg Kroah-Hartman 	},
146740e518eSGreg Kroah-Hartman 	{
147740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
148740e518eSGreg Kroah-Hartman 		.start = 0,
149740e518eSGreg Kroah-Hartman 		.end = 0,
150740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
151740e518eSGreg Kroah-Hartman 	}
1521da177e4SLinus Torvalds };
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds #define video_ram   mem_res[0]
1551da177e4SLinus Torvalds #define kernel_code mem_res[1]
1561da177e4SLinus Torvalds #define kernel_data mem_res[2]
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds static struct resource io_res[] = {
159740e518eSGreg Kroah-Hartman 	{
160740e518eSGreg Kroah-Hartman 		.name = "reserved",
161740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
162740e518eSGreg Kroah-Hartman 		.end = 0x3be,
163740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
164740e518eSGreg Kroah-Hartman 	},
165740e518eSGreg Kroah-Hartman 	{
166740e518eSGreg Kroah-Hartman 		.name = "reserved",
167740e518eSGreg Kroah-Hartman 		.start = 0x378,
168740e518eSGreg Kroah-Hartman 		.end = 0x37f,
169740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
170740e518eSGreg Kroah-Hartman 	},
171740e518eSGreg Kroah-Hartman 	{
172740e518eSGreg Kroah-Hartman 		.name = "reserved",
173740e518eSGreg Kroah-Hartman 		.start = 0x278,
174740e518eSGreg Kroah-Hartman 		.end = 0x27f,
175740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
176740e518eSGreg Kroah-Hartman 	}
1771da177e4SLinus Torvalds };
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds #define lp0 io_res[0]
1801da177e4SLinus Torvalds #define lp1 io_res[1]
1811da177e4SLinus Torvalds #define lp2 io_res[2]
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds static const char *proc_arch[] = {
1841da177e4SLinus Torvalds 	"undefined/unknown",
1851da177e4SLinus Torvalds 	"3",
1861da177e4SLinus Torvalds 	"4",
1871da177e4SLinus Torvalds 	"4T",
1881da177e4SLinus Torvalds 	"5",
1891da177e4SLinus Torvalds 	"5T",
1901da177e4SLinus Torvalds 	"5TE",
1911da177e4SLinus Torvalds 	"5TEJ",
1921da177e4SLinus Torvalds 	"6TEJ",
1936b090a25SCatalin Marinas 	"7",
1941da177e4SLinus Torvalds 	"?(11)",
1951da177e4SLinus Torvalds 	"?(12)",
1961da177e4SLinus Torvalds 	"?(13)",
1971da177e4SLinus Torvalds 	"?(14)",
1981da177e4SLinus Torvalds 	"?(15)",
1991da177e4SLinus Torvalds 	"?(16)",
2001da177e4SLinus Torvalds 	"?(17)",
2011da177e4SLinus Torvalds };
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds int cpu_architecture(void)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	int cpu_arch;
2061da177e4SLinus Torvalds 
2070ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2081da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2090ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2100ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2110ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2120ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2131da177e4SLinus Torvalds 		if (cpu_arch)
2141da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2150ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
216180005c4SCatalin Marinas 		unsigned int mmfr0;
217180005c4SCatalin Marinas 
218180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
219180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
220180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
221180005c4SCatalin Marinas 		    : "=r" (mmfr0));
222180005c4SCatalin Marinas 		if ((mmfr0 & 0x0000000f) == 0x00000003 ||
223180005c4SCatalin Marinas 		    (mmfr0 & 0x000000f0) == 0x00000030)
224180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
225180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
226180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
227180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
228180005c4SCatalin Marinas 		else
229180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
230180005c4SCatalin Marinas 	} else
231180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	return cpu_arch;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
236c0e95878SRussell King static void __init cacheid_init(void)
237c0e95878SRussell King {
238c0e95878SRussell King 	unsigned int cachetype = read_cpuid_cachetype();
239c0e95878SRussell King 	unsigned int arch = cpu_architecture();
240c0e95878SRussell King 
241b57ee99fSCatalin Marinas 	if (arch >= CPU_ARCH_ARMv6) {
242b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
243b57ee99fSCatalin Marinas 			/* ARMv7 register format */
244c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
245c0e95878SRussell King 			if ((cachetype & (3 << 14)) == 1 << 14)
246c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
247b57ee99fSCatalin Marinas 		} else if (cachetype & (1 << 23))
248c0e95878SRussell King 			cacheid = CACHEID_VIPT_ALIASING;
249c0e95878SRussell King 		else
250c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
251c0e95878SRussell King 	} else {
252c0e95878SRussell King 		cacheid = CACHEID_VIVT;
253c0e95878SRussell King 	}
2542b4ae1f1SRussell King 
2552b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
2562b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
2572b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
2582b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
2592b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
2602b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
2612b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
2622b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
263c0e95878SRussell King }
264c0e95878SRussell King 
2651da177e4SLinus Torvalds /*
2661da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
2671da177e4SLinus Torvalds  * already provide the required functionality.
2681da177e4SLinus Torvalds  */
2690f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
2701da177e4SLinus Torvalds extern struct machine_desc *lookup_machine_type(unsigned int);
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds static void __init setup_processor(void)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds 	struct proc_info_list *list;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	/*
2771da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
2781da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
2791da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
2801da177e4SLinus Torvalds 	 */
2810ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
2821da177e4SLinus Torvalds 	if (!list) {
2831da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
2840ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
2851da177e4SLinus Torvalds 		while (1);
2861da177e4SLinus Torvalds 	}
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds #ifdef MULTI_CPU
2911da177e4SLinus Torvalds 	processor = *list->proc;
2921da177e4SLinus Torvalds #endif
2931da177e4SLinus Torvalds #ifdef MULTI_TLB
2941da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
2951da177e4SLinus Torvalds #endif
2961da177e4SLinus Torvalds #ifdef MULTI_USER
2971da177e4SLinus Torvalds 	cpu_user = *list->user;
2981da177e4SLinus Torvalds #endif
2991da177e4SLinus Torvalds #ifdef MULTI_CACHE
3001da177e4SLinus Torvalds 	cpu_cache = *list->cache;
3011da177e4SLinus Torvalds #endif
3021da177e4SLinus Torvalds 
3034e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
3040ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
305264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
3061da177e4SLinus Torvalds 
30796b644bdSSerge E. Hallyn 	sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
3081da177e4SLinus Torvalds 	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
3091da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
310adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
311adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
312adeff422SCatalin Marinas #endif
3131da177e4SLinus Torvalds 
314c0e95878SRussell King 	cacheid_init();
3151da177e4SLinus Torvalds 	cpu_proc_init();
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds 
318ccea7a19SRussell King /*
319ccea7a19SRussell King  * cpu_init - initialise one CPU.
320ccea7a19SRussell King  *
32190f1e084SRussell King  * cpu_init sets up the per-CPU stacks.
322ccea7a19SRussell King  */
32336c5ed23SRussell King void cpu_init(void)
324ccea7a19SRussell King {
325ccea7a19SRussell King 	unsigned int cpu = smp_processor_id();
326ccea7a19SRussell King 	struct stack *stk = &stacks[cpu];
327ccea7a19SRussell King 
328ccea7a19SRussell King 	if (cpu >= NR_CPUS) {
329ccea7a19SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
330ccea7a19SRussell King 		BUG();
331ccea7a19SRussell King 	}
332ccea7a19SRussell King 
333ccea7a19SRussell King 	/*
334b86040a5SCatalin Marinas 	 * Define the placement constraint for the inline asm directive below.
335b86040a5SCatalin Marinas 	 * In Thumb-2, msr with an immediate value is not allowed.
336b86040a5SCatalin Marinas 	 */
337b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL
338b86040a5SCatalin Marinas #define PLC	"r"
339b86040a5SCatalin Marinas #else
340b86040a5SCatalin Marinas #define PLC	"I"
341b86040a5SCatalin Marinas #endif
342b86040a5SCatalin Marinas 
343b86040a5SCatalin Marinas 	/*
344ccea7a19SRussell King 	 * setup stacks for re-entrant exception handlers
345ccea7a19SRussell King 	 */
346ccea7a19SRussell King 	__asm__ (
347ccea7a19SRussell King 	"msr	cpsr_c, %1\n\t"
348b86040a5SCatalin Marinas 	"add	r14, %0, %2\n\t"
349b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
350ccea7a19SRussell King 	"msr	cpsr_c, %3\n\t"
351b86040a5SCatalin Marinas 	"add	r14, %0, %4\n\t"
352b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
353ccea7a19SRussell King 	"msr	cpsr_c, %5\n\t"
354b86040a5SCatalin Marinas 	"add	r14, %0, %6\n\t"
355b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
356ccea7a19SRussell King 	"msr	cpsr_c, %7"
357ccea7a19SRussell King 	    :
358ccea7a19SRussell King 	    : "r" (stk),
359b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
360ccea7a19SRussell King 	      "I" (offsetof(struct stack, irq[0])),
361b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
362ccea7a19SRussell King 	      "I" (offsetof(struct stack, abt[0])),
363b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
364ccea7a19SRussell King 	      "I" (offsetof(struct stack, und[0])),
365b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
366aaaa3f9eSCatalin Marinas 	    : "r14");
367ccea7a19SRussell King }
368ccea7a19SRussell King 
3691da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds 	struct machine_desc *list;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	/*
3741da177e4SLinus Torvalds 	 * locate machine in the list of supported machines.
3751da177e4SLinus Torvalds 	 */
3761da177e4SLinus Torvalds 	list = lookup_machine_type(nr);
3771da177e4SLinus Torvalds 	if (!list) {
3781da177e4SLinus Torvalds 		printk("Machine configuration botched (nr %d), unable "
3791da177e4SLinus Torvalds 		       "to continue.\n", nr);
3801da177e4SLinus Torvalds 		while (1);
3811da177e4SLinus Torvalds 	}
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	printk("Machine: %s\n", list->name);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	return list;
3861da177e4SLinus Torvalds }
3871da177e4SLinus Torvalds 
3884b5f32ceSNicolas Pitre static int __init arm_add_memory(unsigned long start, unsigned long size)
3893a669411SRussell King {
3904b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
3914b5f32ceSNicolas Pitre 
3924b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
3934b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
3944b5f32ceSNicolas Pitre 			"ignoring memory at %#lx\n", start);
3954b5f32ceSNicolas Pitre 		return -EINVAL;
3964b5f32ceSNicolas Pitre 	}
39705f96ef1SRussell King 
3983a669411SRussell King 	/*
3993a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
4003a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
4013a669411SRussell King 	 */
4023a669411SRussell King 	size -= start & ~PAGE_MASK;
40305f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
40405f96ef1SRussell King 	bank->size  = size & PAGE_MASK;
40505f96ef1SRussell King 	bank->node  = PHYS_TO_NID(start);
4064b5f32ceSNicolas Pitre 
4074b5f32ceSNicolas Pitre 	/*
4084b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
4094b5f32ceSNicolas Pitre 	 * invalid node number.
4104b5f32ceSNicolas Pitre 	 */
4114b5f32ceSNicolas Pitre 	if (bank->size == 0 || bank->node >= MAX_NUMNODES)
4124b5f32ceSNicolas Pitre 		return -EINVAL;
4134b5f32ceSNicolas Pitre 
4144b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
4154b5f32ceSNicolas Pitre 	return 0;
4163a669411SRussell King }
4173a669411SRussell King 
4181da177e4SLinus Torvalds /*
4191da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
4201da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
4211da177e4SLinus Torvalds  */
4222b0d8c25SJeremy Kerr static int __init early_mem(char *p)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds 	static int usermem __initdata = 0;
4251da177e4SLinus Torvalds 	unsigned long size, start;
4262b0d8c25SJeremy Kerr 	char *endp;
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 	/*
4291da177e4SLinus Torvalds 	 * If the user specifies memory size, we
4301da177e4SLinus Torvalds 	 * blow away any automatically generated
4311da177e4SLinus Torvalds 	 * size.
4321da177e4SLinus Torvalds 	 */
4331da177e4SLinus Torvalds 	if (usermem == 0) {
4341da177e4SLinus Torvalds 		usermem = 1;
4351da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
4361da177e4SLinus Torvalds 	}
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	start = PHYS_OFFSET;
4392b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
4402b0d8c25SJeremy Kerr 	if (*endp == '@')
4412b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
4421da177e4SLinus Torvalds 
4431c97b73eSAndrew Morton 	arm_add_memory(start, size);
4441da177e4SLinus Torvalds 
4452b0d8c25SJeremy Kerr 	return 0;
4461da177e4SLinus Torvalds }
4472b0d8c25SJeremy Kerr early_param("mem", early_mem);
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds static void __init
4501da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
4531da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	rd_image_start = image_start;
4561da177e4SLinus Torvalds 	rd_prompt = prompt;
4571da177e4SLinus Torvalds 	rd_doload = doload;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	if (rd_sz)
4601da177e4SLinus Torvalds 		rd_size = rd_sz;
4611da177e4SLinus Torvalds #endif
4621da177e4SLinus Torvalds }
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds static void __init
4651da177e4SLinus Torvalds request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
4661da177e4SLinus Torvalds {
4671da177e4SLinus Torvalds 	struct resource *res;
4681da177e4SLinus Torvalds 	int i;
4691da177e4SLinus Torvalds 
47037efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
47137efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
47237efe642SRussell King 	kernel_data.start   = virt_to_phys(_data);
47337efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 	for (i = 0; i < mi->nr_banks; i++) {
4761da177e4SLinus Torvalds 		if (mi->bank[i].size == 0)
4771da177e4SLinus Torvalds 			continue;
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
4801da177e4SLinus Torvalds 		res->name  = "System RAM";
4813319f5e5SNicolas Pitre 		res->start = mi->bank[i].start;
4823319f5e5SNicolas Pitre 		res->end   = mi->bank[i].start + mi->bank[i].size - 1;
4831da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
4881da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
4891da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
4901da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
4911da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
4921da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
4931da177e4SLinus Torvalds 	}
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	if (mdesc->video_start) {
4961da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
4971da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
4981da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
4991da177e4SLinus Torvalds 	}
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 	/*
5021da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
5031da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
5041da177e4SLinus Torvalds 	 */
5051da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
5061da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
5071da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
5081da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
5091da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
5101da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds /*
5141da177e4SLinus Torvalds  *  Tag parsing.
5151da177e4SLinus Torvalds  *
5161da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
5171da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
5181da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
5191da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
5201da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
5211da177e4SLinus Torvalds  * is not parsed in any way).
5221da177e4SLinus Torvalds  */
5231da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
5241da177e4SLinus Torvalds {
5251da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
5261da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
5271da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
5281da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
5291da177e4SLinus Torvalds 	}
5301da177e4SLinus Torvalds 	return 0;
5311da177e4SLinus Torvalds }
5321da177e4SLinus Torvalds 
5331da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
5361da177e4SLinus Torvalds {
5374b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
5381da177e4SLinus Torvalds }
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
5431da177e4SLinus Torvalds struct screen_info screen_info = {
5441da177e4SLinus Torvalds  .orig_video_lines	= 30,
5451da177e4SLinus Torvalds  .orig_video_cols	= 80,
5461da177e4SLinus Torvalds  .orig_video_mode	= 0,
5471da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
5481da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
5491da177e4SLinus Torvalds  .orig_video_points	= 8
5501da177e4SLinus Torvalds };
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
5531da177e4SLinus Torvalds {
5541da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
5551da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
5561da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
5571da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
5581da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
5591da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
5601da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
5611da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
5621da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
5631da177e4SLinus Torvalds 	return 0;
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
5671da177e4SLinus Torvalds #endif
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
5701da177e4SLinus Torvalds {
5711da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
5721da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
5731da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
5741da177e4SLinus Torvalds 	return 0;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
5801da177e4SLinus Torvalds {
5811da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
5821da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
5831da177e4SLinus Torvalds 	return 0;
5841da177e4SLinus Torvalds }
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
5891da177e4SLinus Torvalds {
5901da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
5911da177e4SLinus Torvalds 	return 0;
5921da177e4SLinus Torvalds }
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
5951da177e4SLinus Torvalds 
59692d2040dSAlexander Holler #ifndef CONFIG_CMDLINE_FORCE
5971da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
5981da177e4SLinus Torvalds {
5991da177e4SLinus Torvalds 	strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
6001da177e4SLinus Torvalds 	return 0;
6011da177e4SLinus Torvalds }
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
60492d2040dSAlexander Holler #endif /* CONFIG_CMDLINE_FORCE */
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds /*
6071da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
6081da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
6091da177e4SLinus Torvalds  * declarations.
6101da177e4SLinus Torvalds  */
6111da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
6121da177e4SLinus Torvalds {
6131da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
6141da177e4SLinus Torvalds 	struct tagtable *t;
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
6171da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
6181da177e4SLinus Torvalds 			t->parse(tag);
6191da177e4SLinus Torvalds 			break;
6201da177e4SLinus Torvalds 		}
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds 	return t < &__tagtable_end;
6231da177e4SLinus Torvalds }
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds /*
6261da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
6271da177e4SLinus Torvalds  * specific tag tables.
6281da177e4SLinus Torvalds  */
6291da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
6301da177e4SLinus Torvalds {
6311da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
6321da177e4SLinus Torvalds 		if (!parse_tag(t))
6331da177e4SLinus Torvalds 			printk(KERN_WARNING
6341da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
6351da177e4SLinus Torvalds 				t->hdr.tag);
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds /*
6391da177e4SLinus Torvalds  * This holds our defaults.
6401da177e4SLinus Torvalds  */
6411da177e4SLinus Torvalds static struct init_tags {
6421da177e4SLinus Torvalds 	struct tag_header hdr1;
6431da177e4SLinus Torvalds 	struct tag_core   core;
6441da177e4SLinus Torvalds 	struct tag_header hdr2;
6451da177e4SLinus Torvalds 	struct tag_mem32  mem;
6461da177e4SLinus Torvalds 	struct tag_header hdr3;
6471da177e4SLinus Torvalds } init_tags __initdata = {
6481da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
6491da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
6501da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
6511da177e4SLinus Torvalds 	{ MEM_SIZE, PHYS_OFFSET },
6521da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
6531da177e4SLinus Torvalds };
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds static void (*init_machine)(void) __initdata;
6561da177e4SLinus Torvalds 
6571da177e4SLinus Torvalds static int __init customize_machine(void)
6581da177e4SLinus Torvalds {
6591da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
6601da177e4SLinus Torvalds 	if (init_machine)
6611da177e4SLinus Torvalds 		init_machine();
6621da177e4SLinus Torvalds 	return 0;
6631da177e4SLinus Torvalds }
6641da177e4SLinus Torvalds arch_initcall(customize_machine);
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
6671da177e4SLinus Torvalds {
6681da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
6691da177e4SLinus Torvalds 	struct machine_desc *mdesc;
6701da177e4SLinus Torvalds 	char *from = default_command_line;
6711da177e4SLinus Torvalds 
672bff595c1SCatalin Marinas 	unwind_init();
673bff595c1SCatalin Marinas 
6741da177e4SLinus Torvalds 	setup_processor();
6751da177e4SLinus Torvalds 	mdesc = setup_machine(machine_arch_type);
6761da177e4SLinus Torvalds 	machine_name = mdesc->name;
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 	if (mdesc->soft_reboot)
6791da177e4SLinus Torvalds 		reboot_setup("s");
6801da177e4SLinus Torvalds 
6819d20fdd5SBill Gatliff 	if (__atags_pointer)
6829d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
6839d20fdd5SBill Gatliff 	else if (mdesc->boot_params)
684f9bd6ea4SRussell King 		tags = phys_to_virt(mdesc->boot_params);
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	/*
6871da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
6881da177e4SLinus Torvalds 	 * a tag list.
6891da177e4SLinus Torvalds 	 */
6901da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
6911da177e4SLinus Torvalds 		convert_to_tag_list(tags);
6921da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
6931da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	if (mdesc->fixup)
6961da177e4SLinus Torvalds 		mdesc->fixup(mdesc, tags, &from, &meminfo);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
6991da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
7001da177e4SLinus Torvalds 			squash_mem_tags(tags);
7014cd9d6f7SRichard Purdie 		save_atags(tags);
7021da177e4SLinus Torvalds 		parse_tags(tags);
7031da177e4SLinus Torvalds 	}
7041da177e4SLinus Torvalds 
70537efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
70637efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
70737efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
70837efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
7091da177e4SLinus Torvalds 
7102b0d8c25SJeremy Kerr 	/* parse_early_param needs a boot_command_line */
7112b0d8c25SJeremy Kerr 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
7122b0d8c25SJeremy Kerr 
71348ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
71448ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
71548ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
7162b0d8c25SJeremy Kerr 
7172b0d8c25SJeremy Kerr 	parse_early_param();
7182b0d8c25SJeremy Kerr 
7194b5f32ceSNicolas Pitre 	paging_init(mdesc);
7201da177e4SLinus Torvalds 	request_standard_resources(&meminfo, mdesc);
7211da177e4SLinus Torvalds 
7227bbb7940SRussell King #ifdef CONFIG_SMP
7237bbb7940SRussell King 	smp_init_cpus();
7247bbb7940SRussell King #endif
7257bbb7940SRussell King 
726ccea7a19SRussell King 	cpu_init();
727bc581770SLinus Walleij 	tcm_init();
728ccea7a19SRussell King 
7291da177e4SLinus Torvalds 	/*
7301da177e4SLinus Torvalds 	 * Set up various architecture-specific pointers
7311da177e4SLinus Torvalds 	 */
732354e6f72Seric miao 	arch_nr_irqs = mdesc->nr_irqs;
7331da177e4SLinus Torvalds 	init_arch_irq = mdesc->init_irq;
7341da177e4SLinus Torvalds 	system_timer = mdesc->timer;
7351da177e4SLinus Torvalds 	init_machine = mdesc->init_machine;
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds #ifdef CONFIG_VT
7381da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
7391da177e4SLinus Torvalds 	conswitchp = &vga_con;
7401da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
7411da177e4SLinus Torvalds 	conswitchp = &dummy_con;
7421da177e4SLinus Torvalds #endif
7431da177e4SLinus Torvalds #endif
7445cbad0ebSJason Wessel 	early_trap_init();
7451da177e4SLinus Torvalds }
7461da177e4SLinus Torvalds 
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds static int __init topology_init(void)
7491da177e4SLinus Torvalds {
7501da177e4SLinus Torvalds 	int cpu;
7511da177e4SLinus Torvalds 
75266fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
75366fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
75466fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
75566fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
75666fb8bd2SRussell King 	}
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 	return 0;
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds subsys_initcall(topology_init);
7611da177e4SLinus Torvalds 
762e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
763e119bfffSRussell King static int __init proc_cpu_init(void)
764e119bfffSRussell King {
765e119bfffSRussell King 	struct proc_dir_entry *res;
766e119bfffSRussell King 
767e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
768e119bfffSRussell King 	if (!res)
769e119bfffSRussell King 		return -ENOMEM;
770e119bfffSRussell King 	return 0;
771e119bfffSRussell King }
772e119bfffSRussell King fs_initcall(proc_cpu_init);
773e119bfffSRussell King #endif
774e119bfffSRussell King 
7751da177e4SLinus Torvalds static const char *hwcap_str[] = {
7761da177e4SLinus Torvalds 	"swp",
7771da177e4SLinus Torvalds 	"half",
7781da177e4SLinus Torvalds 	"thumb",
7791da177e4SLinus Torvalds 	"26bit",
7801da177e4SLinus Torvalds 	"fastmult",
7811da177e4SLinus Torvalds 	"fpa",
7821da177e4SLinus Torvalds 	"vfp",
7831da177e4SLinus Torvalds 	"edsp",
7841da177e4SLinus Torvalds 	"java",
7858f7f9435SPaul Gortmaker 	"iwmmxt",
78699e4a6ddSLennert Buytenhek 	"crunch",
7874369ae16SCatalin Marinas 	"thumbee",
7882bedbdf4SCatalin Marinas 	"neon",
7897279dc3eSCatalin Marinas 	"vfpv3",
7907279dc3eSCatalin Marinas 	"vfpv3d16",
7911da177e4SLinus Torvalds 	NULL
7921da177e4SLinus Torvalds };
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
7951da177e4SLinus Torvalds {
7961da177e4SLinus Torvalds 	int i;
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
7990ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds #if defined(CONFIG_SMP)
8021da177e4SLinus Torvalds 	for_each_online_cpu(i) {
80315559722SRussell King 		/*
80415559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
80515559722SRussell King 		 * online processors, looking for lines beginning with
80615559722SRussell King 		 * "processor".  Give glibc what it expects.
80715559722SRussell King 		 */
80815559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
8091da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
8101da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
8111da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
8121da177e4SLinus Torvalds 	}
8131da177e4SLinus Torvalds #else /* CONFIG_SMP */
8141da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
8151da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
8161da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
8171da177e4SLinus Torvalds #endif
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	/* dump out the processor features */
8201da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
8211da177e4SLinus Torvalds 
8221da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
8231da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
8241da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
8251da177e4SLinus Torvalds 
8260ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
8271da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
8281da177e4SLinus Torvalds 
8290ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
8301da177e4SLinus Torvalds 		/* pre-ARM7 */
8310ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
8321da177e4SLinus Torvalds 	} else {
8330ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
8341da177e4SLinus Torvalds 			/* ARM7 */
8351da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
8360ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
8371da177e4SLinus Torvalds 		} else {
8381da177e4SLinus Torvalds 			/* post-ARM7 */
8391da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
8400ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
8411da177e4SLinus Torvalds 		}
8421da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
8430ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
8441da177e4SLinus Torvalds 	}
8450ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds 	seq_puts(m, "\n");
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
8501da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
8511da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
8521da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds 	return 0;
8551da177e4SLinus Torvalds }
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
8581da177e4SLinus Torvalds {
8591da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
8601da177e4SLinus Torvalds }
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
8631da177e4SLinus Torvalds {
8641da177e4SLinus Torvalds 	++*pos;
8651da177e4SLinus Torvalds 	return NULL;
8661da177e4SLinus Torvalds }
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
8691da177e4SLinus Torvalds {
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds 
8722ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
8731da177e4SLinus Torvalds 	.start	= c_start,
8741da177e4SLinus Torvalds 	.next	= c_next,
8751da177e4SLinus Torvalds 	.stop	= c_stop,
8761da177e4SLinus Torvalds 	.show	= c_show
8771da177e4SLinus Torvalds };
878