xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 9811ccdf)
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  */
10ecea4ab6SPaul Gortmaker #include <linux/export.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>
2393c02ab4SGrant Likely #include <linux/of_fdt.h>
24cea0bb1bSMika Westerberg #include <linux/crash_dump.h>
251da177e4SLinus Torvalds #include <linux/root_dev.h>
261da177e4SLinus Torvalds #include <linux/cpu.h>
271da177e4SLinus Torvalds #include <linux/interrupt.h>
287bbb7940SRussell King #include <linux/smp.h>
294e950f6fSAlexey Dobriyan #include <linux/fs.h>
30e119bfffSRussell King #include <linux/proc_fs.h>
312778f620SRussell King #include <linux/memblock.h>
322ecccf90SDave Martin #include <linux/bug.h>
332ecccf90SDave Martin #include <linux/compiler.h>
341da177e4SLinus Torvalds 
35b86040a5SCatalin Marinas #include <asm/unified.h>
361da177e4SLinus Torvalds #include <asm/cpu.h>
370ba8b9b2SRussell King #include <asm/cputype.h>
381da177e4SLinus Torvalds #include <asm/elf.h>
391da177e4SLinus Torvalds #include <asm/procinfo.h>
4037efe642SRussell King #include <asm/sections.h>
411da177e4SLinus Torvalds #include <asm/setup.h>
42f00ec48fSRussell King #include <asm/smp_plat.h>
431da177e4SLinus Torvalds #include <asm/mach-types.h>
441da177e4SLinus Torvalds #include <asm/cacheflush.h>
4546097c7dSRussell King #include <asm/cachetype.h>
461da177e4SLinus Torvalds #include <asm/tlbflush.h>
472ecccf90SDave Martin #include <asm/system.h>
481da177e4SLinus Torvalds 
4993c02ab4SGrant Likely #include <asm/prom.h>
501da177e4SLinus Torvalds #include <asm/mach/arch.h>
511da177e4SLinus Torvalds #include <asm/mach/irq.h>
521da177e4SLinus Torvalds #include <asm/mach/time.h>
535cbad0ebSJason Wessel #include <asm/traps.h>
54bff595c1SCatalin Marinas #include <asm/unwind.h>
551da177e4SLinus Torvalds 
5673a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
570fc1c832SBen Dooks #include "compat.h"
5873a65b3fSUwe Kleine-König #endif
594cd9d6f7SRichard Purdie #include "atags.h"
60bc581770SLinus Walleij #include "tcm.h"
610fc1c832SBen Dooks 
621da177e4SLinus Torvalds #ifndef MEM_SIZE
631da177e4SLinus Torvalds #define MEM_SIZE	(16*1024*1024)
641da177e4SLinus Torvalds #endif
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
671da177e4SLinus Torvalds char fpe_type[8];
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds static int __init fpe_setup(char *line)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
721da177e4SLinus Torvalds 	return 1;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
761da177e4SLinus Torvalds #endif
771da177e4SLinus Torvalds 
784b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
790371d3f7SRussell King extern void sanity_check_meminfo(void);
801da177e4SLinus Torvalds extern void reboot_setup(char *str);
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds unsigned int processor_id;
83c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
840385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
851da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
860385ebc0SRussell King unsigned int cacheid __read_mostly;
87c0e95878SRussell King EXPORT_SYMBOL(cacheid);
881da177e4SLinus Torvalds 
899d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
909d20fdd5SBill Gatliff 
911da177e4SLinus Torvalds unsigned int system_rev;
921da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds unsigned int system_serial_low;
951da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds unsigned int system_serial_high;
981da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
991da177e4SLinus Torvalds 
1000385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
1011da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds #ifdef MULTI_CPU
1050385ebc0SRussell King struct processor processor __read_mostly;
1061da177e4SLinus Torvalds #endif
1071da177e4SLinus Torvalds #ifdef MULTI_TLB
1080385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1091da177e4SLinus Torvalds #endif
1101da177e4SLinus Torvalds #ifdef MULTI_USER
1110385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1121da177e4SLinus Torvalds #endif
1131da177e4SLinus Torvalds #ifdef MULTI_CACHE
1140385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1151da177e4SLinus Torvalds #endif
116953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1170385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1186c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
119953233dcSCatalin Marinas #endif
1201da177e4SLinus Torvalds 
1212ecccf90SDave Martin /*
1222ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1232ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1242ecccf90SDave Martin  * variable directly.
1252ecccf90SDave Martin  */
1262ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1272ecccf90SDave Martin 
128ccea7a19SRussell King struct stack {
129ccea7a19SRussell King 	u32 irq[3];
130ccea7a19SRussell King 	u32 abt[3];
131ccea7a19SRussell King 	u32 und[3];
132ccea7a19SRussell King } ____cacheline_aligned;
133ccea7a19SRussell King 
134ccea7a19SRussell King static struct stack stacks[NR_CPUS];
135ccea7a19SRussell King 
1361da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1371da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds static const char *cpu_name;
1401da177e4SLinus Torvalds static const char *machine_name;
14148ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
1428ff1443cSRussell King struct machine_desc *machine_desc __initdata;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
1451da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1461da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds /*
1511da177e4SLinus Torvalds  * Standard memory resources
1521da177e4SLinus Torvalds  */
1531da177e4SLinus Torvalds static struct resource mem_res[] = {
154740e518eSGreg Kroah-Hartman 	{
155740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
156740e518eSGreg Kroah-Hartman 		.start = 0,
157740e518eSGreg Kroah-Hartman 		.end = 0,
158740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
159740e518eSGreg Kroah-Hartman 	},
160740e518eSGreg Kroah-Hartman 	{
161740e518eSGreg Kroah-Hartman 		.name = "Kernel text",
162740e518eSGreg Kroah-Hartman 		.start = 0,
163740e518eSGreg Kroah-Hartman 		.end = 0,
164740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
165740e518eSGreg Kroah-Hartman 	},
166740e518eSGreg Kroah-Hartman 	{
167740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
168740e518eSGreg Kroah-Hartman 		.start = 0,
169740e518eSGreg Kroah-Hartman 		.end = 0,
170740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
171740e518eSGreg Kroah-Hartman 	}
1721da177e4SLinus Torvalds };
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds #define video_ram   mem_res[0]
1751da177e4SLinus Torvalds #define kernel_code mem_res[1]
1761da177e4SLinus Torvalds #define kernel_data mem_res[2]
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds static struct resource io_res[] = {
179740e518eSGreg Kroah-Hartman 	{
180740e518eSGreg Kroah-Hartman 		.name = "reserved",
181740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
182740e518eSGreg Kroah-Hartman 		.end = 0x3be,
183740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
184740e518eSGreg Kroah-Hartman 	},
185740e518eSGreg Kroah-Hartman 	{
186740e518eSGreg Kroah-Hartman 		.name = "reserved",
187740e518eSGreg Kroah-Hartman 		.start = 0x378,
188740e518eSGreg Kroah-Hartman 		.end = 0x37f,
189740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
190740e518eSGreg Kroah-Hartman 	},
191740e518eSGreg Kroah-Hartman 	{
192740e518eSGreg Kroah-Hartman 		.name = "reserved",
193740e518eSGreg Kroah-Hartman 		.start = 0x278,
194740e518eSGreg Kroah-Hartman 		.end = 0x27f,
195740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
196740e518eSGreg Kroah-Hartman 	}
1971da177e4SLinus Torvalds };
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds #define lp0 io_res[0]
2001da177e4SLinus Torvalds #define lp1 io_res[1]
2011da177e4SLinus Torvalds #define lp2 io_res[2]
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds static const char *proc_arch[] = {
2041da177e4SLinus Torvalds 	"undefined/unknown",
2051da177e4SLinus Torvalds 	"3",
2061da177e4SLinus Torvalds 	"4",
2071da177e4SLinus Torvalds 	"4T",
2081da177e4SLinus Torvalds 	"5",
2091da177e4SLinus Torvalds 	"5T",
2101da177e4SLinus Torvalds 	"5TE",
2111da177e4SLinus Torvalds 	"5TEJ",
2121da177e4SLinus Torvalds 	"6TEJ",
2136b090a25SCatalin Marinas 	"7",
2141da177e4SLinus Torvalds 	"?(11)",
2151da177e4SLinus Torvalds 	"?(12)",
2161da177e4SLinus Torvalds 	"?(13)",
2171da177e4SLinus Torvalds 	"?(14)",
2181da177e4SLinus Torvalds 	"?(15)",
2191da177e4SLinus Torvalds 	"?(16)",
2201da177e4SLinus Torvalds 	"?(17)",
2211da177e4SLinus Torvalds };
2221da177e4SLinus Torvalds 
2232ecccf90SDave Martin static int __get_cpu_architecture(void)
2241da177e4SLinus Torvalds {
2251da177e4SLinus Torvalds 	int cpu_arch;
2261da177e4SLinus Torvalds 
2270ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2281da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2290ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2300ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2310ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2320ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2331da177e4SLinus Torvalds 		if (cpu_arch)
2341da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2350ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
236180005c4SCatalin Marinas 		unsigned int mmfr0;
237180005c4SCatalin Marinas 
238180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
239180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
240180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
241180005c4SCatalin Marinas 		    : "=r" (mmfr0));
242315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
243315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
244180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
245180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
246180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
247180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
248180005c4SCatalin Marinas 		else
249180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
250180005c4SCatalin Marinas 	} else
251180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	return cpu_arch;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds 
2562ecccf90SDave Martin int __pure cpu_architecture(void)
2572ecccf90SDave Martin {
2582ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2592ecccf90SDave Martin 
2602ecccf90SDave Martin 	return __cpu_architecture;
2612ecccf90SDave Martin }
2622ecccf90SDave Martin 
2638925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2648925ec4cSWill Deacon {
2658925ec4cSWill Deacon 	int aliasing_icache;
2668925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2678925ec4cSWill Deacon 
2687f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2697f94e9ccSWill Deacon 	if (icache_is_pipt())
2707f94e9ccSWill Deacon 		return 0;
2717f94e9ccSWill Deacon 
2728925ec4cSWill Deacon 	/* arch specifies the register format */
2738925ec4cSWill Deacon 	switch (arch) {
2748925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2755fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2765fb31a96SLinus Walleij 		    : /* No output operands */
2778925ec4cSWill Deacon 		    : "r" (1));
2785fb31a96SLinus Walleij 		isb();
2795fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2805fb31a96SLinus Walleij 		    : "=r" (id_reg));
2818925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2828925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2838925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2848925ec4cSWill Deacon 		break;
2858925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2868925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2878925ec4cSWill Deacon 		break;
2888925ec4cSWill Deacon 	default:
2898925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
2908925ec4cSWill Deacon 		aliasing_icache = 0;
2918925ec4cSWill Deacon 	}
2928925ec4cSWill Deacon 
2938925ec4cSWill Deacon 	return aliasing_icache;
2948925ec4cSWill Deacon }
2958925ec4cSWill Deacon 
296c0e95878SRussell King static void __init cacheid_init(void)
297c0e95878SRussell King {
298c0e95878SRussell King 	unsigned int cachetype = read_cpuid_cachetype();
299c0e95878SRussell King 	unsigned int arch = cpu_architecture();
300c0e95878SRussell King 
301b57ee99fSCatalin Marinas 	if (arch >= CPU_ARCH_ARMv6) {
302b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
303b57ee99fSCatalin Marinas 			/* ARMv7 register format */
30472dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
305c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3067f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3077f94e9ccSWill Deacon 			case (1 << 14):
308c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3097f94e9ccSWill Deacon 				break;
3107f94e9ccSWill Deacon 			case (3 << 14):
3117f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3127f94e9ccSWill Deacon 				break;
3137f94e9ccSWill Deacon 			}
3148925ec4cSWill Deacon 		} else {
31572dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
31672dc53acSWill Deacon 			if (cachetype & (1 << 23))
31772dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
31872dc53acSWill Deacon 			else
319c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3208925ec4cSWill Deacon 		}
32172dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
32272dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
323c0e95878SRussell King 	} else {
324c0e95878SRussell King 		cacheid = CACHEID_VIVT;
325c0e95878SRussell King 	}
3262b4ae1f1SRussell King 
3272b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
3282b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3292b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3307f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3312b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3322b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3338925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3347f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3352b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
336c0e95878SRussell King }
337c0e95878SRussell King 
3381da177e4SLinus Torvalds /*
3391da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3401da177e4SLinus Torvalds  * already provide the required functionality.
3411da177e4SLinus Torvalds  */
3420f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3436fc31d54SRussell King 
34493c02ab4SGrant Likely void __init early_print(const char *str, ...)
3456fc31d54SRussell King {
3466fc31d54SRussell King 	extern void printascii(const char *);
3476fc31d54SRussell King 	char buf[256];
3486fc31d54SRussell King 	va_list ap;
3496fc31d54SRussell King 
3506fc31d54SRussell King 	va_start(ap, str);
3516fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3526fc31d54SRussell King 	va_end(ap);
3536fc31d54SRussell King 
3546fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3556fc31d54SRussell King 	printascii(buf);
3566fc31d54SRussell King #endif
3576fc31d54SRussell King 	printk("%s", buf);
3586fc31d54SRussell King }
3596fc31d54SRussell King 
360f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
361f159f4edSTony Lindgren {
362f159f4edSTony Lindgren 	int id = read_cpuid_id();
363f159f4edSTony Lindgren 
364f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
365f159f4edSTony Lindgren 		return;
366f159f4edSTony Lindgren 
367f159f4edSTony Lindgren 	/*
368f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
369f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
370f159f4edSTony Lindgren 	 */
371f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
372f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
373f159f4edSTony Lindgren }
374f159f4edSTony Lindgren 
375b69874e4SRussell King /*
376b69874e4SRussell King  * cpu_init - initialise one CPU.
377b69874e4SRussell King  *
378b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
379b69874e4SRussell King  */
380b69874e4SRussell King void cpu_init(void)
381b69874e4SRussell King {
382b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
383b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
384b69874e4SRussell King 
385b69874e4SRussell King 	if (cpu >= NR_CPUS) {
386b69874e4SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
387b69874e4SRussell King 		BUG();
388b69874e4SRussell King 	}
389b69874e4SRussell King 
390b69874e4SRussell King 	cpu_proc_init();
391b69874e4SRussell King 
392b69874e4SRussell King 	/*
393b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
394b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
395b69874e4SRussell King 	 */
396b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
397b69874e4SRussell King #define PLC	"r"
398b69874e4SRussell King #else
399b69874e4SRussell King #define PLC	"I"
400b69874e4SRussell King #endif
401b69874e4SRussell King 
402b69874e4SRussell King 	/*
403b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
404b69874e4SRussell King 	 */
405b69874e4SRussell King 	__asm__ (
406b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
407b69874e4SRussell King 	"add	r14, %0, %2\n\t"
408b69874e4SRussell King 	"mov	sp, r14\n\t"
409b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
410b69874e4SRussell King 	"add	r14, %0, %4\n\t"
411b69874e4SRussell King 	"mov	sp, r14\n\t"
412b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
413b69874e4SRussell King 	"add	r14, %0, %6\n\t"
414b69874e4SRussell King 	"mov	sp, r14\n\t"
415b69874e4SRussell King 	"msr	cpsr_c, %7"
416b69874e4SRussell King 	    :
417b69874e4SRussell King 	    : "r" (stk),
418b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
419b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
420b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
421b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
422b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
423b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
424b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
425b69874e4SRussell King 	    : "r14");
426b69874e4SRussell King }
427b69874e4SRussell King 
4281da177e4SLinus Torvalds static void __init setup_processor(void)
4291da177e4SLinus Torvalds {
4301da177e4SLinus Torvalds 	struct proc_info_list *list;
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 	/*
4331da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
4341da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
4351da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
4361da177e4SLinus Torvalds 	 */
4370ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
4381da177e4SLinus Torvalds 	if (!list) {
4391da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
4400ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
4411da177e4SLinus Torvalds 		while (1);
4421da177e4SLinus Torvalds 	}
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
4452ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds #ifdef MULTI_CPU
4481da177e4SLinus Torvalds 	processor = *list->proc;
4491da177e4SLinus Torvalds #endif
4501da177e4SLinus Torvalds #ifdef MULTI_TLB
4511da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
4521da177e4SLinus Torvalds #endif
4531da177e4SLinus Torvalds #ifdef MULTI_USER
4541da177e4SLinus Torvalds 	cpu_user = *list->user;
4551da177e4SLinus Torvalds #endif
4561da177e4SLinus Torvalds #ifdef MULTI_CACHE
4571da177e4SLinus Torvalds 	cpu_cache = *list->cache;
4581da177e4SLinus Torvalds #endif
4591da177e4SLinus Torvalds 
4604e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
4610ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
462264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
4631da177e4SLinus Torvalds 
464a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
465a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
466a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
467a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
4681da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
469adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
470adeff422SCatalin Marinas 	elf_hwcap &= ~HWCAP_THUMB;
471adeff422SCatalin Marinas #endif
4721da177e4SLinus Torvalds 
473f159f4edSTony Lindgren 	feat_v6_fixup();
474f159f4edSTony Lindgren 
475c0e95878SRussell King 	cacheid_init();
476b69874e4SRussell King 	cpu_init();
477ccea7a19SRussell King }
478ccea7a19SRussell King 
47993c02ab4SGrant Likely void __init dump_machine_table(void)
4801da177e4SLinus Torvalds {
481dce72dd0SNicolas Pitre 	struct machine_desc *p;
4821da177e4SLinus Torvalds 
4836291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
4846291319dSGrant Likely 	for_each_machine_desc(p)
485dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
486dce72dd0SNicolas Pitre 
487dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
488dce72dd0SNicolas Pitre 
489dce72dd0SNicolas Pitre 	while (true)
490dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds 
4939eb8f674SGrant Likely int __init arm_add_memory(phys_addr_t start, unsigned long size)
4943a669411SRussell King {
4954b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
4964b5f32ceSNicolas Pitre 
4974b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
4984b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
49929a38193SWill Deacon 			"ignoring memory at 0x%08llx\n", (long long)start);
5004b5f32ceSNicolas Pitre 		return -EINVAL;
5014b5f32ceSNicolas Pitre 	}
50205f96ef1SRussell King 
5033a669411SRussell King 	/*
5043a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
5053a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
5063a669411SRussell King 	 */
5073a669411SRussell King 	size -= start & ~PAGE_MASK;
50805f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
50905f96ef1SRussell King 	bank->size  = size & PAGE_MASK;
5104b5f32ceSNicolas Pitre 
5114b5f32ceSNicolas Pitre 	/*
5124b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
5134b5f32ceSNicolas Pitre 	 * invalid node number.
5144b5f32ceSNicolas Pitre 	 */
515be370302SRussell King 	if (bank->size == 0)
5164b5f32ceSNicolas Pitre 		return -EINVAL;
5174b5f32ceSNicolas Pitre 
5184b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
5194b5f32ceSNicolas Pitre 	return 0;
5203a669411SRussell King }
5213a669411SRussell King 
5221da177e4SLinus Torvalds /*
5231da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
5241da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
5251da177e4SLinus Torvalds  */
5262b0d8c25SJeremy Kerr static int __init early_mem(char *p)
5271da177e4SLinus Torvalds {
5281da177e4SLinus Torvalds 	static int usermem __initdata = 0;
529f60892d3SWill Deacon 	unsigned long size;
530f60892d3SWill Deacon 	phys_addr_t start;
5312b0d8c25SJeremy Kerr 	char *endp;
5321da177e4SLinus Torvalds 
5331da177e4SLinus Torvalds 	/*
5341da177e4SLinus Torvalds 	 * If the user specifies memory size, we
5351da177e4SLinus Torvalds 	 * blow away any automatically generated
5361da177e4SLinus Torvalds 	 * size.
5371da177e4SLinus Torvalds 	 */
5381da177e4SLinus Torvalds 	if (usermem == 0) {
5391da177e4SLinus Torvalds 		usermem = 1;
5401da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
5411da177e4SLinus Torvalds 	}
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 	start = PHYS_OFFSET;
5442b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
5452b0d8c25SJeremy Kerr 	if (*endp == '@')
5462b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
5471da177e4SLinus Torvalds 
5481c97b73eSAndrew Morton 	arm_add_memory(start, size);
5491da177e4SLinus Torvalds 
5502b0d8c25SJeremy Kerr 	return 0;
5511da177e4SLinus Torvalds }
5522b0d8c25SJeremy Kerr early_param("mem", early_mem);
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds static void __init
5551da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
5561da177e4SLinus Torvalds {
5571da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM
5581da177e4SLinus Torvalds 	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
5591da177e4SLinus Torvalds 
5601da177e4SLinus Torvalds 	rd_image_start = image_start;
5611da177e4SLinus Torvalds 	rd_prompt = prompt;
5621da177e4SLinus Torvalds 	rd_doload = doload;
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds 	if (rd_sz)
5651da177e4SLinus Torvalds 		rd_size = rd_sz;
5661da177e4SLinus Torvalds #endif
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
56911b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc)
5701da177e4SLinus Torvalds {
57111b9369cSDima Zavin 	struct memblock_region *region;
5721da177e4SLinus Torvalds 	struct resource *res;
5731da177e4SLinus Torvalds 
57437efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
57537efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
576842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
57737efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
5781da177e4SLinus Torvalds 
57911b9369cSDima Zavin 	for_each_memblock(memory, region) {
5801da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
5811da177e4SLinus Torvalds 		res->name  = "System RAM";
58211b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
58311b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
5841da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
5891da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
5901da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
5911da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
5921da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
5931da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
5941da177e4SLinus Torvalds 	}
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 	if (mdesc->video_start) {
5971da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
5981da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
5991da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
6001da177e4SLinus Torvalds 	}
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 	/*
6031da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
6041da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
6051da177e4SLinus Torvalds 	 */
6061da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
6071da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
6081da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
6091da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
6101da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
6111da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
6121da177e4SLinus Torvalds }
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds /*
6151da177e4SLinus Torvalds  *  Tag parsing.
6161da177e4SLinus Torvalds  *
6171da177e4SLinus Torvalds  * This is the new way of passing data to the kernel at boot time.  Rather
6181da177e4SLinus Torvalds  * than passing a fixed inflexible structure to the kernel, we pass a list
6191da177e4SLinus Torvalds  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
6201da177e4SLinus Torvalds  * tag for the list to be recognised (to distinguish the tagged list from
6211da177e4SLinus Torvalds  * a param_struct).  The list is terminated with a zero-length tag (this tag
6221da177e4SLinus Torvalds  * is not parsed in any way).
6231da177e4SLinus Torvalds  */
6241da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag)
6251da177e4SLinus Torvalds {
6261da177e4SLinus Torvalds 	if (tag->hdr.size > 2) {
6271da177e4SLinus Torvalds 		if ((tag->u.core.flags & 1) == 0)
6281da177e4SLinus Torvalds 			root_mountflags &= ~MS_RDONLY;
6291da177e4SLinus Torvalds 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
6301da177e4SLinus Torvalds 	}
6311da177e4SLinus Torvalds 	return 0;
6321da177e4SLinus Torvalds }
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core);
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag)
6371da177e4SLinus Torvalds {
6384b5f32ceSNicolas Pitre 	return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32);
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
6441da177e4SLinus Torvalds struct screen_info screen_info = {
6451da177e4SLinus Torvalds  .orig_video_lines	= 30,
6461da177e4SLinus Torvalds  .orig_video_cols	= 80,
6471da177e4SLinus Torvalds  .orig_video_mode	= 0,
6481da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
6491da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
6501da177e4SLinus Torvalds  .orig_video_points	= 8
6511da177e4SLinus Torvalds };
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag)
6541da177e4SLinus Torvalds {
6551da177e4SLinus Torvalds 	screen_info.orig_x            = tag->u.videotext.x;
6561da177e4SLinus Torvalds 	screen_info.orig_y            = tag->u.videotext.y;
6571da177e4SLinus Torvalds 	screen_info.orig_video_page   = tag->u.videotext.video_page;
6581da177e4SLinus Torvalds 	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
6591da177e4SLinus Torvalds 	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
6601da177e4SLinus Torvalds 	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
6611da177e4SLinus Torvalds 	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
6621da177e4SLinus Torvalds 	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
6631da177e4SLinus Torvalds 	screen_info.orig_video_points = tag->u.videotext.video_points;
6641da177e4SLinus Torvalds 	return 0;
6651da177e4SLinus Torvalds }
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
6681da177e4SLinus Torvalds #endif
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag)
6711da177e4SLinus Torvalds {
6721da177e4SLinus Torvalds 	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
6731da177e4SLinus Torvalds 		      (tag->u.ramdisk.flags & 2) == 0,
6741da177e4SLinus Torvalds 		      tag->u.ramdisk.start, tag->u.ramdisk.size);
6751da177e4SLinus Torvalds 	return 0;
6761da177e4SLinus Torvalds }
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
6791da177e4SLinus Torvalds 
6801da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag)
6811da177e4SLinus Torvalds {
6821da177e4SLinus Torvalds 	system_serial_low = tag->u.serialnr.low;
6831da177e4SLinus Torvalds 	system_serial_high = tag->u.serialnr.high;
6841da177e4SLinus Torvalds 	return 0;
6851da177e4SLinus Torvalds }
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr);
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag)
6901da177e4SLinus Torvalds {
6911da177e4SLinus Torvalds 	system_rev = tag->u.revision.rev;
6921da177e4SLinus Torvalds 	return 0;
6931da177e4SLinus Torvalds }
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision);
6961da177e4SLinus Torvalds 
6971da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag)
6981da177e4SLinus Torvalds {
6994394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND)
7004394c124SVictor Boivie 	strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
7014394c124SVictor Boivie 	strlcat(default_command_line, tag->u.cmdline.cmdline,
7024394c124SVictor Boivie 		COMMAND_LINE_SIZE);
7034394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE)
70422eeb8f6SAlexander Holler 	pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
7054394c124SVictor Boivie #else
7064394c124SVictor Boivie 	strlcpy(default_command_line, tag->u.cmdline.cmdline,
7074394c124SVictor Boivie 		COMMAND_LINE_SIZE);
7084394c124SVictor Boivie #endif
7091da177e4SLinus Torvalds 	return 0;
7101da177e4SLinus Torvalds }
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds /*
7151da177e4SLinus Torvalds  * Scan the tag table for this tag, and call its parse function.
7161da177e4SLinus Torvalds  * The tag table is built by the linker from all the __tagtable
7171da177e4SLinus Torvalds  * declarations.
7181da177e4SLinus Torvalds  */
7191da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag)
7201da177e4SLinus Torvalds {
7211da177e4SLinus Torvalds 	extern struct tagtable __tagtable_begin, __tagtable_end;
7221da177e4SLinus Torvalds 	struct tagtable *t;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
7251da177e4SLinus Torvalds 		if (tag->hdr.tag == t->tag) {
7261da177e4SLinus Torvalds 			t->parse(tag);
7271da177e4SLinus Torvalds 			break;
7281da177e4SLinus Torvalds 		}
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds 	return t < &__tagtable_end;
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds /*
7341da177e4SLinus Torvalds  * Parse all tags in the list, checking both the global and architecture
7351da177e4SLinus Torvalds  * specific tag tables.
7361da177e4SLinus Torvalds  */
7371da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t)
7381da177e4SLinus Torvalds {
7391da177e4SLinus Torvalds 	for (; t->hdr.size; t = tag_next(t))
7401da177e4SLinus Torvalds 		if (!parse_tag(t))
7411da177e4SLinus Torvalds 			printk(KERN_WARNING
7421da177e4SLinus Torvalds 				"Ignoring unrecognised tag 0x%08x\n",
7431da177e4SLinus Torvalds 				t->hdr.tag);
7441da177e4SLinus Torvalds }
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds /*
7471da177e4SLinus Torvalds  * This holds our defaults.
7481da177e4SLinus Torvalds  */
7491da177e4SLinus Torvalds static struct init_tags {
7501da177e4SLinus Torvalds 	struct tag_header hdr1;
7511da177e4SLinus Torvalds 	struct tag_core   core;
7521da177e4SLinus Torvalds 	struct tag_header hdr2;
7531da177e4SLinus Torvalds 	struct tag_mem32  mem;
7541da177e4SLinus Torvalds 	struct tag_header hdr3;
7551da177e4SLinus Torvalds } init_tags __initdata = {
7561da177e4SLinus Torvalds 	{ tag_size(tag_core), ATAG_CORE },
7571da177e4SLinus Torvalds 	{ 1, PAGE_SIZE, 0xff },
7581da177e4SLinus Torvalds 	{ tag_size(tag_mem32), ATAG_MEM },
759b75c178aSRussell King 	{ MEM_SIZE },
7601da177e4SLinus Torvalds 	{ 0, ATAG_NONE }
7611da177e4SLinus Torvalds };
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds static int __init customize_machine(void)
7641da177e4SLinus Torvalds {
7651da177e4SLinus Torvalds 	/* customizes platform devices, or adds new ones */
7668ff1443cSRussell King 	if (machine_desc->init_machine)
7678ff1443cSRussell King 		machine_desc->init_machine();
7681da177e4SLinus Torvalds 	return 0;
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds arch_initcall(customize_machine);
7711da177e4SLinus Torvalds 
7723c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
7733c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
7743c57fb43SMika Westerberg {
7753c57fb43SMika Westerberg 	unsigned long total;
7763c57fb43SMika Westerberg 
7773c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
7783c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
7793c57fb43SMika Westerberg }
7803c57fb43SMika Westerberg 
7813c57fb43SMika Westerberg /**
7823c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
7833c57fb43SMika Westerberg  *
7843c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
7853c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
7863c57fb43SMika Westerberg  * primary kernel is crashing.
7873c57fb43SMika Westerberg  */
7883c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
7893c57fb43SMika Westerberg {
7903c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
7913c57fb43SMika Westerberg 	unsigned long long total_mem;
7923c57fb43SMika Westerberg 	int ret;
7933c57fb43SMika Westerberg 
7943c57fb43SMika Westerberg 	total_mem = get_total_mem();
7953c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
7963c57fb43SMika Westerberg 				&crash_size, &crash_base);
7973c57fb43SMika Westerberg 	if (ret)
7983c57fb43SMika Westerberg 		return;
7993c57fb43SMika Westerberg 
8003c57fb43SMika Westerberg 	ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
8013c57fb43SMika Westerberg 	if (ret < 0) {
8023c57fb43SMika Westerberg 		printk(KERN_WARNING "crashkernel reservation failed - "
8033c57fb43SMika Westerberg 		       "memory is in use (0x%lx)\n", (unsigned long)crash_base);
8043c57fb43SMika Westerberg 		return;
8053c57fb43SMika Westerberg 	}
8063c57fb43SMika Westerberg 
8073c57fb43SMika Westerberg 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
8083c57fb43SMika Westerberg 	       "for crashkernel (System RAM: %ldMB)\n",
8093c57fb43SMika Westerberg 	       (unsigned long)(crash_size >> 20),
8103c57fb43SMika Westerberg 	       (unsigned long)(crash_base >> 20),
8113c57fb43SMika Westerberg 	       (unsigned long)(total_mem >> 20));
8123c57fb43SMika Westerberg 
8133c57fb43SMika Westerberg 	crashk_res.start = crash_base;
8143c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
8153c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
8163c57fb43SMika Westerberg }
8173c57fb43SMika Westerberg #else
8183c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
8193c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
8203c57fb43SMika Westerberg 
82173a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag)
82273a65b3fSUwe Kleine-König {
82373a65b3fSUwe Kleine-König 	for (; tag->hdr.size; tag = tag_next(tag))
82473a65b3fSUwe Kleine-König 		if (tag->hdr.tag == ATAG_MEM)
82573a65b3fSUwe Kleine-König 			tag->hdr.tag = ATAG_NONE;
82673a65b3fSUwe Kleine-König }
82773a65b3fSUwe Kleine-König 
8286291319dSGrant Likely static struct machine_desc * __init setup_machine_tags(unsigned int nr)
8291da177e4SLinus Torvalds {
8301da177e4SLinus Torvalds 	struct tag *tags = (struct tag *)&init_tags;
8316291319dSGrant Likely 	struct machine_desc *mdesc = NULL, *p;
8321da177e4SLinus Torvalds 	char *from = default_command_line;
8331da177e4SLinus Torvalds 
834b75c178aSRussell King 	init_tags.mem.start = PHYS_OFFSET;
835b75c178aSRussell King 
8366291319dSGrant Likely 	/*
8376291319dSGrant Likely 	 * locate machine in the list of supported machines.
8386291319dSGrant Likely 	 */
8396291319dSGrant Likely 	for_each_machine_desc(p)
8406291319dSGrant Likely 		if (nr == p->nr) {
8416291319dSGrant Likely 			printk("Machine: %s\n", p->name);
8426291319dSGrant Likely 			mdesc = p;
8436291319dSGrant Likely 			break;
8446291319dSGrant Likely 		}
845bff595c1SCatalin Marinas 
8466291319dSGrant Likely 	if (!mdesc) {
8476291319dSGrant Likely 		early_print("\nError: unrecognized/unsupported machine ID"
8486291319dSGrant Likely 			" (r1 = 0x%08x).\n\n", nr);
8496291319dSGrant Likely 		dump_machine_table(); /* does not return */
8506291319dSGrant Likely 	}
8511da177e4SLinus Torvalds 
8529d20fdd5SBill Gatliff 	if (__atags_pointer)
8539d20fdd5SBill Gatliff 		tags = phys_to_virt(__atags_pointer);
8542bb9839eSNicolas Pitre 	else if (mdesc->atag_offset)
8552bb9839eSNicolas Pitre 		tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
8561da177e4SLinus Torvalds 
85773a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
8581da177e4SLinus Torvalds 	/*
8591da177e4SLinus Torvalds 	 * If we have the old style parameters, convert them to
8601da177e4SLinus Torvalds 	 * a tag list.
8611da177e4SLinus Torvalds 	 */
8621da177e4SLinus Torvalds 	if (tags->hdr.tag != ATAG_CORE)
8631da177e4SLinus Torvalds 		convert_to_tag_list(tags);
86473a65b3fSUwe Kleine-König #endif
86593c02ab4SGrant Likely 
86693c02ab4SGrant Likely 	if (tags->hdr.tag != ATAG_CORE) {
86793c02ab4SGrant Likely #if defined(CONFIG_OF)
86893c02ab4SGrant Likely 		/*
86993c02ab4SGrant Likely 		 * If CONFIG_OF is set, then assume this is a reasonably
87093c02ab4SGrant Likely 		 * modern system that should pass boot parameters
87193c02ab4SGrant Likely 		 */
87293c02ab4SGrant Likely 		early_print("Warning: Neither atags nor dtb found\n");
87393c02ab4SGrant Likely #endif
8741da177e4SLinus Torvalds 		tags = (struct tag *)&init_tags;
87593c02ab4SGrant Likely 	}
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 	if (mdesc->fixup)
8780744a3eeSRussell King 		mdesc->fixup(tags, &from, &meminfo);
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 	if (tags->hdr.tag == ATAG_CORE) {
8811da177e4SLinus Torvalds 		if (meminfo.nr_banks != 0)
8821da177e4SLinus Torvalds 			squash_mem_tags(tags);
8834cd9d6f7SRichard Purdie 		save_atags(tags);
8841da177e4SLinus Torvalds 		parse_tags(tags);
8851da177e4SLinus Torvalds 	}
8861da177e4SLinus Torvalds 
8876291319dSGrant Likely 	/* parse_early_param needs a boot_command_line */
8886291319dSGrant Likely 	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
8896291319dSGrant Likely 
8906291319dSGrant Likely 	return mdesc;
8916291319dSGrant Likely }
8926291319dSGrant Likely 
8936291319dSGrant Likely 
8946291319dSGrant Likely void __init setup_arch(char **cmdline_p)
8956291319dSGrant Likely {
8966291319dSGrant Likely 	struct machine_desc *mdesc;
8976291319dSGrant Likely 
8986291319dSGrant Likely 	setup_processor();
89993c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
90093c02ab4SGrant Likely 	if (!mdesc)
9016291319dSGrant Likely 		mdesc = setup_machine_tags(machine_arch_type);
9026291319dSGrant Likely 	machine_desc = mdesc;
9036291319dSGrant Likely 	machine_name = mdesc->name;
9046291319dSGrant Likely 
9059811ccdfSArnaud Patard #ifdef CONFIG_ZONE_DMA
9069811ccdfSArnaud Patard 	if (mdesc->dma_zone_size) {
9079811ccdfSArnaud Patard 		extern unsigned long arm_dma_zone_size;
9089811ccdfSArnaud Patard 		arm_dma_zone_size = mdesc->dma_zone_size;
9099811ccdfSArnaud Patard 	}
9109811ccdfSArnaud Patard #endif
9116291319dSGrant Likely 	if (mdesc->soft_reboot)
9126291319dSGrant Likely 		reboot_setup("s");
9136291319dSGrant Likely 
91437efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
91537efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
91637efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
91737efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
9181da177e4SLinus Torvalds 
91948ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
92048ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
92148ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
9222b0d8c25SJeremy Kerr 
9232b0d8c25SJeremy Kerr 	parse_early_param();
9242b0d8c25SJeremy Kerr 
9250371d3f7SRussell King 	sanity_check_meminfo();
9268d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
9272778f620SRussell King 
9284b5f32ceSNicolas Pitre 	paging_init(mdesc);
92911b9369cSDima Zavin 	request_standard_resources(mdesc);
9301da177e4SLinus Torvalds 
93193c02ab4SGrant Likely 	unflatten_device_tree();
93293c02ab4SGrant Likely 
9337bbb7940SRussell King #ifdef CONFIG_SMP
934f00ec48fSRussell King 	if (is_smp())
9357bbb7940SRussell King 		smp_init_cpus();
9367bbb7940SRussell King #endif
9373c57fb43SMika Westerberg 	reserve_crashkernel();
9387bbb7940SRussell King 
939bc581770SLinus Walleij 	tcm_init();
940ccea7a19SRussell King 
94152108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
94252108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
94352108641Seric miao #endif
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds #ifdef CONFIG_VT
9461da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9471da177e4SLinus Torvalds 	conswitchp = &vga_con;
9481da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9491da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9501da177e4SLinus Torvalds #endif
9511da177e4SLinus Torvalds #endif
9525cbad0ebSJason Wessel 	early_trap_init();
953dec12e62SRussell King 
954dec12e62SRussell King 	if (mdesc->init_early)
955dec12e62SRussell King 		mdesc->init_early();
9561da177e4SLinus Torvalds }
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds static int __init topology_init(void)
9601da177e4SLinus Torvalds {
9611da177e4SLinus Torvalds 	int cpu;
9621da177e4SLinus Torvalds 
96366fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
96466fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
96566fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
96666fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
96766fb8bd2SRussell King 	}
9681da177e4SLinus Torvalds 
9691da177e4SLinus Torvalds 	return 0;
9701da177e4SLinus Torvalds }
9711da177e4SLinus Torvalds subsys_initcall(topology_init);
9721da177e4SLinus Torvalds 
973e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
974e119bfffSRussell King static int __init proc_cpu_init(void)
975e119bfffSRussell King {
976e119bfffSRussell King 	struct proc_dir_entry *res;
977e119bfffSRussell King 
978e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
979e119bfffSRussell King 	if (!res)
980e119bfffSRussell King 		return -ENOMEM;
981e119bfffSRussell King 	return 0;
982e119bfffSRussell King }
983e119bfffSRussell King fs_initcall(proc_cpu_init);
984e119bfffSRussell King #endif
985e119bfffSRussell King 
9861da177e4SLinus Torvalds static const char *hwcap_str[] = {
9871da177e4SLinus Torvalds 	"swp",
9881da177e4SLinus Torvalds 	"half",
9891da177e4SLinus Torvalds 	"thumb",
9901da177e4SLinus Torvalds 	"26bit",
9911da177e4SLinus Torvalds 	"fastmult",
9921da177e4SLinus Torvalds 	"fpa",
9931da177e4SLinus Torvalds 	"vfp",
9941da177e4SLinus Torvalds 	"edsp",
9951da177e4SLinus Torvalds 	"java",
9968f7f9435SPaul Gortmaker 	"iwmmxt",
99799e4a6ddSLennert Buytenhek 	"crunch",
9984369ae16SCatalin Marinas 	"thumbee",
9992bedbdf4SCatalin Marinas 	"neon",
10007279dc3eSCatalin Marinas 	"vfpv3",
10017279dc3eSCatalin Marinas 	"vfpv3d16",
1002254cdf8eSWill Deacon 	"tls",
1003254cdf8eSWill Deacon 	"vfpv4",
1004254cdf8eSWill Deacon 	"idiva",
1005254cdf8eSWill Deacon 	"idivt",
10061da177e4SLinus Torvalds 	NULL
10071da177e4SLinus Torvalds };
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
10101da177e4SLinus Torvalds {
10111da177e4SLinus Torvalds 	int i;
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds 	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
10140ba8b9b2SRussell King 		   cpu_name, read_cpuid_id() & 15, elf_platform);
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds #if defined(CONFIG_SMP)
10171da177e4SLinus Torvalds 	for_each_online_cpu(i) {
101815559722SRussell King 		/*
101915559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
102015559722SRussell King 		 * online processors, looking for lines beginning with
102115559722SRussell King 		 * "processor".  Give glibc what it expects.
102215559722SRussell King 		 */
102315559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
10241da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n",
10251da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
10261da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
10271da177e4SLinus Torvalds 	}
10281da177e4SLinus Torvalds #else /* CONFIG_SMP */
10291da177e4SLinus Torvalds 	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
10301da177e4SLinus Torvalds 		   loops_per_jiffy / (500000/HZ),
10311da177e4SLinus Torvalds 		   (loops_per_jiffy / (5000/HZ)) % 100);
10321da177e4SLinus Torvalds #endif
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 	/* dump out the processor features */
10351da177e4SLinus Torvalds 	seq_puts(m, "Features\t: ");
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 	for (i = 0; hwcap_str[i]; i++)
10381da177e4SLinus Torvalds 		if (elf_hwcap & (1 << i))
10391da177e4SLinus Torvalds 			seq_printf(m, "%s ", hwcap_str[i]);
10401da177e4SLinus Torvalds 
10410ba8b9b2SRussell King 	seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
10421da177e4SLinus Torvalds 	seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]);
10431da177e4SLinus Torvalds 
10440ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0x00000000) {
10451da177e4SLinus Torvalds 		/* pre-ARM7 */
10460ba8b9b2SRussell King 		seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4);
10471da177e4SLinus Torvalds 	} else {
10480ba8b9b2SRussell King 		if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
10491da177e4SLinus Torvalds 			/* ARM7 */
10501da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%02x\n",
10510ba8b9b2SRussell King 				   (read_cpuid_id() >> 16) & 127);
10521da177e4SLinus Torvalds 		} else {
10531da177e4SLinus Torvalds 			/* post-ARM7 */
10541da177e4SLinus Torvalds 			seq_printf(m, "CPU variant\t: 0x%x\n",
10550ba8b9b2SRussell King 				   (read_cpuid_id() >> 20) & 15);
10561da177e4SLinus Torvalds 		}
10571da177e4SLinus Torvalds 		seq_printf(m, "CPU part\t: 0x%03x\n",
10580ba8b9b2SRussell King 			   (read_cpuid_id() >> 4) & 0xfff);
10591da177e4SLinus Torvalds 	}
10600ba8b9b2SRussell King 	seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 	seq_puts(m, "\n");
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
10651da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
10661da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
10671da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
10681da177e4SLinus Torvalds 
10691da177e4SLinus Torvalds 	return 0;
10701da177e4SLinus Torvalds }
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
10731da177e4SLinus Torvalds {
10741da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
10781da177e4SLinus Torvalds {
10791da177e4SLinus Torvalds 	++*pos;
10801da177e4SLinus Torvalds 	return NULL;
10811da177e4SLinus Torvalds }
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
10841da177e4SLinus Torvalds {
10851da177e4SLinus Torvalds }
10861da177e4SLinus Torvalds 
10872ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
10881da177e4SLinus Torvalds 	.start	= c_start,
10891da177e4SLinus Torvalds 	.next	= c_next,
10901da177e4SLinus Torvalds 	.stop	= c_stop,
10911da177e4SLinus Torvalds 	.show	= c_show
10921da177e4SLinus Torvalds };
1093