xref: /openbmc/linux/arch/arm/kernel/setup.c (revision ad1cfe62)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/arch/arm/kernel/setup.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1995-2001 Russell King
61da177e4SLinus Torvalds  */
7da58fb65SArd Biesheuvel #include <linux/efi.h>
8ecea4ab6SPaul Gortmaker #include <linux/export.h>
91da177e4SLinus Torvalds #include <linux/kernel.h>
101da177e4SLinus Torvalds #include <linux/stddef.h>
111da177e4SLinus Torvalds #include <linux/ioport.h>
121da177e4SLinus Torvalds #include <linux/delay.h>
131da177e4SLinus Torvalds #include <linux/utsname.h>
141da177e4SLinus Torvalds #include <linux/initrd.h>
151da177e4SLinus Torvalds #include <linux/console.h>
161da177e4SLinus Torvalds #include <linux/seq_file.h>
17894673eeSJon Smirl #include <linux/screen_info.h>
18883a106bSArnd Bergmann #include <linux/of_platform.h>
191da177e4SLinus Torvalds #include <linux/init.h>
203c57fb43SMika Westerberg #include <linux/kexec.h>
217a1be318SArd Biesheuvel #include <linux/libfdt.h>
2293c02ab4SGrant Likely #include <linux/of_fdt.h>
231da177e4SLinus Torvalds #include <linux/cpu.h>
241da177e4SLinus Torvalds #include <linux/interrupt.h>
257bbb7940SRussell King #include <linux/smp.h>
26e119bfffSRussell King #include <linux/proc_fs.h>
272778f620SRussell King #include <linux/memblock.h>
282ecccf90SDave Martin #include <linux/bug.h>
292ecccf90SDave Martin #include <linux/compiler.h>
3027a3f0e9SNicolas Pitre #include <linux/sort.h>
31be120397SMark Rutland #include <linux/psci.h>
321da177e4SLinus Torvalds 
33b86040a5SCatalin Marinas #include <asm/unified.h>
3415d07dc9SRussell King #include <asm/cp15.h>
351da177e4SLinus Torvalds #include <asm/cpu.h>
360ba8b9b2SRussell King #include <asm/cputype.h>
37da58fb65SArd Biesheuvel #include <asm/efi.h>
381da177e4SLinus Torvalds #include <asm/elf.h>
392937367bSArd Biesheuvel #include <asm/early_ioremap.h>
40a5f4c561SStefan Agner #include <asm/fixmap.h>
411da177e4SLinus Torvalds #include <asm/procinfo.h>
4205774088SStefano Stabellini #include <asm/psci.h>
4337efe642SRussell King #include <asm/sections.h>
441da177e4SLinus Torvalds #include <asm/setup.h>
45f00ec48fSRussell King #include <asm/smp_plat.h>
461da177e4SLinus Torvalds #include <asm/mach-types.h>
471da177e4SLinus Torvalds #include <asm/cacheflush.h>
4846097c7dSRussell King #include <asm/cachetype.h>
491da177e4SLinus Torvalds #include <asm/tlbflush.h>
505882bfefSStefano Stabellini #include <asm/xen/hypervisor.h>
511da177e4SLinus Torvalds 
5293c02ab4SGrant Likely #include <asm/prom.h>
531da177e4SLinus Torvalds #include <asm/mach/arch.h>
541da177e4SLinus Torvalds #include <asm/mach/irq.h>
551da177e4SLinus Torvalds #include <asm/mach/time.h>
569f97da78SDavid Howells #include <asm/system_info.h>
579f97da78SDavid Howells #include <asm/system_misc.h>
585cbad0ebSJason Wessel #include <asm/traps.h>
59bff595c1SCatalin Marinas #include <asm/unwind.h>
601c16d242STejun Heo #include <asm/memblock.h>
614588c34dSDave Martin #include <asm/virt.h>
625615f69bSLinus Walleij #include <asm/kasan.h>
631da177e4SLinus Torvalds 
644cd9d6f7SRichard Purdie #include "atags.h"
650fc1c832SBen Dooks 
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
681da177e4SLinus Torvalds char fpe_type[8];
691da177e4SLinus Torvalds 
fpe_setup(char * line)701da177e4SLinus Torvalds static int __init fpe_setup(char *line)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
731da177e4SLinus Torvalds 	return 1;
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
771da177e4SLinus Torvalds #endif
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds unsigned int processor_id;
80c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
810385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
821da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
830385ebc0SRussell King unsigned int cacheid __read_mostly;
84c0e95878SRussell King EXPORT_SYMBOL(cacheid);
851da177e4SLinus Torvalds 
869d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
879d20fdd5SBill Gatliff 
881da177e4SLinus Torvalds unsigned int system_rev;
891da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
901da177e4SLinus Torvalds 
913f599875SPaul Kocialkowski const char *system_serial;
923f599875SPaul Kocialkowski EXPORT_SYMBOL(system_serial);
933f599875SPaul Kocialkowski 
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 
103b342ea4eSArd Biesheuvel unsigned int elf_hwcap2 __read_mostly;
104b342ea4eSArd Biesheuvel EXPORT_SYMBOL(elf_hwcap2);
105b342ea4eSArd Biesheuvel 
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds #ifdef MULTI_CPU
1087619751fSKees Cook struct processor processor __ro_after_init;
109383fb3eeSRussell King #if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
110383fb3eeSRussell King struct processor *cpu_vtable[NR_CPUS] = {
111383fb3eeSRussell King 	[0] = &processor,
112383fb3eeSRussell King };
113383fb3eeSRussell King #endif
1141da177e4SLinus Torvalds #endif
1151da177e4SLinus Torvalds #ifdef MULTI_TLB
1167619751fSKees Cook struct cpu_tlb_fns cpu_tlb __ro_after_init;
1171da177e4SLinus Torvalds #endif
1181da177e4SLinus Torvalds #ifdef MULTI_USER
1197619751fSKees Cook struct cpu_user_fns cpu_user __ro_after_init;
1201da177e4SLinus Torvalds #endif
1211da177e4SLinus Torvalds #ifdef MULTI_CACHE
1227619751fSKees Cook struct cpu_cache_fns cpu_cache __ro_after_init;
1231da177e4SLinus Torvalds #endif
124953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1257619751fSKees Cook struct outer_cache_fns outer_cache __ro_after_init;
1266c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
127953233dcSCatalin Marinas #endif
1281da177e4SLinus Torvalds 
1292ecccf90SDave Martin /*
1302ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1312ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1322ecccf90SDave Martin  * variable directly.
1332ecccf90SDave Martin  */
1342ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1352ecccf90SDave Martin 
136ccea7a19SRussell King struct stack {
137a1c510d0SArd Biesheuvel 	u32 irq[4];
138a1c510d0SArd Biesheuvel 	u32 abt[4];
139a1c510d0SArd Biesheuvel 	u32 und[4];
140a1c510d0SArd Biesheuvel 	u32 fiq[4];
141ccea7a19SRussell King } ____cacheline_aligned;
142ccea7a19SRussell King 
14355bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
144ccea7a19SRussell King static struct stack stacks[NR_CPUS];
14555bdd694SCatalin Marinas #endif
146ccea7a19SRussell King 
1471da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1481da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds static const char *cpu_name;
1511da177e4SLinus Torvalds static const char *machine_name;
15248ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
153ff69a4c8SRussell King const struct machine_desc *machine_desc __initdata;
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1561da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /*
1611da177e4SLinus Torvalds  * Standard memory resources
1621da177e4SLinus Torvalds  */
1631da177e4SLinus Torvalds static struct resource mem_res[] = {
164740e518eSGreg Kroah-Hartman 	{
165740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
166740e518eSGreg Kroah-Hartman 		.start = 0,
167740e518eSGreg Kroah-Hartman 		.end = 0,
168740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
169740e518eSGreg Kroah-Hartman 	},
170740e518eSGreg Kroah-Hartman 	{
171a36d8e5bSKees Cook 		.name = "Kernel code",
172740e518eSGreg Kroah-Hartman 		.start = 0,
173740e518eSGreg Kroah-Hartman 		.end = 0,
17435d98e93SToshi Kani 		.flags = IORESOURCE_SYSTEM_RAM
175740e518eSGreg Kroah-Hartman 	},
176740e518eSGreg Kroah-Hartman 	{
177740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
178740e518eSGreg Kroah-Hartman 		.start = 0,
179740e518eSGreg Kroah-Hartman 		.end = 0,
18035d98e93SToshi Kani 		.flags = IORESOURCE_SYSTEM_RAM
181740e518eSGreg Kroah-Hartman 	}
1821da177e4SLinus Torvalds };
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds #define video_ram   mem_res[0]
1851da177e4SLinus Torvalds #define kernel_code mem_res[1]
1861da177e4SLinus Torvalds #define kernel_data mem_res[2]
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds static struct resource io_res[] = {
189740e518eSGreg Kroah-Hartman 	{
190740e518eSGreg Kroah-Hartman 		.name = "reserved",
191740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
192740e518eSGreg Kroah-Hartman 		.end = 0x3be,
193740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
194740e518eSGreg Kroah-Hartman 	},
195740e518eSGreg Kroah-Hartman 	{
196740e518eSGreg Kroah-Hartman 		.name = "reserved",
197740e518eSGreg Kroah-Hartman 		.start = 0x378,
198740e518eSGreg Kroah-Hartman 		.end = 0x37f,
199740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
200740e518eSGreg Kroah-Hartman 	},
201740e518eSGreg Kroah-Hartman 	{
202740e518eSGreg Kroah-Hartman 		.name = "reserved",
203740e518eSGreg Kroah-Hartman 		.start = 0x278,
204740e518eSGreg Kroah-Hartman 		.end = 0x27f,
205740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
206740e518eSGreg Kroah-Hartman 	}
2071da177e4SLinus Torvalds };
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds #define lp0 io_res[0]
2101da177e4SLinus Torvalds #define lp1 io_res[1]
2111da177e4SLinus Torvalds #define lp2 io_res[2]
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds static const char *proc_arch[] = {
2141da177e4SLinus Torvalds 	"undefined/unknown",
2151da177e4SLinus Torvalds 	"3",
2161da177e4SLinus Torvalds 	"4",
2171da177e4SLinus Torvalds 	"4T",
2181da177e4SLinus Torvalds 	"5",
2191da177e4SLinus Torvalds 	"5T",
2201da177e4SLinus Torvalds 	"5TE",
2211da177e4SLinus Torvalds 	"5TEJ",
2221da177e4SLinus Torvalds 	"6TEJ",
2236b090a25SCatalin Marinas 	"7",
22455bdd694SCatalin Marinas 	"7M",
2251da177e4SLinus Torvalds 	"?(12)",
2261da177e4SLinus Torvalds 	"?(13)",
2271da177e4SLinus Torvalds 	"?(14)",
2281da177e4SLinus Torvalds 	"?(15)",
2291da177e4SLinus Torvalds 	"?(16)",
2301da177e4SLinus Torvalds 	"?(17)",
2311da177e4SLinus Torvalds };
2321da177e4SLinus Torvalds 
23355bdd694SCatalin Marinas #ifdef CONFIG_CPU_V7M
__get_cpu_architecture(void)23455bdd694SCatalin Marinas static int __get_cpu_architecture(void)
23555bdd694SCatalin Marinas {
23655bdd694SCatalin Marinas 	return CPU_ARCH_ARMv7M;
23755bdd694SCatalin Marinas }
23855bdd694SCatalin Marinas #else
__get_cpu_architecture(void)2392ecccf90SDave Martin static int __get_cpu_architecture(void)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds 	int cpu_arch;
2421da177e4SLinus Torvalds 
2430ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2441da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2450ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2460ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2470ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2480ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2491da177e4SLinus Torvalds 		if (cpu_arch)
2501da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2510ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
252180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
253180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
254526299ceSMason 		unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
255315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
256315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
257180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
258180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
259180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
260180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
261180005c4SCatalin Marinas 		else
262180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
263180005c4SCatalin Marinas 	} else
264180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	return cpu_arch;
2671da177e4SLinus Torvalds }
26855bdd694SCatalin Marinas #endif
2691da177e4SLinus Torvalds 
cpu_architecture(void)2702ecccf90SDave Martin int __pure cpu_architecture(void)
2712ecccf90SDave Martin {
2722ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2732ecccf90SDave Martin 
2742ecccf90SDave Martin 	return __cpu_architecture;
2752ecccf90SDave Martin }
2762ecccf90SDave Martin 
cpu_has_aliasing_icache(unsigned int arch)2778925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2788925ec4cSWill Deacon {
2798925ec4cSWill Deacon 	int aliasing_icache;
2808925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2818925ec4cSWill Deacon 
2827f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2837f94e9ccSWill Deacon 	if (icache_is_pipt())
2847f94e9ccSWill Deacon 		return 0;
2857f94e9ccSWill Deacon 
2868925ec4cSWill Deacon 	/* arch specifies the register format */
2878925ec4cSWill Deacon 	switch (arch) {
2888925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
28926150aa9SJonathan Austin 		set_csselr(CSSELR_ICACHE | CSSELR_L1);
2905fb31a96SLinus Walleij 		isb();
29126150aa9SJonathan Austin 		id_reg = read_ccsidr();
2928925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
2938925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
2948925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
2958925ec4cSWill Deacon 		break;
2968925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
2978925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
2988925ec4cSWill Deacon 		break;
2998925ec4cSWill Deacon 	default:
3008925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
3018925ec4cSWill Deacon 		aliasing_icache = 0;
3028925ec4cSWill Deacon 	}
3038925ec4cSWill Deacon 
3048925ec4cSWill Deacon 	return aliasing_icache;
3058925ec4cSWill Deacon }
3068925ec4cSWill Deacon 
cacheid_init(void)307c0e95878SRussell King static void __init cacheid_init(void)
308c0e95878SRussell King {
309c0e95878SRussell King 	unsigned int arch = cpu_architecture();
310c0e95878SRussell King 
311f5a5c89eSJonathan Austin 	if (arch >= CPU_ARCH_ARMv6) {
312ac52e83fSUwe Kleine-König 		unsigned int cachetype = read_cpuid_cachetype();
313f5a5c89eSJonathan Austin 
314d360a687SVladimir Murzin 		if ((arch == CPU_ARCH_ARMv7M) && !(cachetype & 0xf000f)) {
315f5a5c89eSJonathan Austin 			cacheid = 0;
316f5a5c89eSJonathan Austin 		} else if ((cachetype & (7 << 29)) == 4 << 29) {
317b57ee99fSCatalin Marinas 			/* ARMv7 register format */
31872dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
319c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3207f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3217f94e9ccSWill Deacon 			case (1 << 14):
322c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3237f94e9ccSWill Deacon 				break;
3247f94e9ccSWill Deacon 			case (3 << 14):
3257f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3267f94e9ccSWill Deacon 				break;
3277f94e9ccSWill Deacon 			}
3288925ec4cSWill Deacon 		} else {
32972dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
33072dc53acSWill Deacon 			if (cachetype & (1 << 23))
33172dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
33272dc53acSWill Deacon 			else
333c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3348925ec4cSWill Deacon 		}
33572dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
33672dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
337c0e95878SRussell King 	} else {
338c0e95878SRussell King 		cacheid = CACHEID_VIVT;
339c0e95878SRussell King 	}
3402b4ae1f1SRussell King 
3411b0f6681SOlof Johansson 	pr_info("CPU: %s data cache, %s instruction cache\n",
3422b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3432b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3447f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3452b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3462b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3478925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3487f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3492b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
350c0e95878SRussell King }
351c0e95878SRussell King 
3521da177e4SLinus Torvalds /*
3531da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3541da177e4SLinus Torvalds  * already provide the required functionality.
3551da177e4SLinus Torvalds  */
3560f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3576fc31d54SRussell King 
early_print(const char * str,...)35893c02ab4SGrant Likely void __init early_print(const char *str, ...)
3596fc31d54SRussell King {
3606fc31d54SRussell King 	extern void printascii(const char *);
3616fc31d54SRussell King 	char buf[256];
3626fc31d54SRussell King 	va_list ap;
3636fc31d54SRussell King 
3646fc31d54SRussell King 	va_start(ap, str);
3656fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3666fc31d54SRussell King 	va_end(ap);
3676fc31d54SRussell King 
3686fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3696fc31d54SRussell King 	printascii(buf);
3706fc31d54SRussell King #endif
3716fc31d54SRussell King 	printk("%s", buf);
3726fc31d54SRussell King }
3736fc31d54SRussell King 
37442f25bddSNicolas Pitre #ifdef CONFIG_ARM_PATCH_IDIV
37542f25bddSNicolas Pitre 
sdiv_instruction(void)37642f25bddSNicolas Pitre static inline u32 __attribute_const__ sdiv_instruction(void)
37742f25bddSNicolas Pitre {
37842f25bddSNicolas Pitre 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
37942f25bddSNicolas Pitre 		/* "sdiv r0, r0, r1" */
38042f25bddSNicolas Pitre 		u32 insn = __opcode_thumb32_compose(0xfb90, 0xf0f1);
38142f25bddSNicolas Pitre 		return __opcode_to_mem_thumb32(insn);
38242f25bddSNicolas Pitre 	}
38342f25bddSNicolas Pitre 
38442f25bddSNicolas Pitre 	/* "sdiv r0, r0, r1" */
38542f25bddSNicolas Pitre 	return __opcode_to_mem_arm(0xe710f110);
38642f25bddSNicolas Pitre }
38742f25bddSNicolas Pitre 
udiv_instruction(void)38842f25bddSNicolas Pitre static inline u32 __attribute_const__ udiv_instruction(void)
38942f25bddSNicolas Pitre {
39042f25bddSNicolas Pitre 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
39142f25bddSNicolas Pitre 		/* "udiv r0, r0, r1" */
39242f25bddSNicolas Pitre 		u32 insn = __opcode_thumb32_compose(0xfbb0, 0xf0f1);
39342f25bddSNicolas Pitre 		return __opcode_to_mem_thumb32(insn);
39442f25bddSNicolas Pitre 	}
39542f25bddSNicolas Pitre 
39642f25bddSNicolas Pitre 	/* "udiv r0, r0, r1" */
39742f25bddSNicolas Pitre 	return __opcode_to_mem_arm(0xe730f110);
39842f25bddSNicolas Pitre }
39942f25bddSNicolas Pitre 
bx_lr_instruction(void)40042f25bddSNicolas Pitre static inline u32 __attribute_const__ bx_lr_instruction(void)
40142f25bddSNicolas Pitre {
40242f25bddSNicolas Pitre 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
40342f25bddSNicolas Pitre 		/* "bx lr; nop" */
40442f25bddSNicolas Pitre 		u32 insn = __opcode_thumb32_compose(0x4770, 0x46c0);
40542f25bddSNicolas Pitre 		return __opcode_to_mem_thumb32(insn);
40642f25bddSNicolas Pitre 	}
40742f25bddSNicolas Pitre 
40842f25bddSNicolas Pitre 	/* "bx lr" */
40942f25bddSNicolas Pitre 	return __opcode_to_mem_arm(0xe12fff1e);
41042f25bddSNicolas Pitre }
41142f25bddSNicolas Pitre 
patch_aeabi_idiv(void)41242f25bddSNicolas Pitre static void __init patch_aeabi_idiv(void)
41342f25bddSNicolas Pitre {
41442f25bddSNicolas Pitre 	extern void __aeabi_uidiv(void);
41542f25bddSNicolas Pitre 	extern void __aeabi_idiv(void);
41642f25bddSNicolas Pitre 	uintptr_t fn_addr;
41742f25bddSNicolas Pitre 	unsigned int mask;
41842f25bddSNicolas Pitre 
41942f25bddSNicolas Pitre 	mask = IS_ENABLED(CONFIG_THUMB2_KERNEL) ? HWCAP_IDIVT : HWCAP_IDIVA;
42042f25bddSNicolas Pitre 	if (!(elf_hwcap & mask))
42142f25bddSNicolas Pitre 		return;
42242f25bddSNicolas Pitre 
42342f25bddSNicolas Pitre 	pr_info("CPU: div instructions available: patching division code\n");
42442f25bddSNicolas Pitre 
42542f25bddSNicolas Pitre 	fn_addr = ((uintptr_t)&__aeabi_uidiv) & ~1;
426208fae5cSNicolas Pitre 	asm ("" : "+g" (fn_addr));
42742f25bddSNicolas Pitre 	((u32 *)fn_addr)[0] = udiv_instruction();
42842f25bddSNicolas Pitre 	((u32 *)fn_addr)[1] = bx_lr_instruction();
42942f25bddSNicolas Pitre 	flush_icache_range(fn_addr, fn_addr + 8);
43042f25bddSNicolas Pitre 
43142f25bddSNicolas Pitre 	fn_addr = ((uintptr_t)&__aeabi_idiv) & ~1;
432208fae5cSNicolas Pitre 	asm ("" : "+g" (fn_addr));
43342f25bddSNicolas Pitre 	((u32 *)fn_addr)[0] = sdiv_instruction();
43442f25bddSNicolas Pitre 	((u32 *)fn_addr)[1] = bx_lr_instruction();
43542f25bddSNicolas Pitre 	flush_icache_range(fn_addr, fn_addr + 8);
43642f25bddSNicolas Pitre }
43742f25bddSNicolas Pitre 
43842f25bddSNicolas Pitre #else
patch_aeabi_idiv(void)43942f25bddSNicolas Pitre static inline void patch_aeabi_idiv(void) { }
44042f25bddSNicolas Pitre #endif
44142f25bddSNicolas Pitre 
cpuid_init_hwcaps(void)4428164f7afSStephen Boyd static void __init cpuid_init_hwcaps(void)
4438164f7afSStephen Boyd {
444b8c9592bSArd Biesheuvel 	int block;
445a092aedbSArd Biesheuvel 	u32 isar5;
4463bda6d88SAmit Daniel Kachhap 	u32 isar6;
447fea53546SAmit Daniel Kachhap 	u32 pfr2;
4488164f7afSStephen Boyd 
4498164f7afSStephen Boyd 	if (cpu_architecture() < CPU_ARCH_ARMv7)
4508164f7afSStephen Boyd 		return;
4518164f7afSStephen Boyd 
452b8c9592bSArd Biesheuvel 	block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24);
453b8c9592bSArd Biesheuvel 	if (block >= 2)
4548164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVA;
455b8c9592bSArd Biesheuvel 	if (block >= 1)
4568164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVT;
457a469abd0SWill Deacon 
458a469abd0SWill Deacon 	/* LPAE implies atomic ldrd/strd instructions */
459b8c9592bSArd Biesheuvel 	block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
460b8c9592bSArd Biesheuvel 	if (block >= 5)
461a469abd0SWill Deacon 		elf_hwcap |= HWCAP_LPAE;
462a092aedbSArd Biesheuvel 
463a092aedbSArd Biesheuvel 	/* check for supported v8 Crypto instructions */
464a092aedbSArd Biesheuvel 	isar5 = read_cpuid_ext(CPUID_EXT_ISAR5);
465a092aedbSArd Biesheuvel 
466a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 4);
467a092aedbSArd Biesheuvel 	if (block >= 2)
468a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_PMULL;
469a092aedbSArd Biesheuvel 	if (block >= 1)
470a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_AES;
471a092aedbSArd Biesheuvel 
472a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 8);
473a092aedbSArd Biesheuvel 	if (block >= 1)
474a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_SHA1;
475a092aedbSArd Biesheuvel 
476a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 12);
477a092aedbSArd Biesheuvel 	if (block >= 1)
478a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_SHA2;
479a092aedbSArd Biesheuvel 
480a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 16);
481a092aedbSArd Biesheuvel 	if (block >= 1)
482a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_CRC32;
4833bda6d88SAmit Daniel Kachhap 
4843bda6d88SAmit Daniel Kachhap 	/* Check for Speculation barrier instruction */
4853bda6d88SAmit Daniel Kachhap 	isar6 = read_cpuid_ext(CPUID_EXT_ISAR6);
4863bda6d88SAmit Daniel Kachhap 	block = cpuid_feature_extract_field(isar6, 12);
4873bda6d88SAmit Daniel Kachhap 	if (block >= 1)
4883bda6d88SAmit Daniel Kachhap 		elf_hwcap2 |= HWCAP2_SB;
489fea53546SAmit Daniel Kachhap 
490fea53546SAmit Daniel Kachhap 	/* Check for Speculative Store Bypassing control */
491fea53546SAmit Daniel Kachhap 	pfr2 = read_cpuid_ext(CPUID_EXT_PFR2);
492fea53546SAmit Daniel Kachhap 	block = cpuid_feature_extract_field(pfr2, 4);
493fea53546SAmit Daniel Kachhap 	if (block >= 1)
494fea53546SAmit Daniel Kachhap 		elf_hwcap2 |= HWCAP2_SSBS;
4958164f7afSStephen Boyd }
4968164f7afSStephen Boyd 
elf_hwcap_fixup(void)49758171bf2SRussell King static void __init elf_hwcap_fixup(void)
498f159f4edSTony Lindgren {
49958171bf2SRussell King 	unsigned id = read_cpuid_id();
500f159f4edSTony Lindgren 
501f159f4edSTony Lindgren 	/*
502f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
503f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
504f159f4edSTony Lindgren 	 */
50558171bf2SRussell King 	if (read_cpuid_part() == ARM_CPU_PART_ARM1136 &&
50658171bf2SRussell King 	    ((id >> 20) & 3) == 0) {
507f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
50858171bf2SRussell King 		return;
50958171bf2SRussell King 	}
51058171bf2SRussell King 
51158171bf2SRussell King 	/* Verify if CPUID scheme is implemented */
51258171bf2SRussell King 	if ((id & 0x000f0000) != 0x000f0000)
51358171bf2SRussell King 		return;
51458171bf2SRussell King 
51558171bf2SRussell King 	/*
51658171bf2SRussell King 	 * If the CPU supports LDREX/STREX and LDREXB/STREXB,
51758171bf2SRussell King 	 * avoid advertising SWP; it may not be atomic with
51858171bf2SRussell King 	 * multiprocessing cores.
51958171bf2SRussell King 	 */
520b8c9592bSArd Biesheuvel 	if (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) > 1 ||
521b8c9592bSArd Biesheuvel 	    (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) == 1 &&
52203f1217eSVladimir Murzin 	     cpuid_feature_extract(CPUID_EXT_ISAR4, 20) >= 3))
52358171bf2SRussell King 		elf_hwcap &= ~HWCAP_SWP;
524f159f4edSTony Lindgren }
525f159f4edSTony Lindgren 
526b69874e4SRussell King /*
527b69874e4SRussell King  * cpu_init - initialise one CPU.
528b69874e4SRussell King  *
529b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
530b69874e4SRussell King  */
cpu_init(void)5311783d457SJon Medhurst void notrace cpu_init(void)
532b69874e4SRussell King {
53355bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
534b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
535b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
536b69874e4SRussell King 
537b69874e4SRussell King 	if (cpu >= NR_CPUS) {
5381b0f6681SOlof Johansson 		pr_crit("CPU%u: bad primary CPU number\n", cpu);
539b69874e4SRussell King 		BUG();
540b69874e4SRussell King 	}
541b69874e4SRussell King 
54214318efbSRob Herring 	/*
54314318efbSRob Herring 	 * This only works on resume and secondary cores. For booting on the
54414318efbSRob Herring 	 * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
54514318efbSRob Herring 	 */
54614318efbSRob Herring 	set_my_cpu_offset(per_cpu_offset(cpu));
54714318efbSRob Herring 
548b69874e4SRussell King 	cpu_proc_init();
549b69874e4SRussell King 
550b69874e4SRussell King 	/*
551b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
552b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
553b69874e4SRussell King 	 */
554b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
555dad7b989SArnd Bergmann #define PLC_l	"l"
556dad7b989SArnd Bergmann #define PLC_r	"r"
557b69874e4SRussell King #else
558dad7b989SArnd Bergmann #define PLC_l	"I"
559dad7b989SArnd Bergmann #define PLC_r	"I"
560b69874e4SRussell King #endif
561b69874e4SRussell King 
562b69874e4SRussell King 	/*
563b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
564b69874e4SRussell King 	 */
565b69874e4SRussell King 	__asm__ (
566b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
567b69874e4SRussell King 	"add	r14, %0, %2\n\t"
568b69874e4SRussell King 	"mov	sp, r14\n\t"
569b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
570b69874e4SRussell King 	"add	r14, %0, %4\n\t"
571b69874e4SRussell King 	"mov	sp, r14\n\t"
572b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
573b69874e4SRussell King 	"add	r14, %0, %6\n\t"
574b69874e4SRussell King 	"mov	sp, r14\n\t"
575c0e7f7eeSDaniel Thompson 	"msr	cpsr_c, %7\n\t"
576c0e7f7eeSDaniel Thompson 	"add	r14, %0, %8\n\t"
577c0e7f7eeSDaniel Thompson 	"mov	sp, r14\n\t"
578c0e7f7eeSDaniel Thompson 	"msr	cpsr_c, %9"
579b69874e4SRussell King 	    :
580b69874e4SRussell King 	    : "r" (stk),
581dad7b989SArnd Bergmann 	      PLC_r (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
582b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
583dad7b989SArnd Bergmann 	      PLC_r (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
584b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
585dad7b989SArnd Bergmann 	      PLC_r (PSR_F_BIT | PSR_I_BIT | UND_MODE),
586b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
587dad7b989SArnd Bergmann 	      PLC_r (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
588c0e7f7eeSDaniel Thompson 	      "I" (offsetof(struct stack, fiq[0])),
589dad7b989SArnd Bergmann 	      PLC_l (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
590b69874e4SRussell King 	    : "r14");
59155bdd694SCatalin Marinas #endif
592b69874e4SRussell King }
593b69874e4SRussell King 
59418d7f152SLorenzo Pieralisi u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
595eb50439bSWill Deacon 
smp_setup_processor_id(void)596eb50439bSWill Deacon void __init smp_setup_processor_id(void)
597eb50439bSWill Deacon {
598eb50439bSWill Deacon 	int i;
599cb8cf4f8SLorenzo Pieralisi 	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
600cb8cf4f8SLorenzo Pieralisi 	u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
601eb50439bSWill Deacon 
602eb50439bSWill Deacon 	cpu_logical_map(0) = cpu;
603cb8cf4f8SLorenzo Pieralisi 	for (i = 1; i < nr_cpu_ids; ++i)
604eb50439bSWill Deacon 		cpu_logical_map(i) = i == cpu ? 0 : i;
605eb50439bSWill Deacon 
6069394c1c6SMing Lei 	/*
6079394c1c6SMing Lei 	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
6089394c1c6SMing Lei 	 * using percpu variable early, for example, lockdep will
6099394c1c6SMing Lei 	 * access percpu variable inside lock_release
6109394c1c6SMing Lei 	 */
6119394c1c6SMing Lei 	set_my_cpu_offset(0);
6129394c1c6SMing Lei 
6131b0f6681SOlof Johansson 	pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
614eb50439bSWill Deacon }
615eb50439bSWill Deacon 
6168cf72172SLorenzo Pieralisi struct mpidr_hash mpidr_hash;
6178cf72172SLorenzo Pieralisi #ifdef CONFIG_SMP
6188cf72172SLorenzo Pieralisi /**
6198cf72172SLorenzo Pieralisi  * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
6208cf72172SLorenzo Pieralisi  *			  level in order to build a linear index from an
6218cf72172SLorenzo Pieralisi  *			  MPIDR value. Resulting algorithm is a collision
6228cf72172SLorenzo Pieralisi  *			  free hash carried out through shifting and ORing
6238cf72172SLorenzo Pieralisi  */
smp_build_mpidr_hash(void)6248cf72172SLorenzo Pieralisi static void __init smp_build_mpidr_hash(void)
6258cf72172SLorenzo Pieralisi {
6268cf72172SLorenzo Pieralisi 	u32 i, affinity;
6278cf72172SLorenzo Pieralisi 	u32 fs[3], bits[3], ls, mask = 0;
6288cf72172SLorenzo Pieralisi 	/*
6298cf72172SLorenzo Pieralisi 	 * Pre-scan the list of MPIDRS and filter out bits that do
6308cf72172SLorenzo Pieralisi 	 * not contribute to affinity levels, ie they never toggle.
6318cf72172SLorenzo Pieralisi 	 */
6328cf72172SLorenzo Pieralisi 	for_each_possible_cpu(i)
6338cf72172SLorenzo Pieralisi 		mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
6348cf72172SLorenzo Pieralisi 	pr_debug("mask of set bits 0x%x\n", mask);
6358cf72172SLorenzo Pieralisi 	/*
6368cf72172SLorenzo Pieralisi 	 * Find and stash the last and first bit set at all affinity levels to
6378cf72172SLorenzo Pieralisi 	 * check how many bits are required to represent them.
6388cf72172SLorenzo Pieralisi 	 */
6398cf72172SLorenzo Pieralisi 	for (i = 0; i < 3; i++) {
6408cf72172SLorenzo Pieralisi 		affinity = MPIDR_AFFINITY_LEVEL(mask, i);
6418cf72172SLorenzo Pieralisi 		/*
6428cf72172SLorenzo Pieralisi 		 * Find the MSB bit and LSB bits position
6438cf72172SLorenzo Pieralisi 		 * to determine how many bits are required
6448cf72172SLorenzo Pieralisi 		 * to express the affinity level.
6458cf72172SLorenzo Pieralisi 		 */
6468cf72172SLorenzo Pieralisi 		ls = fls(affinity);
6478cf72172SLorenzo Pieralisi 		fs[i] = affinity ? ffs(affinity) - 1 : 0;
6488cf72172SLorenzo Pieralisi 		bits[i] = ls - fs[i];
6498cf72172SLorenzo Pieralisi 	}
6508cf72172SLorenzo Pieralisi 	/*
6518cf72172SLorenzo Pieralisi 	 * An index can be created from the MPIDR by isolating the
6528cf72172SLorenzo Pieralisi 	 * significant bits at each affinity level and by shifting
6538cf72172SLorenzo Pieralisi 	 * them in order to compress the 24 bits values space to a
6548cf72172SLorenzo Pieralisi 	 * compressed set of values. This is equivalent to hashing
6558cf72172SLorenzo Pieralisi 	 * the MPIDR through shifting and ORing. It is a collision free
6568cf72172SLorenzo Pieralisi 	 * hash though not minimal since some levels might contain a number
6578cf72172SLorenzo Pieralisi 	 * of CPUs that is not an exact power of 2 and their bit
6588cf72172SLorenzo Pieralisi 	 * representation might contain holes, eg MPIDR[7:0] = {0x2, 0x80}.
6598cf72172SLorenzo Pieralisi 	 */
6608cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[0] = fs[0];
6618cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[1] = MPIDR_LEVEL_BITS + fs[1] - bits[0];
6628cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[2] = 2*MPIDR_LEVEL_BITS + fs[2] -
6638cf72172SLorenzo Pieralisi 						(bits[1] + bits[0]);
6648cf72172SLorenzo Pieralisi 	mpidr_hash.mask = mask;
6658cf72172SLorenzo Pieralisi 	mpidr_hash.bits = bits[2] + bits[1] + bits[0];
6668cf72172SLorenzo Pieralisi 	pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] mask[0x%x] bits[%u]\n",
6678cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[0],
6688cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[1],
6698cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[2],
6708cf72172SLorenzo Pieralisi 				mpidr_hash.mask,
6718cf72172SLorenzo Pieralisi 				mpidr_hash.bits);
6728cf72172SLorenzo Pieralisi 	/*
6738cf72172SLorenzo Pieralisi 	 * 4x is an arbitrary value used to warn on a hash table much bigger
6748cf72172SLorenzo Pieralisi 	 * than expected on most systems.
6758cf72172SLorenzo Pieralisi 	 */
6768cf72172SLorenzo Pieralisi 	if (mpidr_hash_size() > 4 * num_possible_cpus())
6778cf72172SLorenzo Pieralisi 		pr_warn("Large number of MPIDR hash buckets detected\n");
6788cf72172SLorenzo Pieralisi 	sync_cache_w(&mpidr_hash);
6798cf72172SLorenzo Pieralisi }
6808cf72172SLorenzo Pieralisi #endif
6818cf72172SLorenzo Pieralisi 
68265987a85SRussell King /*
68365987a85SRussell King  * locate processor in the list of supported processor types.  The linker
68465987a85SRussell King  * builds this table for us from the entries in arch/arm/mm/proc-*.S
68565987a85SRussell King  */
lookup_processor(u32 midr)68665987a85SRussell King struct proc_info_list *lookup_processor(u32 midr)
68765987a85SRussell King {
68865987a85SRussell King 	struct proc_info_list *list = lookup_processor_type(midr);
68965987a85SRussell King 
69065987a85SRussell King 	if (!list) {
69165987a85SRussell King 		pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
69265987a85SRussell King 		       smp_processor_id(), midr);
69365987a85SRussell King 		while (1)
69465987a85SRussell King 		/* can't use cpu_relax() here as it may require MMU setup */;
69565987a85SRussell King 	}
69665987a85SRussell King 
69765987a85SRussell King 	return list;
69865987a85SRussell King }
69965987a85SRussell King 
setup_processor(void)7001da177e4SLinus Torvalds static void __init setup_processor(void)
7011da177e4SLinus Torvalds {
70265987a85SRussell King 	unsigned int midr = read_cpuid_id();
70365987a85SRussell King 	struct proc_info_list *list = lookup_processor(midr);
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
7062ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
7071da177e4SLinus Torvalds 
708e209950fSRussell King 	init_proc_vtable(list->proc);
7091da177e4SLinus Torvalds #ifdef MULTI_TLB
7101da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
7111da177e4SLinus Torvalds #endif
7121da177e4SLinus Torvalds #ifdef MULTI_USER
7131da177e4SLinus Torvalds 	cpu_user = *list->user;
7141da177e4SLinus Torvalds #endif
7151da177e4SLinus Torvalds #ifdef MULTI_CACHE
7161da177e4SLinus Torvalds 	cpu_cache = *list->cache;
7171da177e4SLinus Torvalds #endif
7181da177e4SLinus Torvalds 
7191b0f6681SOlof Johansson 	pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
72065987a85SRussell King 		list->cpu_name, midr, midr & 15,
7214585eaffSRussell King 		proc_arch[cpu_architecture()], get_cr());
7221da177e4SLinus Torvalds 
723a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
724a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
725a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
726a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
7271da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
7288164f7afSStephen Boyd 
7298164f7afSStephen Boyd 	cpuid_init_hwcaps();
73042f25bddSNicolas Pitre 	patch_aeabi_idiv();
7318164f7afSStephen Boyd 
732adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
733c40e3641SStephen Boyd 	elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
734adeff422SCatalin Marinas #endif
735ca8f0b0aSRussell King #ifdef CONFIG_MMU
736ca8f0b0aSRussell King 	init_default_cache_policy(list->__cpu_mm_mmu_flags);
737ca8f0b0aSRussell King #endif
73892871b94SRob Herring 	erratum_a15_798181_init();
73992871b94SRob Herring 
74058171bf2SRussell King 	elf_hwcap_fixup();
741f159f4edSTony Lindgren 
742c0e95878SRussell King 	cacheid_init();
743b69874e4SRussell King 	cpu_init();
744ccea7a19SRussell King }
745ccea7a19SRussell King 
dump_machine_table(void)74693c02ab4SGrant Likely void __init dump_machine_table(void)
7471da177e4SLinus Torvalds {
748ff69a4c8SRussell King 	const struct machine_desc *p;
7491da177e4SLinus Torvalds 
7506291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
7516291319dSGrant Likely 	for_each_machine_desc(p)
752dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
753dce72dd0SNicolas Pitre 
754dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
755dce72dd0SNicolas Pitre 
756dce72dd0SNicolas Pitre 	while (true)
757dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
7581da177e4SLinus Torvalds }
7591da177e4SLinus Torvalds 
arm_add_memory(u64 start,u64 size)7606a5014aaSMagnus Damm int __init arm_add_memory(u64 start, u64 size)
7613a669411SRussell King {
7626d7d5da7SMagnus Damm 	u64 aligned_start;
7634b5f32ceSNicolas Pitre 
7643a669411SRussell King 	/*
7653a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
766909ba297SMasahiro Yamada 	 * Size is rounded down, start is rounded up.
7673a669411SRussell King 	 */
7686d7d5da7SMagnus Damm 	aligned_start = PAGE_ALIGN(start);
769909ba297SMasahiro Yamada 	if (aligned_start > start + size)
770909ba297SMasahiro Yamada 		size = 0;
771909ba297SMasahiro Yamada 	else
772909ba297SMasahiro Yamada 		size -= aligned_start - start;
773e5ab8580SWill Deacon 
774d4a451d5SChristoph Hellwig #ifndef CONFIG_PHYS_ADDR_T_64BIT
7756d7d5da7SMagnus Damm 	if (aligned_start > ULONG_MAX) {
7761b0f6681SOlof Johansson 		pr_crit("Ignoring memory at 0x%08llx outside 32-bit physical address space\n",
777730b5764SGeert Uytterhoeven 			start);
7786d7d5da7SMagnus Damm 		return -EINVAL;
7796d7d5da7SMagnus Damm 	}
7806d7d5da7SMagnus Damm 
7816d7d5da7SMagnus Damm 	if (aligned_start + size > ULONG_MAX) {
7821b0f6681SOlof Johansson 		pr_crit("Truncating memory at 0x%08llx to fit in 32-bit physical address space\n",
7831b0f6681SOlof Johansson 			(long long)start);
784e5ab8580SWill Deacon 		/*
785e5ab8580SWill Deacon 		 * To ensure bank->start + bank->size is representable in
786e5ab8580SWill Deacon 		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.
787e5ab8580SWill Deacon 		 * This means we lose a page after masking.
788e5ab8580SWill Deacon 		 */
7896d7d5da7SMagnus Damm 		size = ULONG_MAX - aligned_start;
790e5ab8580SWill Deacon 	}
791e5ab8580SWill Deacon #endif
792e5ab8580SWill Deacon 
793571b1437SRussell King 	if (aligned_start < PHYS_OFFSET) {
794571b1437SRussell King 		if (aligned_start + size <= PHYS_OFFSET) {
795571b1437SRussell King 			pr_info("Ignoring memory below PHYS_OFFSET: 0x%08llx-0x%08llx\n",
796571b1437SRussell King 				aligned_start, aligned_start + size);
797571b1437SRussell King 			return -EINVAL;
798571b1437SRussell King 		}
799571b1437SRussell King 
800571b1437SRussell King 		pr_info("Ignoring memory below PHYS_OFFSET: 0x%08llx-0x%08llx\n",
801571b1437SRussell King 			aligned_start, (u64)PHYS_OFFSET);
802571b1437SRussell King 
803571b1437SRussell King 		size -= PHYS_OFFSET - aligned_start;
804571b1437SRussell King 		aligned_start = PHYS_OFFSET;
805571b1437SRussell King 	}
806571b1437SRussell King 
8071c2f87c2SLaura Abbott 	start = aligned_start;
8081c2f87c2SLaura Abbott 	size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
8094b5f32ceSNicolas Pitre 
8104b5f32ceSNicolas Pitre 	/*
8114b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
8124b5f32ceSNicolas Pitre 	 * invalid node number.
8134b5f32ceSNicolas Pitre 	 */
8141c2f87c2SLaura Abbott 	if (size == 0)
8154b5f32ceSNicolas Pitre 		return -EINVAL;
8164b5f32ceSNicolas Pitre 
8171c2f87c2SLaura Abbott 	memblock_add(start, size);
8184b5f32ceSNicolas Pitre 	return 0;
8193a669411SRussell King }
8203a669411SRussell King 
8211da177e4SLinus Torvalds /*
8221da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
8231da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
8241da177e4SLinus Torvalds  */
8251c2f87c2SLaura Abbott 
early_mem(char * p)8262b0d8c25SJeremy Kerr static int __init early_mem(char *p)
8271da177e4SLinus Torvalds {
8281da177e4SLinus Torvalds 	static int usermem __initdata = 0;
8296a5014aaSMagnus Damm 	u64 size;
8306a5014aaSMagnus Damm 	u64 start;
8312b0d8c25SJeremy Kerr 	char *endp;
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	/*
8341da177e4SLinus Torvalds 	 * If the user specifies memory size, we
8351da177e4SLinus Torvalds 	 * blow away any automatically generated
8361da177e4SLinus Torvalds 	 * size.
8371da177e4SLinus Torvalds 	 */
8381da177e4SLinus Torvalds 	if (usermem == 0) {
8391da177e4SLinus Torvalds 		usermem = 1;
8401c2f87c2SLaura Abbott 		memblock_remove(memblock_start_of_DRAM(),
8411c2f87c2SLaura Abbott 			memblock_end_of_DRAM() - memblock_start_of_DRAM());
8421da177e4SLinus Torvalds 	}
8431da177e4SLinus Torvalds 
8441da177e4SLinus Torvalds 	start = PHYS_OFFSET;
8452b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
8462b0d8c25SJeremy Kerr 	if (*endp == '@')
8472b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
8481da177e4SLinus Torvalds 
8491c97b73eSAndrew Morton 	arm_add_memory(start, size);
8501da177e4SLinus Torvalds 
8512b0d8c25SJeremy Kerr 	return 0;
8521da177e4SLinus Torvalds }
8532b0d8c25SJeremy Kerr early_param("mem", early_mem);
8541da177e4SLinus Torvalds 
request_standard_resources(const struct machine_desc * mdesc)855ff69a4c8SRussell King static void __init request_standard_resources(const struct machine_desc *mdesc)
8561da177e4SLinus Torvalds {
857b10d6bcaSMike Rapoport 	phys_addr_t start, end, res_end;
8581da177e4SLinus Torvalds 	struct resource *res;
859b10d6bcaSMike Rapoport 	u64 i;
8601da177e4SLinus Torvalds 
86137efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
86214c4a533SKees Cook 	kernel_code.end     = virt_to_phys(__init_begin - 1);
863842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
86437efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
8651da177e4SLinus Torvalds 
866b10d6bcaSMike Rapoport 	for_each_mem_range(i, &start, &end) {
867966fab00SRussell King 		unsigned long boot_alias_start;
868966fab00SRussell King 
869966fab00SRussell King 		/*
870b10d6bcaSMike Rapoport 		 * In memblock, end points to the first byte after the
871b10d6bcaSMike Rapoport 		 * range while in resourses, end points to the last byte in
872b10d6bcaSMike Rapoport 		 * the range.
873b10d6bcaSMike Rapoport 		 */
874b10d6bcaSMike Rapoport 		res_end = end - 1;
875b10d6bcaSMike Rapoport 
876b10d6bcaSMike Rapoport 		/*
877966fab00SRussell King 		 * Some systems have a special memory alias which is only
878966fab00SRussell King 		 * used for booting.  We need to advertise this region to
879966fab00SRussell King 		 * kexec-tools so they know where bootable RAM is located.
880966fab00SRussell King 		 */
881966fab00SRussell King 		boot_alias_start = phys_to_idmap(start);
882966fab00SRussell King 		if (arm_has_idmap_alias() && boot_alias_start != IDMAP_INVALID_ADDR) {
8837e1c4e27SMike Rapoport 			res = memblock_alloc(sizeof(*res), SMP_CACHE_BYTES);
8848a7f97b9SMike Rapoport 			if (!res)
8858a7f97b9SMike Rapoport 				panic("%s: Failed to allocate %zu bytes\n",
8868a7f97b9SMike Rapoport 				      __func__, sizeof(*res));
887966fab00SRussell King 			res->name = "System RAM (boot alias)";
888966fab00SRussell King 			res->start = boot_alias_start;
889b10d6bcaSMike Rapoport 			res->end = phys_to_idmap(res_end);
890966fab00SRussell King 			res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
891966fab00SRussell King 			request_resource(&iomem_resource, res);
892966fab00SRussell King 		}
893966fab00SRussell King 
8947e1c4e27SMike Rapoport 		res = memblock_alloc(sizeof(*res), SMP_CACHE_BYTES);
8958a7f97b9SMike Rapoport 		if (!res)
8968a7f97b9SMike Rapoport 			panic("%s: Failed to allocate %zu bytes\n", __func__,
8978a7f97b9SMike Rapoport 			      sizeof(*res));
8981da177e4SLinus Torvalds 		res->name  = "System RAM";
899966fab00SRussell King 		res->start = start;
900b10d6bcaSMike Rapoport 		res->end = res_end;
90135d98e93SToshi Kani 		res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
9061da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
9071da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
9081da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
9091da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
9101da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
9111da177e4SLinus Torvalds 	}
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	if (mdesc->video_start) {
9141da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
9151da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
9161da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
9171da177e4SLinus Torvalds 	}
9181da177e4SLinus Torvalds 
9191da177e4SLinus Torvalds 	/*
9201da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
9211da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
9221da177e4SLinus Torvalds 	 */
9231da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
9241da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
9251da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
9261da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
9271da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
9281da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
9291da177e4SLinus Torvalds }
9301da177e4SLinus Torvalds 
931801820beSArd Biesheuvel #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) || \
932801820beSArd Biesheuvel     defined(CONFIG_EFI)
9331da177e4SLinus Torvalds struct screen_info screen_info = {
9341da177e4SLinus Torvalds  .orig_video_lines	= 30,
9351da177e4SLinus Torvalds  .orig_video_cols	= 80,
9361da177e4SLinus Torvalds  .orig_video_mode	= 0,
9371da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
9381da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
9391da177e4SLinus Torvalds  .orig_video_points	= 8
9401da177e4SLinus Torvalds };
9411da177e4SLinus Torvalds #endif
9421da177e4SLinus Torvalds 
customize_machine(void)9431da177e4SLinus Torvalds static int __init customize_machine(void)
9441da177e4SLinus Torvalds {
945883a106bSArnd Bergmann 	/*
946883a106bSArnd Bergmann 	 * customizes platform devices, or adds new ones
947883a106bSArnd Bergmann 	 * On DT based machines, we fall back to populating the
948883a106bSArnd Bergmann 	 * machine from the device tree, if no callback is provided,
949883a106bSArnd Bergmann 	 * otherwise we would always need an init_machine callback.
950883a106bSArnd Bergmann 	 */
9518ff1443cSRussell King 	if (machine_desc->init_machine)
9528ff1443cSRussell King 		machine_desc->init_machine();
953850bea23SKefeng Wang 
9541da177e4SLinus Torvalds 	return 0;
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds arch_initcall(customize_machine);
9571da177e4SLinus Torvalds 
init_machine_late(void)95890de4137SShawn Guo static int __init init_machine_late(void)
95990de4137SShawn Guo {
9603f599875SPaul Kocialkowski 	struct device_node *root;
9613f599875SPaul Kocialkowski 	int ret;
9623f599875SPaul Kocialkowski 
96390de4137SShawn Guo 	if (machine_desc->init_late)
96490de4137SShawn Guo 		machine_desc->init_late();
9653f599875SPaul Kocialkowski 
9663f599875SPaul Kocialkowski 	root = of_find_node_by_path("/");
9673f599875SPaul Kocialkowski 	if (root) {
9683f599875SPaul Kocialkowski 		ret = of_property_read_string(root, "serial-number",
9693f599875SPaul Kocialkowski 					      &system_serial);
9703f599875SPaul Kocialkowski 		if (ret)
9713f599875SPaul Kocialkowski 			system_serial = NULL;
9723f599875SPaul Kocialkowski 	}
9733f599875SPaul Kocialkowski 
9743f599875SPaul Kocialkowski 	if (!system_serial)
9753f599875SPaul Kocialkowski 		system_serial = kasprintf(GFP_KERNEL, "%08x%08x",
9763f599875SPaul Kocialkowski 					  system_serial_high,
9773f599875SPaul Kocialkowski 					  system_serial_low);
9783f599875SPaul Kocialkowski 
97990de4137SShawn Guo 	return 0;
98090de4137SShawn Guo }
98190de4137SShawn Guo late_initcall(init_machine_late);
98290de4137SShawn Guo 
9833c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
98461603016SRussell King /*
98561603016SRussell King  * The crash region must be aligned to 128MB to avoid
98661603016SRussell King  * zImage relocating below the reserved region.
98761603016SRussell King  */
98861603016SRussell King #define CRASH_ALIGN	(128 << 20)
98961603016SRussell King 
get_total_mem(void)9903c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
9913c57fb43SMika Westerberg {
9923c57fb43SMika Westerberg 	unsigned long total;
9933c57fb43SMika Westerberg 
9943c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
9953c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
9963c57fb43SMika Westerberg }
9973c57fb43SMika Westerberg 
9983c57fb43SMika Westerberg /**
9993c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
10003c57fb43SMika Westerberg  *
10013c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
10023c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
10033c57fb43SMika Westerberg  * primary kernel is crashing.
10043c57fb43SMika Westerberg  */
reserve_crashkernel(void)10053c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
10063c57fb43SMika Westerberg {
10073c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
10083c57fb43SMika Westerberg 	unsigned long long total_mem;
10093c57fb43SMika Westerberg 	int ret;
10103c57fb43SMika Westerberg 
10113c57fb43SMika Westerberg 	total_mem = get_total_mem();
10123c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
10133c57fb43SMika Westerberg 				&crash_size, &crash_base);
10149d17f337SAustin Kim 	/* invalid value specified or crashkernel=0 */
10159d17f337SAustin Kim 	if (ret || !crash_size)
10163c57fb43SMika Westerberg 		return;
10173c57fb43SMika Westerberg 
101861603016SRussell King 	if (crash_base <= 0) {
1019d0506a23SRussell King 		unsigned long long crash_max = idmap_to_phys((u32)~0);
102067556d7aSRussell King 		unsigned long long lowmem_max = __pa(high_memory - 1) + 1;
102167556d7aSRussell King 		if (crash_max > lowmem_max)
102267556d7aSRussell King 			crash_max = lowmem_max;
1023a7259df7SMike Rapoport 
1024a7259df7SMike Rapoport 		crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
1025a7259df7SMike Rapoport 						       CRASH_ALIGN, crash_max);
102661603016SRussell King 		if (!crash_base) {
102761603016SRussell King 			pr_err("crashkernel reservation failed - No suitable area found.\n");
102861603016SRussell King 			return;
102961603016SRussell King 		}
103061603016SRussell King 	} else {
1031a7259df7SMike Rapoport 		unsigned long long crash_max = crash_base + crash_size;
103261603016SRussell King 		unsigned long long start;
103361603016SRussell King 
1034a7259df7SMike Rapoport 		start = memblock_phys_alloc_range(crash_size, SECTION_SIZE,
1035a7259df7SMike Rapoport 						  crash_base, crash_max);
1036a7259df7SMike Rapoport 		if (!start) {
103761603016SRussell King 			pr_err("crashkernel reservation failed - memory is in use.\n");
103861603016SRussell King 			return;
103961603016SRussell King 		}
104061603016SRussell King 	}
104161603016SRussell King 
10421b0f6681SOlof Johansson 	pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
10433c57fb43SMika Westerberg 		(unsigned long)(crash_size >> 20),
10443c57fb43SMika Westerberg 		(unsigned long)(crash_base >> 20),
10453c57fb43SMika Westerberg 		(unsigned long)(total_mem >> 20));
10463c57fb43SMika Westerberg 
1047f7f0b7dcSRussell King 	/* The crashk resource must always be located in normal mem */
10483c57fb43SMika Westerberg 	crashk_res.start = crash_base;
10493c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
10503c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
1051f7f0b7dcSRussell King 
1052f7f0b7dcSRussell King 	if (arm_has_idmap_alias()) {
1053f7f0b7dcSRussell King 		/*
1054f7f0b7dcSRussell King 		 * If we have a special RAM alias for use at boot, we
1055f7f0b7dcSRussell King 		 * need to advertise to kexec tools where the alias is.
1056f7f0b7dcSRussell King 		 */
1057f7f0b7dcSRussell King 		static struct resource crashk_boot_res = {
1058f7f0b7dcSRussell King 			.name = "Crash kernel (boot alias)",
1059f7f0b7dcSRussell King 			.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
1060f7f0b7dcSRussell King 		};
1061f7f0b7dcSRussell King 
1062f7f0b7dcSRussell King 		crashk_boot_res.start = phys_to_idmap(crash_base);
1063f7f0b7dcSRussell King 		crashk_boot_res.end = crashk_boot_res.start + crash_size - 1;
1064f7f0b7dcSRussell King 		insert_resource(&iomem_resource, &crashk_boot_res);
1065f7f0b7dcSRussell King 	}
10663c57fb43SMika Westerberg }
10673c57fb43SMika Westerberg #else
reserve_crashkernel(void)10683c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
10693c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
10703c57fb43SMika Westerberg 
hyp_mode_check(void)10714588c34dSDave Martin void __init hyp_mode_check(void)
10724588c34dSDave Martin {
10734588c34dSDave Martin #ifdef CONFIG_ARM_VIRT_EXT
10748fbac214SMark Rutland 	sync_boot_mode();
10758fbac214SMark Rutland 
10764588c34dSDave Martin 	if (is_hyp_mode_available()) {
10774588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in HYP mode.\n");
10784588c34dSDave Martin 		pr_info("CPU: Virtualization extensions available.\n");
10794588c34dSDave Martin 	} else if (is_hyp_mode_mismatched()) {
10804588c34dSDave Martin 		pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
10814588c34dSDave Martin 			__boot_cpu_mode & MODE_MASK);
10824588c34dSDave Martin 		pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
10834588c34dSDave Martin 	} else
10844588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in SVC mode.\n");
10854588c34dSDave Martin #endif
10864588c34dSDave Martin }
10874588c34dSDave Martin 
1088ce8f1ccbSGuenter Roeck static void (*__arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
1089ce8f1ccbSGuenter Roeck 
arm_restart(struct notifier_block * nb,unsigned long action,void * data)1090ce8f1ccbSGuenter Roeck static int arm_restart(struct notifier_block *nb, unsigned long action,
1091ce8f1ccbSGuenter Roeck 		       void *data)
1092ce8f1ccbSGuenter Roeck {
1093ce8f1ccbSGuenter Roeck 	__arm_pm_restart(action, data);
1094ce8f1ccbSGuenter Roeck 	return NOTIFY_DONE;
1095ce8f1ccbSGuenter Roeck }
1096ce8f1ccbSGuenter Roeck 
1097ce8f1ccbSGuenter Roeck static struct notifier_block arm_restart_nb = {
1098ce8f1ccbSGuenter Roeck 	.notifier_call = arm_restart,
1099ce8f1ccbSGuenter Roeck 	.priority = 128,
1100ce8f1ccbSGuenter Roeck };
1101ce8f1ccbSGuenter Roeck 
setup_arch(char ** cmdline_p)11026291319dSGrant Likely void __init setup_arch(char **cmdline_p)
11036291319dSGrant Likely {
1104e9a2f8b5SArd Biesheuvel 	const struct machine_desc *mdesc = NULL;
11057a1be318SArd Biesheuvel 	void *atags_vaddr = NULL;
1106e9a2f8b5SArd Biesheuvel 
1107e9a2f8b5SArd Biesheuvel 	if (__atags_pointer)
1108fc2933c1SArd Biesheuvel 		atags_vaddr = FDT_VIRT_BASE(__atags_pointer);
11096291319dSGrant Likely 
11106291319dSGrant Likely 	setup_processor();
11117a1be318SArd Biesheuvel 	if (atags_vaddr) {
1112e9a2f8b5SArd Biesheuvel 		mdesc = setup_machine_fdt(atags_vaddr);
11137a1be318SArd Biesheuvel 		if (mdesc)
11147a1be318SArd Biesheuvel 			memblock_reserve(__atags_pointer,
11157a1be318SArd Biesheuvel 					 fdt_totalsize(atags_vaddr));
11167a1be318SArd Biesheuvel 	}
111793c02ab4SGrant Likely 	if (!mdesc)
1118e9a2f8b5SArd Biesheuvel 		mdesc = setup_machine_tags(atags_vaddr, __machine_arch_type);
111999cf8f90SRussell King 	if (!mdesc) {
112099cf8f90SRussell King 		early_print("\nError: invalid dtb and unrecognized/unsupported machine ID\n");
112199cf8f90SRussell King 		early_print("  r1=0x%08x, r2=0x%08x\n", __machine_arch_type,
112299cf8f90SRussell King 			    __atags_pointer);
112399cf8f90SRussell King 		if (__atags_pointer)
1124e9a2f8b5SArd Biesheuvel 			early_print("  r2[]=%*ph\n", 16, atags_vaddr);
112599cf8f90SRussell King 		dump_machine_table();
112699cf8f90SRussell King 	}
112799cf8f90SRussell King 
11286291319dSGrant Likely 	machine_desc = mdesc;
11296291319dSGrant Likely 	machine_name = mdesc->name;
1130719c9d14SRussell King 	dump_stack_set_arch_desc("%s", mdesc->name);
11316291319dSGrant Likely 
113216d6d5b0SRobin Holt 	if (mdesc->reboot_mode != REBOOT_HARD)
113316d6d5b0SRobin Holt 		reboot_mode = mdesc->reboot_mode;
11346291319dSGrant Likely 
113534f8602eSKefeng Wang 	setup_initial_init_mm(_text, _etext, _edata, _end);
11361da177e4SLinus Torvalds 
113748ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
1138*7611b335SAzeem Shaikh 	strscpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
113948ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
11402b0d8c25SJeremy Kerr 
1141a5f4c561SStefan Agner 	early_fixmap_init();
11422937367bSArd Biesheuvel 	early_ioremap_init();
1143a5f4c561SStefan Agner 
11442b0d8c25SJeremy Kerr 	parse_early_param();
11452b0d8c25SJeremy Kerr 
11461221ed10SRussell King #ifdef CONFIG_MMU
1147b089c31cSJon Medhurst 	early_mm_init(mdesc);
11481221ed10SRussell King #endif
11497c927322SSantosh Shilimkar 	setup_dma_zone(mdesc);
11509b08aaa3SShannon Zhao 	xen_early_init();
115169e377b2SArd Biesheuvel 	arm_efi_init();
115298562656SLaura Abbott 	/*
115398562656SLaura Abbott 	 * Make sure the calculation for lowmem/highmem is set appropriately
1154df8eda0fSGeert Uytterhoeven 	 * before reserving/allocating any memory
115598562656SLaura Abbott 	 */
1156374d446dSLaura Abbott 	adjust_lowmem_bounds();
11571c2f87c2SLaura Abbott 	arm_memblock_init(mdesc);
115898562656SLaura Abbott 	/* Memory may have been removed so recalculate the bounds. */
115998562656SLaura Abbott 	adjust_lowmem_bounds();
11602778f620SRussell King 
11612937367bSArd Biesheuvel 	early_ioremap_reset();
11622937367bSArd Biesheuvel 
11634b5f32ceSNicolas Pitre 	paging_init(mdesc);
11645615f69bSLinus Walleij 	kasan_init();
116511b9369cSDima Zavin 	request_standard_resources(mdesc);
11661da177e4SLinus Torvalds 
1167ce8f1ccbSGuenter Roeck 	if (mdesc->restart) {
1168ce8f1ccbSGuenter Roeck 		__arm_pm_restart = mdesc->restart;
1169ce8f1ccbSGuenter Roeck 		register_restart_handler(&arm_restart_nb);
1170ce8f1ccbSGuenter Roeck 	}
1171a528721dSRussell King 
117293c02ab4SGrant Likely 	unflatten_device_tree();
117393c02ab4SGrant Likely 
11745587164eSLorenzo Pieralisi 	arm_dt_init_cpu_maps();
1175be120397SMark Rutland 	psci_dt_init();
11767bbb7940SRussell King #ifdef CONFIG_SMP
1177abcee5fbSMarc Zyngier 	if (is_smp()) {
1178b382b940SJon Medhurst 		if (!mdesc->smp_init || !mdesc->smp_init()) {
117905774088SStefano Stabellini 			if (psci_smp_available())
118005774088SStefano Stabellini 				smp_set_ops(&psci_smp_ops);
118105774088SStefano Stabellini 			else if (mdesc->smp)
1182abcee5fbSMarc Zyngier 				smp_set_ops(mdesc->smp);
1183b382b940SJon Medhurst 		}
11847bbb7940SRussell King 		smp_init_cpus();
11858cf72172SLorenzo Pieralisi 		smp_build_mpidr_hash();
1186abcee5fbSMarc Zyngier 	}
11877bbb7940SRussell King #endif
11884588c34dSDave Martin 
11894588c34dSDave Martin 	if (!is_smp())
11904588c34dSDave Martin 		hyp_mode_check();
11914588c34dSDave Martin 
11923c57fb43SMika Westerberg 	reserve_crashkernel();
11937bbb7940SRussell King 
11941da177e4SLinus Torvalds #ifdef CONFIG_VT
11951da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
11961da177e4SLinus Torvalds 	conswitchp = &vga_con;
11971da177e4SLinus Torvalds #endif
11981da177e4SLinus Torvalds #endif
1199dec12e62SRussell King 
1200dec12e62SRussell King 	if (mdesc->init_early)
1201dec12e62SRussell King 		mdesc->init_early();
12021da177e4SLinus Torvalds }
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 
topology_init(void)12051da177e4SLinus Torvalds static int __init topology_init(void)
12061da177e4SLinus Torvalds {
12071da177e4SLinus Torvalds 	int cpu;
12081da177e4SLinus Torvalds 
120966fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
121066fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
1211787047eeSStephen Boyd 		cpuinfo->cpu.hotpluggable = platform_can_hotplug_cpu(cpu);
121266fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
121366fb8bd2SRussell King 	}
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds 	return 0;
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds subsys_initcall(topology_init);
12181da177e4SLinus Torvalds 
1219e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
proc_cpu_init(void)1220e119bfffSRussell King static int __init proc_cpu_init(void)
1221e119bfffSRussell King {
1222e119bfffSRussell King 	struct proc_dir_entry *res;
1223e119bfffSRussell King 
1224e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
1225e119bfffSRussell King 	if (!res)
1226e119bfffSRussell King 		return -ENOMEM;
1227e119bfffSRussell King 	return 0;
1228e119bfffSRussell King }
1229e119bfffSRussell King fs_initcall(proc_cpu_init);
1230e119bfffSRussell King #endif
1231e119bfffSRussell King 
12321da177e4SLinus Torvalds static const char *hwcap_str[] = {
12331da177e4SLinus Torvalds 	"swp",
12341da177e4SLinus Torvalds 	"half",
12351da177e4SLinus Torvalds 	"thumb",
12361da177e4SLinus Torvalds 	"26bit",
12371da177e4SLinus Torvalds 	"fastmult",
12381da177e4SLinus Torvalds 	"fpa",
12391da177e4SLinus Torvalds 	"vfp",
12401da177e4SLinus Torvalds 	"edsp",
12411da177e4SLinus Torvalds 	"java",
12428f7f9435SPaul Gortmaker 	"iwmmxt",
124399e4a6ddSLennert Buytenhek 	"crunch",
12444369ae16SCatalin Marinas 	"thumbee",
12452bedbdf4SCatalin Marinas 	"neon",
12467279dc3eSCatalin Marinas 	"vfpv3",
12477279dc3eSCatalin Marinas 	"vfpv3d16",
1248254cdf8eSWill Deacon 	"tls",
1249254cdf8eSWill Deacon 	"vfpv4",
1250254cdf8eSWill Deacon 	"idiva",
1251254cdf8eSWill Deacon 	"idivt",
1252ab8d46c0STetsuyuki Kobayashi 	"vfpd32",
1253a469abd0SWill Deacon 	"lpae",
1254e9faebc6SSudeep KarkadaNagesha 	"evtstrm",
1255c00a19c8SAmit Daniel Kachhap 	"fphp",
1256c00a19c8SAmit Daniel Kachhap 	"asimdhp",
125762ea0d87SAmit Daniel Kachhap 	"asimddp",
1258ce483549SAmit Daniel Kachhap 	"asimdfhm",
125923b6d4adSAmit Daniel Kachhap 	"asimdbf16",
1260956ca3a4SAmit Daniel Kachhap 	"i8mm",
12611da177e4SLinus Torvalds 	NULL
12621da177e4SLinus Torvalds };
12631da177e4SLinus Torvalds 
1264b342ea4eSArd Biesheuvel static const char *hwcap2_str[] = {
12658258a989SArd Biesheuvel 	"aes",
12668258a989SArd Biesheuvel 	"pmull",
12678258a989SArd Biesheuvel 	"sha1",
12688258a989SArd Biesheuvel 	"sha2",
12698258a989SArd Biesheuvel 	"crc32",
12703bda6d88SAmit Daniel Kachhap 	"sb",
1271fea53546SAmit Daniel Kachhap 	"ssbs",
1272b342ea4eSArd Biesheuvel 	NULL
1273b342ea4eSArd Biesheuvel };
1274b342ea4eSArd Biesheuvel 
c_show(struct seq_file * m,void * v)12751da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
12761da177e4SLinus Torvalds {
1277b4b8f770SLorenzo Pieralisi 	int i, j;
1278b4b8f770SLorenzo Pieralisi 	u32 cpuid;
12791da177e4SLinus Torvalds 
12801da177e4SLinus Torvalds 	for_each_online_cpu(i) {
128115559722SRussell King 		/*
128215559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
128315559722SRussell King 		 * online processors, looking for lines beginning with
128415559722SRussell King 		 * "processor".  Give glibc what it expects.
128515559722SRussell King 		 */
128615559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
1287b4b8f770SLorenzo Pieralisi 		cpuid = is_smp() ? per_cpu(cpu_data, i).cpuid : read_cpuid_id();
1288b4b8f770SLorenzo Pieralisi 		seq_printf(m, "model name\t: %s rev %d (%s)\n",
1289b4b8f770SLorenzo Pieralisi 			   cpu_name, cpuid & 15, elf_platform);
1290b4b8f770SLorenzo Pieralisi 
12914bf9636cSPavel Machek #if defined(CONFIG_SMP)
12924bf9636cSPavel Machek 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
12934bf9636cSPavel Machek 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
12944bf9636cSPavel Machek 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
12954bf9636cSPavel Machek #else
12964bf9636cSPavel Machek 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
12974bf9636cSPavel Machek 			   loops_per_jiffy / (500000/HZ),
12984bf9636cSPavel Machek 			   (loops_per_jiffy / (5000/HZ)) % 100);
12994bf9636cSPavel Machek #endif
13001da177e4SLinus Torvalds 		/* dump out the processor features */
13011da177e4SLinus Torvalds 		seq_puts(m, "Features\t: ");
13021da177e4SLinus Torvalds 
1303b4b8f770SLorenzo Pieralisi 		for (j = 0; hwcap_str[j]; j++)
1304b4b8f770SLorenzo Pieralisi 			if (elf_hwcap & (1 << j))
1305b4b8f770SLorenzo Pieralisi 				seq_printf(m, "%s ", hwcap_str[j]);
13061da177e4SLinus Torvalds 
1307b342ea4eSArd Biesheuvel 		for (j = 0; hwcap2_str[j]; j++)
1308b342ea4eSArd Biesheuvel 			if (elf_hwcap2 & (1 << j))
1309b342ea4eSArd Biesheuvel 				seq_printf(m, "%s ", hwcap2_str[j]);
1310b342ea4eSArd Biesheuvel 
1311b4b8f770SLorenzo Pieralisi 		seq_printf(m, "\nCPU implementer\t: 0x%02x\n", cpuid >> 24);
1312b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU architecture: %s\n",
1313b4b8f770SLorenzo Pieralisi 			   proc_arch[cpu_architecture()]);
13141da177e4SLinus Torvalds 
1315b4b8f770SLorenzo Pieralisi 		if ((cpuid & 0x0008f000) == 0x00000000) {
13161da177e4SLinus Torvalds 			/* pre-ARM7 */
1317b4b8f770SLorenzo Pieralisi 			seq_printf(m, "CPU part\t: %07x\n", cpuid >> 4);
13181da177e4SLinus Torvalds 		} else {
1319b4b8f770SLorenzo Pieralisi 			if ((cpuid & 0x0008f000) == 0x00007000) {
13201da177e4SLinus Torvalds 				/* ARM7 */
13211da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%02x\n",
1322b4b8f770SLorenzo Pieralisi 					   (cpuid >> 16) & 127);
13231da177e4SLinus Torvalds 			} else {
13241da177e4SLinus Torvalds 				/* post-ARM7 */
13251da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%x\n",
1326b4b8f770SLorenzo Pieralisi 					   (cpuid >> 20) & 15);
13271da177e4SLinus Torvalds 			}
13281da177e4SLinus Torvalds 			seq_printf(m, "CPU part\t: 0x%03x\n",
1329b4b8f770SLorenzo Pieralisi 				   (cpuid >> 4) & 0xfff);
13301da177e4SLinus Torvalds 		}
1331b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU revision\t: %d\n\n", cpuid & 15);
1332b4b8f770SLorenzo Pieralisi 	}
13331da177e4SLinus Torvalds 
13341da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
13351da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
13363f599875SPaul Kocialkowski 	seq_printf(m, "Serial\t\t: %s\n", system_serial);
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	return 0;
13391da177e4SLinus Torvalds }
13401da177e4SLinus Torvalds 
c_start(struct seq_file * m,loff_t * pos)13411da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
13421da177e4SLinus Torvalds {
13431da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
13441da177e4SLinus Torvalds }
13451da177e4SLinus Torvalds 
c_next(struct seq_file * m,void * v,loff_t * pos)13461da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
13471da177e4SLinus Torvalds {
13481da177e4SLinus Torvalds 	++*pos;
13491da177e4SLinus Torvalds 	return NULL;
13501da177e4SLinus Torvalds }
13511da177e4SLinus Torvalds 
c_stop(struct seq_file * m,void * v)13521da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
13531da177e4SLinus Torvalds {
13541da177e4SLinus Torvalds }
13551da177e4SLinus Torvalds 
13562ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
13571da177e4SLinus Torvalds 	.start	= c_start,
13581da177e4SLinus Torvalds 	.next	= c_next,
13591da177e4SLinus Torvalds 	.stop	= c_stop,
13601da177e4SLinus Torvalds 	.show	= c_show
13611da177e4SLinus Torvalds };
1362