xref: /openbmc/linux/arch/arm64/kernel/setup.c (revision 06f9eb88)
19703d9d7SCatalin Marinas /*
29703d9d7SCatalin Marinas  * Based on arch/arm/kernel/setup.c
39703d9d7SCatalin Marinas  *
49703d9d7SCatalin Marinas  * Copyright (C) 1995-2001 Russell King
59703d9d7SCatalin Marinas  * Copyright (C) 2012 ARM Ltd.
69703d9d7SCatalin Marinas  *
79703d9d7SCatalin Marinas  * This program is free software; you can redistribute it and/or modify
89703d9d7SCatalin Marinas  * it under the terms of the GNU General Public License version 2 as
99703d9d7SCatalin Marinas  * published by the Free Software Foundation.
109703d9d7SCatalin Marinas  *
119703d9d7SCatalin Marinas  * This program is distributed in the hope that it will be useful,
129703d9d7SCatalin Marinas  * but WITHOUT ANY WARRANTY; without even the implied warranty of
139703d9d7SCatalin Marinas  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149703d9d7SCatalin Marinas  * GNU General Public License for more details.
159703d9d7SCatalin Marinas  *
169703d9d7SCatalin Marinas  * You should have received a copy of the GNU General Public License
179703d9d7SCatalin Marinas  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
189703d9d7SCatalin Marinas  */
199703d9d7SCatalin Marinas 
209703d9d7SCatalin Marinas #include <linux/export.h>
219703d9d7SCatalin Marinas #include <linux/kernel.h>
229703d9d7SCatalin Marinas #include <linux/stddef.h>
239703d9d7SCatalin Marinas #include <linux/ioport.h>
249703d9d7SCatalin Marinas #include <linux/delay.h>
259703d9d7SCatalin Marinas #include <linux/utsname.h>
269703d9d7SCatalin Marinas #include <linux/initrd.h>
279703d9d7SCatalin Marinas #include <linux/console.h>
28a41dc0e8SCatalin Marinas #include <linux/cache.h>
299703d9d7SCatalin Marinas #include <linux/bootmem.h>
309703d9d7SCatalin Marinas #include <linux/seq_file.h>
319703d9d7SCatalin Marinas #include <linux/screen_info.h>
329703d9d7SCatalin Marinas #include <linux/init.h>
339703d9d7SCatalin Marinas #include <linux/kexec.h>
349703d9d7SCatalin Marinas #include <linux/crash_dump.h>
359703d9d7SCatalin Marinas #include <linux/root_dev.h>
36de79a64dSCatalin Marinas #include <linux/clk-provider.h>
379703d9d7SCatalin Marinas #include <linux/cpu.h>
389703d9d7SCatalin Marinas #include <linux/interrupt.h>
399703d9d7SCatalin Marinas #include <linux/smp.h>
409703d9d7SCatalin Marinas #include <linux/fs.h>
419703d9d7SCatalin Marinas #include <linux/proc_fs.h>
429703d9d7SCatalin Marinas #include <linux/memblock.h>
439703d9d7SCatalin Marinas #include <linux/of_fdt.h>
44d6bafb9bSCatalin Marinas #include <linux/of_platform.h>
45f84d0275SMark Salter #include <linux/efi.h>
4644b82b77SMark Rutland #include <linux/personality.h>
479703d9d7SCatalin Marinas 
48bf4b558eSMark Salter #include <asm/fixmap.h>
49df857416SMark Rutland #include <asm/cpu.h>
509703d9d7SCatalin Marinas #include <asm/cputype.h>
519703d9d7SCatalin Marinas #include <asm/elf.h>
529703d9d7SCatalin Marinas #include <asm/cputable.h>
53930da09fSAndre Przywara #include <asm/cpufeature.h>
54e8765b26SMark Rutland #include <asm/cpu_ops.h>
559703d9d7SCatalin Marinas #include <asm/sections.h>
569703d9d7SCatalin Marinas #include <asm/setup.h>
574c7aa002SJavi Merino #include <asm/smp_plat.h>
589703d9d7SCatalin Marinas #include <asm/cacheflush.h>
599703d9d7SCatalin Marinas #include <asm/tlbflush.h>
609703d9d7SCatalin Marinas #include <asm/traps.h>
619703d9d7SCatalin Marinas #include <asm/memblock.h>
62e790f1deSWill Deacon #include <asm/psci.h>
63f84d0275SMark Salter #include <asm/efi.h>
649703d9d7SCatalin Marinas 
659703d9d7SCatalin Marinas unsigned int processor_id;
669703d9d7SCatalin Marinas EXPORT_SYMBOL(processor_id);
679703d9d7SCatalin Marinas 
6825804e6aSSteve Capper unsigned long elf_hwcap __read_mostly;
699703d9d7SCatalin Marinas EXPORT_SYMBOL_GPL(elf_hwcap);
709703d9d7SCatalin Marinas 
7146efe547SSudeep KarkadaNagesha #ifdef CONFIG_COMPAT
7246efe547SSudeep KarkadaNagesha #define COMPAT_ELF_HWCAP_DEFAULT	\
7346efe547SSudeep KarkadaNagesha 				(COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
7446efe547SSudeep KarkadaNagesha 				 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
7546efe547SSudeep KarkadaNagesha 				 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
7646efe547SSudeep KarkadaNagesha 				 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
777d57511dSCatalin Marinas 				 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\
787d57511dSCatalin Marinas 				 COMPAT_HWCAP_LPAE)
7946efe547SSudeep KarkadaNagesha unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
8028964d32SArd Biesheuvel unsigned int compat_elf_hwcap2 __read_mostly;
8146efe547SSudeep KarkadaNagesha #endif
8246efe547SSudeep KarkadaNagesha 
8306f9eb88SFabio Estevam DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
84930da09fSAndre Przywara 
859703d9d7SCatalin Marinas static const char *cpu_name;
869703d9d7SCatalin Marinas phys_addr_t __fdt_pointer __initdata;
879703d9d7SCatalin Marinas 
889703d9d7SCatalin Marinas /*
899703d9d7SCatalin Marinas  * Standard memory resources
909703d9d7SCatalin Marinas  */
919703d9d7SCatalin Marinas static struct resource mem_res[] = {
929703d9d7SCatalin Marinas 	{
939703d9d7SCatalin Marinas 		.name = "Kernel code",
949703d9d7SCatalin Marinas 		.start = 0,
959703d9d7SCatalin Marinas 		.end = 0,
969703d9d7SCatalin Marinas 		.flags = IORESOURCE_MEM
979703d9d7SCatalin Marinas 	},
989703d9d7SCatalin Marinas 	{
999703d9d7SCatalin Marinas 		.name = "Kernel data",
1009703d9d7SCatalin Marinas 		.start = 0,
1019703d9d7SCatalin Marinas 		.end = 0,
1029703d9d7SCatalin Marinas 		.flags = IORESOURCE_MEM
1039703d9d7SCatalin Marinas 	}
1049703d9d7SCatalin Marinas };
1059703d9d7SCatalin Marinas 
1069703d9d7SCatalin Marinas #define kernel_code mem_res[0]
1079703d9d7SCatalin Marinas #define kernel_data mem_res[1]
1089703d9d7SCatalin Marinas 
1099703d9d7SCatalin Marinas void __init early_print(const char *str, ...)
1109703d9d7SCatalin Marinas {
1119703d9d7SCatalin Marinas 	char buf[256];
1129703d9d7SCatalin Marinas 	va_list ap;
1139703d9d7SCatalin Marinas 
1149703d9d7SCatalin Marinas 	va_start(ap, str);
1159703d9d7SCatalin Marinas 	vsnprintf(buf, sizeof(buf), str, ap);
1169703d9d7SCatalin Marinas 	va_end(ap);
1179703d9d7SCatalin Marinas 
1189703d9d7SCatalin Marinas 	printk("%s", buf);
1199703d9d7SCatalin Marinas }
1209703d9d7SCatalin Marinas 
12171586276SWill Deacon void __init smp_setup_processor_id(void)
12271586276SWill Deacon {
12380708677SMark Rutland 	u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
12480708677SMark Rutland 	cpu_logical_map(0) = mpidr;
12580708677SMark Rutland 
12671586276SWill Deacon 	/*
12771586276SWill Deacon 	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
12871586276SWill Deacon 	 * using percpu variable early, for example, lockdep will
12971586276SWill Deacon 	 * access percpu variable inside lock_release
13071586276SWill Deacon 	 */
13171586276SWill Deacon 	set_my_cpu_offset(0);
13280708677SMark Rutland 	pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);
13371586276SWill Deacon }
13471586276SWill Deacon 
1356e15d0e0SSudeep KarkadaNagesha bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
1366e15d0e0SSudeep KarkadaNagesha {
1376e15d0e0SSudeep KarkadaNagesha 	return phys_id == cpu_logical_map(cpu);
1386e15d0e0SSudeep KarkadaNagesha }
1396e15d0e0SSudeep KarkadaNagesha 
140976d7d3fSLorenzo Pieralisi struct mpidr_hash mpidr_hash;
141976d7d3fSLorenzo Pieralisi #ifdef CONFIG_SMP
142976d7d3fSLorenzo Pieralisi /**
143976d7d3fSLorenzo Pieralisi  * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
144976d7d3fSLorenzo Pieralisi  *			  level in order to build a linear index from an
145976d7d3fSLorenzo Pieralisi  *			  MPIDR value. Resulting algorithm is a collision
146976d7d3fSLorenzo Pieralisi  *			  free hash carried out through shifting and ORing
147976d7d3fSLorenzo Pieralisi  */
148976d7d3fSLorenzo Pieralisi static void __init smp_build_mpidr_hash(void)
149976d7d3fSLorenzo Pieralisi {
150976d7d3fSLorenzo Pieralisi 	u32 i, affinity, fs[4], bits[4], ls;
151976d7d3fSLorenzo Pieralisi 	u64 mask = 0;
152976d7d3fSLorenzo Pieralisi 	/*
153976d7d3fSLorenzo Pieralisi 	 * Pre-scan the list of MPIDRS and filter out bits that do
154976d7d3fSLorenzo Pieralisi 	 * not contribute to affinity levels, ie they never toggle.
155976d7d3fSLorenzo Pieralisi 	 */
156976d7d3fSLorenzo Pieralisi 	for_each_possible_cpu(i)
157976d7d3fSLorenzo Pieralisi 		mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
158976d7d3fSLorenzo Pieralisi 	pr_debug("mask of set bits %#llx\n", mask);
159976d7d3fSLorenzo Pieralisi 	/*
160976d7d3fSLorenzo Pieralisi 	 * Find and stash the last and first bit set at all affinity levels to
161976d7d3fSLorenzo Pieralisi 	 * check how many bits are required to represent them.
162976d7d3fSLorenzo Pieralisi 	 */
163976d7d3fSLorenzo Pieralisi 	for (i = 0; i < 4; i++) {
164976d7d3fSLorenzo Pieralisi 		affinity = MPIDR_AFFINITY_LEVEL(mask, i);
165976d7d3fSLorenzo Pieralisi 		/*
166976d7d3fSLorenzo Pieralisi 		 * Find the MSB bit and LSB bits position
167976d7d3fSLorenzo Pieralisi 		 * to determine how many bits are required
168976d7d3fSLorenzo Pieralisi 		 * to express the affinity level.
169976d7d3fSLorenzo Pieralisi 		 */
170976d7d3fSLorenzo Pieralisi 		ls = fls(affinity);
171976d7d3fSLorenzo Pieralisi 		fs[i] = affinity ? ffs(affinity) - 1 : 0;
172976d7d3fSLorenzo Pieralisi 		bits[i] = ls - fs[i];
173976d7d3fSLorenzo Pieralisi 	}
174976d7d3fSLorenzo Pieralisi 	/*
175976d7d3fSLorenzo Pieralisi 	 * An index can be created from the MPIDR_EL1 by isolating the
176976d7d3fSLorenzo Pieralisi 	 * significant bits at each affinity level and by shifting
177976d7d3fSLorenzo Pieralisi 	 * them in order to compress the 32 bits values space to a
178976d7d3fSLorenzo Pieralisi 	 * compressed set of values. This is equivalent to hashing
179976d7d3fSLorenzo Pieralisi 	 * the MPIDR_EL1 through shifting and ORing. It is a collision free
180976d7d3fSLorenzo Pieralisi 	 * hash though not minimal since some levels might contain a number
181976d7d3fSLorenzo Pieralisi 	 * of CPUs that is not an exact power of 2 and their bit
182976d7d3fSLorenzo Pieralisi 	 * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}.
183976d7d3fSLorenzo Pieralisi 	 */
184976d7d3fSLorenzo Pieralisi 	mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0];
185976d7d3fSLorenzo Pieralisi 	mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0];
186976d7d3fSLorenzo Pieralisi 	mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] -
187976d7d3fSLorenzo Pieralisi 						(bits[1] + bits[0]);
188976d7d3fSLorenzo Pieralisi 	mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) +
189976d7d3fSLorenzo Pieralisi 				  fs[3] - (bits[2] + bits[1] + bits[0]);
190976d7d3fSLorenzo Pieralisi 	mpidr_hash.mask = mask;
191976d7d3fSLorenzo Pieralisi 	mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0];
192976d7d3fSLorenzo Pieralisi 	pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n",
193976d7d3fSLorenzo Pieralisi 		mpidr_hash.shift_aff[0],
194976d7d3fSLorenzo Pieralisi 		mpidr_hash.shift_aff[1],
195976d7d3fSLorenzo Pieralisi 		mpidr_hash.shift_aff[2],
196976d7d3fSLorenzo Pieralisi 		mpidr_hash.shift_aff[3],
197976d7d3fSLorenzo Pieralisi 		mpidr_hash.mask,
198976d7d3fSLorenzo Pieralisi 		mpidr_hash.bits);
199976d7d3fSLorenzo Pieralisi 	/*
200976d7d3fSLorenzo Pieralisi 	 * 4x is an arbitrary value used to warn on a hash table much bigger
201976d7d3fSLorenzo Pieralisi 	 * than expected on most systems.
202976d7d3fSLorenzo Pieralisi 	 */
203976d7d3fSLorenzo Pieralisi 	if (mpidr_hash_size() > 4 * num_possible_cpus())
204976d7d3fSLorenzo Pieralisi 		pr_warn("Large number of MPIDR hash buckets detected\n");
205976d7d3fSLorenzo Pieralisi 	__flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash));
206976d7d3fSLorenzo Pieralisi }
207976d7d3fSLorenzo Pieralisi #endif
208976d7d3fSLorenzo Pieralisi 
2099703d9d7SCatalin Marinas static void __init setup_processor(void)
2109703d9d7SCatalin Marinas {
2119703d9d7SCatalin Marinas 	struct cpu_info *cpu_info;
2124bff28ccSSteve Capper 	u64 features, block;
213a41dc0e8SCatalin Marinas 	u32 cwg;
214a41dc0e8SCatalin Marinas 	int cls;
2159703d9d7SCatalin Marinas 
2169703d9d7SCatalin Marinas 	cpu_info = lookup_processor_type(read_cpuid_id());
2179703d9d7SCatalin Marinas 	if (!cpu_info) {
2189703d9d7SCatalin Marinas 		printk("CPU configuration botched (ID %08x), unable to continue.\n",
2199703d9d7SCatalin Marinas 		       read_cpuid_id());
2209703d9d7SCatalin Marinas 		while (1);
2219703d9d7SCatalin Marinas 	}
2229703d9d7SCatalin Marinas 
2239703d9d7SCatalin Marinas 	cpu_name = cpu_info->cpu_name;
2249703d9d7SCatalin Marinas 
2259703d9d7SCatalin Marinas 	printk("CPU: %s [%08x] revision %d\n",
2269703d9d7SCatalin Marinas 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
2279703d9d7SCatalin Marinas 
22894ed1f2cSWill Deacon 	sprintf(init_utsname()->machine, ELF_PLATFORM);
2299703d9d7SCatalin Marinas 	elf_hwcap = 0;
2304bff28ccSSteve Capper 
231df857416SMark Rutland 	cpuinfo_store_boot_cpu();
232df857416SMark Rutland 
2334bff28ccSSteve Capper 	/*
234a41dc0e8SCatalin Marinas 	 * Check for sane CTR_EL0.CWG value.
235a41dc0e8SCatalin Marinas 	 */
236a41dc0e8SCatalin Marinas 	cwg = cache_type_cwg();
237a41dc0e8SCatalin Marinas 	cls = cache_line_size();
238a41dc0e8SCatalin Marinas 	if (!cwg)
239a41dc0e8SCatalin Marinas 		pr_warn("No Cache Writeback Granule information, assuming cache line size %d\n",
240a41dc0e8SCatalin Marinas 			cls);
241a41dc0e8SCatalin Marinas 	if (L1_CACHE_BYTES < cls)
242a41dc0e8SCatalin Marinas 		pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n",
243a41dc0e8SCatalin Marinas 			L1_CACHE_BYTES, cls);
244a41dc0e8SCatalin Marinas 
245a41dc0e8SCatalin Marinas 	/*
2464bff28ccSSteve Capper 	 * ID_AA64ISAR0_EL1 contains 4-bit wide signed feature blocks.
2474bff28ccSSteve Capper 	 * The blocks we test below represent incremental functionality
2484bff28ccSSteve Capper 	 * for non-negative values. Negative values are reserved.
2494bff28ccSSteve Capper 	 */
2504bff28ccSSteve Capper 	features = read_cpuid(ID_AA64ISAR0_EL1);
2514bff28ccSSteve Capper 	block = (features >> 4) & 0xf;
2524bff28ccSSteve Capper 	if (!(block & 0x8)) {
2534bff28ccSSteve Capper 		switch (block) {
2544bff28ccSSteve Capper 		default:
2554bff28ccSSteve Capper 		case 2:
2564bff28ccSSteve Capper 			elf_hwcap |= HWCAP_PMULL;
2574bff28ccSSteve Capper 		case 1:
2584bff28ccSSteve Capper 			elf_hwcap |= HWCAP_AES;
2594bff28ccSSteve Capper 		case 0:
2604bff28ccSSteve Capper 			break;
2614bff28ccSSteve Capper 		}
2624bff28ccSSteve Capper 	}
2634bff28ccSSteve Capper 
2644bff28ccSSteve Capper 	block = (features >> 8) & 0xf;
2654bff28ccSSteve Capper 	if (block && !(block & 0x8))
2664bff28ccSSteve Capper 		elf_hwcap |= HWCAP_SHA1;
2674bff28ccSSteve Capper 
2684bff28ccSSteve Capper 	block = (features >> 12) & 0xf;
2694bff28ccSSteve Capper 	if (block && !(block & 0x8))
2704bff28ccSSteve Capper 		elf_hwcap |= HWCAP_SHA2;
2714bff28ccSSteve Capper 
2724bff28ccSSteve Capper 	block = (features >> 16) & 0xf;
2734bff28ccSSteve Capper 	if (block && !(block & 0x8))
2744bff28ccSSteve Capper 		elf_hwcap |= HWCAP_CRC32;
2754cf761cdSArd Biesheuvel 
2764cf761cdSArd Biesheuvel #ifdef CONFIG_COMPAT
2774cf761cdSArd Biesheuvel 	/*
2784cf761cdSArd Biesheuvel 	 * ID_ISAR5_EL1 carries similar information as above, but pertaining to
2794cf761cdSArd Biesheuvel 	 * the Aarch32 32-bit execution state.
2804cf761cdSArd Biesheuvel 	 */
2814cf761cdSArd Biesheuvel 	features = read_cpuid(ID_ISAR5_EL1);
2824cf761cdSArd Biesheuvel 	block = (features >> 4) & 0xf;
2834cf761cdSArd Biesheuvel 	if (!(block & 0x8)) {
2844cf761cdSArd Biesheuvel 		switch (block) {
2854cf761cdSArd Biesheuvel 		default:
2864cf761cdSArd Biesheuvel 		case 2:
2874cf761cdSArd Biesheuvel 			compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL;
2884cf761cdSArd Biesheuvel 		case 1:
2894cf761cdSArd Biesheuvel 			compat_elf_hwcap2 |= COMPAT_HWCAP2_AES;
2904cf761cdSArd Biesheuvel 		case 0:
2914cf761cdSArd Biesheuvel 			break;
2924cf761cdSArd Biesheuvel 		}
2934cf761cdSArd Biesheuvel 	}
2944cf761cdSArd Biesheuvel 
2954cf761cdSArd Biesheuvel 	block = (features >> 8) & 0xf;
2964cf761cdSArd Biesheuvel 	if (block && !(block & 0x8))
2974cf761cdSArd Biesheuvel 		compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1;
2984cf761cdSArd Biesheuvel 
2994cf761cdSArd Biesheuvel 	block = (features >> 12) & 0xf;
3004cf761cdSArd Biesheuvel 	if (block && !(block & 0x8))
3014cf761cdSArd Biesheuvel 		compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2;
3024cf761cdSArd Biesheuvel 
3034cf761cdSArd Biesheuvel 	block = (features >> 16) & 0xf;
3044cf761cdSArd Biesheuvel 	if (block && !(block & 0x8))
3054cf761cdSArd Biesheuvel 		compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32;
3064cf761cdSArd Biesheuvel #endif
3079703d9d7SCatalin Marinas }
3089703d9d7SCatalin Marinas 
3099703d9d7SCatalin Marinas static void __init setup_machine_fdt(phys_addr_t dt_phys)
3109703d9d7SCatalin Marinas {
311d5189cc5SRob Herring 	if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) {
3129703d9d7SCatalin Marinas 		early_print("\n"
3139703d9d7SCatalin Marinas 			"Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
314d5189cc5SRob Herring 			"The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
3159703d9d7SCatalin Marinas 			"\nPlease check your bootloader.\n",
316d5189cc5SRob Herring 			dt_phys, phys_to_virt(dt_phys));
3179703d9d7SCatalin Marinas 
3189703d9d7SCatalin Marinas 		while (true)
3199703d9d7SCatalin Marinas 			cpu_relax();
3209703d9d7SCatalin Marinas 	}
3215e39977eSWill Deacon 
32244b82b77SMark Rutland 	dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
3239703d9d7SCatalin Marinas }
3249703d9d7SCatalin Marinas 
3259703d9d7SCatalin Marinas /*
3269703d9d7SCatalin Marinas  * Limit the memory size that was specified via FDT.
3279703d9d7SCatalin Marinas  */
3289703d9d7SCatalin Marinas static int __init early_mem(char *p)
3299703d9d7SCatalin Marinas {
3309703d9d7SCatalin Marinas 	phys_addr_t limit;
3319703d9d7SCatalin Marinas 
3329703d9d7SCatalin Marinas 	if (!p)
3339703d9d7SCatalin Marinas 		return 1;
3349703d9d7SCatalin Marinas 
3359703d9d7SCatalin Marinas 	limit = memparse(p, &p) & PAGE_MASK;
3369703d9d7SCatalin Marinas 	pr_notice("Memory limited to %lldMB\n", limit >> 20);
3379703d9d7SCatalin Marinas 
3389703d9d7SCatalin Marinas 	memblock_enforce_memory_limit(limit);
3399703d9d7SCatalin Marinas 
3409703d9d7SCatalin Marinas 	return 0;
3419703d9d7SCatalin Marinas }
3429703d9d7SCatalin Marinas early_param("mem", early_mem);
3439703d9d7SCatalin Marinas 
3449703d9d7SCatalin Marinas static void __init request_standard_resources(void)
3459703d9d7SCatalin Marinas {
3469703d9d7SCatalin Marinas 	struct memblock_region *region;
3479703d9d7SCatalin Marinas 	struct resource *res;
3489703d9d7SCatalin Marinas 
3499703d9d7SCatalin Marinas 	kernel_code.start   = virt_to_phys(_text);
3509703d9d7SCatalin Marinas 	kernel_code.end     = virt_to_phys(_etext - 1);
3519703d9d7SCatalin Marinas 	kernel_data.start   = virt_to_phys(_sdata);
3529703d9d7SCatalin Marinas 	kernel_data.end     = virt_to_phys(_end - 1);
3539703d9d7SCatalin Marinas 
3549703d9d7SCatalin Marinas 	for_each_memblock(memory, region) {
3559703d9d7SCatalin Marinas 		res = alloc_bootmem_low(sizeof(*res));
3569703d9d7SCatalin Marinas 		res->name  = "System RAM";
3579703d9d7SCatalin Marinas 		res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
3589703d9d7SCatalin Marinas 		res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
3599703d9d7SCatalin Marinas 		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
3609703d9d7SCatalin Marinas 
3619703d9d7SCatalin Marinas 		request_resource(&iomem_resource, res);
3629703d9d7SCatalin Marinas 
3639703d9d7SCatalin Marinas 		if (kernel_code.start >= res->start &&
3649703d9d7SCatalin Marinas 		    kernel_code.end <= res->end)
3659703d9d7SCatalin Marinas 			request_resource(res, &kernel_code);
3669703d9d7SCatalin Marinas 		if (kernel_data.start >= res->start &&
3679703d9d7SCatalin Marinas 		    kernel_data.end <= res->end)
3689703d9d7SCatalin Marinas 			request_resource(res, &kernel_data);
3699703d9d7SCatalin Marinas 	}
3709703d9d7SCatalin Marinas }
3719703d9d7SCatalin Marinas 
3724c7aa002SJavi Merino u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
3734c7aa002SJavi Merino 
3749703d9d7SCatalin Marinas void __init setup_arch(char **cmdline_p)
3759703d9d7SCatalin Marinas {
3769703d9d7SCatalin Marinas 	setup_processor();
3779703d9d7SCatalin Marinas 
3789703d9d7SCatalin Marinas 	setup_machine_fdt(__fdt_pointer);
3799703d9d7SCatalin Marinas 
3809703d9d7SCatalin Marinas 	init_mm.start_code = (unsigned long) _text;
3819703d9d7SCatalin Marinas 	init_mm.end_code   = (unsigned long) _etext;
3829703d9d7SCatalin Marinas 	init_mm.end_data   = (unsigned long) _edata;
3839703d9d7SCatalin Marinas 	init_mm.brk	   = (unsigned long) _end;
3849703d9d7SCatalin Marinas 
3859703d9d7SCatalin Marinas 	*cmdline_p = boot_command_line;
3869703d9d7SCatalin Marinas 
387af86e597SLaura Abbott 	early_fixmap_init();
388bf4b558eSMark Salter 	early_ioremap_init();
3890bf757c7SMark Salter 
3909703d9d7SCatalin Marinas 	parse_early_param();
3919703d9d7SCatalin Marinas 
3927a9c43beSJon Masters 	/*
3937a9c43beSJon Masters 	 *  Unmask asynchronous aborts after bringing up possible earlycon.
3947a9c43beSJon Masters 	 * (Report possible System Errors once we can report this occurred)
3957a9c43beSJon Masters 	 */
3967a9c43beSJon Masters 	local_async_enable();
3977a9c43beSJon Masters 
398f84d0275SMark Salter 	efi_init();
3999703d9d7SCatalin Marinas 	arm64_memblock_init();
4009703d9d7SCatalin Marinas 
4019703d9d7SCatalin Marinas 	paging_init();
4029703d9d7SCatalin Marinas 	request_standard_resources();
4039703d9d7SCatalin Marinas 
404f84d0275SMark Salter 	efi_idmap_init();
405f84d0275SMark Salter 
4069703d9d7SCatalin Marinas 	unflatten_device_tree();
4079703d9d7SCatalin Marinas 
408e790f1deSWill Deacon 	psci_init();
409e790f1deSWill Deacon 
410e8765b26SMark Rutland 	cpu_read_bootcpu_ops();
4119703d9d7SCatalin Marinas #ifdef CONFIG_SMP
4129703d9d7SCatalin Marinas 	smp_init_cpus();
413976d7d3fSLorenzo Pieralisi 	smp_build_mpidr_hash();
4149703d9d7SCatalin Marinas #endif
4159703d9d7SCatalin Marinas 
4169703d9d7SCatalin Marinas #ifdef CONFIG_VT
4179703d9d7SCatalin Marinas #if defined(CONFIG_VGA_CONSOLE)
4189703d9d7SCatalin Marinas 	conswitchp = &vga_con;
4199703d9d7SCatalin Marinas #elif defined(CONFIG_DUMMY_CONSOLE)
4209703d9d7SCatalin Marinas 	conswitchp = &dummy_con;
4219703d9d7SCatalin Marinas #endif
4229703d9d7SCatalin Marinas #endif
4239703d9d7SCatalin Marinas }
4249703d9d7SCatalin Marinas 
425c560ecfeSCatalin Marinas static int __init arm64_device_init(void)
426de79a64dSCatalin Marinas {
427c560ecfeSCatalin Marinas 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
428de79a64dSCatalin Marinas 	return 0;
429de79a64dSCatalin Marinas }
4306ecba8ebSCatalin Marinas arch_initcall_sync(arm64_device_init);
431de79a64dSCatalin Marinas 
4329703d9d7SCatalin Marinas static int __init topology_init(void)
4339703d9d7SCatalin Marinas {
4349703d9d7SCatalin Marinas 	int i;
4359703d9d7SCatalin Marinas 
4369703d9d7SCatalin Marinas 	for_each_possible_cpu(i) {
437df857416SMark Rutland 		struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
4389703d9d7SCatalin Marinas 		cpu->hotpluggable = 1;
4399703d9d7SCatalin Marinas 		register_cpu(cpu, i);
4409703d9d7SCatalin Marinas 	}
4419703d9d7SCatalin Marinas 
4429703d9d7SCatalin Marinas 	return 0;
4439703d9d7SCatalin Marinas }
4449703d9d7SCatalin Marinas subsys_initcall(topology_init);
4459703d9d7SCatalin Marinas 
4469703d9d7SCatalin Marinas static const char *hwcap_str[] = {
4479703d9d7SCatalin Marinas 	"fp",
4489703d9d7SCatalin Marinas 	"asimd",
44946efe547SSudeep KarkadaNagesha 	"evtstrm",
4504bff28ccSSteve Capper 	"aes",
4514bff28ccSSteve Capper 	"pmull",
4524bff28ccSSteve Capper 	"sha1",
4534bff28ccSSteve Capper 	"sha2",
4544bff28ccSSteve Capper 	"crc32",
4559703d9d7SCatalin Marinas 	NULL
4569703d9d7SCatalin Marinas };
4579703d9d7SCatalin Marinas 
45844b82b77SMark Rutland #ifdef CONFIG_COMPAT
45944b82b77SMark Rutland static const char *compat_hwcap_str[] = {
46044b82b77SMark Rutland 	"swp",
46144b82b77SMark Rutland 	"half",
46244b82b77SMark Rutland 	"thumb",
46344b82b77SMark Rutland 	"26bit",
46444b82b77SMark Rutland 	"fastmult",
46544b82b77SMark Rutland 	"fpa",
46644b82b77SMark Rutland 	"vfp",
46744b82b77SMark Rutland 	"edsp",
46844b82b77SMark Rutland 	"java",
46944b82b77SMark Rutland 	"iwmmxt",
47044b82b77SMark Rutland 	"crunch",
47144b82b77SMark Rutland 	"thumbee",
47244b82b77SMark Rutland 	"neon",
47344b82b77SMark Rutland 	"vfpv3",
47444b82b77SMark Rutland 	"vfpv3d16",
47544b82b77SMark Rutland 	"tls",
47644b82b77SMark Rutland 	"vfpv4",
47744b82b77SMark Rutland 	"idiva",
47844b82b77SMark Rutland 	"idivt",
47944b82b77SMark Rutland 	"vfpd32",
48044b82b77SMark Rutland 	"lpae",
48144b82b77SMark Rutland 	"evtstrm"
48244b82b77SMark Rutland };
48344b82b77SMark Rutland 
48444b82b77SMark Rutland static const char *compat_hwcap2_str[] = {
48544b82b77SMark Rutland 	"aes",
48644b82b77SMark Rutland 	"pmull",
48744b82b77SMark Rutland 	"sha1",
48844b82b77SMark Rutland 	"sha2",
48944b82b77SMark Rutland 	"crc32",
49044b82b77SMark Rutland 	NULL
49144b82b77SMark Rutland };
49244b82b77SMark Rutland #endif /* CONFIG_COMPAT */
49344b82b77SMark Rutland 
4949703d9d7SCatalin Marinas static int c_show(struct seq_file *m, void *v)
4959703d9d7SCatalin Marinas {
49644b82b77SMark Rutland 	int i, j;
4979703d9d7SCatalin Marinas 
4989703d9d7SCatalin Marinas 	for_each_online_cpu(i) {
49944b82b77SMark Rutland 		struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
50044b82b77SMark Rutland 		u32 midr = cpuinfo->reg_midr;
50144b82b77SMark Rutland 
5029703d9d7SCatalin Marinas 		/*
5039703d9d7SCatalin Marinas 		 * glibc reads /proc/cpuinfo to determine the number of
5049703d9d7SCatalin Marinas 		 * online processors, looking for lines beginning with
5059703d9d7SCatalin Marinas 		 * "processor".  Give glibc what it expects.
5069703d9d7SCatalin Marinas 		 */
5079703d9d7SCatalin Marinas #ifdef CONFIG_SMP
5089703d9d7SCatalin Marinas 		seq_printf(m, "processor\t: %d\n", i);
5099703d9d7SCatalin Marinas #endif
5109703d9d7SCatalin Marinas 
51144b82b77SMark Rutland 		/*
51244b82b77SMark Rutland 		 * Dump out the common processor features in a single line.
51344b82b77SMark Rutland 		 * Userspace should read the hwcaps with getauxval(AT_HWCAP)
51444b82b77SMark Rutland 		 * rather than attempting to parse this, but there's a body of
51544b82b77SMark Rutland 		 * software which does already (at least for 32-bit).
51644b82b77SMark Rutland 		 */
5175e39977eSWill Deacon 		seq_puts(m, "Features\t:");
51844b82b77SMark Rutland 		if (personality(current->personality) == PER_LINUX32) {
51944b82b77SMark Rutland #ifdef CONFIG_COMPAT
52044b82b77SMark Rutland 			for (j = 0; compat_hwcap_str[j]; j++)
52144b82b77SMark Rutland 				if (compat_elf_hwcap & (1 << j))
52244b82b77SMark Rutland 					seq_printf(m, " %s", compat_hwcap_str[j]);
5235e39977eSWill Deacon 
52444b82b77SMark Rutland 			for (j = 0; compat_hwcap2_str[j]; j++)
52544b82b77SMark Rutland 				if (compat_elf_hwcap2 & (1 << j))
52644b82b77SMark Rutland 					seq_printf(m, " %s", compat_hwcap2_str[j]);
52744b82b77SMark Rutland #endif /* CONFIG_COMPAT */
52844b82b77SMark Rutland 		} else {
52944b82b77SMark Rutland 			for (j = 0; hwcap_str[j]; j++)
53044b82b77SMark Rutland 				if (elf_hwcap & (1 << j))
53144b82b77SMark Rutland 					seq_printf(m, " %s", hwcap_str[j]);
53244b82b77SMark Rutland 		}
5335e39977eSWill Deacon 		seq_puts(m, "\n");
5345e39977eSWill Deacon 
53544b82b77SMark Rutland 		seq_printf(m, "CPU implementer\t: 0x%02x\n",
53644b82b77SMark Rutland 			   MIDR_IMPLEMENTOR(midr));
53744b82b77SMark Rutland 		seq_printf(m, "CPU architecture: 8\n");
53844b82b77SMark Rutland 		seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
53944b82b77SMark Rutland 		seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
54044b82b77SMark Rutland 		seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
54144b82b77SMark Rutland 	}
5425e39977eSWill Deacon 
5439703d9d7SCatalin Marinas 	return 0;
5449703d9d7SCatalin Marinas }
5459703d9d7SCatalin Marinas 
5469703d9d7SCatalin Marinas static void *c_start(struct seq_file *m, loff_t *pos)
5479703d9d7SCatalin Marinas {
5489703d9d7SCatalin Marinas 	return *pos < 1 ? (void *)1 : NULL;
5499703d9d7SCatalin Marinas }
5509703d9d7SCatalin Marinas 
5519703d9d7SCatalin Marinas static void *c_next(struct seq_file *m, void *v, loff_t *pos)
5529703d9d7SCatalin Marinas {
5539703d9d7SCatalin Marinas 	++*pos;
5549703d9d7SCatalin Marinas 	return NULL;
5559703d9d7SCatalin Marinas }
5569703d9d7SCatalin Marinas 
5579703d9d7SCatalin Marinas static void c_stop(struct seq_file *m, void *v)
5589703d9d7SCatalin Marinas {
5599703d9d7SCatalin Marinas }
5609703d9d7SCatalin Marinas 
5619703d9d7SCatalin Marinas const struct seq_operations cpuinfo_op = {
5629703d9d7SCatalin Marinas 	.start	= c_start,
5639703d9d7SCatalin Marinas 	.next	= c_next,
5649703d9d7SCatalin Marinas 	.stop	= c_stop,
5659703d9d7SCatalin Marinas 	.show	= c_show
5669703d9d7SCatalin Marinas };
567