xref: /linux-6.15/arch/arm/kernel/setup.c (revision c6f23979)
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>
181da177e4SLinus Torvalds #include <linux/init.h>
193c57fb43SMika Westerberg #include <linux/kexec.h>
207a1be318SArd Biesheuvel #include <linux/libfdt.h>
213562257bSRob Herring #include <linux/of.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) {
883*c6f23979SGuo Weikang 			res = memblock_alloc_or_panic(sizeof(*res), SMP_CACHE_BYTES);
884966fab00SRussell King 			res->name = "System RAM (boot alias)";
885966fab00SRussell King 			res->start = boot_alias_start;
886b10d6bcaSMike Rapoport 			res->end = phys_to_idmap(res_end);
887966fab00SRussell King 			res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
888966fab00SRussell King 			request_resource(&iomem_resource, res);
889966fab00SRussell King 		}
890966fab00SRussell King 
891*c6f23979SGuo Weikang 		res = memblock_alloc_or_panic(sizeof(*res), SMP_CACHE_BYTES);
8921da177e4SLinus Torvalds 		res->name  = "System RAM";
893966fab00SRussell King 		res->start = start;
894b10d6bcaSMike Rapoport 		res->end = res_end;
89535d98e93SToshi Kani 		res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
9001da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
9011da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
9021da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
9031da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
9041da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
9051da177e4SLinus Torvalds 	}
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds 	if (mdesc->video_start) {
9081da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
9091da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
9101da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
9111da177e4SLinus Torvalds 	}
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	/*
9141da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
9151da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
9161da177e4SLinus Torvalds 	 */
9171da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
9181da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
9191da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
9201da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
9211da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
9221da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds 
925555624c0SArnd Bergmann #if defined(CONFIG_VGA_CONSOLE)
9260059bc9aSArnd Bergmann struct screen_info vgacon_screen_info = {
9271da177e4SLinus Torvalds  .orig_video_lines	= 30,
9281da177e4SLinus Torvalds  .orig_video_cols	= 80,
9291da177e4SLinus Torvalds  .orig_video_mode	= 0,
9301da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
9311da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
9321da177e4SLinus Torvalds  .orig_video_points	= 8
9331da177e4SLinus Torvalds };
9341da177e4SLinus Torvalds #endif
9351da177e4SLinus Torvalds 
customize_machine(void)9361da177e4SLinus Torvalds static int __init customize_machine(void)
9371da177e4SLinus Torvalds {
938883a106bSArnd Bergmann 	/*
939883a106bSArnd Bergmann 	 * customizes platform devices, or adds new ones
940883a106bSArnd Bergmann 	 * On DT based machines, we fall back to populating the
941883a106bSArnd Bergmann 	 * machine from the device tree, if no callback is provided,
942883a106bSArnd Bergmann 	 * otherwise we would always need an init_machine callback.
943883a106bSArnd Bergmann 	 */
9448ff1443cSRussell King 	if (machine_desc->init_machine)
9458ff1443cSRussell King 		machine_desc->init_machine();
946850bea23SKefeng Wang 
9471da177e4SLinus Torvalds 	return 0;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds arch_initcall(customize_machine);
9501da177e4SLinus Torvalds 
init_machine_late(void)95190de4137SShawn Guo static int __init init_machine_late(void)
95290de4137SShawn Guo {
9533f599875SPaul Kocialkowski 	struct device_node *root;
9543f599875SPaul Kocialkowski 	int ret;
9553f599875SPaul Kocialkowski 
95690de4137SShawn Guo 	if (machine_desc->init_late)
95790de4137SShawn Guo 		machine_desc->init_late();
9583f599875SPaul Kocialkowski 
9593f599875SPaul Kocialkowski 	root = of_find_node_by_path("/");
9603f599875SPaul Kocialkowski 	if (root) {
9613f599875SPaul Kocialkowski 		ret = of_property_read_string(root, "serial-number",
9623f599875SPaul Kocialkowski 					      &system_serial);
9633f599875SPaul Kocialkowski 		if (ret)
9643f599875SPaul Kocialkowski 			system_serial = NULL;
9653f599875SPaul Kocialkowski 	}
9663f599875SPaul Kocialkowski 
9673f599875SPaul Kocialkowski 	if (!system_serial)
9683f599875SPaul Kocialkowski 		system_serial = kasprintf(GFP_KERNEL, "%08x%08x",
9693f599875SPaul Kocialkowski 					  system_serial_high,
9703f599875SPaul Kocialkowski 					  system_serial_low);
9713f599875SPaul Kocialkowski 
97290de4137SShawn Guo 	return 0;
97390de4137SShawn Guo }
97490de4137SShawn Guo late_initcall(init_machine_late);
97590de4137SShawn Guo 
9765057dff3SBaoquan He #ifdef CONFIG_CRASH_RESERVE
97761603016SRussell King /*
97861603016SRussell King  * The crash region must be aligned to 128MB to avoid
97961603016SRussell King  * zImage relocating below the reserved region.
98061603016SRussell King  */
98161603016SRussell King #define CRASH_ALIGN	(128 << 20)
98261603016SRussell King 
get_total_mem(void)9833c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
9843c57fb43SMika Westerberg {
9853c57fb43SMika Westerberg 	unsigned long total;
9863c57fb43SMika Westerberg 
9873c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
9883c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
9893c57fb43SMika Westerberg }
9903c57fb43SMika Westerberg 
9913c57fb43SMika Westerberg /**
9923c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
9933c57fb43SMika Westerberg  *
9943c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
9953c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
9963c57fb43SMika Westerberg  * primary kernel is crashing.
9973c57fb43SMika Westerberg  */
reserve_crashkernel(void)9983c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
9993c57fb43SMika Westerberg {
10003c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
10013c57fb43SMika Westerberg 	unsigned long long total_mem;
10023c57fb43SMika Westerberg 	int ret;
10033c57fb43SMika Westerberg 
10043c57fb43SMika Westerberg 	total_mem = get_total_mem();
10053c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
1006a9e1a3d8SBaoquan He 				&crash_size, &crash_base,
1007a9e1a3d8SBaoquan He 				NULL, NULL);
10089d17f337SAustin Kim 	/* invalid value specified or crashkernel=0 */
10099d17f337SAustin Kim 	if (ret || !crash_size)
10103c57fb43SMika Westerberg 		return;
10113c57fb43SMika Westerberg 
101261603016SRussell King 	if (crash_base <= 0) {
1013d0506a23SRussell King 		unsigned long long crash_max = idmap_to_phys((u32)~0);
101467556d7aSRussell King 		unsigned long long lowmem_max = __pa(high_memory - 1) + 1;
101567556d7aSRussell King 		if (crash_max > lowmem_max)
101667556d7aSRussell King 			crash_max = lowmem_max;
1017a7259df7SMike Rapoport 
1018a7259df7SMike Rapoport 		crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
1019a7259df7SMike Rapoport 						       CRASH_ALIGN, crash_max);
102061603016SRussell King 		if (!crash_base) {
102161603016SRussell King 			pr_err("crashkernel reservation failed - No suitable area found.\n");
102261603016SRussell King 			return;
102361603016SRussell King 		}
102461603016SRussell King 	} else {
1025a7259df7SMike Rapoport 		unsigned long long crash_max = crash_base + crash_size;
102661603016SRussell King 		unsigned long long start;
102761603016SRussell King 
1028a7259df7SMike Rapoport 		start = memblock_phys_alloc_range(crash_size, SECTION_SIZE,
1029a7259df7SMike Rapoport 						  crash_base, crash_max);
1030a7259df7SMike Rapoport 		if (!start) {
103161603016SRussell King 			pr_err("crashkernel reservation failed - memory is in use.\n");
103261603016SRussell King 			return;
103361603016SRussell King 		}
103461603016SRussell King 	}
103561603016SRussell King 
10361b0f6681SOlof Johansson 	pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
10373c57fb43SMika Westerberg 		(unsigned long)(crash_size >> 20),
10383c57fb43SMika Westerberg 		(unsigned long)(crash_base >> 20),
10393c57fb43SMika Westerberg 		(unsigned long)(total_mem >> 20));
10403c57fb43SMika Westerberg 
1041f7f0b7dcSRussell King 	/* The crashk resource must always be located in normal mem */
10423c57fb43SMika Westerberg 	crashk_res.start = crash_base;
10433c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
10443c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
1045f7f0b7dcSRussell King 
1046f7f0b7dcSRussell King 	if (arm_has_idmap_alias()) {
1047f7f0b7dcSRussell King 		/*
1048f7f0b7dcSRussell King 		 * If we have a special RAM alias for use at boot, we
1049f7f0b7dcSRussell King 		 * need to advertise to kexec tools where the alias is.
1050f7f0b7dcSRussell King 		 */
1051f7f0b7dcSRussell King 		static struct resource crashk_boot_res = {
1052f7f0b7dcSRussell King 			.name = "Crash kernel (boot alias)",
1053f7f0b7dcSRussell King 			.flags = IORESOURCE_BUSY | IORESOURCE_MEM,
1054f7f0b7dcSRussell King 		};
1055f7f0b7dcSRussell King 
1056f7f0b7dcSRussell King 		crashk_boot_res.start = phys_to_idmap(crash_base);
1057f7f0b7dcSRussell King 		crashk_boot_res.end = crashk_boot_res.start + crash_size - 1;
1058f7f0b7dcSRussell King 		insert_resource(&iomem_resource, &crashk_boot_res);
1059f7f0b7dcSRussell King 	}
10603c57fb43SMika Westerberg }
10613c57fb43SMika Westerberg #else
reserve_crashkernel(void)10623c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
10635057dff3SBaoquan He #endif /* CONFIG_CRASH_RESERVE*/
10643c57fb43SMika Westerberg 
hyp_mode_check(void)10654588c34dSDave Martin void __init hyp_mode_check(void)
10664588c34dSDave Martin {
10674588c34dSDave Martin #ifdef CONFIG_ARM_VIRT_EXT
10688fbac214SMark Rutland 	sync_boot_mode();
10698fbac214SMark Rutland 
10704588c34dSDave Martin 	if (is_hyp_mode_available()) {
10714588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in HYP mode.\n");
10724588c34dSDave Martin 		pr_info("CPU: Virtualization extensions available.\n");
10734588c34dSDave Martin 	} else if (is_hyp_mode_mismatched()) {
10744588c34dSDave Martin 		pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
10754588c34dSDave Martin 			__boot_cpu_mode & MODE_MASK);
10764588c34dSDave Martin 		pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
10774588c34dSDave Martin 	} else
10784588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in SVC mode.\n");
10794588c34dSDave Martin #endif
10804588c34dSDave Martin }
10814588c34dSDave Martin 
1082ce8f1ccbSGuenter Roeck static void (*__arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
1083ce8f1ccbSGuenter Roeck 
arm_restart(struct notifier_block * nb,unsigned long action,void * data)1084ce8f1ccbSGuenter Roeck static int arm_restart(struct notifier_block *nb, unsigned long action,
1085ce8f1ccbSGuenter Roeck 		       void *data)
1086ce8f1ccbSGuenter Roeck {
1087ce8f1ccbSGuenter Roeck 	__arm_pm_restart(action, data);
1088ce8f1ccbSGuenter Roeck 	return NOTIFY_DONE;
1089ce8f1ccbSGuenter Roeck }
1090ce8f1ccbSGuenter Roeck 
1091ce8f1ccbSGuenter Roeck static struct notifier_block arm_restart_nb = {
1092ce8f1ccbSGuenter Roeck 	.notifier_call = arm_restart,
1093ce8f1ccbSGuenter Roeck 	.priority = 128,
1094ce8f1ccbSGuenter Roeck };
1095ce8f1ccbSGuenter Roeck 
setup_arch(char ** cmdline_p)10966291319dSGrant Likely void __init setup_arch(char **cmdline_p)
10976291319dSGrant Likely {
1098e9a2f8b5SArd Biesheuvel 	const struct machine_desc *mdesc = NULL;
10997a1be318SArd Biesheuvel 	void *atags_vaddr = NULL;
1100e9a2f8b5SArd Biesheuvel 
1101e9a2f8b5SArd Biesheuvel 	if (__atags_pointer)
1102fc2933c1SArd Biesheuvel 		atags_vaddr = FDT_VIRT_BASE(__atags_pointer);
11036291319dSGrant Likely 
11046291319dSGrant Likely 	setup_processor();
11057a1be318SArd Biesheuvel 	if (atags_vaddr) {
1106e9a2f8b5SArd Biesheuvel 		mdesc = setup_machine_fdt(atags_vaddr);
11077a1be318SArd Biesheuvel 		if (mdesc)
11087a1be318SArd Biesheuvel 			memblock_reserve(__atags_pointer,
11097a1be318SArd Biesheuvel 					 fdt_totalsize(atags_vaddr));
11107a1be318SArd Biesheuvel 	}
111193c02ab4SGrant Likely 	if (!mdesc)
1112e9a2f8b5SArd Biesheuvel 		mdesc = setup_machine_tags(atags_vaddr, __machine_arch_type);
111399cf8f90SRussell King 	if (!mdesc) {
111499cf8f90SRussell King 		early_print("\nError: invalid dtb and unrecognized/unsupported machine ID\n");
111599cf8f90SRussell King 		early_print("  r1=0x%08x, r2=0x%08x\n", __machine_arch_type,
111699cf8f90SRussell King 			    __atags_pointer);
111799cf8f90SRussell King 		if (__atags_pointer)
1118e9a2f8b5SArd Biesheuvel 			early_print("  r2[]=%*ph\n", 16, atags_vaddr);
111999cf8f90SRussell King 		dump_machine_table();
112099cf8f90SRussell King 	}
112199cf8f90SRussell King 
11226291319dSGrant Likely 	machine_desc = mdesc;
11236291319dSGrant Likely 	machine_name = mdesc->name;
1124719c9d14SRussell King 	dump_stack_set_arch_desc("%s", mdesc->name);
11256291319dSGrant Likely 
112616d6d5b0SRobin Holt 	if (mdesc->reboot_mode != REBOOT_HARD)
112716d6d5b0SRobin Holt 		reboot_mode = mdesc->reboot_mode;
11286291319dSGrant Likely 
112934f8602eSKefeng Wang 	setup_initial_init_mm(_text, _etext, _edata, _end);
11301da177e4SLinus Torvalds 
113148ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
11327611b335SAzeem Shaikh 	strscpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
113348ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
11342b0d8c25SJeremy Kerr 
1135a5f4c561SStefan Agner 	early_fixmap_init();
11362937367bSArd Biesheuvel 	early_ioremap_init();
1137a5f4c561SStefan Agner 
11382b0d8c25SJeremy Kerr 	parse_early_param();
11392b0d8c25SJeremy Kerr 
11401221ed10SRussell King #ifdef CONFIG_MMU
1141b089c31cSJon Medhurst 	early_mm_init(mdesc);
11421221ed10SRussell King #endif
11437c927322SSantosh Shilimkar 	setup_dma_zone(mdesc);
11449b08aaa3SShannon Zhao 	xen_early_init();
114569e377b2SArd Biesheuvel 	arm_efi_init();
114698562656SLaura Abbott 	/*
114798562656SLaura Abbott 	 * Make sure the calculation for lowmem/highmem is set appropriately
1148df8eda0fSGeert Uytterhoeven 	 * before reserving/allocating any memory
114998562656SLaura Abbott 	 */
1150374d446dSLaura Abbott 	adjust_lowmem_bounds();
11511c2f87c2SLaura Abbott 	arm_memblock_init(mdesc);
115298562656SLaura Abbott 	/* Memory may have been removed so recalculate the bounds. */
115398562656SLaura Abbott 	adjust_lowmem_bounds();
11542778f620SRussell King 
11552937367bSArd Biesheuvel 	early_ioremap_reset();
11562937367bSArd Biesheuvel 
11574b5f32ceSNicolas Pitre 	paging_init(mdesc);
11585615f69bSLinus Walleij 	kasan_init();
115911b9369cSDima Zavin 	request_standard_resources(mdesc);
11601da177e4SLinus Torvalds 
1161ce8f1ccbSGuenter Roeck 	if (mdesc->restart) {
1162ce8f1ccbSGuenter Roeck 		__arm_pm_restart = mdesc->restart;
1163ce8f1ccbSGuenter Roeck 		register_restart_handler(&arm_restart_nb);
1164ce8f1ccbSGuenter Roeck 	}
1165a528721dSRussell King 
116693c02ab4SGrant Likely 	unflatten_device_tree();
116793c02ab4SGrant Likely 
11685587164eSLorenzo Pieralisi 	arm_dt_init_cpu_maps();
1169be120397SMark Rutland 	psci_dt_init();
11707bbb7940SRussell King #ifdef CONFIG_SMP
1171abcee5fbSMarc Zyngier 	if (is_smp()) {
1172b382b940SJon Medhurst 		if (!mdesc->smp_init || !mdesc->smp_init()) {
117305774088SStefano Stabellini 			if (psci_smp_available())
117405774088SStefano Stabellini 				smp_set_ops(&psci_smp_ops);
117505774088SStefano Stabellini 			else if (mdesc->smp)
1176abcee5fbSMarc Zyngier 				smp_set_ops(mdesc->smp);
1177b382b940SJon Medhurst 		}
11787bbb7940SRussell King 		smp_init_cpus();
11798cf72172SLorenzo Pieralisi 		smp_build_mpidr_hash();
1180abcee5fbSMarc Zyngier 	}
11817bbb7940SRussell King #endif
11824588c34dSDave Martin 
11834588c34dSDave Martin 	if (!is_smp())
11844588c34dSDave Martin 		hyp_mode_check();
11854588c34dSDave Martin 
11863c57fb43SMika Westerberg 	reserve_crashkernel();
11877bbb7940SRussell King 
11881da177e4SLinus Torvalds #ifdef CONFIG_VT
11891da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
1190555624c0SArnd Bergmann 	vgacon_register_screen(&vgacon_screen_info);
11911da177e4SLinus Torvalds #endif
11921da177e4SLinus Torvalds #endif
1193dec12e62SRussell King 
1194dec12e62SRussell King 	if (mdesc->init_early)
1195dec12e62SRussell King 		mdesc->init_early();
11961da177e4SLinus Torvalds }
11971da177e4SLinus Torvalds 
arch_cpu_is_hotpluggable(int num)1198f7f8b433SJinjie Ruan bool arch_cpu_is_hotpluggable(int num)
11991da177e4SLinus Torvalds {
1200f7f8b433SJinjie Ruan 	return platform_can_hotplug_cpu(num);
120166fb8bd2SRussell King }
12021da177e4SLinus Torvalds 
1203e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
proc_cpu_init(void)1204e119bfffSRussell King static int __init proc_cpu_init(void)
1205e119bfffSRussell King {
1206e119bfffSRussell King 	struct proc_dir_entry *res;
1207e119bfffSRussell King 
1208e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
1209e119bfffSRussell King 	if (!res)
1210e119bfffSRussell King 		return -ENOMEM;
1211e119bfffSRussell King 	return 0;
1212e119bfffSRussell King }
1213e119bfffSRussell King fs_initcall(proc_cpu_init);
1214e119bfffSRussell King #endif
1215e119bfffSRussell King 
12161da177e4SLinus Torvalds static const char *hwcap_str[] = {
12171da177e4SLinus Torvalds 	"swp",
12181da177e4SLinus Torvalds 	"half",
12191da177e4SLinus Torvalds 	"thumb",
12201da177e4SLinus Torvalds 	"26bit",
12211da177e4SLinus Torvalds 	"fastmult",
12221da177e4SLinus Torvalds 	"fpa",
12231da177e4SLinus Torvalds 	"vfp",
12241da177e4SLinus Torvalds 	"edsp",
12251da177e4SLinus Torvalds 	"java",
12268f7f9435SPaul Gortmaker 	"iwmmxt",
122799e4a6ddSLennert Buytenhek 	"crunch",
12284369ae16SCatalin Marinas 	"thumbee",
12292bedbdf4SCatalin Marinas 	"neon",
12307279dc3eSCatalin Marinas 	"vfpv3",
12317279dc3eSCatalin Marinas 	"vfpv3d16",
1232254cdf8eSWill Deacon 	"tls",
1233254cdf8eSWill Deacon 	"vfpv4",
1234254cdf8eSWill Deacon 	"idiva",
1235254cdf8eSWill Deacon 	"idivt",
1236ab8d46c0STetsuyuki Kobayashi 	"vfpd32",
1237a469abd0SWill Deacon 	"lpae",
1238e9faebc6SSudeep KarkadaNagesha 	"evtstrm",
1239c00a19c8SAmit Daniel Kachhap 	"fphp",
1240c00a19c8SAmit Daniel Kachhap 	"asimdhp",
124162ea0d87SAmit Daniel Kachhap 	"asimddp",
1242ce483549SAmit Daniel Kachhap 	"asimdfhm",
124323b6d4adSAmit Daniel Kachhap 	"asimdbf16",
1244956ca3a4SAmit Daniel Kachhap 	"i8mm",
12451da177e4SLinus Torvalds 	NULL
12461da177e4SLinus Torvalds };
12471da177e4SLinus Torvalds 
1248b342ea4eSArd Biesheuvel static const char *hwcap2_str[] = {
12498258a989SArd Biesheuvel 	"aes",
12508258a989SArd Biesheuvel 	"pmull",
12518258a989SArd Biesheuvel 	"sha1",
12528258a989SArd Biesheuvel 	"sha2",
12538258a989SArd Biesheuvel 	"crc32",
12543bda6d88SAmit Daniel Kachhap 	"sb",
1255fea53546SAmit Daniel Kachhap 	"ssbs",
1256b342ea4eSArd Biesheuvel 	NULL
1257b342ea4eSArd Biesheuvel };
1258b342ea4eSArd Biesheuvel 
c_show(struct seq_file * m,void * v)12591da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
12601da177e4SLinus Torvalds {
1261b4b8f770SLorenzo Pieralisi 	int i, j;
1262b4b8f770SLorenzo Pieralisi 	u32 cpuid;
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	for_each_online_cpu(i) {
126515559722SRussell King 		/*
126615559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
126715559722SRussell King 		 * online processors, looking for lines beginning with
126815559722SRussell King 		 * "processor".  Give glibc what it expects.
126915559722SRussell King 		 */
127015559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
1271b4b8f770SLorenzo Pieralisi 		cpuid = is_smp() ? per_cpu(cpu_data, i).cpuid : read_cpuid_id();
1272b4b8f770SLorenzo Pieralisi 		seq_printf(m, "model name\t: %s rev %d (%s)\n",
1273b4b8f770SLorenzo Pieralisi 			   cpu_name, cpuid & 15, elf_platform);
1274b4b8f770SLorenzo Pieralisi 
12754bf9636cSPavel Machek #if defined(CONFIG_SMP)
12764bf9636cSPavel Machek 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
12774bf9636cSPavel Machek 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
12784bf9636cSPavel Machek 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
12794bf9636cSPavel Machek #else
12804bf9636cSPavel Machek 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
12814bf9636cSPavel Machek 			   loops_per_jiffy / (500000/HZ),
12824bf9636cSPavel Machek 			   (loops_per_jiffy / (5000/HZ)) % 100);
12834bf9636cSPavel Machek #endif
12841da177e4SLinus Torvalds 		/* dump out the processor features */
12851da177e4SLinus Torvalds 		seq_puts(m, "Features\t: ");
12861da177e4SLinus Torvalds 
1287b4b8f770SLorenzo Pieralisi 		for (j = 0; hwcap_str[j]; j++)
1288b4b8f770SLorenzo Pieralisi 			if (elf_hwcap & (1 << j))
1289b4b8f770SLorenzo Pieralisi 				seq_printf(m, "%s ", hwcap_str[j]);
12901da177e4SLinus Torvalds 
1291b342ea4eSArd Biesheuvel 		for (j = 0; hwcap2_str[j]; j++)
1292b342ea4eSArd Biesheuvel 			if (elf_hwcap2 & (1 << j))
1293b342ea4eSArd Biesheuvel 				seq_printf(m, "%s ", hwcap2_str[j]);
1294b342ea4eSArd Biesheuvel 
1295b4b8f770SLorenzo Pieralisi 		seq_printf(m, "\nCPU implementer\t: 0x%02x\n", cpuid >> 24);
1296b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU architecture: %s\n",
1297b4b8f770SLorenzo Pieralisi 			   proc_arch[cpu_architecture()]);
12981da177e4SLinus Torvalds 
1299b4b8f770SLorenzo Pieralisi 		if ((cpuid & 0x0008f000) == 0x00000000) {
13001da177e4SLinus Torvalds 			/* pre-ARM7 */
1301b4b8f770SLorenzo Pieralisi 			seq_printf(m, "CPU part\t: %07x\n", cpuid >> 4);
13021da177e4SLinus Torvalds 		} else {
1303b4b8f770SLorenzo Pieralisi 			if ((cpuid & 0x0008f000) == 0x00007000) {
13041da177e4SLinus Torvalds 				/* ARM7 */
13051da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%02x\n",
1306b4b8f770SLorenzo Pieralisi 					   (cpuid >> 16) & 127);
13071da177e4SLinus Torvalds 			} else {
13081da177e4SLinus Torvalds 				/* post-ARM7 */
13091da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%x\n",
1310b4b8f770SLorenzo Pieralisi 					   (cpuid >> 20) & 15);
13111da177e4SLinus Torvalds 			}
13121da177e4SLinus Torvalds 			seq_printf(m, "CPU part\t: 0x%03x\n",
1313b4b8f770SLorenzo Pieralisi 				   (cpuid >> 4) & 0xfff);
13141da177e4SLinus Torvalds 		}
1315b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU revision\t: %d\n\n", cpuid & 15);
1316b4b8f770SLorenzo Pieralisi 	}
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
13191da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
13203f599875SPaul Kocialkowski 	seq_printf(m, "Serial\t\t: %s\n", system_serial);
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 	return 0;
13231da177e4SLinus Torvalds }
13241da177e4SLinus Torvalds 
c_start(struct seq_file * m,loff_t * pos)13251da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
13261da177e4SLinus Torvalds {
13271da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
13281da177e4SLinus Torvalds }
13291da177e4SLinus Torvalds 
c_next(struct seq_file * m,void * v,loff_t * pos)13301da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
13311da177e4SLinus Torvalds {
13321da177e4SLinus Torvalds 	++*pos;
13331da177e4SLinus Torvalds 	return NULL;
13341da177e4SLinus Torvalds }
13351da177e4SLinus Torvalds 
c_stop(struct seq_file * m,void * v)13361da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
13371da177e4SLinus Torvalds {
13381da177e4SLinus Torvalds }
13391da177e4SLinus Torvalds 
13402ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
13411da177e4SLinus Torvalds 	.start	= c_start,
13421da177e4SLinus Torvalds 	.next	= c_next,
13431da177e4SLinus Torvalds 	.stop	= c_stop,
13441da177e4SLinus Torvalds 	.show	= c_show
13451da177e4SLinus Torvalds };
1346