xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 16d6d5b0)
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>
21883a106bSArnd Bergmann #include <linux/of_platform.h>
221da177e4SLinus Torvalds #include <linux/init.h>
233c57fb43SMika Westerberg #include <linux/kexec.h>
2493c02ab4SGrant Likely #include <linux/of_fdt.h>
251da177e4SLinus Torvalds #include <linux/cpu.h>
261da177e4SLinus Torvalds #include <linux/interrupt.h>
277bbb7940SRussell King #include <linux/smp.h>
28e119bfffSRussell King #include <linux/proc_fs.h>
292778f620SRussell King #include <linux/memblock.h>
302ecccf90SDave Martin #include <linux/bug.h>
312ecccf90SDave Martin #include <linux/compiler.h>
3227a3f0e9SNicolas Pitre #include <linux/sort.h>
331da177e4SLinus Torvalds 
34b86040a5SCatalin Marinas #include <asm/unified.h>
3515d07dc9SRussell King #include <asm/cp15.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>
4005774088SStefano Stabellini #include <asm/psci.h>
4137efe642SRussell King #include <asm/sections.h>
421da177e4SLinus Torvalds #include <asm/setup.h>
43f00ec48fSRussell King #include <asm/smp_plat.h>
441da177e4SLinus Torvalds #include <asm/mach-types.h>
451da177e4SLinus Torvalds #include <asm/cacheflush.h>
4646097c7dSRussell King #include <asm/cachetype.h>
471da177e4SLinus Torvalds #include <asm/tlbflush.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>
539f97da78SDavid Howells #include <asm/system_info.h>
549f97da78SDavid Howells #include <asm/system_misc.h>
555cbad0ebSJason Wessel #include <asm/traps.h>
56bff595c1SCatalin Marinas #include <asm/unwind.h>
571c16d242STejun Heo #include <asm/memblock.h>
584588c34dSDave Martin #include <asm/virt.h>
591da177e4SLinus Torvalds 
604cd9d6f7SRichard Purdie #include "atags.h"
610fc1c832SBen Dooks 
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
641da177e4SLinus Torvalds char fpe_type[8];
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds static int __init fpe_setup(char *line)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
691da177e4SLinus Torvalds 	return 1;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
731da177e4SLinus Torvalds #endif
741da177e4SLinus Torvalds 
754b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc);
760371d3f7SRussell King extern void sanity_check_meminfo(void);
7716d6d5b0SRobin Holt extern enum reboot_mode reboot_mode;
78c7909509SMarek Szyprowski extern void setup_dma_zone(struct machine_desc *desc);
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds unsigned int processor_id;
81c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
820385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
831da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
840385ebc0SRussell King unsigned int cacheid __read_mostly;
85c0e95878SRussell King EXPORT_SYMBOL(cacheid);
861da177e4SLinus Torvalds 
879d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
889d20fdd5SBill Gatliff 
891da177e4SLinus Torvalds unsigned int system_rev;
901da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds unsigned int system_serial_low;
931da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds unsigned int system_serial_high;
961da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
971da177e4SLinus Torvalds 
980385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
991da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds #ifdef MULTI_CPU
1030385ebc0SRussell King struct processor processor __read_mostly;
1041da177e4SLinus Torvalds #endif
1051da177e4SLinus Torvalds #ifdef MULTI_TLB
1060385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1071da177e4SLinus Torvalds #endif
1081da177e4SLinus Torvalds #ifdef MULTI_USER
1090385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1101da177e4SLinus Torvalds #endif
1111da177e4SLinus Torvalds #ifdef MULTI_CACHE
1120385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1131da177e4SLinus Torvalds #endif
114953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1150385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1166c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
117953233dcSCatalin Marinas #endif
1181da177e4SLinus Torvalds 
1192ecccf90SDave Martin /*
1202ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1212ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1222ecccf90SDave Martin  * variable directly.
1232ecccf90SDave Martin  */
1242ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1252ecccf90SDave Martin 
126ccea7a19SRussell King struct stack {
127ccea7a19SRussell King 	u32 irq[3];
128ccea7a19SRussell King 	u32 abt[3];
129ccea7a19SRussell King 	u32 und[3];
130ccea7a19SRussell King } ____cacheline_aligned;
131ccea7a19SRussell King 
13255bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
133ccea7a19SRussell King static struct stack stacks[NR_CPUS];
13455bdd694SCatalin Marinas #endif
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 union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1451da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /*
1501da177e4SLinus Torvalds  * Standard memory resources
1511da177e4SLinus Torvalds  */
1521da177e4SLinus Torvalds static struct resource mem_res[] = {
153740e518eSGreg Kroah-Hartman 	{
154740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
155740e518eSGreg Kroah-Hartman 		.start = 0,
156740e518eSGreg Kroah-Hartman 		.end = 0,
157740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
158740e518eSGreg Kroah-Hartman 	},
159740e518eSGreg Kroah-Hartman 	{
160a36d8e5bSKees Cook 		.name = "Kernel code",
161740e518eSGreg Kroah-Hartman 		.start = 0,
162740e518eSGreg Kroah-Hartman 		.end = 0,
163740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
164740e518eSGreg Kroah-Hartman 	},
165740e518eSGreg Kroah-Hartman 	{
166740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
167740e518eSGreg Kroah-Hartman 		.start = 0,
168740e518eSGreg Kroah-Hartman 		.end = 0,
169740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
170740e518eSGreg Kroah-Hartman 	}
1711da177e4SLinus Torvalds };
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds #define video_ram   mem_res[0]
1741da177e4SLinus Torvalds #define kernel_code mem_res[1]
1751da177e4SLinus Torvalds #define kernel_data mem_res[2]
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds static struct resource io_res[] = {
178740e518eSGreg Kroah-Hartman 	{
179740e518eSGreg Kroah-Hartman 		.name = "reserved",
180740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
181740e518eSGreg Kroah-Hartman 		.end = 0x3be,
182740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
183740e518eSGreg Kroah-Hartman 	},
184740e518eSGreg Kroah-Hartman 	{
185740e518eSGreg Kroah-Hartman 		.name = "reserved",
186740e518eSGreg Kroah-Hartman 		.start = 0x378,
187740e518eSGreg Kroah-Hartman 		.end = 0x37f,
188740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
189740e518eSGreg Kroah-Hartman 	},
190740e518eSGreg Kroah-Hartman 	{
191740e518eSGreg Kroah-Hartman 		.name = "reserved",
192740e518eSGreg Kroah-Hartman 		.start = 0x278,
193740e518eSGreg Kroah-Hartman 		.end = 0x27f,
194740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
195740e518eSGreg Kroah-Hartman 	}
1961da177e4SLinus Torvalds };
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds #define lp0 io_res[0]
1991da177e4SLinus Torvalds #define lp1 io_res[1]
2001da177e4SLinus Torvalds #define lp2 io_res[2]
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds static const char *proc_arch[] = {
2031da177e4SLinus Torvalds 	"undefined/unknown",
2041da177e4SLinus Torvalds 	"3",
2051da177e4SLinus Torvalds 	"4",
2061da177e4SLinus Torvalds 	"4T",
2071da177e4SLinus Torvalds 	"5",
2081da177e4SLinus Torvalds 	"5T",
2091da177e4SLinus Torvalds 	"5TE",
2101da177e4SLinus Torvalds 	"5TEJ",
2111da177e4SLinus Torvalds 	"6TEJ",
2126b090a25SCatalin Marinas 	"7",
21355bdd694SCatalin Marinas 	"7M",
2141da177e4SLinus Torvalds 	"?(12)",
2151da177e4SLinus Torvalds 	"?(13)",
2161da177e4SLinus Torvalds 	"?(14)",
2171da177e4SLinus Torvalds 	"?(15)",
2181da177e4SLinus Torvalds 	"?(16)",
2191da177e4SLinus Torvalds 	"?(17)",
2201da177e4SLinus Torvalds };
2211da177e4SLinus Torvalds 
22255bdd694SCatalin Marinas #ifdef CONFIG_CPU_V7M
22355bdd694SCatalin Marinas static int __get_cpu_architecture(void)
22455bdd694SCatalin Marinas {
22555bdd694SCatalin Marinas 	return CPU_ARCH_ARMv7M;
22655bdd694SCatalin Marinas }
22755bdd694SCatalin Marinas #else
2282ecccf90SDave Martin static int __get_cpu_architecture(void)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	int cpu_arch;
2311da177e4SLinus Torvalds 
2320ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2331da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2340ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2350ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2360ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2370ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2381da177e4SLinus Torvalds 		if (cpu_arch)
2391da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2400ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
241180005c4SCatalin Marinas 		unsigned int mmfr0;
242180005c4SCatalin Marinas 
243180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
244180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
245180005c4SCatalin Marinas 		asm("mrc	p15, 0, %0, c0, c1, 4"
246180005c4SCatalin Marinas 		    : "=r" (mmfr0));
247315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
248315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
249180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
250180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
251180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
252180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
253180005c4SCatalin Marinas 		else
254180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
255180005c4SCatalin Marinas 	} else
256180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	return cpu_arch;
2591da177e4SLinus Torvalds }
26055bdd694SCatalin Marinas #endif
2611da177e4SLinus Torvalds 
2622ecccf90SDave Martin int __pure cpu_architecture(void)
2632ecccf90SDave Martin {
2642ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2652ecccf90SDave Martin 
2662ecccf90SDave Martin 	return __cpu_architecture;
2672ecccf90SDave Martin }
2682ecccf90SDave Martin 
2698925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2708925ec4cSWill Deacon {
2718925ec4cSWill Deacon 	int aliasing_icache;
2728925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2738925ec4cSWill Deacon 
2747f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2757f94e9ccSWill Deacon 	if (icache_is_pipt())
2767f94e9ccSWill Deacon 		return 0;
2777f94e9ccSWill Deacon 
2788925ec4cSWill Deacon 	/* arch specifies the register format */
2798925ec4cSWill Deacon 	switch (arch) {
2808925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2815fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2825fb31a96SLinus Walleij 		    : /* No output operands */
2838925ec4cSWill Deacon 		    : "r" (1));
2845fb31a96SLinus Walleij 		isb();
2855fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2865fb31a96SLinus Walleij 		    : "=r" (id_reg));
2878925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2888925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2898925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2908925ec4cSWill Deacon 		break;
2918925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2928925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2938925ec4cSWill Deacon 		break;
2948925ec4cSWill Deacon 	default:
2958925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
2968925ec4cSWill Deacon 		aliasing_icache = 0;
2978925ec4cSWill Deacon 	}
2988925ec4cSWill Deacon 
2998925ec4cSWill Deacon 	return aliasing_icache;
3008925ec4cSWill Deacon }
3018925ec4cSWill Deacon 
302c0e95878SRussell King static void __init cacheid_init(void)
303c0e95878SRussell King {
304c0e95878SRussell King 	unsigned int arch = cpu_architecture();
305c0e95878SRussell King 
30655bdd694SCatalin Marinas 	if (arch == CPU_ARCH_ARMv7M) {
30755bdd694SCatalin Marinas 		cacheid = 0;
30855bdd694SCatalin Marinas 	} else if (arch >= CPU_ARCH_ARMv6) {
309ac52e83fSUwe Kleine-König 		unsigned int cachetype = read_cpuid_cachetype();
310b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
311b57ee99fSCatalin Marinas 			/* ARMv7 register format */
31272dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
313c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3147f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3157f94e9ccSWill Deacon 			case (1 << 14):
316c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3177f94e9ccSWill Deacon 				break;
3187f94e9ccSWill Deacon 			case (3 << 14):
3197f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3207f94e9ccSWill Deacon 				break;
3217f94e9ccSWill Deacon 			}
3228925ec4cSWill Deacon 		} else {
32372dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
32472dc53acSWill Deacon 			if (cachetype & (1 << 23))
32572dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
32672dc53acSWill Deacon 			else
327c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3288925ec4cSWill Deacon 		}
32972dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
33072dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
331c0e95878SRussell King 	} else {
332c0e95878SRussell King 		cacheid = CACHEID_VIVT;
333c0e95878SRussell King 	}
3342b4ae1f1SRussell King 
3352b4ae1f1SRussell King 	printk("CPU: %s data cache, %s instruction cache\n",
3362b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3372b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3387f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3392b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3402b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3418925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3427f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3432b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
344c0e95878SRussell King }
345c0e95878SRussell King 
3461da177e4SLinus Torvalds /*
3471da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3481da177e4SLinus Torvalds  * already provide the required functionality.
3491da177e4SLinus Torvalds  */
3500f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3516fc31d54SRussell King 
35293c02ab4SGrant Likely void __init early_print(const char *str, ...)
3536fc31d54SRussell King {
3546fc31d54SRussell King 	extern void printascii(const char *);
3556fc31d54SRussell King 	char buf[256];
3566fc31d54SRussell King 	va_list ap;
3576fc31d54SRussell King 
3586fc31d54SRussell King 	va_start(ap, str);
3596fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3606fc31d54SRussell King 	va_end(ap);
3616fc31d54SRussell King 
3626fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3636fc31d54SRussell King 	printascii(buf);
3646fc31d54SRussell King #endif
3656fc31d54SRussell King 	printk("%s", buf);
3666fc31d54SRussell King }
3676fc31d54SRussell King 
3688164f7afSStephen Boyd static void __init cpuid_init_hwcaps(void)
3698164f7afSStephen Boyd {
370a469abd0SWill Deacon 	unsigned int divide_instrs, vmsa;
3718164f7afSStephen Boyd 
3728164f7afSStephen Boyd 	if (cpu_architecture() < CPU_ARCH_ARMv7)
3738164f7afSStephen Boyd 		return;
3748164f7afSStephen Boyd 
3758164f7afSStephen Boyd 	divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24;
3768164f7afSStephen Boyd 
3778164f7afSStephen Boyd 	switch (divide_instrs) {
3788164f7afSStephen Boyd 	case 2:
3798164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVA;
3808164f7afSStephen Boyd 	case 1:
3818164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVT;
3828164f7afSStephen Boyd 	}
383a469abd0SWill Deacon 
384a469abd0SWill Deacon 	/* LPAE implies atomic ldrd/strd instructions */
385a469abd0SWill Deacon 	vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
386a469abd0SWill Deacon 	if (vmsa >= 5)
387a469abd0SWill Deacon 		elf_hwcap |= HWCAP_LPAE;
3888164f7afSStephen Boyd }
3898164f7afSStephen Boyd 
390f159f4edSTony Lindgren static void __init feat_v6_fixup(void)
391f159f4edSTony Lindgren {
392f159f4edSTony Lindgren 	int id = read_cpuid_id();
393f159f4edSTony Lindgren 
394f159f4edSTony Lindgren 	if ((id & 0xff0f0000) != 0x41070000)
395f159f4edSTony Lindgren 		return;
396f159f4edSTony Lindgren 
397f159f4edSTony Lindgren 	/*
398f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
399f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
400f159f4edSTony Lindgren 	 */
401f159f4edSTony Lindgren 	if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0))
402f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
403f159f4edSTony Lindgren }
404f159f4edSTony Lindgren 
405b69874e4SRussell King /*
406b69874e4SRussell King  * cpu_init - initialise one CPU.
407b69874e4SRussell King  *
408b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
409b69874e4SRussell King  */
4101783d457SJon Medhurst void notrace cpu_init(void)
411b69874e4SRussell King {
41255bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
413b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
414b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
415b69874e4SRussell King 
416b69874e4SRussell King 	if (cpu >= NR_CPUS) {
417b69874e4SRussell King 		printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
418b69874e4SRussell King 		BUG();
419b69874e4SRussell King 	}
420b69874e4SRussell King 
42114318efbSRob Herring 	/*
42214318efbSRob Herring 	 * This only works on resume and secondary cores. For booting on the
42314318efbSRob Herring 	 * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
42414318efbSRob Herring 	 */
42514318efbSRob Herring 	set_my_cpu_offset(per_cpu_offset(cpu));
42614318efbSRob Herring 
427b69874e4SRussell King 	cpu_proc_init();
428b69874e4SRussell King 
429b69874e4SRussell King 	/*
430b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
431b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
432b69874e4SRussell King 	 */
433b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
434b69874e4SRussell King #define PLC	"r"
435b69874e4SRussell King #else
436b69874e4SRussell King #define PLC	"I"
437b69874e4SRussell King #endif
438b69874e4SRussell King 
439b69874e4SRussell King 	/*
440b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
441b69874e4SRussell King 	 */
442b69874e4SRussell King 	__asm__ (
443b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
444b69874e4SRussell King 	"add	r14, %0, %2\n\t"
445b69874e4SRussell King 	"mov	sp, r14\n\t"
446b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
447b69874e4SRussell King 	"add	r14, %0, %4\n\t"
448b69874e4SRussell King 	"mov	sp, r14\n\t"
449b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
450b69874e4SRussell King 	"add	r14, %0, %6\n\t"
451b69874e4SRussell King 	"mov	sp, r14\n\t"
452b69874e4SRussell King 	"msr	cpsr_c, %7"
453b69874e4SRussell King 	    :
454b69874e4SRussell King 	    : "r" (stk),
455b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
456b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
457b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
458b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
459b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
460b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
461b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
462b69874e4SRussell King 	    : "r14");
46355bdd694SCatalin Marinas #endif
464b69874e4SRussell King }
465b69874e4SRussell King 
46618d7f152SLorenzo Pieralisi u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
467eb50439bSWill Deacon 
468eb50439bSWill Deacon void __init smp_setup_processor_id(void)
469eb50439bSWill Deacon {
470eb50439bSWill Deacon 	int i;
471cb8cf4f8SLorenzo Pieralisi 	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
472cb8cf4f8SLorenzo Pieralisi 	u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
473eb50439bSWill Deacon 
474eb50439bSWill Deacon 	cpu_logical_map(0) = cpu;
475cb8cf4f8SLorenzo Pieralisi 	for (i = 1; i < nr_cpu_ids; ++i)
476eb50439bSWill Deacon 		cpu_logical_map(i) = i == cpu ? 0 : i;
477eb50439bSWill Deacon 
4789394c1c6SMing Lei 	/*
4799394c1c6SMing Lei 	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
4809394c1c6SMing Lei 	 * using percpu variable early, for example, lockdep will
4819394c1c6SMing Lei 	 * access percpu variable inside lock_release
4829394c1c6SMing Lei 	 */
4839394c1c6SMing Lei 	set_my_cpu_offset(0);
4849394c1c6SMing Lei 
485cb8cf4f8SLorenzo Pieralisi 	printk(KERN_INFO "Booting Linux on physical CPU 0x%x\n", mpidr);
486eb50439bSWill Deacon }
487eb50439bSWill Deacon 
4888cf72172SLorenzo Pieralisi struct mpidr_hash mpidr_hash;
4898cf72172SLorenzo Pieralisi #ifdef CONFIG_SMP
4908cf72172SLorenzo Pieralisi /**
4918cf72172SLorenzo Pieralisi  * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
4928cf72172SLorenzo Pieralisi  *			  level in order to build a linear index from an
4938cf72172SLorenzo Pieralisi  *			  MPIDR value. Resulting algorithm is a collision
4948cf72172SLorenzo Pieralisi  *			  free hash carried out through shifting and ORing
4958cf72172SLorenzo Pieralisi  */
4968cf72172SLorenzo Pieralisi static void __init smp_build_mpidr_hash(void)
4978cf72172SLorenzo Pieralisi {
4988cf72172SLorenzo Pieralisi 	u32 i, affinity;
4998cf72172SLorenzo Pieralisi 	u32 fs[3], bits[3], ls, mask = 0;
5008cf72172SLorenzo Pieralisi 	/*
5018cf72172SLorenzo Pieralisi 	 * Pre-scan the list of MPIDRS and filter out bits that do
5028cf72172SLorenzo Pieralisi 	 * not contribute to affinity levels, ie they never toggle.
5038cf72172SLorenzo Pieralisi 	 */
5048cf72172SLorenzo Pieralisi 	for_each_possible_cpu(i)
5058cf72172SLorenzo Pieralisi 		mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
5068cf72172SLorenzo Pieralisi 	pr_debug("mask of set bits 0x%x\n", mask);
5078cf72172SLorenzo Pieralisi 	/*
5088cf72172SLorenzo Pieralisi 	 * Find and stash the last and first bit set at all affinity levels to
5098cf72172SLorenzo Pieralisi 	 * check how many bits are required to represent them.
5108cf72172SLorenzo Pieralisi 	 */
5118cf72172SLorenzo Pieralisi 	for (i = 0; i < 3; i++) {
5128cf72172SLorenzo Pieralisi 		affinity = MPIDR_AFFINITY_LEVEL(mask, i);
5138cf72172SLorenzo Pieralisi 		/*
5148cf72172SLorenzo Pieralisi 		 * Find the MSB bit and LSB bits position
5158cf72172SLorenzo Pieralisi 		 * to determine how many bits are required
5168cf72172SLorenzo Pieralisi 		 * to express the affinity level.
5178cf72172SLorenzo Pieralisi 		 */
5188cf72172SLorenzo Pieralisi 		ls = fls(affinity);
5198cf72172SLorenzo Pieralisi 		fs[i] = affinity ? ffs(affinity) - 1 : 0;
5208cf72172SLorenzo Pieralisi 		bits[i] = ls - fs[i];
5218cf72172SLorenzo Pieralisi 	}
5228cf72172SLorenzo Pieralisi 	/*
5238cf72172SLorenzo Pieralisi 	 * An index can be created from the MPIDR by isolating the
5248cf72172SLorenzo Pieralisi 	 * significant bits at each affinity level and by shifting
5258cf72172SLorenzo Pieralisi 	 * them in order to compress the 24 bits values space to a
5268cf72172SLorenzo Pieralisi 	 * compressed set of values. This is equivalent to hashing
5278cf72172SLorenzo Pieralisi 	 * the MPIDR through shifting and ORing. It is a collision free
5288cf72172SLorenzo Pieralisi 	 * hash though not minimal since some levels might contain a number
5298cf72172SLorenzo Pieralisi 	 * of CPUs that is not an exact power of 2 and their bit
5308cf72172SLorenzo Pieralisi 	 * representation might contain holes, eg MPIDR[7:0] = {0x2, 0x80}.
5318cf72172SLorenzo Pieralisi 	 */
5328cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[0] = fs[0];
5338cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[1] = MPIDR_LEVEL_BITS + fs[1] - bits[0];
5348cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[2] = 2*MPIDR_LEVEL_BITS + fs[2] -
5358cf72172SLorenzo Pieralisi 						(bits[1] + bits[0]);
5368cf72172SLorenzo Pieralisi 	mpidr_hash.mask = mask;
5378cf72172SLorenzo Pieralisi 	mpidr_hash.bits = bits[2] + bits[1] + bits[0];
5388cf72172SLorenzo Pieralisi 	pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] mask[0x%x] bits[%u]\n",
5398cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[0],
5408cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[1],
5418cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[2],
5428cf72172SLorenzo Pieralisi 				mpidr_hash.mask,
5438cf72172SLorenzo Pieralisi 				mpidr_hash.bits);
5448cf72172SLorenzo Pieralisi 	/*
5458cf72172SLorenzo Pieralisi 	 * 4x is an arbitrary value used to warn on a hash table much bigger
5468cf72172SLorenzo Pieralisi 	 * than expected on most systems.
5478cf72172SLorenzo Pieralisi 	 */
5488cf72172SLorenzo Pieralisi 	if (mpidr_hash_size() > 4 * num_possible_cpus())
5498cf72172SLorenzo Pieralisi 		pr_warn("Large number of MPIDR hash buckets detected\n");
5508cf72172SLorenzo Pieralisi 	sync_cache_w(&mpidr_hash);
5518cf72172SLorenzo Pieralisi }
5528cf72172SLorenzo Pieralisi #endif
5538cf72172SLorenzo Pieralisi 
5541da177e4SLinus Torvalds static void __init setup_processor(void)
5551da177e4SLinus Torvalds {
5561da177e4SLinus Torvalds 	struct proc_info_list *list;
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 	/*
5591da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
5601da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
5611da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
5621da177e4SLinus Torvalds 	 */
5630ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
5641da177e4SLinus Torvalds 	if (!list) {
5651da177e4SLinus Torvalds 		printk("CPU configuration botched (ID %08x), unable "
5660ba8b9b2SRussell King 		       "to continue.\n", read_cpuid_id());
5671da177e4SLinus Torvalds 		while (1);
5681da177e4SLinus Torvalds 	}
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
5712ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds #ifdef MULTI_CPU
5741da177e4SLinus Torvalds 	processor = *list->proc;
5751da177e4SLinus Torvalds #endif
5761da177e4SLinus Torvalds #ifdef MULTI_TLB
5771da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
5781da177e4SLinus Torvalds #endif
5791da177e4SLinus Torvalds #ifdef MULTI_USER
5801da177e4SLinus Torvalds 	cpu_user = *list->user;
5811da177e4SLinus Torvalds #endif
5821da177e4SLinus Torvalds #ifdef MULTI_CACHE
5831da177e4SLinus Torvalds 	cpu_cache = *list->cache;
5841da177e4SLinus Torvalds #endif
5851da177e4SLinus Torvalds 
5864e19025bSRussell King 	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
5870ba8b9b2SRussell King 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
588264edb35SRussell King 	       proc_arch[cpu_architecture()], cr_alignment);
5891da177e4SLinus Torvalds 
590a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
591a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
592a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
593a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
5941da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
5958164f7afSStephen Boyd 
5968164f7afSStephen Boyd 	cpuid_init_hwcaps();
5978164f7afSStephen Boyd 
598adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
599c40e3641SStephen Boyd 	elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
600adeff422SCatalin Marinas #endif
6011da177e4SLinus Torvalds 
602f159f4edSTony Lindgren 	feat_v6_fixup();
603f159f4edSTony Lindgren 
604c0e95878SRussell King 	cacheid_init();
605b69874e4SRussell King 	cpu_init();
606ccea7a19SRussell King }
607ccea7a19SRussell King 
60893c02ab4SGrant Likely void __init dump_machine_table(void)
6091da177e4SLinus Torvalds {
610dce72dd0SNicolas Pitre 	struct machine_desc *p;
6111da177e4SLinus Torvalds 
6126291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
6136291319dSGrant Likely 	for_each_machine_desc(p)
614dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
615dce72dd0SNicolas Pitre 
616dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
617dce72dd0SNicolas Pitre 
618dce72dd0SNicolas Pitre 	while (true)
619dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds 
622a5d5f7daSPeter Maydell int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
6233a669411SRussell King {
6244b5f32ceSNicolas Pitre 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
6254b5f32ceSNicolas Pitre 
6264b5f32ceSNicolas Pitre 	if (meminfo.nr_banks >= NR_BANKS) {
6274b5f32ceSNicolas Pitre 		printk(KERN_CRIT "NR_BANKS too low, "
62829a38193SWill Deacon 			"ignoring memory at 0x%08llx\n", (long long)start);
6294b5f32ceSNicolas Pitre 		return -EINVAL;
6304b5f32ceSNicolas Pitre 	}
63105f96ef1SRussell King 
6323a669411SRussell King 	/*
6333a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
6343a669411SRussell King 	 * Size is appropriately rounded down, start is rounded up.
6353a669411SRussell King 	 */
6363a669411SRussell King 	size -= start & ~PAGE_MASK;
63705f96ef1SRussell King 	bank->start = PAGE_ALIGN(start);
638e5ab8580SWill Deacon 
6394e1db26aSPaul Bolle #ifndef CONFIG_ARM_LPAE
640e5ab8580SWill Deacon 	if (bank->start + size < bank->start) {
641e5ab8580SWill Deacon 		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
642e5ab8580SWill Deacon 			"32-bit physical address space\n", (long long)start);
643e5ab8580SWill Deacon 		/*
644e5ab8580SWill Deacon 		 * To ensure bank->start + bank->size is representable in
645e5ab8580SWill Deacon 		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.
646e5ab8580SWill Deacon 		 * This means we lose a page after masking.
647e5ab8580SWill Deacon 		 */
648e5ab8580SWill Deacon 		size = ULONG_MAX - bank->start;
649e5ab8580SWill Deacon 	}
650e5ab8580SWill Deacon #endif
651e5ab8580SWill Deacon 
652a5d5f7daSPeter Maydell 	bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
6534b5f32ceSNicolas Pitre 
6544b5f32ceSNicolas Pitre 	/*
6554b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
6564b5f32ceSNicolas Pitre 	 * invalid node number.
6574b5f32ceSNicolas Pitre 	 */
658be370302SRussell King 	if (bank->size == 0)
6594b5f32ceSNicolas Pitre 		return -EINVAL;
6604b5f32ceSNicolas Pitre 
6614b5f32ceSNicolas Pitre 	meminfo.nr_banks++;
6624b5f32ceSNicolas Pitre 	return 0;
6633a669411SRussell King }
6643a669411SRussell King 
6651da177e4SLinus Torvalds /*
6661da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
6671da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
6681da177e4SLinus Torvalds  */
6692b0d8c25SJeremy Kerr static int __init early_mem(char *p)
6701da177e4SLinus Torvalds {
6711da177e4SLinus Torvalds 	static int usermem __initdata = 0;
672a5d5f7daSPeter Maydell 	phys_addr_t size;
673f60892d3SWill Deacon 	phys_addr_t start;
6742b0d8c25SJeremy Kerr 	char *endp;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	/*
6771da177e4SLinus Torvalds 	 * If the user specifies memory size, we
6781da177e4SLinus Torvalds 	 * blow away any automatically generated
6791da177e4SLinus Torvalds 	 * size.
6801da177e4SLinus Torvalds 	 */
6811da177e4SLinus Torvalds 	if (usermem == 0) {
6821da177e4SLinus Torvalds 		usermem = 1;
6831da177e4SLinus Torvalds 		meminfo.nr_banks = 0;
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	start = PHYS_OFFSET;
6872b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
6882b0d8c25SJeremy Kerr 	if (*endp == '@')
6892b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
6901da177e4SLinus Torvalds 
6911c97b73eSAndrew Morton 	arm_add_memory(start, size);
6921da177e4SLinus Torvalds 
6932b0d8c25SJeremy Kerr 	return 0;
6941da177e4SLinus Torvalds }
6952b0d8c25SJeremy Kerr early_param("mem", early_mem);
6961da177e4SLinus Torvalds 
69711b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc)
6981da177e4SLinus Torvalds {
69911b9369cSDima Zavin 	struct memblock_region *region;
7001da177e4SLinus Torvalds 	struct resource *res;
7011da177e4SLinus Torvalds 
70237efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
70337efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
704842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
70537efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
7061da177e4SLinus Torvalds 
70711b9369cSDima Zavin 	for_each_memblock(memory, region) {
7081da177e4SLinus Torvalds 		res = alloc_bootmem_low(sizeof(*res));
7091da177e4SLinus Torvalds 		res->name  = "System RAM";
71011b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
71111b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
7121da177e4SLinus Torvalds 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
7171da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
7181da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
7191da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
7201da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
7211da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
7221da177e4SLinus Torvalds 	}
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	if (mdesc->video_start) {
7251da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
7261da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
7271da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
7281da177e4SLinus Torvalds 	}
7291da177e4SLinus Torvalds 
7301da177e4SLinus Torvalds 	/*
7311da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
7321da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
7331da177e4SLinus Torvalds 	 */
7341da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
7351da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
7361da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
7371da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
7381da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
7391da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
7401da177e4SLinus Torvalds }
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
7431da177e4SLinus Torvalds struct screen_info screen_info = {
7441da177e4SLinus Torvalds  .orig_video_lines	= 30,
7451da177e4SLinus Torvalds  .orig_video_cols	= 80,
7461da177e4SLinus Torvalds  .orig_video_mode	= 0,
7471da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
7481da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
7491da177e4SLinus Torvalds  .orig_video_points	= 8
7501da177e4SLinus Torvalds };
7511da177e4SLinus Torvalds #endif
7521da177e4SLinus Torvalds 
7531da177e4SLinus Torvalds static int __init customize_machine(void)
7541da177e4SLinus Torvalds {
755883a106bSArnd Bergmann 	/*
756883a106bSArnd Bergmann 	 * customizes platform devices, or adds new ones
757883a106bSArnd Bergmann 	 * On DT based machines, we fall back to populating the
758883a106bSArnd Bergmann 	 * machine from the device tree, if no callback is provided,
759883a106bSArnd Bergmann 	 * otherwise we would always need an init_machine callback.
760883a106bSArnd Bergmann 	 */
7618ff1443cSRussell King 	if (machine_desc->init_machine)
7628ff1443cSRussell King 		machine_desc->init_machine();
763883a106bSArnd Bergmann #ifdef CONFIG_OF
764883a106bSArnd Bergmann 	else
765883a106bSArnd Bergmann 		of_platform_populate(NULL, of_default_bus_match_table,
766883a106bSArnd Bergmann 					NULL, NULL);
767883a106bSArnd Bergmann #endif
7681da177e4SLinus Torvalds 	return 0;
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds arch_initcall(customize_machine);
7711da177e4SLinus Torvalds 
77290de4137SShawn Guo static int __init init_machine_late(void)
77390de4137SShawn Guo {
77490de4137SShawn Guo 	if (machine_desc->init_late)
77590de4137SShawn Guo 		machine_desc->init_late();
77690de4137SShawn Guo 	return 0;
77790de4137SShawn Guo }
77890de4137SShawn Guo late_initcall(init_machine_late);
77990de4137SShawn Guo 
7803c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
7813c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
7823c57fb43SMika Westerberg {
7833c57fb43SMika Westerberg 	unsigned long total;
7843c57fb43SMika Westerberg 
7853c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
7863c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
7873c57fb43SMika Westerberg }
7883c57fb43SMika Westerberg 
7893c57fb43SMika Westerberg /**
7903c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
7913c57fb43SMika Westerberg  *
7923c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
7933c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
7943c57fb43SMika Westerberg  * primary kernel is crashing.
7953c57fb43SMika Westerberg  */
7963c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
7973c57fb43SMika Westerberg {
7983c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
7993c57fb43SMika Westerberg 	unsigned long long total_mem;
8003c57fb43SMika Westerberg 	int ret;
8013c57fb43SMika Westerberg 
8023c57fb43SMika Westerberg 	total_mem = get_total_mem();
8033c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
8043c57fb43SMika Westerberg 				&crash_size, &crash_base);
8053c57fb43SMika Westerberg 	if (ret)
8063c57fb43SMika Westerberg 		return;
8073c57fb43SMika Westerberg 
8083c57fb43SMika Westerberg 	ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE);
8093c57fb43SMika Westerberg 	if (ret < 0) {
8103c57fb43SMika Westerberg 		printk(KERN_WARNING "crashkernel reservation failed - "
8113c57fb43SMika Westerberg 		       "memory is in use (0x%lx)\n", (unsigned long)crash_base);
8123c57fb43SMika Westerberg 		return;
8133c57fb43SMika Westerberg 	}
8143c57fb43SMika Westerberg 
8153c57fb43SMika Westerberg 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
8163c57fb43SMika Westerberg 	       "for crashkernel (System RAM: %ldMB)\n",
8173c57fb43SMika Westerberg 	       (unsigned long)(crash_size >> 20),
8183c57fb43SMika Westerberg 	       (unsigned long)(crash_base >> 20),
8193c57fb43SMika Westerberg 	       (unsigned long)(total_mem >> 20));
8203c57fb43SMika Westerberg 
8213c57fb43SMika Westerberg 	crashk_res.start = crash_base;
8223c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
8233c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
8243c57fb43SMika Westerberg }
8253c57fb43SMika Westerberg #else
8263c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
8273c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
8283c57fb43SMika Westerberg 
82927a3f0e9SNicolas Pitre static int __init meminfo_cmp(const void *_a, const void *_b)
83027a3f0e9SNicolas Pitre {
83127a3f0e9SNicolas Pitre 	const struct membank *a = _a, *b = _b;
83227a3f0e9SNicolas Pitre 	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
83327a3f0e9SNicolas Pitre 	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
83427a3f0e9SNicolas Pitre }
8356291319dSGrant Likely 
8364588c34dSDave Martin void __init hyp_mode_check(void)
8374588c34dSDave Martin {
8384588c34dSDave Martin #ifdef CONFIG_ARM_VIRT_EXT
8394588c34dSDave Martin 	if (is_hyp_mode_available()) {
8404588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in HYP mode.\n");
8414588c34dSDave Martin 		pr_info("CPU: Virtualization extensions available.\n");
8424588c34dSDave Martin 	} else if (is_hyp_mode_mismatched()) {
8434588c34dSDave Martin 		pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
8444588c34dSDave Martin 			__boot_cpu_mode & MODE_MASK);
8454588c34dSDave Martin 		pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
8464588c34dSDave Martin 	} else
8474588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in SVC mode.\n");
8484588c34dSDave Martin #endif
8494588c34dSDave Martin }
8504588c34dSDave Martin 
8516291319dSGrant Likely void __init setup_arch(char **cmdline_p)
8526291319dSGrant Likely {
8536291319dSGrant Likely 	struct machine_desc *mdesc;
8546291319dSGrant Likely 
8556291319dSGrant Likely 	setup_processor();
85693c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
85793c02ab4SGrant Likely 	if (!mdesc)
858b8b499c8SAlexander Shiyan 		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
8596291319dSGrant Likely 	machine_desc = mdesc;
8606291319dSGrant Likely 	machine_name = mdesc->name;
8616291319dSGrant Likely 
862c7909509SMarek Szyprowski 	setup_dma_zone(mdesc);
863c7909509SMarek Szyprowski 
86416d6d5b0SRobin Holt 	if (mdesc->reboot_mode != REBOOT_HARD)
86516d6d5b0SRobin Holt 		reboot_mode = mdesc->reboot_mode;
8666291319dSGrant Likely 
86737efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
86837efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
86937efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
87037efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
8711da177e4SLinus Torvalds 
87248ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
87348ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
87448ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
8752b0d8c25SJeremy Kerr 
8762b0d8c25SJeremy Kerr 	parse_early_param();
8772b0d8c25SJeremy Kerr 
87827a3f0e9SNicolas Pitre 	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
8790371d3f7SRussell King 	sanity_check_meminfo();
8808d717a52SRussell King 	arm_memblock_init(&meminfo, mdesc);
8812778f620SRussell King 
8824b5f32ceSNicolas Pitre 	paging_init(mdesc);
88311b9369cSDima Zavin 	request_standard_resources(mdesc);
8841da177e4SLinus Torvalds 
885a528721dSRussell King 	if (mdesc->restart)
886a528721dSRussell King 		arm_pm_restart = mdesc->restart;
887a528721dSRussell King 
88893c02ab4SGrant Likely 	unflatten_device_tree();
88993c02ab4SGrant Likely 
8905587164eSLorenzo Pieralisi 	arm_dt_init_cpu_maps();
89105774088SStefano Stabellini 	psci_init();
8927bbb7940SRussell King #ifdef CONFIG_SMP
893abcee5fbSMarc Zyngier 	if (is_smp()) {
894b382b940SJon Medhurst 		if (!mdesc->smp_init || !mdesc->smp_init()) {
89505774088SStefano Stabellini 			if (psci_smp_available())
89605774088SStefano Stabellini 				smp_set_ops(&psci_smp_ops);
89705774088SStefano Stabellini 			else if (mdesc->smp)
898abcee5fbSMarc Zyngier 				smp_set_ops(mdesc->smp);
899b382b940SJon Medhurst 		}
9007bbb7940SRussell King 		smp_init_cpus();
9018cf72172SLorenzo Pieralisi 		smp_build_mpidr_hash();
902abcee5fbSMarc Zyngier 	}
9037bbb7940SRussell King #endif
9044588c34dSDave Martin 
9054588c34dSDave Martin 	if (!is_smp())
9064588c34dSDave Martin 		hyp_mode_check();
9074588c34dSDave Martin 
9083c57fb43SMika Westerberg 	reserve_crashkernel();
9097bbb7940SRussell King 
91052108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
91152108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
91252108641Seric miao #endif
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds #ifdef CONFIG_VT
9151da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
9161da177e4SLinus Torvalds 	conswitchp = &vga_con;
9171da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
9181da177e4SLinus Torvalds 	conswitchp = &dummy_con;
9191da177e4SLinus Torvalds #endif
9201da177e4SLinus Torvalds #endif
921dec12e62SRussell King 
922dec12e62SRussell King 	if (mdesc->init_early)
923dec12e62SRussell King 		mdesc->init_early();
9241da177e4SLinus Torvalds }
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds static int __init topology_init(void)
9281da177e4SLinus Torvalds {
9291da177e4SLinus Torvalds 	int cpu;
9301da177e4SLinus Torvalds 
93166fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
93266fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
93366fb8bd2SRussell King 		cpuinfo->cpu.hotpluggable = 1;
93466fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
93566fb8bd2SRussell King 	}
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds 	return 0;
9381da177e4SLinus Torvalds }
9391da177e4SLinus Torvalds subsys_initcall(topology_init);
9401da177e4SLinus Torvalds 
941e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
942e119bfffSRussell King static int __init proc_cpu_init(void)
943e119bfffSRussell King {
944e119bfffSRussell King 	struct proc_dir_entry *res;
945e119bfffSRussell King 
946e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
947e119bfffSRussell King 	if (!res)
948e119bfffSRussell King 		return -ENOMEM;
949e119bfffSRussell King 	return 0;
950e119bfffSRussell King }
951e119bfffSRussell King fs_initcall(proc_cpu_init);
952e119bfffSRussell King #endif
953e119bfffSRussell King 
9541da177e4SLinus Torvalds static const char *hwcap_str[] = {
9551da177e4SLinus Torvalds 	"swp",
9561da177e4SLinus Torvalds 	"half",
9571da177e4SLinus Torvalds 	"thumb",
9581da177e4SLinus Torvalds 	"26bit",
9591da177e4SLinus Torvalds 	"fastmult",
9601da177e4SLinus Torvalds 	"fpa",
9611da177e4SLinus Torvalds 	"vfp",
9621da177e4SLinus Torvalds 	"edsp",
9631da177e4SLinus Torvalds 	"java",
9648f7f9435SPaul Gortmaker 	"iwmmxt",
96599e4a6ddSLennert Buytenhek 	"crunch",
9664369ae16SCatalin Marinas 	"thumbee",
9672bedbdf4SCatalin Marinas 	"neon",
9687279dc3eSCatalin Marinas 	"vfpv3",
9697279dc3eSCatalin Marinas 	"vfpv3d16",
970254cdf8eSWill Deacon 	"tls",
971254cdf8eSWill Deacon 	"vfpv4",
972254cdf8eSWill Deacon 	"idiva",
973254cdf8eSWill Deacon 	"idivt",
974a469abd0SWill Deacon 	"lpae",
9751da177e4SLinus Torvalds 	NULL
9761da177e4SLinus Torvalds };
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
9791da177e4SLinus Torvalds {
980b4b8f770SLorenzo Pieralisi 	int i, j;
981b4b8f770SLorenzo Pieralisi 	u32 cpuid;
9821da177e4SLinus Torvalds 
9831da177e4SLinus Torvalds 	for_each_online_cpu(i) {
98415559722SRussell King 		/*
98515559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
98615559722SRussell King 		 * online processors, looking for lines beginning with
98715559722SRussell King 		 * "processor".  Give glibc what it expects.
98815559722SRussell King 		 */
98915559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
990b4b8f770SLorenzo Pieralisi 		cpuid = is_smp() ? per_cpu(cpu_data, i).cpuid : read_cpuid_id();
991b4b8f770SLorenzo Pieralisi 		seq_printf(m, "model name\t: %s rev %d (%s)\n",
992b4b8f770SLorenzo Pieralisi 			   cpu_name, cpuid & 15, elf_platform);
993b4b8f770SLorenzo Pieralisi 
994b4b8f770SLorenzo Pieralisi #if defined(CONFIG_SMP)
995b4b8f770SLorenzo Pieralisi 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
9961da177e4SLinus Torvalds 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
9971da177e4SLinus Torvalds 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
998b4b8f770SLorenzo Pieralisi #else
9991da177e4SLinus Torvalds 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
10001da177e4SLinus Torvalds 			   loops_per_jiffy / (500000/HZ),
10011da177e4SLinus Torvalds 			   (loops_per_jiffy / (5000/HZ)) % 100);
10021da177e4SLinus Torvalds #endif
10031da177e4SLinus Torvalds 		/* dump out the processor features */
10041da177e4SLinus Torvalds 		seq_puts(m, "Features\t: ");
10051da177e4SLinus Torvalds 
1006b4b8f770SLorenzo Pieralisi 		for (j = 0; hwcap_str[j]; j++)
1007b4b8f770SLorenzo Pieralisi 			if (elf_hwcap & (1 << j))
1008b4b8f770SLorenzo Pieralisi 				seq_printf(m, "%s ", hwcap_str[j]);
10091da177e4SLinus Torvalds 
1010b4b8f770SLorenzo Pieralisi 		seq_printf(m, "\nCPU implementer\t: 0x%02x\n", cpuid >> 24);
1011b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU architecture: %s\n",
1012b4b8f770SLorenzo Pieralisi 			   proc_arch[cpu_architecture()]);
10131da177e4SLinus Torvalds 
1014b4b8f770SLorenzo Pieralisi 		if ((cpuid & 0x0008f000) == 0x00000000) {
10151da177e4SLinus Torvalds 			/* pre-ARM7 */
1016b4b8f770SLorenzo Pieralisi 			seq_printf(m, "CPU part\t: %07x\n", cpuid >> 4);
10171da177e4SLinus Torvalds 		} else {
1018b4b8f770SLorenzo Pieralisi 			if ((cpuid & 0x0008f000) == 0x00007000) {
10191da177e4SLinus Torvalds 				/* ARM7 */
10201da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%02x\n",
1021b4b8f770SLorenzo Pieralisi 					   (cpuid >> 16) & 127);
10221da177e4SLinus Torvalds 			} else {
10231da177e4SLinus Torvalds 				/* post-ARM7 */
10241da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%x\n",
1025b4b8f770SLorenzo Pieralisi 					   (cpuid >> 20) & 15);
10261da177e4SLinus Torvalds 			}
10271da177e4SLinus Torvalds 			seq_printf(m, "CPU part\t: 0x%03x\n",
1028b4b8f770SLorenzo Pieralisi 				   (cpuid >> 4) & 0xfff);
10291da177e4SLinus Torvalds 		}
1030b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU revision\t: %d\n\n", cpuid & 15);
1031b4b8f770SLorenzo Pieralisi 	}
10321da177e4SLinus Torvalds 
10331da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
10341da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
10351da177e4SLinus Torvalds 	seq_printf(m, "Serial\t\t: %08x%08x\n",
10361da177e4SLinus Torvalds 		   system_serial_high, system_serial_low);
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds 	return 0;
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
10421da177e4SLinus Torvalds {
10431da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
10441da177e4SLinus Torvalds }
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
10471da177e4SLinus Torvalds {
10481da177e4SLinus Torvalds 	++*pos;
10491da177e4SLinus Torvalds 	return NULL;
10501da177e4SLinus Torvalds }
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
10531da177e4SLinus Torvalds {
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds 
10562ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
10571da177e4SLinus Torvalds 	.start	= c_start,
10581da177e4SLinus Torvalds 	.next	= c_next,
10591da177e4SLinus Torvalds 	.stop	= c_stop,
10601da177e4SLinus Torvalds 	.show	= c_show
10611da177e4SLinus Torvalds };
1062