xref: /openbmc/linux/arch/arm/kernel/setup.c (revision b75c178a)
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>
223c57fb43SMika Westerberg #include <linux/kexec.h>
23cea0bb1bSMika Westerberg #include <linux/crash_dump.h>
241da177e4SLinus Torvalds #include <linux/root_dev.h>
251da177e4SLinus Torvalds #include <linux/cpu.h>
261da177e4SLinus Torvalds #include <linux/interrupt.h>
277bbb7940SRussell King #include <linux/smp.h>
284e950f6fSAlexey Dobriyan #include <linux/fs.h>
29e119bfffSRussell King #include <linux/proc_fs.h>
302778f620SRussell King #include <linux/memblock.h>
311da177e4SLinus Torvalds 
32b86040a5SCatalin Marinas #include <asm/unified.h>
331da177e4SLinus Torvalds #include <asm/cpu.h>
340ba8b9b2SRussell King #include <asm/cputype.h>
351da177e4SLinus Torvalds #include <asm/elf.h>
361da177e4SLinus Torvalds #include <asm/procinfo.h>
3737efe642SRussell King #include <asm/sections.h>
381da177e4SLinus Torvalds #include <asm/setup.h>
39f00ec48fSRussell King #include <asm/smp_plat.h>
401da177e4SLinus Torvalds #include <asm/mach-types.h>
411da177e4SLinus Torvalds #include <asm/cacheflush.h>
4246097c7dSRussell King #include <asm/cachetype.h>
431da177e4SLinus Torvalds #include <asm/tlbflush.h>
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds #include <asm/mach/arch.h>
461da177e4SLinus Torvalds #include <asm/mach/irq.h>
471da177e4SLinus Torvalds #include <asm/mach/time.h>
485cbad0ebSJason Wessel #include <asm/traps.h>
49bff595c1SCatalin Marinas #include <asm/unwind.h>
501da177e4SLinus Torvalds 
5173a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
520fc1c832SBen Dooks #include "compat.h"
5373a65b3fSUwe Kleine-König #endif
544cd9d6f7SRichard Purdie #include "atags.h"
55bc581770SLinus Walleij #include "tcm.h"
560fc1c832SBen Dooks 
571da177e4SLinus Torvalds #ifndef MEM_SIZE
581da177e4SLinus Torvalds #define MEM_SIZE	(16*1024*1024)
591da177e4SLinus Torvalds #endif
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
621da177e4SLinus Torvalds char fpe_type[8];
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int __init fpe_setup(char *line)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
671da177e4SLinus Torvalds 	return 1;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
711da177e4SLinus Torvalds #endif
721da177e4SLinus Torvalds 
734b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
741da177e4SLinus Torvalds extern void reboot_setup(char *str);
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds unsigned int processor_id;
77c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
780385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
791da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
800385ebc0SRussell King unsigned int cacheid __read_mostly;
81c0e95878SRussell King EXPORT_SYMBOL(cacheid);
821da177e4SLinus Torvalds 
839d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
849d20fdd5SBill Gatliff 
851da177e4SLinus Torvalds unsigned int system_rev;
861da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds unsigned int system_serial_low;
891da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds unsigned int system_serial_high;
921da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
931da177e4SLinus Torvalds 
940385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
951da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds #ifdef MULTI_CPU
990385ebc0SRussell King struct processor processor __read_mostly;
1001da177e4SLinus Torvalds #endif
1011da177e4SLinus Torvalds #ifdef MULTI_TLB
1020385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1031da177e4SLinus Torvalds #endif
1041da177e4SLinus Torvalds #ifdef MULTI_USER
1050385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1061da177e4SLinus Torvalds #endif
1071da177e4SLinus Torvalds #ifdef MULTI_CACHE
1080385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1091da177e4SLinus Torvalds #endif
110953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1110385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1126c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
113953233dcSCatalin Marinas #endif
1141da177e4SLinus Torvalds 
115ccea7a19SRussell King struct stack {
116ccea7a19SRussell King 	u32 irq[3];
117ccea7a19SRussell King 	u32 abt[3];
118ccea7a19SRussell King 	u32 und[3];
119ccea7a19SRussell King } ____cacheline_aligned;
120ccea7a19SRussell King 
121ccea7a19SRussell King static struct stack stacks[NR_CPUS];
122ccea7a19SRussell King 
1231da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1241da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds static const char *cpu_name;
1271da177e4SLinus Torvalds static const char *machine_name;
12848ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
1298ff1443cSRussell King struct machine_desc *machine_desc __initdata;
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
1321da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1331da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds /*
1381da177e4SLinus Torvalds  * Standard memory resources
1391da177e4SLinus Torvalds  */
1401da177e4SLinus Torvalds static struct resource mem_res[] = {
141740e518eSGreg Kroah-Hartman 	{
142740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
143740e518eSGreg Kroah-Hartman 		.start = 0,
144740e518eSGreg Kroah-Hartman 		.end = 0,
145740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
146740e518eSGreg Kroah-Hartman 	},
147740e518eSGreg Kroah-Hartman 	{
148740e518eSGreg Kroah-Hartman 		.name = "Kernel text",
149740e518eSGreg Kroah-Hartman 		.start = 0,
150740e518eSGreg Kroah-Hartman 		.end = 0,
151740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
152740e518eSGreg Kroah-Hartman 	},
153740e518eSGreg Kroah-Hartman 	{
154740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
155740e518eSGreg Kroah-Hartman 		.start = 0,
156740e518eSGreg Kroah-Hartman 		.end = 0,
157740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
158740e518eSGreg Kroah-Hartman 	}
1591da177e4SLinus Torvalds };
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds #define video_ram   mem_res[0]
1621da177e4SLinus Torvalds #define kernel_code mem_res[1]
1631da177e4SLinus Torvalds #define kernel_data mem_res[2]
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds static struct resource io_res[] = {
166740e518eSGreg Kroah-Hartman 	{
167740e518eSGreg Kroah-Hartman 		.name = "reserved",
168740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
169740e518eSGreg Kroah-Hartman 		.end = 0x3be,
170740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
171740e518eSGreg Kroah-Hartman 	},
172740e518eSGreg Kroah-Hartman 	{
173740e518eSGreg Kroah-Hartman 		.name = "reserved",
174740e518eSGreg Kroah-Hartman 		.start = 0x378,
175740e518eSGreg Kroah-Hartman 		.end = 0x37f,
176740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
177740e518eSGreg Kroah-Hartman 	},
178740e518eSGreg Kroah-Hartman 	{
179740e518eSGreg Kroah-Hartman 		.name = "reserved",
180740e518eSGreg Kroah-Hartman 		.start = 0x278,
181740e518eSGreg Kroah-Hartman 		.end = 0x27f,
182740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
183740e518eSGreg Kroah-Hartman 	}
1841da177e4SLinus Torvalds };
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds #define lp0 io_res[0]
1871da177e4SLinus Torvalds #define lp1 io_res[1]
1881da177e4SLinus Torvalds #define lp2 io_res[2]
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds static const char *proc_arch[] = {
1911da177e4SLinus Torvalds 	"undefined/unknown",
1921da177e4SLinus Torvalds 	"3",
1931da177e4SLinus Torvalds 	"4",
1941da177e4SLinus Torvalds 	"4T",
1951da177e4SLinus Torvalds 	"5",
1961da177e4SLinus Torvalds 	"5T",
1971da177e4SLinus Torvalds 	"5TE",
1981da177e4SLinus Torvalds 	"5TEJ",
1991da177e4SLinus Torvalds 	"6TEJ",
2006b090a25SCatalin Marinas 	"7",
2011da177e4SLinus Torvalds 	"?(11)",
2021da177e4SLinus Torvalds 	"?(12)",
2031da177e4SLinus Torvalds 	"?(13)",
2041da177e4SLinus Torvalds 	"?(14)",
2051da177e4SLinus Torvalds 	"?(15)",
2061da177e4SLinus Torvalds 	"?(16)",
2071da177e4SLinus Torvalds 	"?(17)",
2081da177e4SLinus Torvalds };
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds int cpu_architecture(void)
2111da177e4SLinus Torvalds {
2121da177e4SLinus Torvalds 	int cpu_arch;
2131da177e4SLinus Torvalds 
2140ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2151da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2160ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2170ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2180ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2190ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2201da177e4SLinus Torvalds 		if (cpu_arch)
2211da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2220ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
223180005c4SCatalin Marinas 		unsigned int mmfr0;
224180005c4SCatalin Marinas 
225180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
226180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
227180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
228180005c4SCatalin Marinas 		    : "=r" (mmfr0));
229180005c4SCatalin Marinas 		if ((mmfr0 & 0x0000000f) == 0x00000003 ||
230180005c4SCatalin Marinas 		    (mmfr0 & 0x000000f0) == 0x00000030)
231180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
232180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
233180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
234180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
235180005c4SCatalin Marinas 		else
236180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
237180005c4SCatalin Marinas 	} else
238180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	return cpu_arch;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
2438925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2448925ec4cSWill Deacon {
2458925ec4cSWill Deacon 	int aliasing_icache;
2468925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2478925ec4cSWill Deacon 
2488925ec4cSWill Deacon 	/* arch specifies the register format */
2498925ec4cSWill Deacon 	switch (arch) {
2508925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2515fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2525fb31a96SLinus Walleij 		    : /* No output operands */
2538925ec4cSWill Deacon 		    : "r" (1));
2545fb31a96SLinus Walleij 		isb();
2555fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2565fb31a96SLinus Walleij 		    : "=r" (id_reg));
2578925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2588925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2598925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2608925ec4cSWill Deacon 		break;
2618925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2628925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2638925ec4cSWill Deacon 		break;
2648925ec4cSWill Deacon 	default:
2658925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
2668925ec4cSWill Deacon 		aliasing_icache = 0;
2678925ec4cSWill Deacon 	}
2688925ec4cSWill Deacon 
2698925ec4cSWill Deacon 	return aliasing_icache;
2708925ec4cSWill Deacon }
2718925ec4cSWill Deacon 
272c0e95878SRussell King static void __init cacheid_init(void)
273c0e95878SRussell King {
274c0e95878SRussell King 	unsigned int cachetype = read_cpuid_cachetype();
275c0e95878SRussell King 	unsigned int arch = cpu_architecture();
276c0e95878SRussell King 
277b57ee99fSCatalin Marinas 	if (arch >= CPU_ARCH_ARMv6) {
278b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
279b57ee99fSCatalin Marinas 			/* ARMv7 register format */
280c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
281c0e95878SRussell King 			if ((cachetype & (3 << 14)) == 1 << 14)
282c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
2838925ec4cSWill Deacon 			else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
2848925ec4cSWill Deacon 				cacheid |= CACHEID_VIPT_I_ALIASING;
2858925ec4cSWill Deacon 		} else if (cachetype & (1 << 23)) {
286c0e95878SRussell King 			cacheid = CACHEID_VIPT_ALIASING;
2878925ec4cSWill Deacon 		} else {
288c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
2898925ec4cSWill Deacon 			if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
2908925ec4cSWill Deacon 				cacheid |= CACHEID_VIPT_I_ALIASING;
2918925ec4cSWill Deacon 		}
292c0e95878SRussell King 	} else {
293c0e95878SRussell King 		cacheid = CACHEID_VIVT;
294c0e95878SRussell King 	}
2952b4ae1f1SRussell King 
2962b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
2972b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
2982b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
2992b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
3002b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3012b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3028925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3032b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
304c0e95878SRussell King }
305c0e95878SRussell King 
3061da177e4SLinus Torvalds /*
3071da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3081da177e4SLinus Torvalds  * already provide the required functionality.
3091da177e4SLinus Torvalds  */
3100f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3116fc31d54SRussell King 
3126fc31d54SRussell King static void __init early_print(const char *str, ...)
3136fc31d54SRussell King {
3146fc31d54SRussell King 	extern void printascii(const char *);
3156fc31d54SRussell King 	char buf[256];
3166fc31d54SRussell King 	va_list ap;
3176fc31d54SRussell King 
3186fc31d54SRussell King 	va_start(ap, str);
3196fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3206fc31d54SRussell King 	va_end(ap);
3216fc31d54SRussell King 
3226fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3236fc31d54SRussell King 	printascii(buf);
3246fc31d54SRussell King #endif
3256fc31d54SRussell King 	printk("%s", buf);
3266fc31d54SRussell King }
3276fc31d54SRussell King 
3286fc31d54SRussell King static struct machine_desc * __init lookup_machine_type(unsigned int type)
3296fc31d54SRussell King {
3306fc31d54SRussell King 	extern struct machine_desc __arch_info_begin[], __arch_info_end[];
3316fc31d54SRussell King 	struct machine_desc *p;
3326fc31d54SRussell King 
3336fc31d54SRussell King 	for (p = __arch_info_begin; p < __arch_info_end; p++)
3346fc31d54SRussell King 		if (type == p->nr)
3356fc31d54SRussell King 			return p;
3366fc31d54SRussell King 
3376fc31d54SRussell King 	early_print("\n"
3386fc31d54SRussell King 		"Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
3396fc31d54SRussell King 		"Available machine support:\n\nID (hex)\tNAME\n", type);
3406fc31d54SRussell King 
3416fc31d54SRussell King 	for (p = __arch_info_begin; p < __arch_info_end; p++)
3426fc31d54SRussell King 		early_print("%08x\t%s\n", p->nr, p->name);
3436fc31d54SRussell King 
3446fc31d54SRussell King 	early_print("\nPlease check your kernel config and/or bootloader.\n");
3456fc31d54SRussell King 
3466fc31d54SRussell King 	while (true)
3476fc31d54SRussell King 		/* can't use cpu_relax() here as it may require MMU setup */;
3486fc31d54SRussell King }
3491da177e4SLinus Torvalds 
350f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
351f159f4edSTony Lindgren {
352f159f4edSTony Lindgren 	int id = read_cpuid_id();
353f159f4edSTony Lindgren 
354f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
355f159f4edSTony Lindgren 		return;
356f159f4edSTony Lindgren 
357f159f4edSTony Lindgren 	/*
358f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
359f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
360f159f4edSTony Lindgren 	 */
361f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
362f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
363f159f4edSTony Lindgren }
364f159f4edSTony Lindgren 
3651da177e4SLinus Torvalds static void __init setup_processor(void)
3661da177e4SLinus Torvalds {
3671da177e4SLinus Torvalds 	struct proc_info_list *list;
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 	/*
3701da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
3711da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
3721da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
3731da177e4SLinus Torvalds 	 */
3740ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
3751da177e4SLinus Torvalds 	if (!list) {
3761da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
3770ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
3781da177e4SLinus Torvalds 		while (1);
3791da177e4SLinus Torvalds 	}
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds #ifdef MULTI_CPU
3841da177e4SLinus Torvalds 	processor = *list->proc;
3851da177e4SLinus Torvalds #endif
3861da177e4SLinus Torvalds #ifdef MULTI_TLB
3871da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
3881da177e4SLinus Torvalds #endif
3891da177e4SLinus Torvalds #ifdef MULTI_USER
3901da177e4SLinus Torvalds 	cpu_user = *list->user;
3911da177e4SLinus Torvalds #endif
3921da177e4SLinus Torvalds #ifdef MULTI_CACHE
3931da177e4SLinus Torvalds 	cpu_cache = *list->cache;
3941da177e4SLinus Torvalds #endif
3951da177e4SLinus Torvalds 
3964e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
3970ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
398264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
3991da177e4SLinus Torvalds 
40096b644bdSSerge E. Hallyn 	sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
4011da177e4SLinus Torvalds 	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
4021da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
403adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
404adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
405adeff422SCatalin Marinas #endif
4061da177e4SLinus Torvalds 
407f159f4edSTony Lindgren 	feat_v6_fixup();
408f159f4edSTony Lindgren 
409c0e95878SRussell King 	cacheid_init();
4101da177e4SLinus Torvalds 	cpu_proc_init();
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
413ccea7a19SRussell King /*
414ccea7a19SRussell King  * cpu_init - initialise one CPU.
415ccea7a19SRussell King  *
41690f1e084SRussell King  * cpu_init sets up the per-CPU stacks.
417ccea7a19SRussell King  */
41836c5ed23SRussell King void cpu_init(void)
419ccea7a19SRussell King {
420ccea7a19SRussell King 	unsigned int cpu = smp_processor_id();
421ccea7a19SRussell King 	struct stack *stk = &stacks[cpu];
422ccea7a19SRussell King 
423ccea7a19SRussell King 	if (cpu >= NR_CPUS) {
424ccea7a19SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
425ccea7a19SRussell King 		BUG();
426ccea7a19SRussell King 	}
427ccea7a19SRussell King 
428ccea7a19SRussell King 	/*
429b86040a5SCatalin Marinas 	 * Define the placement constraint for the inline asm directive below.
430b86040a5SCatalin Marinas 	 * In Thumb-2, msr with an immediate value is not allowed.
431b86040a5SCatalin Marinas 	 */
432b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL
433b86040a5SCatalin Marinas #define PLC	"r"
434b86040a5SCatalin Marinas #else
435b86040a5SCatalin Marinas #define PLC	"I"
436b86040a5SCatalin Marinas #endif
437b86040a5SCatalin Marinas 
438b86040a5SCatalin Marinas 	/*
439ccea7a19SRussell King 	 * setup stacks for re-entrant exception handlers
440ccea7a19SRussell King 	 */
441ccea7a19SRussell King 	__asm__ (
442ccea7a19SRussell King 	"msr	cpsr_c, %1\n\t"
443b86040a5SCatalin Marinas 	"add	r14, %0, %2\n\t"
444b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
445ccea7a19SRussell King 	"msr	cpsr_c, %3\n\t"
446b86040a5SCatalin Marinas 	"add	r14, %0, %4\n\t"
447b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
448ccea7a19SRussell King 	"msr	cpsr_c, %5\n\t"
449b86040a5SCatalin Marinas 	"add	r14, %0, %6\n\t"
450b86040a5SCatalin Marinas 	"mov	sp, r14\n\t"
451ccea7a19SRussell King 	"msr	cpsr_c, %7"
452ccea7a19SRussell King 	    :
453ccea7a19SRussell King 	    : "r" (stk),
454b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
455ccea7a19SRussell King 	      "I" (offsetof(struct stack, irq[0])),
456b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
457ccea7a19SRussell King 	      "I" (offsetof(struct stack, abt[0])),
458b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
459ccea7a19SRussell King 	      "I" (offsetof(struct stack, und[0])),
460b86040a5SCatalin Marinas 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
461aaaa3f9eSCatalin Marinas 	    : "r14");
462ccea7a19SRussell King }
463ccea7a19SRussell King 
4641da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr)
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds 	struct machine_desc *list;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	/*
4691da177e4SLinus Torvalds 	 * locate machine in the list of supported machines.
4701da177e4SLinus Torvalds 	 */
4711da177e4SLinus Torvalds 	list = lookup_machine_type(nr);
4721da177e4SLinus Torvalds 	if (!list) {
4731da177e4SLinus Torvalds 		printk("Machine configuration botched (nr %d), unable "
4741da177e4SLinus Torvalds 		       "to continue.\n", nr);
4751da177e4SLinus Torvalds 		while (1);
4761da177e4SLinus Torvalds 	}
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 	printk("Machine: %s\n", list->name);
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	return list;
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
4834b5f32ceSNicolas Pitre static int __init arm_add_memory(unsigned long start, unsigned long size)
4843a669411SRussell King {
4854b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
4864b5f32ceSNicolas Pitre 
4874b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
4884b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
4894b5f32ceSNicolas Pitre 			"ignoring memory at %#lx\n", start);
4904b5f32ceSNicolas Pitre 		return -EINVAL;
4914b5f32ceSNicolas Pitre 	}
49205f96ef1SRussell King 
4933a669411SRussell King 	/*
4943a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
4953a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
4963a669411SRussell King 	 */
4973a669411SRussell King 	size -= start & ~PAGE_MASK;
49805f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
49905f96ef1SRussell King 	bank->size  = size & PAGE_MASK;
5004b5f32ceSNicolas Pitre 
5014b5f32ceSNicolas Pitre 	/*
5024b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
5034b5f32ceSNicolas Pitre 	 * invalid node number.
5044b5f32ceSNicolas Pitre 	 */
505be370302SRussell King 	if (bank->size == 0)
5064b5f32ceSNicolas Pitre 		return -EINVAL;
5074b5f32ceSNicolas Pitre 
5084b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
5094b5f32ceSNicolas Pitre 	return 0;
5103a669411SRussell King }
5113a669411SRussell King 
5121da177e4SLinus Torvalds /*
5131da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
5141da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
5151da177e4SLinus Torvalds  */
5162b0d8c25SJeremy Kerr static int __init early_mem(char *p)
5171da177e4SLinus Torvalds {
5181da177e4SLinus Torvalds 	static int usermem __initdata = 0;
5191da177e4SLinus Torvalds 	unsigned long size, start;
5202b0d8c25SJeremy Kerr 	char *endp;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	/*
5231da177e4SLinus Torvalds 	 * If the user specifies memory size, we
5241da177e4SLinus Torvalds 	 * blow away any automatically generated
5251da177e4SLinus Torvalds 	 * size.
5261da177e4SLinus Torvalds 	 */
5271da177e4SLinus Torvalds 	if (usermem == 0) {
5281da177e4SLinus Torvalds 		usermem = 1;
5291da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
5301da177e4SLinus Torvalds 	}
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 	start = PHYS_OFFSET;
5332b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
5342b0d8c25SJeremy Kerr 	if (*endp == '@')
5352b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
5361da177e4SLinus Torvalds 
5371c97b73eSAndrew Morton 	arm_add_memory(start, size);
5381da177e4SLinus Torvalds 
5392b0d8c25SJeremy Kerr 	return 0;
5401da177e4SLinus Torvalds }
5412b0d8c25SJeremy Kerr early_param("mem", early_mem);
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds static void __init
5441da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
5451da177e4SLinus Torvalds {
5461da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
5471da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	rd_image_start = image_start;
5501da177e4SLinus Torvalds 	rd_prompt = prompt;
5511da177e4SLinus Torvalds 	rd_doload = doload;
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds 	if (rd_sz)
5541da177e4SLinus Torvalds 		rd_size = rd_sz;
5551da177e4SLinus Torvalds #endif
5561da177e4SLinus Torvalds }
5571da177e4SLinus Torvalds 
55811b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc)
5591da177e4SLinus Torvalds {
56011b9369cSDima Zavin 	struct memblock_region *region;
5611da177e4SLinus Torvalds 	struct resource *res;
5621da177e4SLinus Torvalds 
56337efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
56437efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
565842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
56637efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
5671da177e4SLinus Torvalds 
56811b9369cSDima Zavin 	for_each_memblock(memory, region) {
5691da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
5701da177e4SLinus Torvalds 		res->name  = "System RAM";
57111b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
57211b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
5731da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
5781da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
5791da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
5801da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
5811da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
5821da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
5831da177e4SLinus Torvalds 	}
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	if (mdesc->video_start) {
5861da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
5871da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
5881da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
5891da177e4SLinus Torvalds 	}
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	/*
5921da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
5931da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
5941da177e4SLinus Torvalds 	 */
5951da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
5961da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
5971da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
5981da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
5991da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
6001da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
6011da177e4SLinus Torvalds }
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds /*
6041da177e4SLinus Torvalds  *  Tag parsing.
6051da177e4SLinus Torvalds  *
6061da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
6071da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
6081da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
6091da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
6101da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
6111da177e4SLinus Torvalds  * is not parsed in any way).
6121da177e4SLinus Torvalds  */
6131da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
6141da177e4SLinus Torvalds {
6151da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
6161da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
6171da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
6181da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
6191da177e4SLinus Torvalds 	}
6201da177e4SLinus Torvalds 	return 0;
6211da177e4SLinus Torvalds }
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
6261da177e4SLinus Torvalds {
6274b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
6331da177e4SLinus Torvalds struct screen_info screen_info = {
6341da177e4SLinus Torvalds  .orig_video_lines	= 30,
6351da177e4SLinus Torvalds  .orig_video_cols	= 80,
6361da177e4SLinus Torvalds  .orig_video_mode	= 0,
6371da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
6381da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
6391da177e4SLinus Torvalds  .orig_video_points	= 8
6401da177e4SLinus Torvalds };
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
6451da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
6461da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
6471da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
6481da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
6491da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
6501da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
6511da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
6521da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
6531da177e4SLinus Torvalds 	return 0;
6541da177e4SLinus Torvalds }
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
6571da177e4SLinus Torvalds #endif
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
6601da177e4SLinus Torvalds {
6611da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
6621da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
6631da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
6641da177e4SLinus Torvalds 	return 0;
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
6701da177e4SLinus Torvalds {
6711da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
6721da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
6731da177e4SLinus Torvalds 	return 0;
6741da177e4SLinus Torvalds }
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
6791da177e4SLinus Torvalds {
6801da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
6811da177e4SLinus Torvalds 	return 0;
6821da177e4SLinus Torvalds }
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
6871da177e4SLinus Torvalds {
68822eeb8f6SAlexander Holler #ifndef CONFIG_CMDLINE_FORCE
6891da177e4SLinus Torvalds 	strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
69022eeb8f6SAlexander Holler #else
69122eeb8f6SAlexander Holler 	pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
69222eeb8f6SAlexander Holler #endif /* CONFIG_CMDLINE_FORCE */
6931da177e4SLinus Torvalds 	return 0;
6941da177e4SLinus Torvalds }
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds /*
6991da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
7001da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
7011da177e4SLinus Torvalds  * declarations.
7021da177e4SLinus Torvalds  */
7031da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
7041da177e4SLinus Torvalds {
7051da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
7061da177e4SLinus Torvalds 	struct tagtable *t;
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
7091da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
7101da177e4SLinus Torvalds 			t->parse(tag);
7111da177e4SLinus Torvalds 			break;
7121da177e4SLinus Torvalds 		}
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	return t < &__tagtable_end;
7151da177e4SLinus Torvalds }
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds /*
7181da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
7191da177e4SLinus Torvalds  * specific tag tables.
7201da177e4SLinus Torvalds  */
7211da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
7221da177e4SLinus Torvalds {
7231da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
7241da177e4SLinus Torvalds 		if (!parse_tag(t))
7251da177e4SLinus Torvalds 			printk(KERN_WARNING
7261da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
7271da177e4SLinus Torvalds 				t->hdr.tag);
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds /*
7311da177e4SLinus Torvalds  * This holds our defaults.
7321da177e4SLinus Torvalds  */
7331da177e4SLinus Torvalds static struct init_tags {
7341da177e4SLinus Torvalds 	struct tag_header hdr1;
7351da177e4SLinus Torvalds 	struct tag_core   core;
7361da177e4SLinus Torvalds 	struct tag_header hdr2;
7371da177e4SLinus Torvalds 	struct tag_mem32  mem;
7381da177e4SLinus Torvalds 	struct tag_header hdr3;
7391da177e4SLinus Torvalds } init_tags __initdata = {
7401da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
7411da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
7421da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
743b75c178aSRussell King 	{ MEM_SIZE },
7441da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
7451da177e4SLinus Torvalds };
7461da177e4SLinus Torvalds 
7471da177e4SLinus Torvalds static int __init customize_machine(void)
7481da177e4SLinus Torvalds {
7491da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
7508ff1443cSRussell King 	if (machine_desc->init_machine)
7518ff1443cSRussell King 		machine_desc->init_machine();
7521da177e4SLinus Torvalds 	return 0;
7531da177e4SLinus Torvalds }
7541da177e4SLinus Torvalds arch_initcall(customize_machine);
7551da177e4SLinus Torvalds 
7563c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
7573c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
7583c57fb43SMika Westerberg {
7593c57fb43SMika Westerberg 	unsigned long total;
7603c57fb43SMika Westerberg 
7613c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
7623c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
7633c57fb43SMika Westerberg }
7643c57fb43SMika Westerberg 
7653c57fb43SMika Westerberg /**
7663c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
7673c57fb43SMika Westerberg  *
7683c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
7693c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
7703c57fb43SMika Westerberg  * primary kernel is crashing.
7713c57fb43SMika Westerberg  */
7723c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
7733c57fb43SMika Westerberg {
7743c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
7753c57fb43SMika Westerberg 	unsigned long long total_mem;
7763c57fb43SMika Westerberg 	int ret;
7773c57fb43SMika Westerberg 
7783c57fb43SMika Westerberg 	total_mem = get_total_mem();
7793c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
7803c57fb43SMika Westerberg 				&crash_size, &crash_base);
7813c57fb43SMika Westerberg 	if (ret)
7823c57fb43SMika Westerberg 		return;
7833c57fb43SMika Westerberg 
7843c57fb43SMika Westerberg 	ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
7853c57fb43SMika Westerberg 	if (ret < 0) {
7863c57fb43SMika Westerberg 		printk(KERN_WARNING "crashkernel reservation failed - "
7873c57fb43SMika Westerberg 		       "memory is in use (0x%lx)\n", (unsigned long)crash_base);
7883c57fb43SMika Westerberg 		return;
7893c57fb43SMika Westerberg 	}
7903c57fb43SMika Westerberg 
7913c57fb43SMika Westerberg 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
7923c57fb43SMika Westerberg 	       "for crashkernel (System RAM: %ldMB)\n",
7933c57fb43SMika Westerberg 	       (unsigned long)(crash_size >> 20),
7943c57fb43SMika Westerberg 	       (unsigned long)(crash_base >> 20),
7953c57fb43SMika Westerberg 	       (unsigned long)(total_mem >> 20));
7963c57fb43SMika Westerberg 
7973c57fb43SMika Westerberg 	crashk_res.start = crash_base;
7983c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
7993c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
8003c57fb43SMika Westerberg }
8013c57fb43SMika Westerberg #else
8023c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
8033c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
8043c57fb43SMika Westerberg 
805cea0bb1bSMika Westerberg /*
806cea0bb1bSMika Westerberg  * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
807cea0bb1bSMika Westerberg  * is_kdump_kernel() to determine if we are booting after a panic. Hence
808cea0bb1bSMika Westerberg  * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
809cea0bb1bSMika Westerberg  */
810cea0bb1bSMika Westerberg 
811cea0bb1bSMika Westerberg #ifdef CONFIG_CRASH_DUMP
812cea0bb1bSMika Westerberg /*
813cea0bb1bSMika Westerberg  * elfcorehdr= specifies the location of elf core header stored by the crashed
814cea0bb1bSMika Westerberg  * kernel. This option will be passed by kexec loader to the capture kernel.
815cea0bb1bSMika Westerberg  */
816cea0bb1bSMika Westerberg static int __init setup_elfcorehdr(char *arg)
817cea0bb1bSMika Westerberg {
818cea0bb1bSMika Westerberg 	char *end;
819cea0bb1bSMika Westerberg 
820cea0bb1bSMika Westerberg 	if (!arg)
821cea0bb1bSMika Westerberg 		return -EINVAL;
822cea0bb1bSMika Westerberg 
823cea0bb1bSMika Westerberg 	elfcorehdr_addr = memparse(arg, &end);
824cea0bb1bSMika Westerberg 	return end > arg ? 0 : -EINVAL;
825cea0bb1bSMika Westerberg }
826cea0bb1bSMika Westerberg early_param("elfcorehdr", setup_elfcorehdr);
827cea0bb1bSMika Westerberg #endif /* CONFIG_CRASH_DUMP */
828cea0bb1bSMika Westerberg 
82973a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag)
83073a65b3fSUwe Kleine-König {
83173a65b3fSUwe Kleine-König 	for (; tag->hdr.size; tag = tag_next(tag))
83273a65b3fSUwe Kleine-König 		if (tag->hdr.tag == ATAG_MEM)
83373a65b3fSUwe Kleine-König 			tag->hdr.tag = ATAG_NONE;
83473a65b3fSUwe Kleine-König }
83573a65b3fSUwe Kleine-König 
8361da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p)
8371da177e4SLinus Torvalds {
8381da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
8391da177e4SLinus Torvalds 	struct machine_desc *mdesc;
8401da177e4SLinus Torvalds 	char *from = default_command_line;
8411da177e4SLinus Torvalds 
842b75c178aSRussell King 	init_tags.mem.start = PHYS_OFFSET;
843b75c178aSRussell King 
844bff595c1SCatalin Marinas 	unwind_init();
845bff595c1SCatalin Marinas 
8461da177e4SLinus Torvalds 	setup_processor();
8471da177e4SLinus Torvalds 	mdesc = setup_machine(machine_arch_type);
8488ff1443cSRussell King 	machine_desc = mdesc;
8491da177e4SLinus Torvalds 	machine_name = mdesc->name;
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	if (mdesc->soft_reboot)
8521da177e4SLinus Torvalds 		reboot_setup("s");
8531da177e4SLinus Torvalds 
8549d20fdd5SBill Gatliff 	if (__atags_pointer)
8559d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
8569d20fdd5SBill Gatliff 	else if (mdesc->boot_params)
857f9bd6ea4SRussell King 		tags = phys_to_virt(mdesc->boot_params);
8581da177e4SLinus Torvalds 
85973a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
8601da177e4SLinus Torvalds 	/*
8611da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
8621da177e4SLinus Torvalds 	 * a tag list.
8631da177e4SLinus Torvalds 	 */
8641da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
8651da177e4SLinus Torvalds 		convert_to_tag_list(tags);
86673a65b3fSUwe Kleine-König #endif
8671da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
8681da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 	if (mdesc->fixup)
8711da177e4SLinus Torvalds 		mdesc->fixup(mdesc, tags, &from, &meminfo);
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
8741da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
8751da177e4SLinus Torvalds 			squash_mem_tags(tags);
8764cd9d6f7SRichard Purdie 		save_atags(tags);
8771da177e4SLinus Torvalds 		parse_tags(tags);
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 
88037efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
88137efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
88237efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
88337efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
8841da177e4SLinus Torvalds 
8852b0d8c25SJeremy Kerr 	/* parse_early_param needs a boot_command_line */
8862b0d8c25SJeremy Kerr 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
8872b0d8c25SJeremy Kerr 
88848ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
88948ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
89048ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
8912b0d8c25SJeremy Kerr 
8922b0d8c25SJeremy Kerr 	parse_early_param();
8932b0d8c25SJeremy Kerr 
8948d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
8952778f620SRussell King 
8964b5f32ceSNicolas Pitre 	paging_init(mdesc);
89711b9369cSDima Zavin 	request_standard_resources(mdesc);
8981da177e4SLinus Torvalds 
8997bbb7940SRussell King #ifdef CONFIG_SMP
900f00ec48fSRussell King 	if (is_smp())
9017bbb7940SRussell King 		smp_init_cpus();
9027bbb7940SRussell King #endif
9033c57fb43SMika Westerberg 	reserve_crashkernel();
9047bbb7940SRussell King 
905ccea7a19SRussell King 	cpu_init();
906bc581770SLinus Walleij 	tcm_init();
907ccea7a19SRussell King 
90852108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
90952108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
91052108641Seric miao #endif
9111da177e4SLinus Torvalds 
9121da177e4SLinus Torvalds #ifdef CONFIG_VT
9131da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9141da177e4SLinus Torvalds 	conswitchp = &vga_con;
9151da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9161da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9171da177e4SLinus Torvalds #endif
9181da177e4SLinus Torvalds #endif
9195cbad0ebSJason Wessel 	early_trap_init();
920dec12e62SRussell King 
921dec12e62SRussell King 	if (mdesc->init_early)
922dec12e62SRussell King 		mdesc->init_early();
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds static int __init topology_init(void)
9271da177e4SLinus Torvalds {
9281da177e4SLinus Torvalds 	int cpu;
9291da177e4SLinus Torvalds 
93066fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
93166fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
93266fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
93366fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
93466fb8bd2SRussell King 	}
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	return 0;
9371da177e4SLinus Torvalds }
9381da177e4SLinus Torvalds subsys_initcall(topology_init);
9391da177e4SLinus Torvalds 
940e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
941e119bfffSRussell King static int __init proc_cpu_init(void)
942e119bfffSRussell King {
943e119bfffSRussell King 	struct proc_dir_entry *res;
944e119bfffSRussell King 
945e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
946e119bfffSRussell King 	if (!res)
947e119bfffSRussell King 		return -ENOMEM;
948e119bfffSRussell King 	return 0;
949e119bfffSRussell King }
950e119bfffSRussell King fs_initcall(proc_cpu_init);
951e119bfffSRussell King #endif
952e119bfffSRussell King 
9531da177e4SLinus Torvalds static const char *hwcap_str[] = {
9541da177e4SLinus Torvalds 	"swp",
9551da177e4SLinus Torvalds 	"half",
9561da177e4SLinus Torvalds 	"thumb",
9571da177e4SLinus Torvalds 	"26bit",
9581da177e4SLinus Torvalds 	"fastmult",
9591da177e4SLinus Torvalds 	"fpa",
9601da177e4SLinus Torvalds 	"vfp",
9611da177e4SLinus Torvalds 	"edsp",
9621da177e4SLinus Torvalds 	"java",
9638f7f9435SPaul Gortmaker 	"iwmmxt",
96499e4a6ddSLennert Buytenhek 	"crunch",
9654369ae16SCatalin Marinas 	"thumbee",
9662bedbdf4SCatalin Marinas 	"neon",
9677279dc3eSCatalin Marinas 	"vfpv3",
9687279dc3eSCatalin Marinas 	"vfpv3d16",
9691da177e4SLinus Torvalds 	NULL
9701da177e4SLinus Torvalds };
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
9731da177e4SLinus Torvalds {
9741da177e4SLinus Torvalds 	int i;
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
9770ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds #if defined(CONFIG_SMP)
9801da177e4SLinus Torvalds 	for_each_online_cpu(i) {
98115559722SRussell King 		/*
98215559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
98315559722SRussell King 		 * online processors, looking for lines beginning with
98415559722SRussell King 		 * "processor".  Give glibc what it expects.
98515559722SRussell King 		 */
98615559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
9871da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
9881da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
9891da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
9901da177e4SLinus Torvalds 	}
9911da177e4SLinus Torvalds #else /* CONFIG_SMP */
9921da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
9931da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
9941da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
9951da177e4SLinus Torvalds #endif
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 	/* dump out the processor features */
9981da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
10011da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
10021da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
10031da177e4SLinus Torvalds 
10040ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
10051da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
10061da177e4SLinus Torvalds 
10070ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
10081da177e4SLinus Torvalds 		/* pre-ARM7 */
10090ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
10101da177e4SLinus Torvalds 	} else {
10110ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
10121da177e4SLinus Torvalds 			/* ARM7 */
10131da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
10140ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
10151da177e4SLinus Torvalds 		} else {
10161da177e4SLinus Torvalds 			/* post-ARM7 */
10171da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
10180ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
10191da177e4SLinus Torvalds 		}
10201da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
10210ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
10221da177e4SLinus Torvalds 	}
10230ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
10241da177e4SLinus Torvalds 
10251da177e4SLinus Torvalds 	seq_puts(m, "\n");
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
10281da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
10291da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
10301da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
10311da177e4SLinus Torvalds 
10321da177e4SLinus Torvalds 	return 0;
10331da177e4SLinus Torvalds }
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
10361da177e4SLinus Torvalds {
10371da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
10381da177e4SLinus Torvalds }
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
10411da177e4SLinus Torvalds {
10421da177e4SLinus Torvalds 	++*pos;
10431da177e4SLinus Torvalds 	return NULL;
10441da177e4SLinus Torvalds }
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
10471da177e4SLinus Torvalds {
10481da177e4SLinus Torvalds }
10491da177e4SLinus Torvalds 
10502ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
10511da177e4SLinus Torvalds 	.start	= c_start,
10521da177e4SLinus Torvalds 	.next	= c_next,
10531da177e4SLinus Torvalds 	.stop	= c_stop,
10541da177e4SLinus Torvalds 	.show	= c_show
10551da177e4SLinus Torvalds };
1056