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> 289703d9d7SCatalin Marinas #include <linux/bootmem.h> 299703d9d7SCatalin Marinas #include <linux/seq_file.h> 309703d9d7SCatalin Marinas #include <linux/screen_info.h> 319703d9d7SCatalin Marinas #include <linux/init.h> 329703d9d7SCatalin Marinas #include <linux/kexec.h> 339703d9d7SCatalin Marinas #include <linux/crash_dump.h> 349703d9d7SCatalin Marinas #include <linux/root_dev.h> 359703d9d7SCatalin Marinas #include <linux/cpu.h> 369703d9d7SCatalin Marinas #include <linux/interrupt.h> 379703d9d7SCatalin Marinas #include <linux/smp.h> 389703d9d7SCatalin Marinas #include <linux/fs.h> 399703d9d7SCatalin Marinas #include <linux/proc_fs.h> 409703d9d7SCatalin Marinas #include <linux/memblock.h> 419703d9d7SCatalin Marinas #include <linux/of_fdt.h> 42d6bafb9bSCatalin Marinas #include <linux/of_platform.h> 439703d9d7SCatalin Marinas 449703d9d7SCatalin Marinas #include <asm/cputype.h> 459703d9d7SCatalin Marinas #include <asm/elf.h> 469703d9d7SCatalin Marinas #include <asm/cputable.h> 479703d9d7SCatalin Marinas #include <asm/sections.h> 489703d9d7SCatalin Marinas #include <asm/setup.h> 499703d9d7SCatalin Marinas #include <asm/cacheflush.h> 509703d9d7SCatalin Marinas #include <asm/tlbflush.h> 519703d9d7SCatalin Marinas #include <asm/traps.h> 529703d9d7SCatalin Marinas #include <asm/memblock.h> 539703d9d7SCatalin Marinas 549703d9d7SCatalin Marinas unsigned int processor_id; 559703d9d7SCatalin Marinas EXPORT_SYMBOL(processor_id); 569703d9d7SCatalin Marinas 579703d9d7SCatalin Marinas unsigned int elf_hwcap __read_mostly; 589703d9d7SCatalin Marinas EXPORT_SYMBOL_GPL(elf_hwcap); 599703d9d7SCatalin Marinas 609703d9d7SCatalin Marinas static const char *cpu_name; 619703d9d7SCatalin Marinas static const char *machine_name; 629703d9d7SCatalin Marinas phys_addr_t __fdt_pointer __initdata; 639703d9d7SCatalin Marinas 649703d9d7SCatalin Marinas /* 659703d9d7SCatalin Marinas * Standard memory resources 669703d9d7SCatalin Marinas */ 679703d9d7SCatalin Marinas static struct resource mem_res[] = { 689703d9d7SCatalin Marinas { 699703d9d7SCatalin Marinas .name = "Kernel code", 709703d9d7SCatalin Marinas .start = 0, 719703d9d7SCatalin Marinas .end = 0, 729703d9d7SCatalin Marinas .flags = IORESOURCE_MEM 739703d9d7SCatalin Marinas }, 749703d9d7SCatalin Marinas { 759703d9d7SCatalin Marinas .name = "Kernel data", 769703d9d7SCatalin Marinas .start = 0, 779703d9d7SCatalin Marinas .end = 0, 789703d9d7SCatalin Marinas .flags = IORESOURCE_MEM 799703d9d7SCatalin Marinas } 809703d9d7SCatalin Marinas }; 819703d9d7SCatalin Marinas 829703d9d7SCatalin Marinas #define kernel_code mem_res[0] 839703d9d7SCatalin Marinas #define kernel_data mem_res[1] 849703d9d7SCatalin Marinas 859703d9d7SCatalin Marinas void __init early_print(const char *str, ...) 869703d9d7SCatalin Marinas { 879703d9d7SCatalin Marinas char buf[256]; 889703d9d7SCatalin Marinas va_list ap; 899703d9d7SCatalin Marinas 909703d9d7SCatalin Marinas va_start(ap, str); 919703d9d7SCatalin Marinas vsnprintf(buf, sizeof(buf), str, ap); 929703d9d7SCatalin Marinas va_end(ap); 939703d9d7SCatalin Marinas 949703d9d7SCatalin Marinas printk("%s", buf); 959703d9d7SCatalin Marinas } 969703d9d7SCatalin Marinas 979703d9d7SCatalin Marinas static void __init setup_processor(void) 989703d9d7SCatalin Marinas { 999703d9d7SCatalin Marinas struct cpu_info *cpu_info; 1009703d9d7SCatalin Marinas 1019703d9d7SCatalin Marinas /* 1029703d9d7SCatalin Marinas * locate processor in the list of supported processor 1039703d9d7SCatalin Marinas * types. The linker builds this table for us from the 1049703d9d7SCatalin Marinas * entries in arch/arm/mm/proc.S 1059703d9d7SCatalin Marinas */ 1069703d9d7SCatalin Marinas cpu_info = lookup_processor_type(read_cpuid_id()); 1079703d9d7SCatalin Marinas if (!cpu_info) { 1089703d9d7SCatalin Marinas printk("CPU configuration botched (ID %08x), unable to continue.\n", 1099703d9d7SCatalin Marinas read_cpuid_id()); 1109703d9d7SCatalin Marinas while (1); 1119703d9d7SCatalin Marinas } 1129703d9d7SCatalin Marinas 1139703d9d7SCatalin Marinas cpu_name = cpu_info->cpu_name; 1149703d9d7SCatalin Marinas 1159703d9d7SCatalin Marinas printk("CPU: %s [%08x] revision %d\n", 1169703d9d7SCatalin Marinas cpu_name, read_cpuid_id(), read_cpuid_id() & 15); 1179703d9d7SCatalin Marinas 1189703d9d7SCatalin Marinas sprintf(init_utsname()->machine, "aarch64"); 1199703d9d7SCatalin Marinas elf_hwcap = 0; 1209703d9d7SCatalin Marinas } 1219703d9d7SCatalin Marinas 1229703d9d7SCatalin Marinas static void __init setup_machine_fdt(phys_addr_t dt_phys) 1239703d9d7SCatalin Marinas { 1249703d9d7SCatalin Marinas struct boot_param_header *devtree; 1259703d9d7SCatalin Marinas unsigned long dt_root; 1269703d9d7SCatalin Marinas 1279703d9d7SCatalin Marinas /* Check we have a non-NULL DT pointer */ 1289703d9d7SCatalin Marinas if (!dt_phys) { 1299703d9d7SCatalin Marinas early_print("\n" 1309703d9d7SCatalin Marinas "Error: NULL or invalid device tree blob\n" 1319703d9d7SCatalin Marinas "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n" 1329703d9d7SCatalin Marinas "\nPlease check your bootloader.\n"); 1339703d9d7SCatalin Marinas 1349703d9d7SCatalin Marinas while (true) 1359703d9d7SCatalin Marinas cpu_relax(); 1369703d9d7SCatalin Marinas 1379703d9d7SCatalin Marinas } 1389703d9d7SCatalin Marinas 1399703d9d7SCatalin Marinas devtree = phys_to_virt(dt_phys); 1409703d9d7SCatalin Marinas 1419703d9d7SCatalin Marinas /* Check device tree validity */ 1429703d9d7SCatalin Marinas if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) { 1439703d9d7SCatalin Marinas early_print("\n" 1449703d9d7SCatalin Marinas "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" 1459703d9d7SCatalin Marinas "Expected 0x%x, found 0x%x\n" 1469703d9d7SCatalin Marinas "\nPlease check your bootloader.\n", 1479703d9d7SCatalin Marinas dt_phys, devtree, OF_DT_HEADER, 1489703d9d7SCatalin Marinas be32_to_cpu(devtree->magic)); 1499703d9d7SCatalin Marinas 1509703d9d7SCatalin Marinas while (true) 1519703d9d7SCatalin Marinas cpu_relax(); 1529703d9d7SCatalin Marinas } 1539703d9d7SCatalin Marinas 1549703d9d7SCatalin Marinas initial_boot_params = devtree; 1559703d9d7SCatalin Marinas dt_root = of_get_flat_dt_root(); 1569703d9d7SCatalin Marinas 1579703d9d7SCatalin Marinas machine_name = of_get_flat_dt_prop(dt_root, "model", NULL); 1589703d9d7SCatalin Marinas if (!machine_name) 1599703d9d7SCatalin Marinas machine_name = of_get_flat_dt_prop(dt_root, "compatible", NULL); 1609703d9d7SCatalin Marinas if (!machine_name) 1619703d9d7SCatalin Marinas machine_name = "<unknown>"; 1629703d9d7SCatalin Marinas pr_info("Machine: %s\n", machine_name); 1639703d9d7SCatalin Marinas 1649703d9d7SCatalin Marinas /* Retrieve various information from the /chosen node */ 1659703d9d7SCatalin Marinas of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); 1669703d9d7SCatalin Marinas /* Initialize {size,address}-cells info */ 1679703d9d7SCatalin Marinas of_scan_flat_dt(early_init_dt_scan_root, NULL); 1689703d9d7SCatalin Marinas /* Setup memory, calling early_init_dt_add_memory_arch */ 1699703d9d7SCatalin Marinas of_scan_flat_dt(early_init_dt_scan_memory, NULL); 1709703d9d7SCatalin Marinas } 1719703d9d7SCatalin Marinas 1729703d9d7SCatalin Marinas void __init early_init_dt_add_memory_arch(u64 base, u64 size) 1739703d9d7SCatalin Marinas { 174f71a1a42SCatalin Marinas base &= PAGE_MASK; 1759703d9d7SCatalin Marinas size &= PAGE_MASK; 176f71a1a42SCatalin Marinas if (base + size < PHYS_OFFSET) { 177f71a1a42SCatalin Marinas pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 178f71a1a42SCatalin Marinas base, base + size); 179f71a1a42SCatalin Marinas return; 180f71a1a42SCatalin Marinas } 181f71a1a42SCatalin Marinas if (base < PHYS_OFFSET) { 182f71a1a42SCatalin Marinas pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 183f71a1a42SCatalin Marinas base, PHYS_OFFSET); 184f71a1a42SCatalin Marinas size -= PHYS_OFFSET - base; 185f71a1a42SCatalin Marinas base = PHYS_OFFSET; 186f71a1a42SCatalin Marinas } 1879703d9d7SCatalin Marinas memblock_add(base, size); 1889703d9d7SCatalin Marinas } 1899703d9d7SCatalin Marinas 1909703d9d7SCatalin Marinas void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) 1919703d9d7SCatalin Marinas { 1929703d9d7SCatalin Marinas return __va(memblock_alloc(size, align)); 1939703d9d7SCatalin Marinas } 1949703d9d7SCatalin Marinas 1959703d9d7SCatalin Marinas /* 1969703d9d7SCatalin Marinas * Limit the memory size that was specified via FDT. 1979703d9d7SCatalin Marinas */ 1989703d9d7SCatalin Marinas static int __init early_mem(char *p) 1999703d9d7SCatalin Marinas { 2009703d9d7SCatalin Marinas phys_addr_t limit; 2019703d9d7SCatalin Marinas 2029703d9d7SCatalin Marinas if (!p) 2039703d9d7SCatalin Marinas return 1; 2049703d9d7SCatalin Marinas 2059703d9d7SCatalin Marinas limit = memparse(p, &p) & PAGE_MASK; 2069703d9d7SCatalin Marinas pr_notice("Memory limited to %lldMB\n", limit >> 20); 2079703d9d7SCatalin Marinas 2089703d9d7SCatalin Marinas memblock_enforce_memory_limit(limit); 2099703d9d7SCatalin Marinas 2109703d9d7SCatalin Marinas return 0; 2119703d9d7SCatalin Marinas } 2129703d9d7SCatalin Marinas early_param("mem", early_mem); 2139703d9d7SCatalin Marinas 2149703d9d7SCatalin Marinas static void __init request_standard_resources(void) 2159703d9d7SCatalin Marinas { 2169703d9d7SCatalin Marinas struct memblock_region *region; 2179703d9d7SCatalin Marinas struct resource *res; 2189703d9d7SCatalin Marinas 2199703d9d7SCatalin Marinas kernel_code.start = virt_to_phys(_text); 2209703d9d7SCatalin Marinas kernel_code.end = virt_to_phys(_etext - 1); 2219703d9d7SCatalin Marinas kernel_data.start = virt_to_phys(_sdata); 2229703d9d7SCatalin Marinas kernel_data.end = virt_to_phys(_end - 1); 2239703d9d7SCatalin Marinas 2249703d9d7SCatalin Marinas for_each_memblock(memory, region) { 2259703d9d7SCatalin Marinas res = alloc_bootmem_low(sizeof(*res)); 2269703d9d7SCatalin Marinas res->name = "System RAM"; 2279703d9d7SCatalin Marinas res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 2289703d9d7SCatalin Marinas res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 2299703d9d7SCatalin Marinas res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 2309703d9d7SCatalin Marinas 2319703d9d7SCatalin Marinas request_resource(&iomem_resource, res); 2329703d9d7SCatalin Marinas 2339703d9d7SCatalin Marinas if (kernel_code.start >= res->start && 2349703d9d7SCatalin Marinas kernel_code.end <= res->end) 2359703d9d7SCatalin Marinas request_resource(res, &kernel_code); 2369703d9d7SCatalin Marinas if (kernel_data.start >= res->start && 2379703d9d7SCatalin Marinas kernel_data.end <= res->end) 2389703d9d7SCatalin Marinas request_resource(res, &kernel_data); 2399703d9d7SCatalin Marinas } 2409703d9d7SCatalin Marinas } 2419703d9d7SCatalin Marinas 2429703d9d7SCatalin Marinas void __init setup_arch(char **cmdline_p) 2439703d9d7SCatalin Marinas { 2449703d9d7SCatalin Marinas setup_processor(); 2459703d9d7SCatalin Marinas 2469703d9d7SCatalin Marinas setup_machine_fdt(__fdt_pointer); 2479703d9d7SCatalin Marinas 2489703d9d7SCatalin Marinas init_mm.start_code = (unsigned long) _text; 2499703d9d7SCatalin Marinas init_mm.end_code = (unsigned long) _etext; 2509703d9d7SCatalin Marinas init_mm.end_data = (unsigned long) _edata; 2519703d9d7SCatalin Marinas init_mm.brk = (unsigned long) _end; 2529703d9d7SCatalin Marinas 2539703d9d7SCatalin Marinas *cmdline_p = boot_command_line; 2549703d9d7SCatalin Marinas 2559703d9d7SCatalin Marinas parse_early_param(); 2569703d9d7SCatalin Marinas 2579703d9d7SCatalin Marinas arm64_memblock_init(); 2589703d9d7SCatalin Marinas 2599703d9d7SCatalin Marinas paging_init(); 2609703d9d7SCatalin Marinas request_standard_resources(); 2619703d9d7SCatalin Marinas 2629703d9d7SCatalin Marinas unflatten_device_tree(); 2639703d9d7SCatalin Marinas 2649703d9d7SCatalin Marinas #ifdef CONFIG_SMP 2659703d9d7SCatalin Marinas smp_init_cpus(); 2669703d9d7SCatalin Marinas #endif 2679703d9d7SCatalin Marinas 2689703d9d7SCatalin Marinas #ifdef CONFIG_VT 2699703d9d7SCatalin Marinas #if defined(CONFIG_VGA_CONSOLE) 2709703d9d7SCatalin Marinas conswitchp = &vga_con; 2719703d9d7SCatalin Marinas #elif defined(CONFIG_DUMMY_CONSOLE) 2729703d9d7SCatalin Marinas conswitchp = &dummy_con; 2739703d9d7SCatalin Marinas #endif 2749703d9d7SCatalin Marinas #endif 2759703d9d7SCatalin Marinas } 2769703d9d7SCatalin Marinas 2779703d9d7SCatalin Marinas static DEFINE_PER_CPU(struct cpu, cpu_data); 2789703d9d7SCatalin Marinas 2799703d9d7SCatalin Marinas static int __init topology_init(void) 2809703d9d7SCatalin Marinas { 2819703d9d7SCatalin Marinas int i; 2829703d9d7SCatalin Marinas 2839703d9d7SCatalin Marinas for_each_possible_cpu(i) { 2849703d9d7SCatalin Marinas struct cpu *cpu = &per_cpu(cpu_data, i); 2859703d9d7SCatalin Marinas cpu->hotpluggable = 1; 2869703d9d7SCatalin Marinas register_cpu(cpu, i); 2879703d9d7SCatalin Marinas } 2889703d9d7SCatalin Marinas 2899703d9d7SCatalin Marinas return 0; 2909703d9d7SCatalin Marinas } 2919703d9d7SCatalin Marinas subsys_initcall(topology_init); 2929703d9d7SCatalin Marinas 293d6bafb9bSCatalin Marinas static int __init arm64_device_probe(void) 294d6bafb9bSCatalin Marinas { 295d6bafb9bSCatalin Marinas of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 296d6bafb9bSCatalin Marinas return 0; 297d6bafb9bSCatalin Marinas } 298d6bafb9bSCatalin Marinas device_initcall(arm64_device_probe); 299d6bafb9bSCatalin Marinas 3009703d9d7SCatalin Marinas static const char *hwcap_str[] = { 3019703d9d7SCatalin Marinas "fp", 3029703d9d7SCatalin Marinas "asimd", 3039703d9d7SCatalin Marinas NULL 3049703d9d7SCatalin Marinas }; 3059703d9d7SCatalin Marinas 3069703d9d7SCatalin Marinas static int c_show(struct seq_file *m, void *v) 3079703d9d7SCatalin Marinas { 3089703d9d7SCatalin Marinas int i; 3099703d9d7SCatalin Marinas 3109703d9d7SCatalin Marinas seq_printf(m, "Processor\t: %s rev %d (%s)\n", 3119703d9d7SCatalin Marinas cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); 3129703d9d7SCatalin Marinas 3139703d9d7SCatalin Marinas for_each_online_cpu(i) { 3149703d9d7SCatalin Marinas /* 3159703d9d7SCatalin Marinas * glibc reads /proc/cpuinfo to determine the number of 3169703d9d7SCatalin Marinas * online processors, looking for lines beginning with 3179703d9d7SCatalin Marinas * "processor". Give glibc what it expects. 3189703d9d7SCatalin Marinas */ 3199703d9d7SCatalin Marinas #ifdef CONFIG_SMP 3209703d9d7SCatalin Marinas seq_printf(m, "processor\t: %d\n", i); 3219703d9d7SCatalin Marinas #endif 3229703d9d7SCatalin Marinas seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 3239703d9d7SCatalin Marinas loops_per_jiffy / (500000UL/HZ), 3249703d9d7SCatalin Marinas loops_per_jiffy / (5000UL/HZ) % 100); 3259703d9d7SCatalin Marinas } 3269703d9d7SCatalin Marinas 3279703d9d7SCatalin Marinas /* dump out the processor features */ 3289703d9d7SCatalin Marinas seq_puts(m, "Features\t: "); 3299703d9d7SCatalin Marinas 3309703d9d7SCatalin Marinas for (i = 0; hwcap_str[i]; i++) 3319703d9d7SCatalin Marinas if (elf_hwcap & (1 << i)) 3329703d9d7SCatalin Marinas seq_printf(m, "%s ", hwcap_str[i]); 3339703d9d7SCatalin Marinas 3349703d9d7SCatalin Marinas seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 3359703d9d7SCatalin Marinas seq_printf(m, "CPU architecture: AArch64\n"); 3369703d9d7SCatalin Marinas seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15); 3379703d9d7SCatalin Marinas seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff); 3389703d9d7SCatalin Marinas seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 3399703d9d7SCatalin Marinas 3409703d9d7SCatalin Marinas seq_puts(m, "\n"); 3419703d9d7SCatalin Marinas 3429703d9d7SCatalin Marinas seq_printf(m, "Hardware\t: %s\n", machine_name); 3439703d9d7SCatalin Marinas 3449703d9d7SCatalin Marinas return 0; 3459703d9d7SCatalin Marinas } 3469703d9d7SCatalin Marinas 3479703d9d7SCatalin Marinas static void *c_start(struct seq_file *m, loff_t *pos) 3489703d9d7SCatalin Marinas { 3499703d9d7SCatalin Marinas return *pos < 1 ? (void *)1 : NULL; 3509703d9d7SCatalin Marinas } 3519703d9d7SCatalin Marinas 3529703d9d7SCatalin Marinas static void *c_next(struct seq_file *m, void *v, loff_t *pos) 3539703d9d7SCatalin Marinas { 3549703d9d7SCatalin Marinas ++*pos; 3559703d9d7SCatalin Marinas return NULL; 3569703d9d7SCatalin Marinas } 3579703d9d7SCatalin Marinas 3589703d9d7SCatalin Marinas static void c_stop(struct seq_file *m, void *v) 3599703d9d7SCatalin Marinas { 3609703d9d7SCatalin Marinas } 3619703d9d7SCatalin Marinas 3629703d9d7SCatalin Marinas const struct seq_operations cpuinfo_op = { 3639703d9d7SCatalin Marinas .start = c_start, 3649703d9d7SCatalin Marinas .next = c_next, 3659703d9d7SCatalin Marinas .stop = c_stop, 3669703d9d7SCatalin Marinas .show = c_show 3679703d9d7SCatalin Marinas }; 368