xref: /openbmc/linux/arch/arm/kernel/setup.c (revision 9b08aaa3)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/arch/arm/kernel/setup.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1995-2001 Russell King
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
71da177e4SLinus Torvalds  * it under the terms of the GNU General Public License version 2 as
81da177e4SLinus Torvalds  * published by the Free Software Foundation.
91da177e4SLinus Torvalds  */
10da58fb65SArd Biesheuvel #include <linux/efi.h>
11ecea4ab6SPaul Gortmaker #include <linux/export.h>
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/stddef.h>
141da177e4SLinus Torvalds #include <linux/ioport.h>
151da177e4SLinus Torvalds #include <linux/delay.h>
161da177e4SLinus Torvalds #include <linux/utsname.h>
171da177e4SLinus Torvalds #include <linux/initrd.h>
181da177e4SLinus Torvalds #include <linux/console.h>
191da177e4SLinus Torvalds #include <linux/bootmem.h>
201da177e4SLinus Torvalds #include <linux/seq_file.h>
21894673eeSJon Smirl #include <linux/screen_info.h>
22af4dda73SWill Deacon #include <linux/of_iommu.h>
23883a106bSArnd Bergmann #include <linux/of_platform.h>
241da177e4SLinus Torvalds #include <linux/init.h>
253c57fb43SMika Westerberg #include <linux/kexec.h>
2693c02ab4SGrant Likely #include <linux/of_fdt.h>
271da177e4SLinus Torvalds #include <linux/cpu.h>
281da177e4SLinus Torvalds #include <linux/interrupt.h>
297bbb7940SRussell King #include <linux/smp.h>
30e119bfffSRussell King #include <linux/proc_fs.h>
312778f620SRussell King #include <linux/memblock.h>
322ecccf90SDave Martin #include <linux/bug.h>
332ecccf90SDave Martin #include <linux/compiler.h>
3427a3f0e9SNicolas Pitre #include <linux/sort.h>
35be120397SMark Rutland #include <linux/psci.h>
361da177e4SLinus Torvalds 
37b86040a5SCatalin Marinas #include <asm/unified.h>
3815d07dc9SRussell King #include <asm/cp15.h>
391da177e4SLinus Torvalds #include <asm/cpu.h>
400ba8b9b2SRussell King #include <asm/cputype.h>
41da58fb65SArd Biesheuvel #include <asm/efi.h>
421da177e4SLinus Torvalds #include <asm/elf.h>
432937367bSArd Biesheuvel #include <asm/early_ioremap.h>
44a5f4c561SStefan Agner #include <asm/fixmap.h>
451da177e4SLinus Torvalds #include <asm/procinfo.h>
4605774088SStefano Stabellini #include <asm/psci.h>
4737efe642SRussell King #include <asm/sections.h>
481da177e4SLinus Torvalds #include <asm/setup.h>
49f00ec48fSRussell King #include <asm/smp_plat.h>
501da177e4SLinus Torvalds #include <asm/mach-types.h>
511da177e4SLinus Torvalds #include <asm/cacheflush.h>
5246097c7dSRussell King #include <asm/cachetype.h>
531da177e4SLinus Torvalds #include <asm/tlbflush.h>
545882bfefSStefano Stabellini #include <asm/xen/hypervisor.h>
551da177e4SLinus Torvalds 
5693c02ab4SGrant Likely #include <asm/prom.h>
571da177e4SLinus Torvalds #include <asm/mach/arch.h>
581da177e4SLinus Torvalds #include <asm/mach/irq.h>
591da177e4SLinus Torvalds #include <asm/mach/time.h>
609f97da78SDavid Howells #include <asm/system_info.h>
619f97da78SDavid Howells #include <asm/system_misc.h>
625cbad0ebSJason Wessel #include <asm/traps.h>
63bff595c1SCatalin Marinas #include <asm/unwind.h>
641c16d242STejun Heo #include <asm/memblock.h>
654588c34dSDave Martin #include <asm/virt.h>
661da177e4SLinus Torvalds 
674cd9d6f7SRichard Purdie #include "atags.h"
680fc1c832SBen Dooks 
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
711da177e4SLinus Torvalds char fpe_type[8];
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds static int __init fpe_setup(char *line)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	memcpy(fpe_type, line, 8);
761da177e4SLinus Torvalds 	return 1;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds __setup("fpe=", fpe_setup);
801da177e4SLinus Torvalds #endif
811da177e4SLinus Torvalds 
82ca8f0b0aSRussell King extern void init_default_cache_policy(unsigned long);
83ff69a4c8SRussell King extern void paging_init(const struct machine_desc *desc);
841221ed10SRussell King extern void early_paging_init(const struct machine_desc *);
850371d3f7SRussell King extern void sanity_check_meminfo(void);
8616d6d5b0SRobin Holt extern enum reboot_mode reboot_mode;
87ff69a4c8SRussell King extern void setup_dma_zone(const struct machine_desc *desc);
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds unsigned int processor_id;
90c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id);
910385ebc0SRussell King unsigned int __machine_arch_type __read_mostly;
921da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type);
930385ebc0SRussell King unsigned int cacheid __read_mostly;
94c0e95878SRussell King EXPORT_SYMBOL(cacheid);
951da177e4SLinus Torvalds 
969d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata;
979d20fdd5SBill Gatliff 
981da177e4SLinus Torvalds unsigned int system_rev;
991da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev);
1001da177e4SLinus Torvalds 
1013f599875SPaul Kocialkowski const char *system_serial;
1023f599875SPaul Kocialkowski EXPORT_SYMBOL(system_serial);
1033f599875SPaul Kocialkowski 
1041da177e4SLinus Torvalds unsigned int system_serial_low;
1051da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low);
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds unsigned int system_serial_high;
1081da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high);
1091da177e4SLinus Torvalds 
1100385ebc0SRussell King unsigned int elf_hwcap __read_mostly;
1111da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap);
1121da177e4SLinus Torvalds 
113b342ea4eSArd Biesheuvel unsigned int elf_hwcap2 __read_mostly;
114b342ea4eSArd Biesheuvel EXPORT_SYMBOL(elf_hwcap2);
115b342ea4eSArd Biesheuvel 
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds #ifdef MULTI_CPU
1180385ebc0SRussell King struct processor processor __read_mostly;
1191da177e4SLinus Torvalds #endif
1201da177e4SLinus Torvalds #ifdef MULTI_TLB
1210385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly;
1221da177e4SLinus Torvalds #endif
1231da177e4SLinus Torvalds #ifdef MULTI_USER
1240385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly;
1251da177e4SLinus Torvalds #endif
1261da177e4SLinus Torvalds #ifdef MULTI_CACHE
1270385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly;
1281da177e4SLinus Torvalds #endif
129953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE
1300385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly;
1316c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache);
132953233dcSCatalin Marinas #endif
1331da177e4SLinus Torvalds 
1342ecccf90SDave Martin /*
1352ecccf90SDave Martin  * Cached cpu_architecture() result for use by assembler code.
1362ecccf90SDave Martin  * C code should use the cpu_architecture() function instead of accessing this
1372ecccf90SDave Martin  * variable directly.
1382ecccf90SDave Martin  */
1392ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN;
1402ecccf90SDave Martin 
141ccea7a19SRussell King struct stack {
142ccea7a19SRussell King 	u32 irq[3];
143ccea7a19SRussell King 	u32 abt[3];
144ccea7a19SRussell King 	u32 und[3];
145c0e7f7eeSDaniel Thompson 	u32 fiq[3];
146ccea7a19SRussell King } ____cacheline_aligned;
147ccea7a19SRussell King 
14855bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
149ccea7a19SRussell King static struct stack stacks[NR_CPUS];
15055bdd694SCatalin Marinas #endif
151ccea7a19SRussell King 
1521da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE];
1531da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform);
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds static const char *cpu_name;
1561da177e4SLinus Torvalds static const char *machine_name;
15748ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE];
158ff69a4c8SRussell King const struct machine_desc *machine_desc __initdata;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
1611da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l)
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds /*
1661da177e4SLinus Torvalds  * Standard memory resources
1671da177e4SLinus Torvalds  */
1681da177e4SLinus Torvalds static struct resource mem_res[] = {
169740e518eSGreg Kroah-Hartman 	{
170740e518eSGreg Kroah-Hartman 		.name = "Video RAM",
171740e518eSGreg Kroah-Hartman 		.start = 0,
172740e518eSGreg Kroah-Hartman 		.end = 0,
173740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_MEM
174740e518eSGreg Kroah-Hartman 	},
175740e518eSGreg Kroah-Hartman 	{
176a36d8e5bSKees Cook 		.name = "Kernel code",
177740e518eSGreg Kroah-Hartman 		.start = 0,
178740e518eSGreg Kroah-Hartman 		.end = 0,
17935d98e93SToshi Kani 		.flags = IORESOURCE_SYSTEM_RAM
180740e518eSGreg Kroah-Hartman 	},
181740e518eSGreg Kroah-Hartman 	{
182740e518eSGreg Kroah-Hartman 		.name = "Kernel data",
183740e518eSGreg Kroah-Hartman 		.start = 0,
184740e518eSGreg Kroah-Hartman 		.end = 0,
18535d98e93SToshi Kani 		.flags = IORESOURCE_SYSTEM_RAM
186740e518eSGreg Kroah-Hartman 	}
1871da177e4SLinus Torvalds };
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds #define video_ram   mem_res[0]
1901da177e4SLinus Torvalds #define kernel_code mem_res[1]
1911da177e4SLinus Torvalds #define kernel_data mem_res[2]
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds static struct resource io_res[] = {
194740e518eSGreg Kroah-Hartman 	{
195740e518eSGreg Kroah-Hartman 		.name = "reserved",
196740e518eSGreg Kroah-Hartman 		.start = 0x3bc,
197740e518eSGreg Kroah-Hartman 		.end = 0x3be,
198740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
199740e518eSGreg Kroah-Hartman 	},
200740e518eSGreg Kroah-Hartman 	{
201740e518eSGreg Kroah-Hartman 		.name = "reserved",
202740e518eSGreg Kroah-Hartman 		.start = 0x378,
203740e518eSGreg Kroah-Hartman 		.end = 0x37f,
204740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
205740e518eSGreg Kroah-Hartman 	},
206740e518eSGreg Kroah-Hartman 	{
207740e518eSGreg Kroah-Hartman 		.name = "reserved",
208740e518eSGreg Kroah-Hartman 		.start = 0x278,
209740e518eSGreg Kroah-Hartman 		.end = 0x27f,
210740e518eSGreg Kroah-Hartman 		.flags = IORESOURCE_IO | IORESOURCE_BUSY
211740e518eSGreg Kroah-Hartman 	}
2121da177e4SLinus Torvalds };
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds #define lp0 io_res[0]
2151da177e4SLinus Torvalds #define lp1 io_res[1]
2161da177e4SLinus Torvalds #define lp2 io_res[2]
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds static const char *proc_arch[] = {
2191da177e4SLinus Torvalds 	"undefined/unknown",
2201da177e4SLinus Torvalds 	"3",
2211da177e4SLinus Torvalds 	"4",
2221da177e4SLinus Torvalds 	"4T",
2231da177e4SLinus Torvalds 	"5",
2241da177e4SLinus Torvalds 	"5T",
2251da177e4SLinus Torvalds 	"5TE",
2261da177e4SLinus Torvalds 	"5TEJ",
2271da177e4SLinus Torvalds 	"6TEJ",
2286b090a25SCatalin Marinas 	"7",
22955bdd694SCatalin Marinas 	"7M",
2301da177e4SLinus Torvalds 	"?(12)",
2311da177e4SLinus Torvalds 	"?(13)",
2321da177e4SLinus Torvalds 	"?(14)",
2331da177e4SLinus Torvalds 	"?(15)",
2341da177e4SLinus Torvalds 	"?(16)",
2351da177e4SLinus Torvalds 	"?(17)",
2361da177e4SLinus Torvalds };
2371da177e4SLinus Torvalds 
23855bdd694SCatalin Marinas #ifdef CONFIG_CPU_V7M
23955bdd694SCatalin Marinas static int __get_cpu_architecture(void)
24055bdd694SCatalin Marinas {
24155bdd694SCatalin Marinas 	return CPU_ARCH_ARMv7M;
24255bdd694SCatalin Marinas }
24355bdd694SCatalin Marinas #else
2442ecccf90SDave Martin static int __get_cpu_architecture(void)
2451da177e4SLinus Torvalds {
2461da177e4SLinus Torvalds 	int cpu_arch;
2471da177e4SLinus Torvalds 
2480ba8b9b2SRussell King 	if ((read_cpuid_id() & 0x0008f000) == 0) {
2491da177e4SLinus Torvalds 		cpu_arch = CPU_ARCH_UNKNOWN;
2500ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
2510ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
2520ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
2530ba8b9b2SRussell King 		cpu_arch = (read_cpuid_id() >> 16) & 7;
2541da177e4SLinus Torvalds 		if (cpu_arch)
2551da177e4SLinus Torvalds 			cpu_arch += CPU_ARCH_ARMv3;
2560ba8b9b2SRussell King 	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
257180005c4SCatalin Marinas 		/* Revised CPUID format. Read the Memory Model Feature
258180005c4SCatalin Marinas 		 * Register 0 and check for VMSAv7 or PMSAv7 */
259526299ceSMason 		unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
260315cfe78SCatalin Marinas 		if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
261315cfe78SCatalin Marinas 		    (mmfr0 & 0x000000f0) >= 0x00000030)
262180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv7;
263180005c4SCatalin Marinas 		else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
264180005c4SCatalin Marinas 			 (mmfr0 & 0x000000f0) == 0x00000020)
265180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_ARMv6;
266180005c4SCatalin Marinas 		else
267180005c4SCatalin Marinas 			cpu_arch = CPU_ARCH_UNKNOWN;
268180005c4SCatalin Marinas 	} else
269180005c4SCatalin Marinas 		cpu_arch = CPU_ARCH_UNKNOWN;
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	return cpu_arch;
2721da177e4SLinus Torvalds }
27355bdd694SCatalin Marinas #endif
2741da177e4SLinus Torvalds 
2752ecccf90SDave Martin int __pure cpu_architecture(void)
2762ecccf90SDave Martin {
2772ecccf90SDave Martin 	BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN);
2782ecccf90SDave Martin 
2792ecccf90SDave Martin 	return __cpu_architecture;
2802ecccf90SDave Martin }
2812ecccf90SDave Martin 
2828925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch)
2838925ec4cSWill Deacon {
2848925ec4cSWill Deacon 	int aliasing_icache;
2858925ec4cSWill Deacon 	unsigned int id_reg, num_sets, line_size;
2868925ec4cSWill Deacon 
2877f94e9ccSWill Deacon 	/* PIPT caches never alias. */
2887f94e9ccSWill Deacon 	if (icache_is_pipt())
2897f94e9ccSWill Deacon 		return 0;
2907f94e9ccSWill Deacon 
2918925ec4cSWill Deacon 	/* arch specifies the register format */
2928925ec4cSWill Deacon 	switch (arch) {
2938925ec4cSWill Deacon 	case CPU_ARCH_ARMv7:
2945fb31a96SLinus Walleij 		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
2955fb31a96SLinus Walleij 		    : /* No output operands */
2968925ec4cSWill Deacon 		    : "r" (1));
2975fb31a96SLinus Walleij 		isb();
2985fb31a96SLinus Walleij 		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
2995fb31a96SLinus Walleij 		    : "=r" (id_reg));
3008925ec4cSWill Deacon 		line_size = 4 << ((id_reg & 0x7) + 2);
3018925ec4cSWill Deacon 		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
3028925ec4cSWill Deacon 		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
3038925ec4cSWill Deacon 		break;
3048925ec4cSWill Deacon 	case CPU_ARCH_ARMv6:
3058925ec4cSWill Deacon 		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
3068925ec4cSWill Deacon 		break;
3078925ec4cSWill Deacon 	default:
3088925ec4cSWill Deacon 		/* I-cache aliases will be handled by D-cache aliasing code */
3098925ec4cSWill Deacon 		aliasing_icache = 0;
3108925ec4cSWill Deacon 	}
3118925ec4cSWill Deacon 
3128925ec4cSWill Deacon 	return aliasing_icache;
3138925ec4cSWill Deacon }
3148925ec4cSWill Deacon 
315c0e95878SRussell King static void __init cacheid_init(void)
316c0e95878SRussell King {
317c0e95878SRussell King 	unsigned int arch = cpu_architecture();
318c0e95878SRussell King 
31955bdd694SCatalin Marinas 	if (arch == CPU_ARCH_ARMv7M) {
32055bdd694SCatalin Marinas 		cacheid = 0;
32155bdd694SCatalin Marinas 	} else if (arch >= CPU_ARCH_ARMv6) {
322ac52e83fSUwe Kleine-König 		unsigned int cachetype = read_cpuid_cachetype();
323b57ee99fSCatalin Marinas 		if ((cachetype & (7 << 29)) == 4 << 29) {
324b57ee99fSCatalin Marinas 			/* ARMv7 register format */
32572dc53acSWill Deacon 			arch = CPU_ARCH_ARMv7;
326c0e95878SRussell King 			cacheid = CACHEID_VIPT_NONALIASING;
3277f94e9ccSWill Deacon 			switch (cachetype & (3 << 14)) {
3287f94e9ccSWill Deacon 			case (1 << 14):
329c0e95878SRussell King 				cacheid |= CACHEID_ASID_TAGGED;
3307f94e9ccSWill Deacon 				break;
3317f94e9ccSWill Deacon 			case (3 << 14):
3327f94e9ccSWill Deacon 				cacheid |= CACHEID_PIPT;
3337f94e9ccSWill Deacon 				break;
3347f94e9ccSWill Deacon 			}
3358925ec4cSWill Deacon 		} else {
33672dc53acSWill Deacon 			arch = CPU_ARCH_ARMv6;
33772dc53acSWill Deacon 			if (cachetype & (1 << 23))
33872dc53acSWill Deacon 				cacheid = CACHEID_VIPT_ALIASING;
33972dc53acSWill Deacon 			else
340c0e95878SRussell King 				cacheid = CACHEID_VIPT_NONALIASING;
3418925ec4cSWill Deacon 		}
34272dc53acSWill Deacon 		if (cpu_has_aliasing_icache(arch))
34372dc53acSWill Deacon 			cacheid |= CACHEID_VIPT_I_ALIASING;
344c0e95878SRussell King 	} else {
345c0e95878SRussell King 		cacheid = CACHEID_VIVT;
346c0e95878SRussell King 	}
3472b4ae1f1SRussell King 
3481b0f6681SOlof Johansson 	pr_info("CPU: %s data cache, %s instruction cache\n",
3492b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3502b4ae1f1SRussell King 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
3517f94e9ccSWill Deacon 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
3522b4ae1f1SRussell King 		cache_is_vivt() ? "VIVT" :
3532b4ae1f1SRussell King 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
3548925ec4cSWill Deacon 		icache_is_vipt_aliasing() ? "VIPT aliasing" :
3557f94e9ccSWill Deacon 		icache_is_pipt() ? "PIPT" :
3562b4ae1f1SRussell King 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
357c0e95878SRussell King }
358c0e95878SRussell King 
3591da177e4SLinus Torvalds /*
3601da177e4SLinus Torvalds  * These functions re-use the assembly code in head.S, which
3611da177e4SLinus Torvalds  * already provide the required functionality.
3621da177e4SLinus Torvalds  */
3630f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int);
3646fc31d54SRussell King 
36593c02ab4SGrant Likely void __init early_print(const char *str, ...)
3666fc31d54SRussell King {
3676fc31d54SRussell King 	extern void printascii(const char *);
3686fc31d54SRussell King 	char buf[256];
3696fc31d54SRussell King 	va_list ap;
3706fc31d54SRussell King 
3716fc31d54SRussell King 	va_start(ap, str);
3726fc31d54SRussell King 	vsnprintf(buf, sizeof(buf), str, ap);
3736fc31d54SRussell King 	va_end(ap);
3746fc31d54SRussell King 
3756fc31d54SRussell King #ifdef CONFIG_DEBUG_LL
3766fc31d54SRussell King 	printascii(buf);
3776fc31d54SRussell King #endif
3786fc31d54SRussell King 	printk("%s", buf);
3796fc31d54SRussell King }
3806fc31d54SRussell King 
38142f25bddSNicolas Pitre #ifdef CONFIG_ARM_PATCH_IDIV
38242f25bddSNicolas Pitre 
38342f25bddSNicolas Pitre static inline u32 __attribute_const__ sdiv_instruction(void)
38442f25bddSNicolas Pitre {
38542f25bddSNicolas Pitre 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
38642f25bddSNicolas Pitre 		/* "sdiv r0, r0, r1" */
38742f25bddSNicolas Pitre 		u32 insn = __opcode_thumb32_compose(0xfb90, 0xf0f1);
38842f25bddSNicolas Pitre 		return __opcode_to_mem_thumb32(insn);
38942f25bddSNicolas Pitre 	}
39042f25bddSNicolas Pitre 
39142f25bddSNicolas Pitre 	/* "sdiv r0, r0, r1" */
39242f25bddSNicolas Pitre 	return __opcode_to_mem_arm(0xe710f110);
39342f25bddSNicolas Pitre }
39442f25bddSNicolas Pitre 
39542f25bddSNicolas Pitre static inline u32 __attribute_const__ udiv_instruction(void)
39642f25bddSNicolas Pitre {
39742f25bddSNicolas Pitre 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
39842f25bddSNicolas Pitre 		/* "udiv r0, r0, r1" */
39942f25bddSNicolas Pitre 		u32 insn = __opcode_thumb32_compose(0xfbb0, 0xf0f1);
40042f25bddSNicolas Pitre 		return __opcode_to_mem_thumb32(insn);
40142f25bddSNicolas Pitre 	}
40242f25bddSNicolas Pitre 
40342f25bddSNicolas Pitre 	/* "udiv r0, r0, r1" */
40442f25bddSNicolas Pitre 	return __opcode_to_mem_arm(0xe730f110);
40542f25bddSNicolas Pitre }
40642f25bddSNicolas Pitre 
40742f25bddSNicolas Pitre static inline u32 __attribute_const__ bx_lr_instruction(void)
40842f25bddSNicolas Pitre {
40942f25bddSNicolas Pitre 	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
41042f25bddSNicolas Pitre 		/* "bx lr; nop" */
41142f25bddSNicolas Pitre 		u32 insn = __opcode_thumb32_compose(0x4770, 0x46c0);
41242f25bddSNicolas Pitre 		return __opcode_to_mem_thumb32(insn);
41342f25bddSNicolas Pitre 	}
41442f25bddSNicolas Pitre 
41542f25bddSNicolas Pitre 	/* "bx lr" */
41642f25bddSNicolas Pitre 	return __opcode_to_mem_arm(0xe12fff1e);
41742f25bddSNicolas Pitre }
41842f25bddSNicolas Pitre 
41942f25bddSNicolas Pitre static void __init patch_aeabi_idiv(void)
42042f25bddSNicolas Pitre {
42142f25bddSNicolas Pitre 	extern void __aeabi_uidiv(void);
42242f25bddSNicolas Pitre 	extern void __aeabi_idiv(void);
42342f25bddSNicolas Pitre 	uintptr_t fn_addr;
42442f25bddSNicolas Pitre 	unsigned int mask;
42542f25bddSNicolas Pitre 
42642f25bddSNicolas Pitre 	mask = IS_ENABLED(CONFIG_THUMB2_KERNEL) ? HWCAP_IDIVT : HWCAP_IDIVA;
42742f25bddSNicolas Pitre 	if (!(elf_hwcap & mask))
42842f25bddSNicolas Pitre 		return;
42942f25bddSNicolas Pitre 
43042f25bddSNicolas Pitre 	pr_info("CPU: div instructions available: patching division code\n");
43142f25bddSNicolas Pitre 
43242f25bddSNicolas Pitre 	fn_addr = ((uintptr_t)&__aeabi_uidiv) & ~1;
433208fae5cSNicolas Pitre 	asm ("" : "+g" (fn_addr));
43442f25bddSNicolas Pitre 	((u32 *)fn_addr)[0] = udiv_instruction();
43542f25bddSNicolas Pitre 	((u32 *)fn_addr)[1] = bx_lr_instruction();
43642f25bddSNicolas Pitre 	flush_icache_range(fn_addr, fn_addr + 8);
43742f25bddSNicolas Pitre 
43842f25bddSNicolas Pitre 	fn_addr = ((uintptr_t)&__aeabi_idiv) & ~1;
439208fae5cSNicolas Pitre 	asm ("" : "+g" (fn_addr));
44042f25bddSNicolas Pitre 	((u32 *)fn_addr)[0] = sdiv_instruction();
44142f25bddSNicolas Pitre 	((u32 *)fn_addr)[1] = bx_lr_instruction();
44242f25bddSNicolas Pitre 	flush_icache_range(fn_addr, fn_addr + 8);
44342f25bddSNicolas Pitre }
44442f25bddSNicolas Pitre 
44542f25bddSNicolas Pitre #else
44642f25bddSNicolas Pitre static inline void patch_aeabi_idiv(void) { }
44742f25bddSNicolas Pitre #endif
44842f25bddSNicolas Pitre 
4498164f7afSStephen Boyd static void __init cpuid_init_hwcaps(void)
4508164f7afSStephen Boyd {
451b8c9592bSArd Biesheuvel 	int block;
452a092aedbSArd Biesheuvel 	u32 isar5;
4538164f7afSStephen Boyd 
4548164f7afSStephen Boyd 	if (cpu_architecture() < CPU_ARCH_ARMv7)
4558164f7afSStephen Boyd 		return;
4568164f7afSStephen Boyd 
457b8c9592bSArd Biesheuvel 	block = cpuid_feature_extract(CPUID_EXT_ISAR0, 24);
458b8c9592bSArd Biesheuvel 	if (block >= 2)
4598164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVA;
460b8c9592bSArd Biesheuvel 	if (block >= 1)
4618164f7afSStephen Boyd 		elf_hwcap |= HWCAP_IDIVT;
462a469abd0SWill Deacon 
463a469abd0SWill Deacon 	/* LPAE implies atomic ldrd/strd instructions */
464b8c9592bSArd Biesheuvel 	block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
465b8c9592bSArd Biesheuvel 	if (block >= 5)
466a469abd0SWill Deacon 		elf_hwcap |= HWCAP_LPAE;
467a092aedbSArd Biesheuvel 
468a092aedbSArd Biesheuvel 	/* check for supported v8 Crypto instructions */
469a092aedbSArd Biesheuvel 	isar5 = read_cpuid_ext(CPUID_EXT_ISAR5);
470a092aedbSArd Biesheuvel 
471a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 4);
472a092aedbSArd Biesheuvel 	if (block >= 2)
473a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_PMULL;
474a092aedbSArd Biesheuvel 	if (block >= 1)
475a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_AES;
476a092aedbSArd Biesheuvel 
477a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 8);
478a092aedbSArd Biesheuvel 	if (block >= 1)
479a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_SHA1;
480a092aedbSArd Biesheuvel 
481a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 12);
482a092aedbSArd Biesheuvel 	if (block >= 1)
483a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_SHA2;
484a092aedbSArd Biesheuvel 
485a092aedbSArd Biesheuvel 	block = cpuid_feature_extract_field(isar5, 16);
486a092aedbSArd Biesheuvel 	if (block >= 1)
487a092aedbSArd Biesheuvel 		elf_hwcap2 |= HWCAP2_CRC32;
4888164f7afSStephen Boyd }
4898164f7afSStephen Boyd 
49058171bf2SRussell King static void __init elf_hwcap_fixup(void)
491f159f4edSTony Lindgren {
49258171bf2SRussell King 	unsigned id = read_cpuid_id();
493f159f4edSTony Lindgren 
494f159f4edSTony Lindgren 	/*
495f159f4edSTony Lindgren 	 * HWCAP_TLS is available only on 1136 r1p0 and later,
496f159f4edSTony Lindgren 	 * see also kuser_get_tls_init.
497f159f4edSTony Lindgren 	 */
49858171bf2SRussell King 	if (read_cpuid_part() == ARM_CPU_PART_ARM1136 &&
49958171bf2SRussell King 	    ((id >> 20) & 3) == 0) {
500f159f4edSTony Lindgren 		elf_hwcap &= ~HWCAP_TLS;
50158171bf2SRussell King 		return;
50258171bf2SRussell King 	}
50358171bf2SRussell King 
50458171bf2SRussell King 	/* Verify if CPUID scheme is implemented */
50558171bf2SRussell King 	if ((id & 0x000f0000) != 0x000f0000)
50658171bf2SRussell King 		return;
50758171bf2SRussell King 
50858171bf2SRussell King 	/*
50958171bf2SRussell King 	 * If the CPU supports LDREX/STREX and LDREXB/STREXB,
51058171bf2SRussell King 	 * avoid advertising SWP; it may not be atomic with
51158171bf2SRussell King 	 * multiprocessing cores.
51258171bf2SRussell King 	 */
513b8c9592bSArd Biesheuvel 	if (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) > 1 ||
514b8c9592bSArd Biesheuvel 	    (cpuid_feature_extract(CPUID_EXT_ISAR3, 12) == 1 &&
51503f1217eSVladimir Murzin 	     cpuid_feature_extract(CPUID_EXT_ISAR4, 20) >= 3))
51658171bf2SRussell King 		elf_hwcap &= ~HWCAP_SWP;
517f159f4edSTony Lindgren }
518f159f4edSTony Lindgren 
519b69874e4SRussell King /*
520b69874e4SRussell King  * cpu_init - initialise one CPU.
521b69874e4SRussell King  *
522b69874e4SRussell King  * cpu_init sets up the per-CPU stacks.
523b69874e4SRussell King  */
5241783d457SJon Medhurst void notrace cpu_init(void)
525b69874e4SRussell King {
52655bdd694SCatalin Marinas #ifndef CONFIG_CPU_V7M
527b69874e4SRussell King 	unsigned int cpu = smp_processor_id();
528b69874e4SRussell King 	struct stack *stk = &stacks[cpu];
529b69874e4SRussell King 
530b69874e4SRussell King 	if (cpu >= NR_CPUS) {
5311b0f6681SOlof Johansson 		pr_crit("CPU%u: bad primary CPU number\n", cpu);
532b69874e4SRussell King 		BUG();
533b69874e4SRussell King 	}
534b69874e4SRussell King 
53514318efbSRob Herring 	/*
53614318efbSRob Herring 	 * This only works on resume and secondary cores. For booting on the
53714318efbSRob Herring 	 * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.
53814318efbSRob Herring 	 */
53914318efbSRob Herring 	set_my_cpu_offset(per_cpu_offset(cpu));
54014318efbSRob Herring 
541b69874e4SRussell King 	cpu_proc_init();
542b69874e4SRussell King 
543b69874e4SRussell King 	/*
544b69874e4SRussell King 	 * Define the placement constraint for the inline asm directive below.
545b69874e4SRussell King 	 * In Thumb-2, msr with an immediate value is not allowed.
546b69874e4SRussell King 	 */
547b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL
548b69874e4SRussell King #define PLC	"r"
549b69874e4SRussell King #else
550b69874e4SRussell King #define PLC	"I"
551b69874e4SRussell King #endif
552b69874e4SRussell King 
553b69874e4SRussell King 	/*
554b69874e4SRussell King 	 * setup stacks for re-entrant exception handlers
555b69874e4SRussell King 	 */
556b69874e4SRussell King 	__asm__ (
557b69874e4SRussell King 	"msr	cpsr_c, %1\n\t"
558b69874e4SRussell King 	"add	r14, %0, %2\n\t"
559b69874e4SRussell King 	"mov	sp, r14\n\t"
560b69874e4SRussell King 	"msr	cpsr_c, %3\n\t"
561b69874e4SRussell King 	"add	r14, %0, %4\n\t"
562b69874e4SRussell King 	"mov	sp, r14\n\t"
563b69874e4SRussell King 	"msr	cpsr_c, %5\n\t"
564b69874e4SRussell King 	"add	r14, %0, %6\n\t"
565b69874e4SRussell King 	"mov	sp, r14\n\t"
566c0e7f7eeSDaniel Thompson 	"msr	cpsr_c, %7\n\t"
567c0e7f7eeSDaniel Thompson 	"add	r14, %0, %8\n\t"
568c0e7f7eeSDaniel Thompson 	"mov	sp, r14\n\t"
569c0e7f7eeSDaniel Thompson 	"msr	cpsr_c, %9"
570b69874e4SRussell King 	    :
571b69874e4SRussell King 	    : "r" (stk),
572b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
573b69874e4SRussell King 	      "I" (offsetof(struct stack, irq[0])),
574b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
575b69874e4SRussell King 	      "I" (offsetof(struct stack, abt[0])),
576b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
577b69874e4SRussell King 	      "I" (offsetof(struct stack, und[0])),
578c0e7f7eeSDaniel Thompson 	      PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),
579c0e7f7eeSDaniel Thompson 	      "I" (offsetof(struct stack, fiq[0])),
580b69874e4SRussell King 	      PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
581b69874e4SRussell King 	    : "r14");
58255bdd694SCatalin Marinas #endif
583b69874e4SRussell King }
584b69874e4SRussell King 
58518d7f152SLorenzo Pieralisi u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
586eb50439bSWill Deacon 
587eb50439bSWill Deacon void __init smp_setup_processor_id(void)
588eb50439bSWill Deacon {
589eb50439bSWill Deacon 	int i;
590cb8cf4f8SLorenzo Pieralisi 	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
591cb8cf4f8SLorenzo Pieralisi 	u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
592eb50439bSWill Deacon 
593eb50439bSWill Deacon 	cpu_logical_map(0) = cpu;
594cb8cf4f8SLorenzo Pieralisi 	for (i = 1; i < nr_cpu_ids; ++i)
595eb50439bSWill Deacon 		cpu_logical_map(i) = i == cpu ? 0 : i;
596eb50439bSWill Deacon 
5979394c1c6SMing Lei 	/*
5989394c1c6SMing Lei 	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
5999394c1c6SMing Lei 	 * using percpu variable early, for example, lockdep will
6009394c1c6SMing Lei 	 * access percpu variable inside lock_release
6019394c1c6SMing Lei 	 */
6029394c1c6SMing Lei 	set_my_cpu_offset(0);
6039394c1c6SMing Lei 
6041b0f6681SOlof Johansson 	pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
605eb50439bSWill Deacon }
606eb50439bSWill Deacon 
6078cf72172SLorenzo Pieralisi struct mpidr_hash mpidr_hash;
6088cf72172SLorenzo Pieralisi #ifdef CONFIG_SMP
6098cf72172SLorenzo Pieralisi /**
6108cf72172SLorenzo Pieralisi  * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
6118cf72172SLorenzo Pieralisi  *			  level in order to build a linear index from an
6128cf72172SLorenzo Pieralisi  *			  MPIDR value. Resulting algorithm is a collision
6138cf72172SLorenzo Pieralisi  *			  free hash carried out through shifting and ORing
6148cf72172SLorenzo Pieralisi  */
6158cf72172SLorenzo Pieralisi static void __init smp_build_mpidr_hash(void)
6168cf72172SLorenzo Pieralisi {
6178cf72172SLorenzo Pieralisi 	u32 i, affinity;
6188cf72172SLorenzo Pieralisi 	u32 fs[3], bits[3], ls, mask = 0;
6198cf72172SLorenzo Pieralisi 	/*
6208cf72172SLorenzo Pieralisi 	 * Pre-scan the list of MPIDRS and filter out bits that do
6218cf72172SLorenzo Pieralisi 	 * not contribute to affinity levels, ie they never toggle.
6228cf72172SLorenzo Pieralisi 	 */
6238cf72172SLorenzo Pieralisi 	for_each_possible_cpu(i)
6248cf72172SLorenzo Pieralisi 		mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
6258cf72172SLorenzo Pieralisi 	pr_debug("mask of set bits 0x%x\n", mask);
6268cf72172SLorenzo Pieralisi 	/*
6278cf72172SLorenzo Pieralisi 	 * Find and stash the last and first bit set at all affinity levels to
6288cf72172SLorenzo Pieralisi 	 * check how many bits are required to represent them.
6298cf72172SLorenzo Pieralisi 	 */
6308cf72172SLorenzo Pieralisi 	for (i = 0; i < 3; i++) {
6318cf72172SLorenzo Pieralisi 		affinity = MPIDR_AFFINITY_LEVEL(mask, i);
6328cf72172SLorenzo Pieralisi 		/*
6338cf72172SLorenzo Pieralisi 		 * Find the MSB bit and LSB bits position
6348cf72172SLorenzo Pieralisi 		 * to determine how many bits are required
6358cf72172SLorenzo Pieralisi 		 * to express the affinity level.
6368cf72172SLorenzo Pieralisi 		 */
6378cf72172SLorenzo Pieralisi 		ls = fls(affinity);
6388cf72172SLorenzo Pieralisi 		fs[i] = affinity ? ffs(affinity) - 1 : 0;
6398cf72172SLorenzo Pieralisi 		bits[i] = ls - fs[i];
6408cf72172SLorenzo Pieralisi 	}
6418cf72172SLorenzo Pieralisi 	/*
6428cf72172SLorenzo Pieralisi 	 * An index can be created from the MPIDR by isolating the
6438cf72172SLorenzo Pieralisi 	 * significant bits at each affinity level and by shifting
6448cf72172SLorenzo Pieralisi 	 * them in order to compress the 24 bits values space to a
6458cf72172SLorenzo Pieralisi 	 * compressed set of values. This is equivalent to hashing
6468cf72172SLorenzo Pieralisi 	 * the MPIDR through shifting and ORing. It is a collision free
6478cf72172SLorenzo Pieralisi 	 * hash though not minimal since some levels might contain a number
6488cf72172SLorenzo Pieralisi 	 * of CPUs that is not an exact power of 2 and their bit
6498cf72172SLorenzo Pieralisi 	 * representation might contain holes, eg MPIDR[7:0] = {0x2, 0x80}.
6508cf72172SLorenzo Pieralisi 	 */
6518cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[0] = fs[0];
6528cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[1] = MPIDR_LEVEL_BITS + fs[1] - bits[0];
6538cf72172SLorenzo Pieralisi 	mpidr_hash.shift_aff[2] = 2*MPIDR_LEVEL_BITS + fs[2] -
6548cf72172SLorenzo Pieralisi 						(bits[1] + bits[0]);
6558cf72172SLorenzo Pieralisi 	mpidr_hash.mask = mask;
6568cf72172SLorenzo Pieralisi 	mpidr_hash.bits = bits[2] + bits[1] + bits[0];
6578cf72172SLorenzo Pieralisi 	pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] mask[0x%x] bits[%u]\n",
6588cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[0],
6598cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[1],
6608cf72172SLorenzo Pieralisi 				mpidr_hash.shift_aff[2],
6618cf72172SLorenzo Pieralisi 				mpidr_hash.mask,
6628cf72172SLorenzo Pieralisi 				mpidr_hash.bits);
6638cf72172SLorenzo Pieralisi 	/*
6648cf72172SLorenzo Pieralisi 	 * 4x is an arbitrary value used to warn on a hash table much bigger
6658cf72172SLorenzo Pieralisi 	 * than expected on most systems.
6668cf72172SLorenzo Pieralisi 	 */
6678cf72172SLorenzo Pieralisi 	if (mpidr_hash_size() > 4 * num_possible_cpus())
6688cf72172SLorenzo Pieralisi 		pr_warn("Large number of MPIDR hash buckets detected\n");
6698cf72172SLorenzo Pieralisi 	sync_cache_w(&mpidr_hash);
6708cf72172SLorenzo Pieralisi }
6718cf72172SLorenzo Pieralisi #endif
6728cf72172SLorenzo Pieralisi 
6731da177e4SLinus Torvalds static void __init setup_processor(void)
6741da177e4SLinus Torvalds {
6751da177e4SLinus Torvalds 	struct proc_info_list *list;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	/*
6781da177e4SLinus Torvalds 	 * locate processor in the list of supported processor
6791da177e4SLinus Torvalds 	 * types.  The linker builds this table for us from the
6801da177e4SLinus Torvalds 	 * entries in arch/arm/mm/proc-*.S
6811da177e4SLinus Torvalds 	 */
6820ba8b9b2SRussell King 	list = lookup_processor_type(read_cpuid_id());
6831da177e4SLinus Torvalds 	if (!list) {
6841b0f6681SOlof Johansson 		pr_err("CPU configuration botched (ID %08x), unable to continue.\n",
6851b0f6681SOlof Johansson 		       read_cpuid_id());
6861da177e4SLinus Torvalds 		while (1);
6871da177e4SLinus Torvalds 	}
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	cpu_name = list->cpu_name;
6902ecccf90SDave Martin 	__cpu_architecture = __get_cpu_architecture();
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds #ifdef MULTI_CPU
6931da177e4SLinus Torvalds 	processor = *list->proc;
6941da177e4SLinus Torvalds #endif
6951da177e4SLinus Torvalds #ifdef MULTI_TLB
6961da177e4SLinus Torvalds 	cpu_tlb = *list->tlb;
6971da177e4SLinus Torvalds #endif
6981da177e4SLinus Torvalds #ifdef MULTI_USER
6991da177e4SLinus Torvalds 	cpu_user = *list->user;
7001da177e4SLinus Torvalds #endif
7011da177e4SLinus Torvalds #ifdef MULTI_CACHE
7021da177e4SLinus Torvalds 	cpu_cache = *list->cache;
7031da177e4SLinus Torvalds #endif
7041da177e4SLinus Torvalds 
7051b0f6681SOlof Johansson 	pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
7060ba8b9b2SRussell King 		cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
7074585eaffSRussell King 		proc_arch[cpu_architecture()], get_cr());
7081da177e4SLinus Torvalds 
709a34dbfb0SWill Deacon 	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
710a34dbfb0SWill Deacon 		 list->arch_name, ENDIANNESS);
711a34dbfb0SWill Deacon 	snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
712a34dbfb0SWill Deacon 		 list->elf_name, ENDIANNESS);
7131da177e4SLinus Torvalds 	elf_hwcap = list->elf_hwcap;
7148164f7afSStephen Boyd 
7158164f7afSStephen Boyd 	cpuid_init_hwcaps();
71642f25bddSNicolas Pitre 	patch_aeabi_idiv();
7178164f7afSStephen Boyd 
718adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB
719c40e3641SStephen Boyd 	elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
720adeff422SCatalin Marinas #endif
721ca8f0b0aSRussell King #ifdef CONFIG_MMU
722ca8f0b0aSRussell King 	init_default_cache_policy(list->__cpu_mm_mmu_flags);
723ca8f0b0aSRussell King #endif
72492871b94SRob Herring 	erratum_a15_798181_init();
72592871b94SRob Herring 
72658171bf2SRussell King 	elf_hwcap_fixup();
727f159f4edSTony Lindgren 
728c0e95878SRussell King 	cacheid_init();
729b69874e4SRussell King 	cpu_init();
730ccea7a19SRussell King }
731ccea7a19SRussell King 
73293c02ab4SGrant Likely void __init dump_machine_table(void)
7331da177e4SLinus Torvalds {
734ff69a4c8SRussell King 	const struct machine_desc *p;
7351da177e4SLinus Torvalds 
7366291319dSGrant Likely 	early_print("Available machine support:\n\nID (hex)\tNAME\n");
7376291319dSGrant Likely 	for_each_machine_desc(p)
738dce72dd0SNicolas Pitre 		early_print("%08x\t%s\n", p->nr, p->name);
739dce72dd0SNicolas Pitre 
740dce72dd0SNicolas Pitre 	early_print("\nPlease check your kernel config and/or bootloader.\n");
741dce72dd0SNicolas Pitre 
742dce72dd0SNicolas Pitre 	while (true)
743dce72dd0SNicolas Pitre 		/* can't use cpu_relax() here as it may require MMU setup */;
7441da177e4SLinus Torvalds }
7451da177e4SLinus Torvalds 
7466a5014aaSMagnus Damm int __init arm_add_memory(u64 start, u64 size)
7473a669411SRussell King {
7486d7d5da7SMagnus Damm 	u64 aligned_start;
7494b5f32ceSNicolas Pitre 
7503a669411SRussell King 	/*
7513a669411SRussell King 	 * Ensure that start/size are aligned to a page boundary.
752909ba297SMasahiro Yamada 	 * Size is rounded down, start is rounded up.
7533a669411SRussell King 	 */
7546d7d5da7SMagnus Damm 	aligned_start = PAGE_ALIGN(start);
755909ba297SMasahiro Yamada 	if (aligned_start > start + size)
756909ba297SMasahiro Yamada 		size = 0;
757909ba297SMasahiro Yamada 	else
758909ba297SMasahiro Yamada 		size -= aligned_start - start;
759e5ab8580SWill Deacon 
7606d7d5da7SMagnus Damm #ifndef CONFIG_ARCH_PHYS_ADDR_T_64BIT
7616d7d5da7SMagnus Damm 	if (aligned_start > ULONG_MAX) {
7621b0f6681SOlof Johansson 		pr_crit("Ignoring memory at 0x%08llx outside 32-bit physical address space\n",
7631b0f6681SOlof Johansson 			(long long)start);
7646d7d5da7SMagnus Damm 		return -EINVAL;
7656d7d5da7SMagnus Damm 	}
7666d7d5da7SMagnus Damm 
7676d7d5da7SMagnus Damm 	if (aligned_start + size > ULONG_MAX) {
7681b0f6681SOlof Johansson 		pr_crit("Truncating memory at 0x%08llx to fit in 32-bit physical address space\n",
7691b0f6681SOlof Johansson 			(long long)start);
770e5ab8580SWill Deacon 		/*
771e5ab8580SWill Deacon 		 * To ensure bank->start + bank->size is representable in
772e5ab8580SWill Deacon 		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.
773e5ab8580SWill Deacon 		 * This means we lose a page after masking.
774e5ab8580SWill Deacon 		 */
7756d7d5da7SMagnus Damm 		size = ULONG_MAX - aligned_start;
776e5ab8580SWill Deacon 	}
777e5ab8580SWill Deacon #endif
778e5ab8580SWill Deacon 
779571b1437SRussell King 	if (aligned_start < PHYS_OFFSET) {
780571b1437SRussell King 		if (aligned_start + size <= PHYS_OFFSET) {
781571b1437SRussell King 			pr_info("Ignoring memory below PHYS_OFFSET: 0x%08llx-0x%08llx\n",
782571b1437SRussell King 				aligned_start, aligned_start + size);
783571b1437SRussell King 			return -EINVAL;
784571b1437SRussell King 		}
785571b1437SRussell King 
786571b1437SRussell King 		pr_info("Ignoring memory below PHYS_OFFSET: 0x%08llx-0x%08llx\n",
787571b1437SRussell King 			aligned_start, (u64)PHYS_OFFSET);
788571b1437SRussell King 
789571b1437SRussell King 		size -= PHYS_OFFSET - aligned_start;
790571b1437SRussell King 		aligned_start = PHYS_OFFSET;
791571b1437SRussell King 	}
792571b1437SRussell King 
7931c2f87c2SLaura Abbott 	start = aligned_start;
7941c2f87c2SLaura Abbott 	size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
7954b5f32ceSNicolas Pitre 
7964b5f32ceSNicolas Pitre 	/*
7974b5f32ceSNicolas Pitre 	 * Check whether this memory region has non-zero size or
7984b5f32ceSNicolas Pitre 	 * invalid node number.
7994b5f32ceSNicolas Pitre 	 */
8001c2f87c2SLaura Abbott 	if (size == 0)
8014b5f32ceSNicolas Pitre 		return -EINVAL;
8024b5f32ceSNicolas Pitre 
8031c2f87c2SLaura Abbott 	memblock_add(start, size);
8044b5f32ceSNicolas Pitre 	return 0;
8053a669411SRussell King }
8063a669411SRussell King 
8071da177e4SLinus Torvalds /*
8081da177e4SLinus Torvalds  * Pick out the memory size.  We look for mem=size@start,
8091da177e4SLinus Torvalds  * where start and size are "size[KkMm]"
8101da177e4SLinus Torvalds  */
8111c2f87c2SLaura Abbott 
8122b0d8c25SJeremy Kerr static int __init early_mem(char *p)
8131da177e4SLinus Torvalds {
8141da177e4SLinus Torvalds 	static int usermem __initdata = 0;
8156a5014aaSMagnus Damm 	u64 size;
8166a5014aaSMagnus Damm 	u64 start;
8172b0d8c25SJeremy Kerr 	char *endp;
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	/*
8201da177e4SLinus Torvalds 	 * If the user specifies memory size, we
8211da177e4SLinus Torvalds 	 * blow away any automatically generated
8221da177e4SLinus Torvalds 	 * size.
8231da177e4SLinus Torvalds 	 */
8241da177e4SLinus Torvalds 	if (usermem == 0) {
8251da177e4SLinus Torvalds 		usermem = 1;
8261c2f87c2SLaura Abbott 		memblock_remove(memblock_start_of_DRAM(),
8271c2f87c2SLaura Abbott 			memblock_end_of_DRAM() - memblock_start_of_DRAM());
8281da177e4SLinus Torvalds 	}
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds 	start = PHYS_OFFSET;
8312b0d8c25SJeremy Kerr 	size  = memparse(p, &endp);
8322b0d8c25SJeremy Kerr 	if (*endp == '@')
8332b0d8c25SJeremy Kerr 		start = memparse(endp + 1, NULL);
8341da177e4SLinus Torvalds 
8351c97b73eSAndrew Morton 	arm_add_memory(start, size);
8361da177e4SLinus Torvalds 
8372b0d8c25SJeremy Kerr 	return 0;
8381da177e4SLinus Torvalds }
8392b0d8c25SJeremy Kerr early_param("mem", early_mem);
8401da177e4SLinus Torvalds 
841ff69a4c8SRussell King static void __init request_standard_resources(const struct machine_desc *mdesc)
8421da177e4SLinus Torvalds {
84311b9369cSDima Zavin 	struct memblock_region *region;
8441da177e4SLinus Torvalds 	struct resource *res;
8451da177e4SLinus Torvalds 
84637efe642SRussell King 	kernel_code.start   = virt_to_phys(_text);
84737efe642SRussell King 	kernel_code.end     = virt_to_phys(_etext - 1);
848842eab40SRussell King 	kernel_data.start   = virt_to_phys(_sdata);
84937efe642SRussell King 	kernel_data.end     = virt_to_phys(_end - 1);
8501da177e4SLinus Torvalds 
85111b9369cSDima Zavin 	for_each_memblock(memory, region) {
852ca474408SSantosh Shilimkar 		res = memblock_virt_alloc(sizeof(*res), 0);
8531da177e4SLinus Torvalds 		res->name  = "System RAM";
85411b9369cSDima Zavin 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
85511b9369cSDima Zavin 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
85635d98e93SToshi Kani 		res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 		request_resource(&iomem_resource, res);
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds 		if (kernel_code.start >= res->start &&
8611da177e4SLinus Torvalds 		    kernel_code.end <= res->end)
8621da177e4SLinus Torvalds 			request_resource(res, &kernel_code);
8631da177e4SLinus Torvalds 		if (kernel_data.start >= res->start &&
8641da177e4SLinus Torvalds 		    kernel_data.end <= res->end)
8651da177e4SLinus Torvalds 			request_resource(res, &kernel_data);
8661da177e4SLinus Torvalds 	}
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 	if (mdesc->video_start) {
8691da177e4SLinus Torvalds 		video_ram.start = mdesc->video_start;
8701da177e4SLinus Torvalds 		video_ram.end   = mdesc->video_end;
8711da177e4SLinus Torvalds 		request_resource(&iomem_resource, &video_ram);
8721da177e4SLinus Torvalds 	}
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	/*
8751da177e4SLinus Torvalds 	 * Some machines don't have the possibility of ever
8761da177e4SLinus Torvalds 	 * possessing lp0, lp1 or lp2
8771da177e4SLinus Torvalds 	 */
8781da177e4SLinus Torvalds 	if (mdesc->reserve_lp0)
8791da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp0);
8801da177e4SLinus Torvalds 	if (mdesc->reserve_lp1)
8811da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp1);
8821da177e4SLinus Torvalds 	if (mdesc->reserve_lp2)
8831da177e4SLinus Torvalds 		request_resource(&ioport_resource, &lp2);
8841da177e4SLinus Torvalds }
8851da177e4SLinus Torvalds 
886801820beSArd Biesheuvel #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) || \
887801820beSArd Biesheuvel     defined(CONFIG_EFI)
8881da177e4SLinus Torvalds struct screen_info screen_info = {
8891da177e4SLinus Torvalds  .orig_video_lines	= 30,
8901da177e4SLinus Torvalds  .orig_video_cols	= 80,
8911da177e4SLinus Torvalds  .orig_video_mode	= 0,
8921da177e4SLinus Torvalds  .orig_video_ega_bx	= 0,
8931da177e4SLinus Torvalds  .orig_video_isVGA	= 1,
8941da177e4SLinus Torvalds  .orig_video_points	= 8
8951da177e4SLinus Torvalds };
8961da177e4SLinus Torvalds #endif
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds static int __init customize_machine(void)
8991da177e4SLinus Torvalds {
900883a106bSArnd Bergmann 	/*
901883a106bSArnd Bergmann 	 * customizes platform devices, or adds new ones
902883a106bSArnd Bergmann 	 * On DT based machines, we fall back to populating the
903883a106bSArnd Bergmann 	 * machine from the device tree, if no callback is provided,
904883a106bSArnd Bergmann 	 * otherwise we would always need an init_machine callback.
905883a106bSArnd Bergmann 	 */
906af4dda73SWill Deacon 	of_iommu_init();
9078ff1443cSRussell King 	if (machine_desc->init_machine)
9088ff1443cSRussell King 		machine_desc->init_machine();
909883a106bSArnd Bergmann #ifdef CONFIG_OF
910883a106bSArnd Bergmann 	else
911883a106bSArnd Bergmann 		of_platform_populate(NULL, of_default_bus_match_table,
912883a106bSArnd Bergmann 					NULL, NULL);
913883a106bSArnd Bergmann #endif
9141da177e4SLinus Torvalds 	return 0;
9151da177e4SLinus Torvalds }
9161da177e4SLinus Torvalds arch_initcall(customize_machine);
9171da177e4SLinus Torvalds 
91890de4137SShawn Guo static int __init init_machine_late(void)
91990de4137SShawn Guo {
9203f599875SPaul Kocialkowski 	struct device_node *root;
9213f599875SPaul Kocialkowski 	int ret;
9223f599875SPaul Kocialkowski 
92390de4137SShawn Guo 	if (machine_desc->init_late)
92490de4137SShawn Guo 		machine_desc->init_late();
9253f599875SPaul Kocialkowski 
9263f599875SPaul Kocialkowski 	root = of_find_node_by_path("/");
9273f599875SPaul Kocialkowski 	if (root) {
9283f599875SPaul Kocialkowski 		ret = of_property_read_string(root, "serial-number",
9293f599875SPaul Kocialkowski 					      &system_serial);
9303f599875SPaul Kocialkowski 		if (ret)
9313f599875SPaul Kocialkowski 			system_serial = NULL;
9323f599875SPaul Kocialkowski 	}
9333f599875SPaul Kocialkowski 
9343f599875SPaul Kocialkowski 	if (!system_serial)
9353f599875SPaul Kocialkowski 		system_serial = kasprintf(GFP_KERNEL, "%08x%08x",
9363f599875SPaul Kocialkowski 					  system_serial_high,
9373f599875SPaul Kocialkowski 					  system_serial_low);
9383f599875SPaul Kocialkowski 
93990de4137SShawn Guo 	return 0;
94090de4137SShawn Guo }
94190de4137SShawn Guo late_initcall(init_machine_late);
94290de4137SShawn Guo 
9433c57fb43SMika Westerberg #ifdef CONFIG_KEXEC
94461603016SRussell King /*
94561603016SRussell King  * The crash region must be aligned to 128MB to avoid
94661603016SRussell King  * zImage relocating below the reserved region.
94761603016SRussell King  */
94861603016SRussell King #define CRASH_ALIGN	(128 << 20)
94961603016SRussell King 
9503c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void)
9513c57fb43SMika Westerberg {
9523c57fb43SMika Westerberg 	unsigned long total;
9533c57fb43SMika Westerberg 
9543c57fb43SMika Westerberg 	total = max_low_pfn - min_low_pfn;
9553c57fb43SMika Westerberg 	return total << PAGE_SHIFT;
9563c57fb43SMika Westerberg }
9573c57fb43SMika Westerberg 
9583c57fb43SMika Westerberg /**
9593c57fb43SMika Westerberg  * reserve_crashkernel() - reserves memory are for crash kernel
9603c57fb43SMika Westerberg  *
9613c57fb43SMika Westerberg  * This function reserves memory area given in "crashkernel=" kernel command
9623c57fb43SMika Westerberg  * line parameter. The memory reserved is used by a dump capture kernel when
9633c57fb43SMika Westerberg  * primary kernel is crashing.
9643c57fb43SMika Westerberg  */
9653c57fb43SMika Westerberg static void __init reserve_crashkernel(void)
9663c57fb43SMika Westerberg {
9673c57fb43SMika Westerberg 	unsigned long long crash_size, crash_base;
9683c57fb43SMika Westerberg 	unsigned long long total_mem;
9693c57fb43SMika Westerberg 	int ret;
9703c57fb43SMika Westerberg 
9713c57fb43SMika Westerberg 	total_mem = get_total_mem();
9723c57fb43SMika Westerberg 	ret = parse_crashkernel(boot_command_line, total_mem,
9733c57fb43SMika Westerberg 				&crash_size, &crash_base);
9743c57fb43SMika Westerberg 	if (ret)
9753c57fb43SMika Westerberg 		return;
9763c57fb43SMika Westerberg 
97761603016SRussell King 	if (crash_base <= 0) {
978d0506a23SRussell King 		unsigned long long crash_max = idmap_to_phys((u32)~0);
97961603016SRussell King 		crash_base = memblock_find_in_range(CRASH_ALIGN, crash_max,
98061603016SRussell King 						    crash_size, CRASH_ALIGN);
98161603016SRussell King 		if (!crash_base) {
98261603016SRussell King 			pr_err("crashkernel reservation failed - No suitable area found.\n");
98361603016SRussell King 			return;
98461603016SRussell King 		}
98561603016SRussell King 	} else {
98661603016SRussell King 		unsigned long long start;
98761603016SRussell King 
98861603016SRussell King 		start = memblock_find_in_range(crash_base,
98961603016SRussell King 					       crash_base + crash_size,
99061603016SRussell King 					       crash_size, SECTION_SIZE);
99161603016SRussell King 		if (start != crash_base) {
99261603016SRussell King 			pr_err("crashkernel reservation failed - memory is in use.\n");
99361603016SRussell King 			return;
99461603016SRussell King 		}
99561603016SRussell King 	}
99661603016SRussell King 
99784f452b1SSantosh Shilimkar 	ret = memblock_reserve(crash_base, crash_size);
9983c57fb43SMika Westerberg 	if (ret < 0) {
9991b0f6681SOlof Johansson 		pr_warn("crashkernel reservation failed - memory is in use (0x%lx)\n",
10001b0f6681SOlof Johansson 			(unsigned long)crash_base);
10013c57fb43SMika Westerberg 		return;
10023c57fb43SMika Westerberg 	}
10033c57fb43SMika Westerberg 
10041b0f6681SOlof Johansson 	pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
10053c57fb43SMika Westerberg 		(unsigned long)(crash_size >> 20),
10063c57fb43SMika Westerberg 		(unsigned long)(crash_base >> 20),
10073c57fb43SMika Westerberg 		(unsigned long)(total_mem >> 20));
10083c57fb43SMika Westerberg 
10093c57fb43SMika Westerberg 	crashk_res.start = crash_base;
10103c57fb43SMika Westerberg 	crashk_res.end = crash_base + crash_size - 1;
10113c57fb43SMika Westerberg 	insert_resource(&iomem_resource, &crashk_res);
10123c57fb43SMika Westerberg }
10133c57fb43SMika Westerberg #else
10143c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {}
10153c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */
10163c57fb43SMika Westerberg 
10174588c34dSDave Martin void __init hyp_mode_check(void)
10184588c34dSDave Martin {
10194588c34dSDave Martin #ifdef CONFIG_ARM_VIRT_EXT
10208fbac214SMark Rutland 	sync_boot_mode();
10218fbac214SMark Rutland 
10224588c34dSDave Martin 	if (is_hyp_mode_available()) {
10234588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in HYP mode.\n");
10244588c34dSDave Martin 		pr_info("CPU: Virtualization extensions available.\n");
10254588c34dSDave Martin 	} else if (is_hyp_mode_mismatched()) {
10264588c34dSDave Martin 		pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
10274588c34dSDave Martin 			__boot_cpu_mode & MODE_MASK);
10284588c34dSDave Martin 		pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
10294588c34dSDave Martin 	} else
10304588c34dSDave Martin 		pr_info("CPU: All CPU(s) started in SVC mode.\n");
10314588c34dSDave Martin #endif
10324588c34dSDave Martin }
10334588c34dSDave Martin 
10346291319dSGrant Likely void __init setup_arch(char **cmdline_p)
10356291319dSGrant Likely {
1036ff69a4c8SRussell King 	const struct machine_desc *mdesc;
10376291319dSGrant Likely 
10386291319dSGrant Likely 	setup_processor();
103993c02ab4SGrant Likely 	mdesc = setup_machine_fdt(__atags_pointer);
104093c02ab4SGrant Likely 	if (!mdesc)
1041b8b499c8SAlexander Shiyan 		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
10426291319dSGrant Likely 	machine_desc = mdesc;
10436291319dSGrant Likely 	machine_name = mdesc->name;
1044719c9d14SRussell King 	dump_stack_set_arch_desc("%s", mdesc->name);
10456291319dSGrant Likely 
104616d6d5b0SRobin Holt 	if (mdesc->reboot_mode != REBOOT_HARD)
104716d6d5b0SRobin Holt 		reboot_mode = mdesc->reboot_mode;
10486291319dSGrant Likely 
104937efe642SRussell King 	init_mm.start_code = (unsigned long) _text;
105037efe642SRussell King 	init_mm.end_code   = (unsigned long) _etext;
105137efe642SRussell King 	init_mm.end_data   = (unsigned long) _edata;
105237efe642SRussell King 	init_mm.brk	   = (unsigned long) _end;
10531da177e4SLinus Torvalds 
105448ab7e09SJeremy Kerr 	/* populate cmd_line too for later use, preserving boot_command_line */
105548ab7e09SJeremy Kerr 	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
105648ab7e09SJeremy Kerr 	*cmdline_p = cmd_line;
10572b0d8c25SJeremy Kerr 
1058a5f4c561SStefan Agner 	early_fixmap_init();
10592937367bSArd Biesheuvel 	early_ioremap_init();
1060a5f4c561SStefan Agner 
10612b0d8c25SJeremy Kerr 	parse_early_param();
10622b0d8c25SJeremy Kerr 
10631221ed10SRussell King #ifdef CONFIG_MMU
10641221ed10SRussell King 	early_paging_init(mdesc);
10651221ed10SRussell King #endif
10667c927322SSantosh Shilimkar 	setup_dma_zone(mdesc);
10679b08aaa3SShannon Zhao 	xen_early_init();
1068da58fb65SArd Biesheuvel 	efi_init();
10690371d3f7SRussell King 	sanity_check_meminfo();
10701c2f87c2SLaura Abbott 	arm_memblock_init(mdesc);
10712778f620SRussell King 
10722937367bSArd Biesheuvel 	early_ioremap_reset();
10732937367bSArd Biesheuvel 
10744b5f32ceSNicolas Pitre 	paging_init(mdesc);
107511b9369cSDima Zavin 	request_standard_resources(mdesc);
10761da177e4SLinus Torvalds 
1077a528721dSRussell King 	if (mdesc->restart)
1078a528721dSRussell King 		arm_pm_restart = mdesc->restart;
1079a528721dSRussell King 
108093c02ab4SGrant Likely 	unflatten_device_tree();
108193c02ab4SGrant Likely 
10825587164eSLorenzo Pieralisi 	arm_dt_init_cpu_maps();
1083be120397SMark Rutland 	psci_dt_init();
10847bbb7940SRussell King #ifdef CONFIG_SMP
1085abcee5fbSMarc Zyngier 	if (is_smp()) {
1086b382b940SJon Medhurst 		if (!mdesc->smp_init || !mdesc->smp_init()) {
108705774088SStefano Stabellini 			if (psci_smp_available())
108805774088SStefano Stabellini 				smp_set_ops(&psci_smp_ops);
108905774088SStefano Stabellini 			else if (mdesc->smp)
1090abcee5fbSMarc Zyngier 				smp_set_ops(mdesc->smp);
1091b382b940SJon Medhurst 		}
10927bbb7940SRussell King 		smp_init_cpus();
10938cf72172SLorenzo Pieralisi 		smp_build_mpidr_hash();
1094abcee5fbSMarc Zyngier 	}
10957bbb7940SRussell King #endif
10964588c34dSDave Martin 
10974588c34dSDave Martin 	if (!is_smp())
10984588c34dSDave Martin 		hyp_mode_check();
10994588c34dSDave Martin 
11003c57fb43SMika Westerberg 	reserve_crashkernel();
11017bbb7940SRussell King 
110252108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER
110352108641Seric miao 	handle_arch_irq = mdesc->handle_irq;
110452108641Seric miao #endif
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds #ifdef CONFIG_VT
11071da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE)
11081da177e4SLinus Torvalds 	conswitchp = &vga_con;
11091da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE)
11101da177e4SLinus Torvalds 	conswitchp = &dummy_con;
11111da177e4SLinus Torvalds #endif
11121da177e4SLinus Torvalds #endif
1113dec12e62SRussell King 
1114dec12e62SRussell King 	if (mdesc->init_early)
1115dec12e62SRussell King 		mdesc->init_early();
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 
11191da177e4SLinus Torvalds static int __init topology_init(void)
11201da177e4SLinus Torvalds {
11211da177e4SLinus Torvalds 	int cpu;
11221da177e4SLinus Torvalds 
112366fb8bd2SRussell King 	for_each_possible_cpu(cpu) {
112466fb8bd2SRussell King 		struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu);
1125787047eeSStephen Boyd 		cpuinfo->cpu.hotpluggable = platform_can_hotplug_cpu(cpu);
112666fb8bd2SRussell King 		register_cpu(&cpuinfo->cpu, cpu);
112766fb8bd2SRussell King 	}
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds 	return 0;
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds subsys_initcall(topology_init);
11321da177e4SLinus Torvalds 
1133e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU
1134e119bfffSRussell King static int __init proc_cpu_init(void)
1135e119bfffSRussell King {
1136e119bfffSRussell King 	struct proc_dir_entry *res;
1137e119bfffSRussell King 
1138e119bfffSRussell King 	res = proc_mkdir("cpu", NULL);
1139e119bfffSRussell King 	if (!res)
1140e119bfffSRussell King 		return -ENOMEM;
1141e119bfffSRussell King 	return 0;
1142e119bfffSRussell King }
1143e119bfffSRussell King fs_initcall(proc_cpu_init);
1144e119bfffSRussell King #endif
1145e119bfffSRussell King 
11461da177e4SLinus Torvalds static const char *hwcap_str[] = {
11471da177e4SLinus Torvalds 	"swp",
11481da177e4SLinus Torvalds 	"half",
11491da177e4SLinus Torvalds 	"thumb",
11501da177e4SLinus Torvalds 	"26bit",
11511da177e4SLinus Torvalds 	"fastmult",
11521da177e4SLinus Torvalds 	"fpa",
11531da177e4SLinus Torvalds 	"vfp",
11541da177e4SLinus Torvalds 	"edsp",
11551da177e4SLinus Torvalds 	"java",
11568f7f9435SPaul Gortmaker 	"iwmmxt",
115799e4a6ddSLennert Buytenhek 	"crunch",
11584369ae16SCatalin Marinas 	"thumbee",
11592bedbdf4SCatalin Marinas 	"neon",
11607279dc3eSCatalin Marinas 	"vfpv3",
11617279dc3eSCatalin Marinas 	"vfpv3d16",
1162254cdf8eSWill Deacon 	"tls",
1163254cdf8eSWill Deacon 	"vfpv4",
1164254cdf8eSWill Deacon 	"idiva",
1165254cdf8eSWill Deacon 	"idivt",
1166ab8d46c0STetsuyuki Kobayashi 	"vfpd32",
1167a469abd0SWill Deacon 	"lpae",
1168e9faebc6SSudeep KarkadaNagesha 	"evtstrm",
11691da177e4SLinus Torvalds 	NULL
11701da177e4SLinus Torvalds };
11711da177e4SLinus Torvalds 
1172b342ea4eSArd Biesheuvel static const char *hwcap2_str[] = {
11738258a989SArd Biesheuvel 	"aes",
11748258a989SArd Biesheuvel 	"pmull",
11758258a989SArd Biesheuvel 	"sha1",
11768258a989SArd Biesheuvel 	"sha2",
11778258a989SArd Biesheuvel 	"crc32",
1178b342ea4eSArd Biesheuvel 	NULL
1179b342ea4eSArd Biesheuvel };
1180b342ea4eSArd Biesheuvel 
11811da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v)
11821da177e4SLinus Torvalds {
1183b4b8f770SLorenzo Pieralisi 	int i, j;
1184b4b8f770SLorenzo Pieralisi 	u32 cpuid;
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 	for_each_online_cpu(i) {
118715559722SRussell King 		/*
118815559722SRussell King 		 * glibc reads /proc/cpuinfo to determine the number of
118915559722SRussell King 		 * online processors, looking for lines beginning with
119015559722SRussell King 		 * "processor".  Give glibc what it expects.
119115559722SRussell King 		 */
119215559722SRussell King 		seq_printf(m, "processor\t: %d\n", i);
1193b4b8f770SLorenzo Pieralisi 		cpuid = is_smp() ? per_cpu(cpu_data, i).cpuid : read_cpuid_id();
1194b4b8f770SLorenzo Pieralisi 		seq_printf(m, "model name\t: %s rev %d (%s)\n",
1195b4b8f770SLorenzo Pieralisi 			   cpu_name, cpuid & 15, elf_platform);
1196b4b8f770SLorenzo Pieralisi 
11974bf9636cSPavel Machek #if defined(CONFIG_SMP)
11984bf9636cSPavel Machek 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
11994bf9636cSPavel Machek 			   per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
12004bf9636cSPavel Machek 			   (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
12014bf9636cSPavel Machek #else
12024bf9636cSPavel Machek 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
12034bf9636cSPavel Machek 			   loops_per_jiffy / (500000/HZ),
12044bf9636cSPavel Machek 			   (loops_per_jiffy / (5000/HZ)) % 100);
12054bf9636cSPavel Machek #endif
12061da177e4SLinus Torvalds 		/* dump out the processor features */
12071da177e4SLinus Torvalds 		seq_puts(m, "Features\t: ");
12081da177e4SLinus Torvalds 
1209b4b8f770SLorenzo Pieralisi 		for (j = 0; hwcap_str[j]; j++)
1210b4b8f770SLorenzo Pieralisi 			if (elf_hwcap & (1 << j))
1211b4b8f770SLorenzo Pieralisi 				seq_printf(m, "%s ", hwcap_str[j]);
12121da177e4SLinus Torvalds 
1213b342ea4eSArd Biesheuvel 		for (j = 0; hwcap2_str[j]; j++)
1214b342ea4eSArd Biesheuvel 			if (elf_hwcap2 & (1 << j))
1215b342ea4eSArd Biesheuvel 				seq_printf(m, "%s ", hwcap2_str[j]);
1216b342ea4eSArd Biesheuvel 
1217b4b8f770SLorenzo Pieralisi 		seq_printf(m, "\nCPU implementer\t: 0x%02x\n", cpuid >> 24);
1218b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU architecture: %s\n",
1219b4b8f770SLorenzo Pieralisi 			   proc_arch[cpu_architecture()]);
12201da177e4SLinus Torvalds 
1221b4b8f770SLorenzo Pieralisi 		if ((cpuid & 0x0008f000) == 0x00000000) {
12221da177e4SLinus Torvalds 			/* pre-ARM7 */
1223b4b8f770SLorenzo Pieralisi 			seq_printf(m, "CPU part\t: %07x\n", cpuid >> 4);
12241da177e4SLinus Torvalds 		} else {
1225b4b8f770SLorenzo Pieralisi 			if ((cpuid & 0x0008f000) == 0x00007000) {
12261da177e4SLinus Torvalds 				/* ARM7 */
12271da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%02x\n",
1228b4b8f770SLorenzo Pieralisi 					   (cpuid >> 16) & 127);
12291da177e4SLinus Torvalds 			} else {
12301da177e4SLinus Torvalds 				/* post-ARM7 */
12311da177e4SLinus Torvalds 				seq_printf(m, "CPU variant\t: 0x%x\n",
1232b4b8f770SLorenzo Pieralisi 					   (cpuid >> 20) & 15);
12331da177e4SLinus Torvalds 			}
12341da177e4SLinus Torvalds 			seq_printf(m, "CPU part\t: 0x%03x\n",
1235b4b8f770SLorenzo Pieralisi 				   (cpuid >> 4) & 0xfff);
12361da177e4SLinus Torvalds 		}
1237b4b8f770SLorenzo Pieralisi 		seq_printf(m, "CPU revision\t: %d\n\n", cpuid & 15);
1238b4b8f770SLorenzo Pieralisi 	}
12391da177e4SLinus Torvalds 
12401da177e4SLinus Torvalds 	seq_printf(m, "Hardware\t: %s\n", machine_name);
12411da177e4SLinus Torvalds 	seq_printf(m, "Revision\t: %04x\n", system_rev);
12423f599875SPaul Kocialkowski 	seq_printf(m, "Serial\t\t: %s\n", system_serial);
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	return 0;
12451da177e4SLinus Torvalds }
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos)
12481da177e4SLinus Torvalds {
12491da177e4SLinus Torvalds 	return *pos < 1 ? (void *)1 : NULL;
12501da177e4SLinus Torvalds }
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos)
12531da177e4SLinus Torvalds {
12541da177e4SLinus Torvalds 	++*pos;
12551da177e4SLinus Torvalds 	return NULL;
12561da177e4SLinus Torvalds }
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v)
12591da177e4SLinus Torvalds {
12601da177e4SLinus Torvalds }
12611da177e4SLinus Torvalds 
12622ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = {
12631da177e4SLinus Torvalds 	.start	= c_start,
12641da177e4SLinus Torvalds 	.next	= c_next,
12651da177e4SLinus Torvalds 	.stop	= c_stop,
12661da177e4SLinus Torvalds 	.show	= c_show
12671da177e4SLinus Torvalds };
1268