xref: /openbmc/linux/arch/arm/kernel/setup.c (revision f159f4ed)
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 
272f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
273f159f4edSTony Lindgren {
274f159f4edSTony Lindgren 	int id = read_cpuid_id();
275f159f4edSTony Lindgren 
276f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
277f159f4edSTony Lindgren 		return;
278f159f4edSTony Lindgren 
279f159f4edSTony Lindgren 	/*
280f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
281f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
282f159f4edSTony Lindgren 	 */
283f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
284f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
285f159f4edSTony Lindgren }
286f159f4edSTony Lindgren 
2871da177e4SLinus Torvalds static void __init setup_processor(void)
2881da177e4SLinus Torvalds {
2891da177e4SLinus Torvalds 	struct proc_info_list *list;
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 	/*
2921da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
2931da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
2941da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
2951da177e4SLinus Torvalds 	 */
2960ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
2971da177e4SLinus Torvalds 	if (!list) {
2981da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
2990ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
3001da177e4SLinus Torvalds 		while (1);
3011da177e4SLinus Torvalds 	}
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds #ifdef MULTI_CPU
3061da177e4SLinus Torvalds 	processor = *list->proc;
3071da177e4SLinus Torvalds #endif
3081da177e4SLinus Torvalds #ifdef MULTI_TLB
3091da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
3101da177e4SLinus Torvalds #endif
3111da177e4SLinus Torvalds #ifdef MULTI_USER
3121da177e4SLinus Torvalds 	cpu_user = *list->user;
3131da177e4SLinus Torvalds #endif
3141da177e4SLinus Torvalds #ifdef MULTI_CACHE
3151da177e4SLinus Torvalds 	cpu_cache = *list->cache;
3161da177e4SLinus Torvalds #endif
3171da177e4SLinus Torvalds 
3184e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
3190ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
320264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
3211da177e4SLinus Torvalds 
32296b644bdSSerge E. Hallyn 	sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
3231da177e4SLinus Torvalds 	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
3241da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
325adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
326adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
327adeff422SCatalin Marinas #endif
3281da177e4SLinus Torvalds 
329f159f4edSTony Lindgren 	feat_v6_fixup();
330f159f4edSTony Lindgren 
331c0e95878SRussell King 	cacheid_init();
3321da177e4SLinus Torvalds 	cpu_proc_init();
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
335ccea7a19SRussell King /*
336ccea7a19SRussell King  * cpu_init - initialise one CPU.
337ccea7a19SRussell King  *
33890f1e084SRussell King  * cpu_init sets up the per-CPU stacks.
339ccea7a19SRussell King  */
34036c5ed23SRussell King void cpu_init(void)
341ccea7a19SRussell King {
342ccea7a19SRussell King 	unsigned int cpu = smp_processor_id();
343ccea7a19SRussell King 	struct stack *stk = &stacks[cpu];
344ccea7a19SRussell King 
345ccea7a19SRussell King 	if (cpu >= NR_CPUS) {
346ccea7a19SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
347ccea7a19SRussell King 		BUG();
348ccea7a19SRussell King 	}
349ccea7a19SRussell King 
350ccea7a19SRussell King 	/*
351b86040a5SCatalin Marinas 	 * Define the placement constraint for the inline asm directive below.
352b86040a5SCatalin Marinas 	 * In Thumb-2, msr with an immediate value is not allowed.
353b86040a5SCatalin Marinas 	 */
354b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL
355b86040a5SCatalin Marinas #define PLC	"r"
356b86040a5SCatalin Marinas #else
357b86040a5SCatalin Marinas #define PLC	"I"
358b86040a5SCatalin Marinas #endif
359b86040a5SCatalin Marinas 
360b86040a5SCatalin Marinas 	/*
361ccea7a19SRussell King 	 * setup stacks for re-entrant exception handlers
362ccea7a19SRussell King 	 */
363ccea7a19SRussell King 	__asm__ (
364ccea7a19SRussell King 	"msr	cpsr_c, %1\n\t"
365b86040a5SCatalin Marinas 	"add	r14, %0, %2\n\t"
366b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
367ccea7a19SRussell King 	"msr	cpsr_c, %3\n\t"
368b86040a5SCatalin Marinas 	"add	r14, %0, %4\n\t"
369b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
370ccea7a19SRussell King 	"msr	cpsr_c, %5\n\t"
371b86040a5SCatalin Marinas 	"add	r14, %0, %6\n\t"
372b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
373ccea7a19SRussell King 	"msr	cpsr_c, %7"
374ccea7a19SRussell King 	    :
375ccea7a19SRussell King 	    : "r" (stk),
376b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
377ccea7a19SRussell King 	      "I" (offsetof(struct stack, irq[0])),
378b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
379ccea7a19SRussell King 	      "I" (offsetof(struct stack, abt[0])),
380b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
381ccea7a19SRussell King 	      "I" (offsetof(struct stack, und[0])),
382b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
383aaaa3f9eSCatalin Marinas 	    : "r14");
384ccea7a19SRussell King }
385ccea7a19SRussell King 
3861da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr)
3871da177e4SLinus Torvalds {
3881da177e4SLinus Torvalds 	struct machine_desc *list;
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 	/*
3911da177e4SLinus Torvalds 	 * locate machine in the list of supported machines.
3921da177e4SLinus Torvalds 	 */
3931da177e4SLinus Torvalds 	list = lookup_machine_type(nr);
3941da177e4SLinus Torvalds 	if (!list) {
3951da177e4SLinus Torvalds 		printk("Machine configuration botched (nr %d), unable "
3961da177e4SLinus Torvalds 		       "to continue.\n", nr);
3971da177e4SLinus Torvalds 		while (1);
3981da177e4SLinus Torvalds 	}
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds 	printk("Machine: %s\n", list->name);
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	return list;
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds 
4054b5f32ceSNicolas Pitre static int __init arm_add_memory(unsigned long start, unsigned long size)
4063a669411SRussell King {
4074b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
4084b5f32ceSNicolas Pitre 
4094b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
4104b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
4114b5f32ceSNicolas Pitre 			"ignoring memory at %#lx\n", start);
4124b5f32ceSNicolas Pitre 		return -EINVAL;
4134b5f32ceSNicolas Pitre 	}
41405f96ef1SRussell King 
4153a669411SRussell King 	/*
4163a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
4173a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
4183a669411SRussell King 	 */
4193a669411SRussell King 	size -= start & ~PAGE_MASK;
42005f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
42105f96ef1SRussell King 	bank->size  = size & PAGE_MASK;
42205f96ef1SRussell King 	bank->node  = PHYS_TO_NID(start);
4234b5f32ceSNicolas Pitre 
4244b5f32ceSNicolas Pitre 	/*
4254b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
4264b5f32ceSNicolas Pitre 	 * invalid node number.
4274b5f32ceSNicolas Pitre 	 */
4284b5f32ceSNicolas Pitre 	if (bank->size == 0 || bank->node >= MAX_NUMNODES)
4294b5f32ceSNicolas Pitre 		return -EINVAL;
4304b5f32ceSNicolas Pitre 
4314b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
4324b5f32ceSNicolas Pitre 	return 0;
4333a669411SRussell King }
4343a669411SRussell King 
4351da177e4SLinus Torvalds /*
4361da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
4371da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
4381da177e4SLinus Torvalds  */
4392b0d8c25SJeremy Kerr static int __init early_mem(char *p)
4401da177e4SLinus Torvalds {
4411da177e4SLinus Torvalds 	static int usermem __initdata = 0;
4421da177e4SLinus Torvalds 	unsigned long size, start;
4432b0d8c25SJeremy Kerr 	char *endp;
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	/*
4461da177e4SLinus Torvalds 	 * If the user specifies memory size, we
4471da177e4SLinus Torvalds 	 * blow away any automatically generated
4481da177e4SLinus Torvalds 	 * size.
4491da177e4SLinus Torvalds 	 */
4501da177e4SLinus Torvalds 	if (usermem == 0) {
4511da177e4SLinus Torvalds 		usermem = 1;
4521da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
4531da177e4SLinus Torvalds 	}
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	start = PHYS_OFFSET;
4562b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
4572b0d8c25SJeremy Kerr 	if (*endp == '@')
4582b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
4591da177e4SLinus Torvalds 
4601c97b73eSAndrew Morton 	arm_add_memory(start, size);
4611da177e4SLinus Torvalds 
4622b0d8c25SJeremy Kerr 	return 0;
4631da177e4SLinus Torvalds }
4642b0d8c25SJeremy Kerr early_param("mem", early_mem);
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds static void __init
4671da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
4681da177e4SLinus Torvalds {
4691da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
4701da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds 	rd_image_start = image_start;
4731da177e4SLinus Torvalds 	rd_prompt = prompt;
4741da177e4SLinus Torvalds 	rd_doload = doload;
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds 	if (rd_sz)
4771da177e4SLinus Torvalds 		rd_size = rd_sz;
4781da177e4SLinus Torvalds #endif
4791da177e4SLinus Torvalds }
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds static void __init
4821da177e4SLinus Torvalds request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
4831da177e4SLinus Torvalds {
4841da177e4SLinus Torvalds 	struct resource *res;
4851da177e4SLinus Torvalds 	int i;
4861da177e4SLinus Torvalds 
48737efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
48837efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
48937efe642SRussell King 	kernel_data.start   = virt_to_phys(_data);
49037efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	for (i = 0; i < mi->nr_banks; i++) {
4931da177e4SLinus Torvalds 		if (mi->bank[i].size == 0)
4941da177e4SLinus Torvalds 			continue;
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
4971da177e4SLinus Torvalds 		res->name  = "System RAM";
4983319f5e5SNicolas Pitre 		res->start = mi->bank[i].start;
4993319f5e5SNicolas Pitre 		res->end   = mi->bank[i].start + mi->bank[i].size - 1;
5001da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
5051da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
5061da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
5071da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
5081da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
5091da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 	if (mdesc->video_start) {
5131da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
5141da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
5151da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
5161da177e4SLinus Torvalds 	}
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	/*
5191da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
5201da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
5211da177e4SLinus Torvalds 	 */
5221da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
5231da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
5241da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
5251da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
5261da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
5271da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds /*
5311da177e4SLinus Torvalds  *  Tag parsing.
5321da177e4SLinus Torvalds  *
5331da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
5341da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
5351da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
5361da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
5371da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
5381da177e4SLinus Torvalds  * is not parsed in any way).
5391da177e4SLinus Torvalds  */
5401da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
5411da177e4SLinus Torvalds {
5421da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
5431da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
5441da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
5451da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
5461da177e4SLinus Torvalds 	}
5471da177e4SLinus Torvalds 	return 0;
5481da177e4SLinus Torvalds }
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
5531da177e4SLinus Torvalds {
5544b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
5551da177e4SLinus Torvalds }
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
5601da177e4SLinus Torvalds struct screen_info screen_info = {
5611da177e4SLinus Torvalds  .orig_video_lines	= 30,
5621da177e4SLinus Torvalds  .orig_video_cols	= 80,
5631da177e4SLinus Torvalds  .orig_video_mode	= 0,
5641da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
5651da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
5661da177e4SLinus Torvalds  .orig_video_points	= 8
5671da177e4SLinus Torvalds };
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
5701da177e4SLinus Torvalds {
5711da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
5721da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
5731da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
5741da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
5751da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
5761da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
5771da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
5781da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
5791da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
5801da177e4SLinus Torvalds 	return 0;
5811da177e4SLinus Torvalds }
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
5841da177e4SLinus Torvalds #endif
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
5871da177e4SLinus Torvalds {
5881da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
5891da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
5901da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
5911da177e4SLinus Torvalds 	return 0;
5921da177e4SLinus Torvalds }
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
5971da177e4SLinus Torvalds {
5981da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
5991da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
6001da177e4SLinus Torvalds 	return 0;
6011da177e4SLinus Torvalds }
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
6061da177e4SLinus Torvalds {
6071da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
6081da177e4SLinus Torvalds 	return 0;
6091da177e4SLinus Torvalds }
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
6121da177e4SLinus Torvalds 
61392d2040dSAlexander Holler #ifndef CONFIG_CMDLINE_FORCE
6141da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
6151da177e4SLinus Torvalds {
6161da177e4SLinus Torvalds 	strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
6171da177e4SLinus Torvalds 	return 0;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
62192d2040dSAlexander Holler #endif /* CONFIG_CMDLINE_FORCE */
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds /*
6241da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
6251da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
6261da177e4SLinus Torvalds  * declarations.
6271da177e4SLinus Torvalds  */
6281da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
6291da177e4SLinus Torvalds {
6301da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
6311da177e4SLinus Torvalds 	struct tagtable *t;
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
6341da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
6351da177e4SLinus Torvalds 			t->parse(tag);
6361da177e4SLinus Torvalds 			break;
6371da177e4SLinus Torvalds 		}
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds 	return t < &__tagtable_end;
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds /*
6431da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
6441da177e4SLinus Torvalds  * specific tag tables.
6451da177e4SLinus Torvalds  */
6461da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
6471da177e4SLinus Torvalds {
6481da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
6491da177e4SLinus Torvalds 		if (!parse_tag(t))
6501da177e4SLinus Torvalds 			printk(KERN_WARNING
6511da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
6521da177e4SLinus Torvalds 				t->hdr.tag);
6531da177e4SLinus Torvalds }
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds /*
6561da177e4SLinus Torvalds  * This holds our defaults.
6571da177e4SLinus Torvalds  */
6581da177e4SLinus Torvalds static struct init_tags {
6591da177e4SLinus Torvalds 	struct tag_header hdr1;
6601da177e4SLinus Torvalds 	struct tag_core   core;
6611da177e4SLinus Torvalds 	struct tag_header hdr2;
6621da177e4SLinus Torvalds 	struct tag_mem32  mem;
6631da177e4SLinus Torvalds 	struct tag_header hdr3;
6641da177e4SLinus Torvalds } init_tags __initdata = {
6651da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
6661da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
6671da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
6681da177e4SLinus Torvalds 	{ MEM_SIZE, PHYS_OFFSET },
6691da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
6701da177e4SLinus Torvalds };
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds static void (*init_machine)(void) __initdata;
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds static int __init customize_machine(void)
6751da177e4SLinus Torvalds {
6761da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
6771da177e4SLinus Torvalds 	if (init_machine)
6781da177e4SLinus Torvalds 		init_machine();
6791da177e4SLinus Torvalds 	return 0;
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds arch_initcall(customize_machine);
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
6841da177e4SLinus Torvalds {
6851da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
6861da177e4SLinus Torvalds 	struct machine_desc *mdesc;
6871da177e4SLinus Torvalds 	char *from = default_command_line;
6881da177e4SLinus Torvalds 
689bff595c1SCatalin Marinas 	unwind_init();
690bff595c1SCatalin Marinas 
6911da177e4SLinus Torvalds 	setup_processor();
6921da177e4SLinus Torvalds 	mdesc = setup_machine(machine_arch_type);
6931da177e4SLinus Torvalds 	machine_name = mdesc->name;
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	if (mdesc->soft_reboot)
6961da177e4SLinus Torvalds 		reboot_setup("s");
6971da177e4SLinus Torvalds 
6989d20fdd5SBill Gatliff 	if (__atags_pointer)
6999d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
7009d20fdd5SBill Gatliff 	else if (mdesc->boot_params)
701f9bd6ea4SRussell King 		tags = phys_to_virt(mdesc->boot_params);
7021da177e4SLinus Torvalds 
7031da177e4SLinus Torvalds 	/*
7041da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
7051da177e4SLinus Torvalds 	 * a tag list.
7061da177e4SLinus Torvalds 	 */
7071da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
7081da177e4SLinus Torvalds 		convert_to_tag_list(tags);
7091da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
7101da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 	if (mdesc->fixup)
7131da177e4SLinus Torvalds 		mdesc->fixup(mdesc, tags, &from, &meminfo);
7141da177e4SLinus Torvalds 
7151da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
7161da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
7171da177e4SLinus Torvalds 			squash_mem_tags(tags);
7184cd9d6f7SRichard Purdie 		save_atags(tags);
7191da177e4SLinus Torvalds 		parse_tags(tags);
7201da177e4SLinus Torvalds 	}
7211da177e4SLinus Torvalds 
72237efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
72337efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
72437efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
72537efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
7261da177e4SLinus Torvalds 
7272b0d8c25SJeremy Kerr 	/* parse_early_param needs a boot_command_line */
7282b0d8c25SJeremy Kerr 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
7292b0d8c25SJeremy Kerr 
73048ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
73148ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
73248ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
7332b0d8c25SJeremy Kerr 
7342b0d8c25SJeremy Kerr 	parse_early_param();
7352b0d8c25SJeremy Kerr 
7364b5f32ceSNicolas Pitre 	paging_init(mdesc);
7371da177e4SLinus Torvalds 	request_standard_resources(&meminfo, mdesc);
7381da177e4SLinus Torvalds 
7397bbb7940SRussell King #ifdef CONFIG_SMP
7407bbb7940SRussell King 	smp_init_cpus();
7417bbb7940SRussell King #endif
7427bbb7940SRussell King 
743ccea7a19SRussell King 	cpu_init();
744bc581770SLinus Walleij 	tcm_init();
745ccea7a19SRussell King 
7461da177e4SLinus Torvalds 	/*
7471da177e4SLinus Torvalds 	 * Set up various architecture-specific pointers
7481da177e4SLinus Torvalds 	 */
749354e6f72Seric miao 	arch_nr_irqs = mdesc->nr_irqs;
7501da177e4SLinus Torvalds 	init_arch_irq = mdesc->init_irq;
7511da177e4SLinus Torvalds 	system_timer = mdesc->timer;
7521da177e4SLinus Torvalds 	init_machine = mdesc->init_machine;
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds #ifdef CONFIG_VT
7551da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
7561da177e4SLinus Torvalds 	conswitchp = &vga_con;
7571da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
7581da177e4SLinus Torvalds 	conswitchp = &dummy_con;
7591da177e4SLinus Torvalds #endif
7601da177e4SLinus Torvalds #endif
7615cbad0ebSJason Wessel 	early_trap_init();
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds static int __init topology_init(void)
7661da177e4SLinus Torvalds {
7671da177e4SLinus Torvalds 	int cpu;
7681da177e4SLinus Torvalds 
76966fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
77066fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
77166fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
77266fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
77366fb8bd2SRussell King 	}
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	return 0;
7761da177e4SLinus Torvalds }
7771da177e4SLinus Torvalds subsys_initcall(topology_init);
7781da177e4SLinus Torvalds 
779e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
780e119bfffSRussell King static int __init proc_cpu_init(void)
781e119bfffSRussell King {
782e119bfffSRussell King 	struct proc_dir_entry *res;
783e119bfffSRussell King 
784e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
785e119bfffSRussell King 	if (!res)
786e119bfffSRussell King 		return -ENOMEM;
787e119bfffSRussell King 	return 0;
788e119bfffSRussell King }
789e119bfffSRussell King fs_initcall(proc_cpu_init);
790e119bfffSRussell King #endif
791e119bfffSRussell King 
7921da177e4SLinus Torvalds static const char *hwcap_str[] = {
7931da177e4SLinus Torvalds 	"swp",
7941da177e4SLinus Torvalds 	"half",
7951da177e4SLinus Torvalds 	"thumb",
7961da177e4SLinus Torvalds 	"26bit",
7971da177e4SLinus Torvalds 	"fastmult",
7981da177e4SLinus Torvalds 	"fpa",
7991da177e4SLinus Torvalds 	"vfp",
8001da177e4SLinus Torvalds 	"edsp",
8011da177e4SLinus Torvalds 	"java",
8028f7f9435SPaul Gortmaker 	"iwmmxt",
80399e4a6ddSLennert Buytenhek 	"crunch",
8044369ae16SCatalin Marinas 	"thumbee",
8052bedbdf4SCatalin Marinas 	"neon",
8067279dc3eSCatalin Marinas 	"vfpv3",
8077279dc3eSCatalin Marinas 	"vfpv3d16",
8081da177e4SLinus Torvalds 	NULL
8091da177e4SLinus Torvalds };
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
8121da177e4SLinus Torvalds {
8131da177e4SLinus Torvalds 	int i;
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
8160ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds #if defined(CONFIG_SMP)
8191da177e4SLinus Torvalds 	for_each_online_cpu(i) {
82015559722SRussell King 		/*
82115559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
82215559722SRussell King 		 * online processors, looking for lines beginning with
82315559722SRussell King 		 * "processor".  Give glibc what it expects.
82415559722SRussell King 		 */
82515559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
8261da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
8271da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
8281da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds #else /* CONFIG_SMP */
8311da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
8321da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
8331da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
8341da177e4SLinus Torvalds #endif
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 	/* dump out the processor features */
8371da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
8401da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
8411da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
8421da177e4SLinus Torvalds 
8430ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
8441da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
8451da177e4SLinus Torvalds 
8460ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
8471da177e4SLinus Torvalds 		/* pre-ARM7 */
8480ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
8491da177e4SLinus Torvalds 	} else {
8500ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
8511da177e4SLinus Torvalds 			/* ARM7 */
8521da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
8530ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
8541da177e4SLinus Torvalds 		} else {
8551da177e4SLinus Torvalds 			/* post-ARM7 */
8561da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
8570ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
8581da177e4SLinus Torvalds 		}
8591da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
8600ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
8611da177e4SLinus Torvalds 	}
8620ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	seq_puts(m, "\n");
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
8671da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
8681da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
8691da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
8701da177e4SLinus Torvalds 
8711da177e4SLinus Torvalds 	return 0;
8721da177e4SLinus Torvalds }
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
8751da177e4SLinus Torvalds {
8761da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
8771da177e4SLinus Torvalds }
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
8801da177e4SLinus Torvalds {
8811da177e4SLinus Torvalds 	++*pos;
8821da177e4SLinus Torvalds 	return NULL;
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
8861da177e4SLinus Torvalds {
8871da177e4SLinus Torvalds }
8881da177e4SLinus Torvalds 
8892ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
8901da177e4SLinus Torvalds 	.start	= c_start,
8911da177e4SLinus Torvalds 	.next	= c_next,
8921da177e4SLinus Torvalds 	.stop	= c_stop,
8931da177e4SLinus Torvalds 	.show	= c_show
8941da177e4SLinus Torvalds };
895