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 */ 10ecea4ab6SPaul Gortmaker #include <linux/export.h> 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/stddef.h> 131da177e4SLinus Torvalds #include <linux/ioport.h> 141da177e4SLinus Torvalds #include <linux/delay.h> 151da177e4SLinus Torvalds #include <linux/utsname.h> 161da177e4SLinus Torvalds #include <linux/initrd.h> 171da177e4SLinus Torvalds #include <linux/console.h> 181da177e4SLinus Torvalds #include <linux/bootmem.h> 191da177e4SLinus Torvalds #include <linux/seq_file.h> 20894673eeSJon Smirl #include <linux/screen_info.h> 211da177e4SLinus Torvalds #include <linux/init.h> 223c57fb43SMika Westerberg #include <linux/kexec.h> 2393c02ab4SGrant Likely #include <linux/of_fdt.h> 241da177e4SLinus Torvalds #include <linux/root_dev.h> 251da177e4SLinus Torvalds #include <linux/cpu.h> 261da177e4SLinus Torvalds #include <linux/interrupt.h> 277bbb7940SRussell King #include <linux/smp.h> 284e950f6fSAlexey Dobriyan #include <linux/fs.h> 29e119bfffSRussell King #include <linux/proc_fs.h> 302778f620SRussell King #include <linux/memblock.h> 312ecccf90SDave Martin #include <linux/bug.h> 322ecccf90SDave Martin #include <linux/compiler.h> 3327a3f0e9SNicolas Pitre #include <linux/sort.h> 341da177e4SLinus Torvalds 35b86040a5SCatalin Marinas #include <asm/unified.h> 361da177e4SLinus Torvalds #include <asm/cpu.h> 370ba8b9b2SRussell King #include <asm/cputype.h> 381da177e4SLinus Torvalds #include <asm/elf.h> 391da177e4SLinus Torvalds #include <asm/procinfo.h> 4037efe642SRussell King #include <asm/sections.h> 411da177e4SLinus Torvalds #include <asm/setup.h> 42f00ec48fSRussell King #include <asm/smp_plat.h> 431da177e4SLinus Torvalds #include <asm/mach-types.h> 441da177e4SLinus Torvalds #include <asm/cacheflush.h> 4546097c7dSRussell King #include <asm/cachetype.h> 461da177e4SLinus Torvalds #include <asm/tlbflush.h> 472ecccf90SDave Martin #include <asm/system.h> 481da177e4SLinus Torvalds 4993c02ab4SGrant Likely #include <asm/prom.h> 501da177e4SLinus Torvalds #include <asm/mach/arch.h> 511da177e4SLinus Torvalds #include <asm/mach/irq.h> 521da177e4SLinus Torvalds #include <asm/mach/time.h> 535cbad0ebSJason Wessel #include <asm/traps.h> 54bff595c1SCatalin Marinas #include <asm/unwind.h> 551c16d242STejun Heo #include <asm/memblock.h> 561da177e4SLinus Torvalds 5773a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 580fc1c832SBen Dooks #include "compat.h" 5973a65b3fSUwe Kleine-König #endif 604cd9d6f7SRichard Purdie #include "atags.h" 61bc581770SLinus Walleij #include "tcm.h" 620fc1c832SBen Dooks 631da177e4SLinus Torvalds #ifndef MEM_SIZE 641da177e4SLinus Torvalds #define MEM_SIZE (16*1024*1024) 651da177e4SLinus Torvalds #endif 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) 681da177e4SLinus Torvalds char fpe_type[8]; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds static int __init fpe_setup(char *line) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds memcpy(fpe_type, line, 8); 731da177e4SLinus Torvalds return 1; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds __setup("fpe=", fpe_setup); 771da177e4SLinus Torvalds #endif 781da177e4SLinus Torvalds 794b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc); 800371d3f7SRussell King extern void sanity_check_meminfo(void); 811da177e4SLinus Torvalds extern void reboot_setup(char *str); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds unsigned int processor_id; 84c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id); 850385ebc0SRussell King unsigned int __machine_arch_type __read_mostly; 861da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type); 870385ebc0SRussell King unsigned int cacheid __read_mostly; 88c0e95878SRussell King EXPORT_SYMBOL(cacheid); 891da177e4SLinus Torvalds 909d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata; 919d20fdd5SBill Gatliff 921da177e4SLinus Torvalds unsigned int system_rev; 931da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds unsigned int system_serial_low; 961da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds unsigned int system_serial_high; 991da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high); 1001da177e4SLinus Torvalds 1010385ebc0SRussell King unsigned int elf_hwcap __read_mostly; 1021da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap); 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds #ifdef MULTI_CPU 1060385ebc0SRussell King struct processor processor __read_mostly; 1071da177e4SLinus Torvalds #endif 1081da177e4SLinus Torvalds #ifdef MULTI_TLB 1090385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly; 1101da177e4SLinus Torvalds #endif 1111da177e4SLinus Torvalds #ifdef MULTI_USER 1120385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly; 1131da177e4SLinus Torvalds #endif 1141da177e4SLinus Torvalds #ifdef MULTI_CACHE 1150385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly; 1161da177e4SLinus Torvalds #endif 117953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE 1180385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly; 1196c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache); 120953233dcSCatalin Marinas #endif 1211da177e4SLinus Torvalds 1222ecccf90SDave Martin /* 1232ecccf90SDave Martin * Cached cpu_architecture() result for use by assembler code. 1242ecccf90SDave Martin * C code should use the cpu_architecture() function instead of accessing this 1252ecccf90SDave Martin * variable directly. 1262ecccf90SDave Martin */ 1272ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; 1282ecccf90SDave Martin 129ccea7a19SRussell King struct stack { 130ccea7a19SRussell King u32 irq[3]; 131ccea7a19SRussell King u32 abt[3]; 132ccea7a19SRussell King u32 und[3]; 133ccea7a19SRussell King } ____cacheline_aligned; 134ccea7a19SRussell King 135ccea7a19SRussell King static struct stack stacks[NR_CPUS]; 136ccea7a19SRussell King 1371da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE]; 1381da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform); 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds static const char *cpu_name; 1411da177e4SLinus Torvalds static const char *machine_name; 14248ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE]; 1438ff1443cSRussell King struct machine_desc *machine_desc __initdata; 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; 1461da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; 1471da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l) 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* 1521da177e4SLinus Torvalds * Standard memory resources 1531da177e4SLinus Torvalds */ 1541da177e4SLinus Torvalds static struct resource mem_res[] = { 155740e518eSGreg Kroah-Hartman { 156740e518eSGreg Kroah-Hartman .name = "Video RAM", 157740e518eSGreg Kroah-Hartman .start = 0, 158740e518eSGreg Kroah-Hartman .end = 0, 159740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 160740e518eSGreg Kroah-Hartman }, 161740e518eSGreg Kroah-Hartman { 162a36d8e5bSKees Cook .name = "Kernel code", 163740e518eSGreg Kroah-Hartman .start = 0, 164740e518eSGreg Kroah-Hartman .end = 0, 165740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 166740e518eSGreg Kroah-Hartman }, 167740e518eSGreg Kroah-Hartman { 168740e518eSGreg Kroah-Hartman .name = "Kernel data", 169740e518eSGreg Kroah-Hartman .start = 0, 170740e518eSGreg Kroah-Hartman .end = 0, 171740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 172740e518eSGreg Kroah-Hartman } 1731da177e4SLinus Torvalds }; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds #define video_ram mem_res[0] 1761da177e4SLinus Torvalds #define kernel_code mem_res[1] 1771da177e4SLinus Torvalds #define kernel_data mem_res[2] 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds static struct resource io_res[] = { 180740e518eSGreg Kroah-Hartman { 181740e518eSGreg Kroah-Hartman .name = "reserved", 182740e518eSGreg Kroah-Hartman .start = 0x3bc, 183740e518eSGreg Kroah-Hartman .end = 0x3be, 184740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 185740e518eSGreg Kroah-Hartman }, 186740e518eSGreg Kroah-Hartman { 187740e518eSGreg Kroah-Hartman .name = "reserved", 188740e518eSGreg Kroah-Hartman .start = 0x378, 189740e518eSGreg Kroah-Hartman .end = 0x37f, 190740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 191740e518eSGreg Kroah-Hartman }, 192740e518eSGreg Kroah-Hartman { 193740e518eSGreg Kroah-Hartman .name = "reserved", 194740e518eSGreg Kroah-Hartman .start = 0x278, 195740e518eSGreg Kroah-Hartman .end = 0x27f, 196740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 197740e518eSGreg Kroah-Hartman } 1981da177e4SLinus Torvalds }; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds #define lp0 io_res[0] 2011da177e4SLinus Torvalds #define lp1 io_res[1] 2021da177e4SLinus Torvalds #define lp2 io_res[2] 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds static const char *proc_arch[] = { 2051da177e4SLinus Torvalds "undefined/unknown", 2061da177e4SLinus Torvalds "3", 2071da177e4SLinus Torvalds "4", 2081da177e4SLinus Torvalds "4T", 2091da177e4SLinus Torvalds "5", 2101da177e4SLinus Torvalds "5T", 2111da177e4SLinus Torvalds "5TE", 2121da177e4SLinus Torvalds "5TEJ", 2131da177e4SLinus Torvalds "6TEJ", 2146b090a25SCatalin Marinas "7", 2151da177e4SLinus Torvalds "?(11)", 2161da177e4SLinus Torvalds "?(12)", 2171da177e4SLinus Torvalds "?(13)", 2181da177e4SLinus Torvalds "?(14)", 2191da177e4SLinus Torvalds "?(15)", 2201da177e4SLinus Torvalds "?(16)", 2211da177e4SLinus Torvalds "?(17)", 2221da177e4SLinus Torvalds }; 2231da177e4SLinus Torvalds 2242ecccf90SDave Martin static int __get_cpu_architecture(void) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds int cpu_arch; 2271da177e4SLinus Torvalds 2280ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0) { 2291da177e4SLinus Torvalds cpu_arch = CPU_ARCH_UNKNOWN; 2300ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 2310ba8b9b2SRussell King cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; 2320ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { 2330ba8b9b2SRussell King cpu_arch = (read_cpuid_id() >> 16) & 7; 2341da177e4SLinus Torvalds if (cpu_arch) 2351da177e4SLinus Torvalds cpu_arch += CPU_ARCH_ARMv3; 2360ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 237180005c4SCatalin Marinas unsigned int mmfr0; 238180005c4SCatalin Marinas 239180005c4SCatalin Marinas /* Revised CPUID format. Read the Memory Model Feature 240180005c4SCatalin Marinas * Register 0 and check for VMSAv7 or PMSAv7 */ 241180005c4SCatalin Marinas asm("mrc p15, 0, %0, c0, c1, 4" 242180005c4SCatalin Marinas : "=r" (mmfr0)); 243315cfe78SCatalin Marinas if ((mmfr0 & 0x0000000f) >= 0x00000003 || 244315cfe78SCatalin Marinas (mmfr0 & 0x000000f0) >= 0x00000030) 245180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv7; 246180005c4SCatalin Marinas else if ((mmfr0 & 0x0000000f) == 0x00000002 || 247180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000020) 248180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv6; 249180005c4SCatalin Marinas else 250180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 251180005c4SCatalin Marinas } else 252180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds return cpu_arch; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2572ecccf90SDave Martin int __pure cpu_architecture(void) 2582ecccf90SDave Martin { 2592ecccf90SDave Martin BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN); 2602ecccf90SDave Martin 2612ecccf90SDave Martin return __cpu_architecture; 2622ecccf90SDave Martin } 2632ecccf90SDave Martin 2648925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch) 2658925ec4cSWill Deacon { 2668925ec4cSWill Deacon int aliasing_icache; 2678925ec4cSWill Deacon unsigned int id_reg, num_sets, line_size; 2688925ec4cSWill Deacon 2697f94e9ccSWill Deacon /* PIPT caches never alias. */ 2707f94e9ccSWill Deacon if (icache_is_pipt()) 2717f94e9ccSWill Deacon return 0; 2727f94e9ccSWill Deacon 2738925ec4cSWill Deacon /* arch specifies the register format */ 2748925ec4cSWill Deacon switch (arch) { 2758925ec4cSWill Deacon case CPU_ARCH_ARMv7: 2765fb31a96SLinus Walleij asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR" 2775fb31a96SLinus Walleij : /* No output operands */ 2788925ec4cSWill Deacon : "r" (1)); 2795fb31a96SLinus Walleij isb(); 2805fb31a96SLinus Walleij asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" 2815fb31a96SLinus Walleij : "=r" (id_reg)); 2828925ec4cSWill Deacon line_size = 4 << ((id_reg & 0x7) + 2); 2838925ec4cSWill Deacon num_sets = ((id_reg >> 13) & 0x7fff) + 1; 2848925ec4cSWill Deacon aliasing_icache = (line_size * num_sets) > PAGE_SIZE; 2858925ec4cSWill Deacon break; 2868925ec4cSWill Deacon case CPU_ARCH_ARMv6: 2878925ec4cSWill Deacon aliasing_icache = read_cpuid_cachetype() & (1 << 11); 2888925ec4cSWill Deacon break; 2898925ec4cSWill Deacon default: 2908925ec4cSWill Deacon /* I-cache aliases will be handled by D-cache aliasing code */ 2918925ec4cSWill Deacon aliasing_icache = 0; 2928925ec4cSWill Deacon } 2938925ec4cSWill Deacon 2948925ec4cSWill Deacon return aliasing_icache; 2958925ec4cSWill Deacon } 2968925ec4cSWill Deacon 297c0e95878SRussell King static void __init cacheid_init(void) 298c0e95878SRussell King { 299c0e95878SRussell King unsigned int cachetype = read_cpuid_cachetype(); 300c0e95878SRussell King unsigned int arch = cpu_architecture(); 301c0e95878SRussell King 302b57ee99fSCatalin Marinas if (arch >= CPU_ARCH_ARMv6) { 303b57ee99fSCatalin Marinas if ((cachetype & (7 << 29)) == 4 << 29) { 304b57ee99fSCatalin Marinas /* ARMv7 register format */ 30572dc53acSWill Deacon arch = CPU_ARCH_ARMv7; 306c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 3077f94e9ccSWill Deacon switch (cachetype & (3 << 14)) { 3087f94e9ccSWill Deacon case (1 << 14): 309c0e95878SRussell King cacheid |= CACHEID_ASID_TAGGED; 3107f94e9ccSWill Deacon break; 3117f94e9ccSWill Deacon case (3 << 14): 3127f94e9ccSWill Deacon cacheid |= CACHEID_PIPT; 3137f94e9ccSWill Deacon break; 3147f94e9ccSWill Deacon } 3158925ec4cSWill Deacon } else { 31672dc53acSWill Deacon arch = CPU_ARCH_ARMv6; 31772dc53acSWill Deacon if (cachetype & (1 << 23)) 31872dc53acSWill Deacon cacheid = CACHEID_VIPT_ALIASING; 31972dc53acSWill Deacon else 320c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 3218925ec4cSWill Deacon } 32272dc53acSWill Deacon if (cpu_has_aliasing_icache(arch)) 32372dc53acSWill Deacon cacheid |= CACHEID_VIPT_I_ALIASING; 324c0e95878SRussell King } else { 325c0e95878SRussell King cacheid = CACHEID_VIVT; 326c0e95878SRussell King } 3272b4ae1f1SRussell King 3282b4ae1f1SRussell King printk("CPU: %s data cache, %s instruction cache\n", 3292b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 3302b4ae1f1SRussell King cache_is_vipt_aliasing() ? "VIPT aliasing" : 3317f94e9ccSWill Deacon cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown", 3322b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 3332b4ae1f1SRussell King icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : 3348925ec4cSWill Deacon icache_is_vipt_aliasing() ? "VIPT aliasing" : 3357f94e9ccSWill Deacon icache_is_pipt() ? "PIPT" : 3362b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); 337c0e95878SRussell King } 338c0e95878SRussell King 3391da177e4SLinus Torvalds /* 3401da177e4SLinus Torvalds * These functions re-use the assembly code in head.S, which 3411da177e4SLinus Torvalds * already provide the required functionality. 3421da177e4SLinus Torvalds */ 3430f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int); 3446fc31d54SRussell King 34593c02ab4SGrant Likely void __init early_print(const char *str, ...) 3466fc31d54SRussell King { 3476fc31d54SRussell King extern void printascii(const char *); 3486fc31d54SRussell King char buf[256]; 3496fc31d54SRussell King va_list ap; 3506fc31d54SRussell King 3516fc31d54SRussell King va_start(ap, str); 3526fc31d54SRussell King vsnprintf(buf, sizeof(buf), str, ap); 3536fc31d54SRussell King va_end(ap); 3546fc31d54SRussell King 3556fc31d54SRussell King #ifdef CONFIG_DEBUG_LL 3566fc31d54SRussell King printascii(buf); 3576fc31d54SRussell King #endif 3586fc31d54SRussell King printk("%s", buf); 3596fc31d54SRussell King } 3606fc31d54SRussell King 361f159f4edSTony Lindgren static void __init feat_v6_fixup(void) 362f159f4edSTony Lindgren { 363f159f4edSTony Lindgren int id = read_cpuid_id(); 364f159f4edSTony Lindgren 365f159f4edSTony Lindgren if ((id & 0xff0f0000) != 0x41070000) 366f159f4edSTony Lindgren return; 367f159f4edSTony Lindgren 368f159f4edSTony Lindgren /* 369f159f4edSTony Lindgren * HWCAP_TLS is available only on 1136 r1p0 and later, 370f159f4edSTony Lindgren * see also kuser_get_tls_init. 371f159f4edSTony Lindgren */ 372f159f4edSTony Lindgren if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0)) 373f159f4edSTony Lindgren elf_hwcap &= ~HWCAP_TLS; 374f159f4edSTony Lindgren } 375f159f4edSTony Lindgren 376b69874e4SRussell King /* 377b69874e4SRussell King * cpu_init - initialise one CPU. 378b69874e4SRussell King * 379b69874e4SRussell King * cpu_init sets up the per-CPU stacks. 380b69874e4SRussell King */ 381b69874e4SRussell King void cpu_init(void) 382b69874e4SRussell King { 383b69874e4SRussell King unsigned int cpu = smp_processor_id(); 384b69874e4SRussell King struct stack *stk = &stacks[cpu]; 385b69874e4SRussell King 386b69874e4SRussell King if (cpu >= NR_CPUS) { 387b69874e4SRussell King printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); 388b69874e4SRussell King BUG(); 389b69874e4SRussell King } 390b69874e4SRussell King 391b69874e4SRussell King cpu_proc_init(); 392b69874e4SRussell King 393b69874e4SRussell King /* 394b69874e4SRussell King * Define the placement constraint for the inline asm directive below. 395b69874e4SRussell King * In Thumb-2, msr with an immediate value is not allowed. 396b69874e4SRussell King */ 397b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL 398b69874e4SRussell King #define PLC "r" 399b69874e4SRussell King #else 400b69874e4SRussell King #define PLC "I" 401b69874e4SRussell King #endif 402b69874e4SRussell King 403b69874e4SRussell King /* 404b69874e4SRussell King * setup stacks for re-entrant exception handlers 405b69874e4SRussell King */ 406b69874e4SRussell King __asm__ ( 407b69874e4SRussell King "msr cpsr_c, %1\n\t" 408b69874e4SRussell King "add r14, %0, %2\n\t" 409b69874e4SRussell King "mov sp, r14\n\t" 410b69874e4SRussell King "msr cpsr_c, %3\n\t" 411b69874e4SRussell King "add r14, %0, %4\n\t" 412b69874e4SRussell King "mov sp, r14\n\t" 413b69874e4SRussell King "msr cpsr_c, %5\n\t" 414b69874e4SRussell King "add r14, %0, %6\n\t" 415b69874e4SRussell King "mov sp, r14\n\t" 416b69874e4SRussell King "msr cpsr_c, %7" 417b69874e4SRussell King : 418b69874e4SRussell King : "r" (stk), 419b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), 420b69874e4SRussell King "I" (offsetof(struct stack, irq[0])), 421b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), 422b69874e4SRussell King "I" (offsetof(struct stack, abt[0])), 423b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), 424b69874e4SRussell King "I" (offsetof(struct stack, und[0])), 425b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) 426b69874e4SRussell King : "r14"); 427b69874e4SRussell King } 428b69874e4SRussell King 429eb50439bSWill Deacon int __cpu_logical_map[NR_CPUS]; 430eb50439bSWill Deacon 431eb50439bSWill Deacon void __init smp_setup_processor_id(void) 432eb50439bSWill Deacon { 433eb50439bSWill Deacon int i; 434eb50439bSWill Deacon u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0; 435eb50439bSWill Deacon 436eb50439bSWill Deacon cpu_logical_map(0) = cpu; 437eb50439bSWill Deacon for (i = 1; i < NR_CPUS; ++i) 438eb50439bSWill Deacon cpu_logical_map(i) = i == cpu ? 0 : i; 439eb50439bSWill Deacon 440eb50439bSWill Deacon printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu); 441eb50439bSWill Deacon } 442eb50439bSWill Deacon 4431da177e4SLinus Torvalds static void __init setup_processor(void) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds struct proc_info_list *list; 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds /* 4481da177e4SLinus Torvalds * locate processor in the list of supported processor 4491da177e4SLinus Torvalds * types. The linker builds this table for us from the 4501da177e4SLinus Torvalds * entries in arch/arm/mm/proc-*.S 4511da177e4SLinus Torvalds */ 4520ba8b9b2SRussell King list = lookup_processor_type(read_cpuid_id()); 4531da177e4SLinus Torvalds if (!list) { 4541da177e4SLinus Torvalds printk("CPU configuration botched (ID %08x), unable " 4550ba8b9b2SRussell King "to continue.\n", read_cpuid_id()); 4561da177e4SLinus Torvalds while (1); 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds cpu_name = list->cpu_name; 4602ecccf90SDave Martin __cpu_architecture = __get_cpu_architecture(); 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds #ifdef MULTI_CPU 4631da177e4SLinus Torvalds processor = *list->proc; 4641da177e4SLinus Torvalds #endif 4651da177e4SLinus Torvalds #ifdef MULTI_TLB 4661da177e4SLinus Torvalds cpu_tlb = *list->tlb; 4671da177e4SLinus Torvalds #endif 4681da177e4SLinus Torvalds #ifdef MULTI_USER 4691da177e4SLinus Torvalds cpu_user = *list->user; 4701da177e4SLinus Torvalds #endif 4711da177e4SLinus Torvalds #ifdef MULTI_CACHE 4721da177e4SLinus Torvalds cpu_cache = *list->cache; 4731da177e4SLinus Torvalds #endif 4741da177e4SLinus Torvalds 4754e19025bSRussell King printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 4760ba8b9b2SRussell King cpu_name, read_cpuid_id(), read_cpuid_id() & 15, 477264edb35SRussell King proc_arch[cpu_architecture()], cr_alignment); 4781da177e4SLinus Torvalds 479a34dbfb0SWill Deacon snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c", 480a34dbfb0SWill Deacon list->arch_name, ENDIANNESS); 481a34dbfb0SWill Deacon snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c", 482a34dbfb0SWill Deacon list->elf_name, ENDIANNESS); 4831da177e4SLinus Torvalds elf_hwcap = list->elf_hwcap; 484adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB 485adeff422SCatalin Marinas elf_hwcap &= ~HWCAP_THUMB; 486adeff422SCatalin Marinas #endif 4871da177e4SLinus Torvalds 488f159f4edSTony Lindgren feat_v6_fixup(); 489f159f4edSTony Lindgren 490c0e95878SRussell King cacheid_init(); 491b69874e4SRussell King cpu_init(); 492ccea7a19SRussell King } 493ccea7a19SRussell King 49493c02ab4SGrant Likely void __init dump_machine_table(void) 4951da177e4SLinus Torvalds { 496dce72dd0SNicolas Pitre struct machine_desc *p; 4971da177e4SLinus Torvalds 4986291319dSGrant Likely early_print("Available machine support:\n\nID (hex)\tNAME\n"); 4996291319dSGrant Likely for_each_machine_desc(p) 500dce72dd0SNicolas Pitre early_print("%08x\t%s\n", p->nr, p->name); 501dce72dd0SNicolas Pitre 502dce72dd0SNicolas Pitre early_print("\nPlease check your kernel config and/or bootloader.\n"); 503dce72dd0SNicolas Pitre 504dce72dd0SNicolas Pitre while (true) 505dce72dd0SNicolas Pitre /* can't use cpu_relax() here as it may require MMU setup */; 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5089eb8f674SGrant Likely int __init arm_add_memory(phys_addr_t start, unsigned long size) 5093a669411SRussell King { 5104b5f32ceSNicolas Pitre struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 5114b5f32ceSNicolas Pitre 5124b5f32ceSNicolas Pitre if (meminfo.nr_banks >= NR_BANKS) { 5134b5f32ceSNicolas Pitre printk(KERN_CRIT "NR_BANKS too low, " 51429a38193SWill Deacon "ignoring memory at 0x%08llx\n", (long long)start); 5154b5f32ceSNicolas Pitre return -EINVAL; 5164b5f32ceSNicolas Pitre } 51705f96ef1SRussell King 5183a669411SRussell King /* 5193a669411SRussell King * Ensure that start/size are aligned to a page boundary. 5203a669411SRussell King * Size is appropriately rounded down, start is rounded up. 5213a669411SRussell King */ 5223a669411SRussell King size -= start & ~PAGE_MASK; 52305f96ef1SRussell King bank->start = PAGE_ALIGN(start); 52405f96ef1SRussell King bank->size = size & PAGE_MASK; 5254b5f32ceSNicolas Pitre 5264b5f32ceSNicolas Pitre /* 5274b5f32ceSNicolas Pitre * Check whether this memory region has non-zero size or 5284b5f32ceSNicolas Pitre * invalid node number. 5294b5f32ceSNicolas Pitre */ 530be370302SRussell King if (bank->size == 0) 5314b5f32ceSNicolas Pitre return -EINVAL; 5324b5f32ceSNicolas Pitre 5334b5f32ceSNicolas Pitre meminfo.nr_banks++; 5344b5f32ceSNicolas Pitre return 0; 5353a669411SRussell King } 5363a669411SRussell King 5371da177e4SLinus Torvalds /* 5381da177e4SLinus Torvalds * Pick out the memory size. We look for mem=size@start, 5391da177e4SLinus Torvalds * where start and size are "size[KkMm]" 5401da177e4SLinus Torvalds */ 5412b0d8c25SJeremy Kerr static int __init early_mem(char *p) 5421da177e4SLinus Torvalds { 5431da177e4SLinus Torvalds static int usermem __initdata = 0; 544f60892d3SWill Deacon unsigned long size; 545f60892d3SWill Deacon phys_addr_t start; 5462b0d8c25SJeremy Kerr char *endp; 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds /* 5491da177e4SLinus Torvalds * If the user specifies memory size, we 5501da177e4SLinus Torvalds * blow away any automatically generated 5511da177e4SLinus Torvalds * size. 5521da177e4SLinus Torvalds */ 5531da177e4SLinus Torvalds if (usermem == 0) { 5541da177e4SLinus Torvalds usermem = 1; 5551da177e4SLinus Torvalds meminfo.nr_banks = 0; 5561da177e4SLinus Torvalds } 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds start = PHYS_OFFSET; 5592b0d8c25SJeremy Kerr size = memparse(p, &endp); 5602b0d8c25SJeremy Kerr if (*endp == '@') 5612b0d8c25SJeremy Kerr start = memparse(endp + 1, NULL); 5621da177e4SLinus Torvalds 5631c97b73eSAndrew Morton arm_add_memory(start, size); 5641da177e4SLinus Torvalds 5652b0d8c25SJeremy Kerr return 0; 5661da177e4SLinus Torvalds } 5672b0d8c25SJeremy Kerr early_param("mem", early_mem); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds static void __init 5701da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM 5731da177e4SLinus Torvalds extern int rd_size, rd_image_start, rd_prompt, rd_doload; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds rd_image_start = image_start; 5761da177e4SLinus Torvalds rd_prompt = prompt; 5771da177e4SLinus Torvalds rd_doload = doload; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds if (rd_sz) 5801da177e4SLinus Torvalds rd_size = rd_sz; 5811da177e4SLinus Torvalds #endif 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 58411b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc) 5851da177e4SLinus Torvalds { 58611b9369cSDima Zavin struct memblock_region *region; 5871da177e4SLinus Torvalds struct resource *res; 5881da177e4SLinus Torvalds 58937efe642SRussell King kernel_code.start = virt_to_phys(_text); 59037efe642SRussell King kernel_code.end = virt_to_phys(_etext - 1); 591842eab40SRussell King kernel_data.start = virt_to_phys(_sdata); 59237efe642SRussell King kernel_data.end = virt_to_phys(_end - 1); 5931da177e4SLinus Torvalds 59411b9369cSDima Zavin for_each_memblock(memory, region) { 5951da177e4SLinus Torvalds res = alloc_bootmem_low(sizeof(*res)); 5961da177e4SLinus Torvalds res->name = "System RAM"; 59711b9369cSDima Zavin res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 59811b9369cSDima Zavin res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 5991da177e4SLinus Torvalds res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds request_resource(&iomem_resource, res); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds if (kernel_code.start >= res->start && 6041da177e4SLinus Torvalds kernel_code.end <= res->end) 6051da177e4SLinus Torvalds request_resource(res, &kernel_code); 6061da177e4SLinus Torvalds if (kernel_data.start >= res->start && 6071da177e4SLinus Torvalds kernel_data.end <= res->end) 6081da177e4SLinus Torvalds request_resource(res, &kernel_data); 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds if (mdesc->video_start) { 6121da177e4SLinus Torvalds video_ram.start = mdesc->video_start; 6131da177e4SLinus Torvalds video_ram.end = mdesc->video_end; 6141da177e4SLinus Torvalds request_resource(&iomem_resource, &video_ram); 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds /* 6181da177e4SLinus Torvalds * Some machines don't have the possibility of ever 6191da177e4SLinus Torvalds * possessing lp0, lp1 or lp2 6201da177e4SLinus Torvalds */ 6211da177e4SLinus Torvalds if (mdesc->reserve_lp0) 6221da177e4SLinus Torvalds request_resource(&ioport_resource, &lp0); 6231da177e4SLinus Torvalds if (mdesc->reserve_lp1) 6241da177e4SLinus Torvalds request_resource(&ioport_resource, &lp1); 6251da177e4SLinus Torvalds if (mdesc->reserve_lp2) 6261da177e4SLinus Torvalds request_resource(&ioport_resource, &lp2); 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds /* 6301da177e4SLinus Torvalds * Tag parsing. 6311da177e4SLinus Torvalds * 6321da177e4SLinus Torvalds * This is the new way of passing data to the kernel at boot time. Rather 6331da177e4SLinus Torvalds * than passing a fixed inflexible structure to the kernel, we pass a list 6341da177e4SLinus Torvalds * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE 6351da177e4SLinus Torvalds * tag for the list to be recognised (to distinguish the tagged list from 6361da177e4SLinus Torvalds * a param_struct). The list is terminated with a zero-length tag (this tag 6371da177e4SLinus Torvalds * is not parsed in any way). 6381da177e4SLinus Torvalds */ 6391da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag) 6401da177e4SLinus Torvalds { 6411da177e4SLinus Torvalds if (tag->hdr.size > 2) { 6421da177e4SLinus Torvalds if ((tag->u.core.flags & 1) == 0) 6431da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY; 6441da177e4SLinus Torvalds ROOT_DEV = old_decode_dev(tag->u.core.rootdev); 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds return 0; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core); 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag) 6521da177e4SLinus Torvalds { 6534b5f32ceSNicolas Pitre return arm_add_memory(tag->u.mem.start, tag->u.mem.size); 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32); 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 6591da177e4SLinus Torvalds struct screen_info screen_info = { 6601da177e4SLinus Torvalds .orig_video_lines = 30, 6611da177e4SLinus Torvalds .orig_video_cols = 80, 6621da177e4SLinus Torvalds .orig_video_mode = 0, 6631da177e4SLinus Torvalds .orig_video_ega_bx = 0, 6641da177e4SLinus Torvalds .orig_video_isVGA = 1, 6651da177e4SLinus Torvalds .orig_video_points = 8 6661da177e4SLinus Torvalds }; 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag) 6691da177e4SLinus Torvalds { 6701da177e4SLinus Torvalds screen_info.orig_x = tag->u.videotext.x; 6711da177e4SLinus Torvalds screen_info.orig_y = tag->u.videotext.y; 6721da177e4SLinus Torvalds screen_info.orig_video_page = tag->u.videotext.video_page; 6731da177e4SLinus Torvalds screen_info.orig_video_mode = tag->u.videotext.video_mode; 6741da177e4SLinus Torvalds screen_info.orig_video_cols = tag->u.videotext.video_cols; 6751da177e4SLinus Torvalds screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; 6761da177e4SLinus Torvalds screen_info.orig_video_lines = tag->u.videotext.video_lines; 6771da177e4SLinus Torvalds screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; 6781da177e4SLinus Torvalds screen_info.orig_video_points = tag->u.videotext.video_points; 6791da177e4SLinus Torvalds return 0; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); 6831da177e4SLinus Torvalds #endif 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag) 6861da177e4SLinus Torvalds { 6871da177e4SLinus Torvalds setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, 6881da177e4SLinus Torvalds (tag->u.ramdisk.flags & 2) == 0, 6891da177e4SLinus Torvalds tag->u.ramdisk.start, tag->u.ramdisk.size); 6901da177e4SLinus Torvalds return 0; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk); 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag) 6961da177e4SLinus Torvalds { 6971da177e4SLinus Torvalds system_serial_low = tag->u.serialnr.low; 6981da177e4SLinus Torvalds system_serial_high = tag->u.serialnr.high; 6991da177e4SLinus Torvalds return 0; 7001da177e4SLinus Torvalds } 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr); 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag) 7051da177e4SLinus Torvalds { 7061da177e4SLinus Torvalds system_rev = tag->u.revision.rev; 7071da177e4SLinus Torvalds return 0; 7081da177e4SLinus Torvalds } 7091da177e4SLinus Torvalds 7101da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision); 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag) 7131da177e4SLinus Torvalds { 7144394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND) 7154394c124SVictor Boivie strlcat(default_command_line, " ", COMMAND_LINE_SIZE); 7164394c124SVictor Boivie strlcat(default_command_line, tag->u.cmdline.cmdline, 7174394c124SVictor Boivie COMMAND_LINE_SIZE); 7184394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE) 71922eeb8f6SAlexander Holler pr_warning("Ignoring tag cmdline (using the default kernel command line)\n"); 7204394c124SVictor Boivie #else 7214394c124SVictor Boivie strlcpy(default_command_line, tag->u.cmdline.cmdline, 7224394c124SVictor Boivie COMMAND_LINE_SIZE); 7234394c124SVictor Boivie #endif 7241da177e4SLinus Torvalds return 0; 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline); 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds /* 7301da177e4SLinus Torvalds * Scan the tag table for this tag, and call its parse function. 7311da177e4SLinus Torvalds * The tag table is built by the linker from all the __tagtable 7321da177e4SLinus Torvalds * declarations. 7331da177e4SLinus Torvalds */ 7341da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag) 7351da177e4SLinus Torvalds { 7361da177e4SLinus Torvalds extern struct tagtable __tagtable_begin, __tagtable_end; 7371da177e4SLinus Torvalds struct tagtable *t; 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds for (t = &__tagtable_begin; t < &__tagtable_end; t++) 7401da177e4SLinus Torvalds if (tag->hdr.tag == t->tag) { 7411da177e4SLinus Torvalds t->parse(tag); 7421da177e4SLinus Torvalds break; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds return t < &__tagtable_end; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* 7491da177e4SLinus Torvalds * Parse all tags in the list, checking both the global and architecture 7501da177e4SLinus Torvalds * specific tag tables. 7511da177e4SLinus Torvalds */ 7521da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t) 7531da177e4SLinus Torvalds { 7541da177e4SLinus Torvalds for (; t->hdr.size; t = tag_next(t)) 7551da177e4SLinus Torvalds if (!parse_tag(t)) 7561da177e4SLinus Torvalds printk(KERN_WARNING 7571da177e4SLinus Torvalds "Ignoring unrecognised tag 0x%08x\n", 7581da177e4SLinus Torvalds t->hdr.tag); 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds /* 7621da177e4SLinus Torvalds * This holds our defaults. 7631da177e4SLinus Torvalds */ 7641da177e4SLinus Torvalds static struct init_tags { 7651da177e4SLinus Torvalds struct tag_header hdr1; 7661da177e4SLinus Torvalds struct tag_core core; 7671da177e4SLinus Torvalds struct tag_header hdr2; 7681da177e4SLinus Torvalds struct tag_mem32 mem; 7691da177e4SLinus Torvalds struct tag_header hdr3; 7701da177e4SLinus Torvalds } init_tags __initdata = { 7711da177e4SLinus Torvalds { tag_size(tag_core), ATAG_CORE }, 7721da177e4SLinus Torvalds { 1, PAGE_SIZE, 0xff }, 7731da177e4SLinus Torvalds { tag_size(tag_mem32), ATAG_MEM }, 774b75c178aSRussell King { MEM_SIZE }, 7751da177e4SLinus Torvalds { 0, ATAG_NONE } 7761da177e4SLinus Torvalds }; 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds static int __init customize_machine(void) 7791da177e4SLinus Torvalds { 7801da177e4SLinus Torvalds /* customizes platform devices, or adds new ones */ 7818ff1443cSRussell King if (machine_desc->init_machine) 7828ff1443cSRussell King machine_desc->init_machine(); 7831da177e4SLinus Torvalds return 0; 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds arch_initcall(customize_machine); 7861da177e4SLinus Torvalds 7873c57fb43SMika Westerberg #ifdef CONFIG_KEXEC 7883c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void) 7893c57fb43SMika Westerberg { 7903c57fb43SMika Westerberg unsigned long total; 7913c57fb43SMika Westerberg 7923c57fb43SMika Westerberg total = max_low_pfn - min_low_pfn; 7933c57fb43SMika Westerberg return total << PAGE_SHIFT; 7943c57fb43SMika Westerberg } 7953c57fb43SMika Westerberg 7963c57fb43SMika Westerberg /** 7973c57fb43SMika Westerberg * reserve_crashkernel() - reserves memory are for crash kernel 7983c57fb43SMika Westerberg * 7993c57fb43SMika Westerberg * This function reserves memory area given in "crashkernel=" kernel command 8003c57fb43SMika Westerberg * line parameter. The memory reserved is used by a dump capture kernel when 8013c57fb43SMika Westerberg * primary kernel is crashing. 8023c57fb43SMika Westerberg */ 8033c57fb43SMika Westerberg static void __init reserve_crashkernel(void) 8043c57fb43SMika Westerberg { 8053c57fb43SMika Westerberg unsigned long long crash_size, crash_base; 8063c57fb43SMika Westerberg unsigned long long total_mem; 8073c57fb43SMika Westerberg int ret; 8083c57fb43SMika Westerberg 8093c57fb43SMika Westerberg total_mem = get_total_mem(); 8103c57fb43SMika Westerberg ret = parse_crashkernel(boot_command_line, total_mem, 8113c57fb43SMika Westerberg &crash_size, &crash_base); 8123c57fb43SMika Westerberg if (ret) 8133c57fb43SMika Westerberg return; 8143c57fb43SMika Westerberg 8153c57fb43SMika Westerberg ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE); 8163c57fb43SMika Westerberg if (ret < 0) { 8173c57fb43SMika Westerberg printk(KERN_WARNING "crashkernel reservation failed - " 8183c57fb43SMika Westerberg "memory is in use (0x%lx)\n", (unsigned long)crash_base); 8193c57fb43SMika Westerberg return; 8203c57fb43SMika Westerberg } 8213c57fb43SMika Westerberg 8223c57fb43SMika Westerberg printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " 8233c57fb43SMika Westerberg "for crashkernel (System RAM: %ldMB)\n", 8243c57fb43SMika Westerberg (unsigned long)(crash_size >> 20), 8253c57fb43SMika Westerberg (unsigned long)(crash_base >> 20), 8263c57fb43SMika Westerberg (unsigned long)(total_mem >> 20)); 8273c57fb43SMika Westerberg 8283c57fb43SMika Westerberg crashk_res.start = crash_base; 8293c57fb43SMika Westerberg crashk_res.end = crash_base + crash_size - 1; 8303c57fb43SMika Westerberg insert_resource(&iomem_resource, &crashk_res); 8313c57fb43SMika Westerberg } 8323c57fb43SMika Westerberg #else 8333c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {} 8343c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */ 8353c57fb43SMika Westerberg 83673a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag) 83773a65b3fSUwe Kleine-König { 83873a65b3fSUwe Kleine-König for (; tag->hdr.size; tag = tag_next(tag)) 83973a65b3fSUwe Kleine-König if (tag->hdr.tag == ATAG_MEM) 84073a65b3fSUwe Kleine-König tag->hdr.tag = ATAG_NONE; 84173a65b3fSUwe Kleine-König } 84273a65b3fSUwe Kleine-König 8436291319dSGrant Likely static struct machine_desc * __init setup_machine_tags(unsigned int nr) 8441da177e4SLinus Torvalds { 8451da177e4SLinus Torvalds struct tag *tags = (struct tag *)&init_tags; 8466291319dSGrant Likely struct machine_desc *mdesc = NULL, *p; 8471da177e4SLinus Torvalds char *from = default_command_line; 8481da177e4SLinus Torvalds 849b75c178aSRussell King init_tags.mem.start = PHYS_OFFSET; 850b75c178aSRussell King 8516291319dSGrant Likely /* 8526291319dSGrant Likely * locate machine in the list of supported machines. 8536291319dSGrant Likely */ 8546291319dSGrant Likely for_each_machine_desc(p) 8556291319dSGrant Likely if (nr == p->nr) { 8566291319dSGrant Likely printk("Machine: %s\n", p->name); 8576291319dSGrant Likely mdesc = p; 8586291319dSGrant Likely break; 8596291319dSGrant Likely } 860bff595c1SCatalin Marinas 8616291319dSGrant Likely if (!mdesc) { 8626291319dSGrant Likely early_print("\nError: unrecognized/unsupported machine ID" 8636291319dSGrant Likely " (r1 = 0x%08x).\n\n", nr); 8646291319dSGrant Likely dump_machine_table(); /* does not return */ 8656291319dSGrant Likely } 8661da177e4SLinus Torvalds 8679d20fdd5SBill Gatliff if (__atags_pointer) 8689d20fdd5SBill Gatliff tags = phys_to_virt(__atags_pointer); 8692bb9839eSNicolas Pitre else if (mdesc->atag_offset) 8702bb9839eSNicolas Pitre tags = (void *)(PAGE_OFFSET + mdesc->atag_offset); 8711da177e4SLinus Torvalds 87273a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 8731da177e4SLinus Torvalds /* 8741da177e4SLinus Torvalds * If we have the old style parameters, convert them to 8751da177e4SLinus Torvalds * a tag list. 8761da177e4SLinus Torvalds */ 8771da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 8781da177e4SLinus Torvalds convert_to_tag_list(tags); 87973a65b3fSUwe Kleine-König #endif 88093c02ab4SGrant Likely 88193c02ab4SGrant Likely if (tags->hdr.tag != ATAG_CORE) { 88293c02ab4SGrant Likely #if defined(CONFIG_OF) 88393c02ab4SGrant Likely /* 88493c02ab4SGrant Likely * If CONFIG_OF is set, then assume this is a reasonably 88593c02ab4SGrant Likely * modern system that should pass boot parameters 88693c02ab4SGrant Likely */ 88793c02ab4SGrant Likely early_print("Warning: Neither atags nor dtb found\n"); 88893c02ab4SGrant Likely #endif 8891da177e4SLinus Torvalds tags = (struct tag *)&init_tags; 89093c02ab4SGrant Likely } 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds if (mdesc->fixup) 8930744a3eeSRussell King mdesc->fixup(tags, &from, &meminfo); 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds if (tags->hdr.tag == ATAG_CORE) { 8961da177e4SLinus Torvalds if (meminfo.nr_banks != 0) 8971da177e4SLinus Torvalds squash_mem_tags(tags); 8984cd9d6f7SRichard Purdie save_atags(tags); 8991da177e4SLinus Torvalds parse_tags(tags); 9001da177e4SLinus Torvalds } 9011da177e4SLinus Torvalds 9026291319dSGrant Likely /* parse_early_param needs a boot_command_line */ 9036291319dSGrant Likely strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); 9046291319dSGrant Likely 9056291319dSGrant Likely return mdesc; 9066291319dSGrant Likely } 9076291319dSGrant Likely 90827a3f0e9SNicolas Pitre static int __init meminfo_cmp(const void *_a, const void *_b) 90927a3f0e9SNicolas Pitre { 91027a3f0e9SNicolas Pitre const struct membank *a = _a, *b = _b; 91127a3f0e9SNicolas Pitre long cmp = bank_pfn_start(a) - bank_pfn_start(b); 91227a3f0e9SNicolas Pitre return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; 91327a3f0e9SNicolas Pitre } 9146291319dSGrant Likely 9156291319dSGrant Likely void __init setup_arch(char **cmdline_p) 9166291319dSGrant Likely { 9176291319dSGrant Likely struct machine_desc *mdesc; 9186291319dSGrant Likely 9196291319dSGrant Likely setup_processor(); 92093c02ab4SGrant Likely mdesc = setup_machine_fdt(__atags_pointer); 92193c02ab4SGrant Likely if (!mdesc) 9226291319dSGrant Likely mdesc = setup_machine_tags(machine_arch_type); 9236291319dSGrant Likely machine_desc = mdesc; 9246291319dSGrant Likely machine_name = mdesc->name; 9256291319dSGrant Likely 9269811ccdfSArnaud Patard #ifdef CONFIG_ZONE_DMA 9279811ccdfSArnaud Patard if (mdesc->dma_zone_size) { 9289811ccdfSArnaud Patard extern unsigned long arm_dma_zone_size; 9299811ccdfSArnaud Patard arm_dma_zone_size = mdesc->dma_zone_size; 9309811ccdfSArnaud Patard } 9319811ccdfSArnaud Patard #endif 932b44c350dSRussell King if (mdesc->restart_mode) 933b44c350dSRussell King reboot_setup(&mdesc->restart_mode); 9346291319dSGrant Likely 93537efe642SRussell King init_mm.start_code = (unsigned long) _text; 93637efe642SRussell King init_mm.end_code = (unsigned long) _etext; 93737efe642SRussell King init_mm.end_data = (unsigned long) _edata; 93837efe642SRussell King init_mm.brk = (unsigned long) _end; 9391da177e4SLinus Torvalds 94048ab7e09SJeremy Kerr /* populate cmd_line too for later use, preserving boot_command_line */ 94148ab7e09SJeremy Kerr strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 94248ab7e09SJeremy Kerr *cmdline_p = cmd_line; 9432b0d8c25SJeremy Kerr 9442b0d8c25SJeremy Kerr parse_early_param(); 9452b0d8c25SJeremy Kerr 94627a3f0e9SNicolas Pitre sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); 9470371d3f7SRussell King sanity_check_meminfo(); 9488d717a52SRussell King arm_memblock_init(&meminfo, mdesc); 9492778f620SRussell King 9504b5f32ceSNicolas Pitre paging_init(mdesc); 95111b9369cSDima Zavin request_standard_resources(mdesc); 9521da177e4SLinus Torvalds 953a528721dSRussell King if (mdesc->restart) 954a528721dSRussell King arm_pm_restart = mdesc->restart; 955a528721dSRussell King 95693c02ab4SGrant Likely unflatten_device_tree(); 95793c02ab4SGrant Likely 9587bbb7940SRussell King #ifdef CONFIG_SMP 959f00ec48fSRussell King if (is_smp()) 9607bbb7940SRussell King smp_init_cpus(); 9617bbb7940SRussell King #endif 9623c57fb43SMika Westerberg reserve_crashkernel(); 9637bbb7940SRussell King 964bc581770SLinus Walleij tcm_init(); 965ccea7a19SRussell King 96652108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER 96752108641Seric miao handle_arch_irq = mdesc->handle_irq; 96852108641Seric miao #endif 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds #ifdef CONFIG_VT 9711da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) 9721da177e4SLinus Torvalds conswitchp = &vga_con; 9731da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE) 9741da177e4SLinus Torvalds conswitchp = &dummy_con; 9751da177e4SLinus Torvalds #endif 9761da177e4SLinus Torvalds #endif 9775cbad0ebSJason Wessel early_trap_init(); 978dec12e62SRussell King 979dec12e62SRussell King if (mdesc->init_early) 980dec12e62SRussell King mdesc->init_early(); 9811da177e4SLinus Torvalds } 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds 9841da177e4SLinus Torvalds static int __init topology_init(void) 9851da177e4SLinus Torvalds { 9861da177e4SLinus Torvalds int cpu; 9871da177e4SLinus Torvalds 98866fb8bd2SRussell King for_each_possible_cpu(cpu) { 98966fb8bd2SRussell King struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); 99066fb8bd2SRussell King cpuinfo->cpu.hotpluggable = 1; 99166fb8bd2SRussell King register_cpu(&cpuinfo->cpu, cpu); 99266fb8bd2SRussell King } 9931da177e4SLinus Torvalds 9941da177e4SLinus Torvalds return 0; 9951da177e4SLinus Torvalds } 9961da177e4SLinus Torvalds subsys_initcall(topology_init); 9971da177e4SLinus Torvalds 998e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU 999e119bfffSRussell King static int __init proc_cpu_init(void) 1000e119bfffSRussell King { 1001e119bfffSRussell King struct proc_dir_entry *res; 1002e119bfffSRussell King 1003e119bfffSRussell King res = proc_mkdir("cpu", NULL); 1004e119bfffSRussell King if (!res) 1005e119bfffSRussell King return -ENOMEM; 1006e119bfffSRussell King return 0; 1007e119bfffSRussell King } 1008e119bfffSRussell King fs_initcall(proc_cpu_init); 1009e119bfffSRussell King #endif 1010e119bfffSRussell King 10111da177e4SLinus Torvalds static const char *hwcap_str[] = { 10121da177e4SLinus Torvalds "swp", 10131da177e4SLinus Torvalds "half", 10141da177e4SLinus Torvalds "thumb", 10151da177e4SLinus Torvalds "26bit", 10161da177e4SLinus Torvalds "fastmult", 10171da177e4SLinus Torvalds "fpa", 10181da177e4SLinus Torvalds "vfp", 10191da177e4SLinus Torvalds "edsp", 10201da177e4SLinus Torvalds "java", 10218f7f9435SPaul Gortmaker "iwmmxt", 102299e4a6ddSLennert Buytenhek "crunch", 10234369ae16SCatalin Marinas "thumbee", 10242bedbdf4SCatalin Marinas "neon", 10257279dc3eSCatalin Marinas "vfpv3", 10267279dc3eSCatalin Marinas "vfpv3d16", 1027254cdf8eSWill Deacon "tls", 1028254cdf8eSWill Deacon "vfpv4", 1029254cdf8eSWill Deacon "idiva", 1030254cdf8eSWill Deacon "idivt", 10311da177e4SLinus Torvalds NULL 10321da177e4SLinus Torvalds }; 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v) 10351da177e4SLinus Torvalds { 10361da177e4SLinus Torvalds int i; 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds seq_printf(m, "Processor\t: %s rev %d (%s)\n", 10390ba8b9b2SRussell King cpu_name, read_cpuid_id() & 15, elf_platform); 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds #if defined(CONFIG_SMP) 10421da177e4SLinus Torvalds for_each_online_cpu(i) { 104315559722SRussell King /* 104415559722SRussell King * glibc reads /proc/cpuinfo to determine the number of 104515559722SRussell King * online processors, looking for lines beginning with 104615559722SRussell King * "processor". Give glibc what it expects. 104715559722SRussell King */ 104815559722SRussell King seq_printf(m, "processor\t: %d\n", i); 10491da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 10501da177e4SLinus Torvalds per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), 10511da177e4SLinus Torvalds (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds #else /* CONFIG_SMP */ 10541da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", 10551da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ), 10561da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100); 10571da177e4SLinus Torvalds #endif 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds /* dump out the processor features */ 10601da177e4SLinus Torvalds seq_puts(m, "Features\t: "); 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds for (i = 0; hwcap_str[i]; i++) 10631da177e4SLinus Torvalds if (elf_hwcap & (1 << i)) 10641da177e4SLinus Torvalds seq_printf(m, "%s ", hwcap_str[i]); 10651da177e4SLinus Torvalds 10660ba8b9b2SRussell King seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 10671da177e4SLinus Torvalds seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); 10681da177e4SLinus Torvalds 10690ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00000000) { 10701da177e4SLinus Torvalds /* pre-ARM7 */ 10710ba8b9b2SRussell King seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4); 10721da177e4SLinus Torvalds } else { 10730ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 10741da177e4SLinus Torvalds /* ARM7 */ 10751da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%02x\n", 10760ba8b9b2SRussell King (read_cpuid_id() >> 16) & 127); 10771da177e4SLinus Torvalds } else { 10781da177e4SLinus Torvalds /* post-ARM7 */ 10791da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%x\n", 10800ba8b9b2SRussell King (read_cpuid_id() >> 20) & 15); 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds seq_printf(m, "CPU part\t: 0x%03x\n", 10830ba8b9b2SRussell King (read_cpuid_id() >> 4) & 0xfff); 10841da177e4SLinus Torvalds } 10850ba8b9b2SRussell King seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds seq_puts(m, "\n"); 10881da177e4SLinus Torvalds 10891da177e4SLinus Torvalds seq_printf(m, "Hardware\t: %s\n", machine_name); 10901da177e4SLinus Torvalds seq_printf(m, "Revision\t: %04x\n", system_rev); 10911da177e4SLinus Torvalds seq_printf(m, "Serial\t\t: %08x%08x\n", 10921da177e4SLinus Torvalds system_serial_high, system_serial_low); 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds return 0; 10951da177e4SLinus Torvalds } 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 10981da177e4SLinus Torvalds { 10991da177e4SLinus Torvalds return *pos < 1 ? (void *)1 : NULL; 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 11031da177e4SLinus Torvalds { 11041da177e4SLinus Torvalds ++*pos; 11051da177e4SLinus Torvalds return NULL; 11061da177e4SLinus Torvalds } 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 11091da177e4SLinus Torvalds { 11101da177e4SLinus Torvalds } 11111da177e4SLinus Torvalds 11122ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = { 11131da177e4SLinus Torvalds .start = c_start, 11141da177e4SLinus Torvalds .next = c_next, 11151da177e4SLinus Torvalds .stop = c_stop, 11161da177e4SLinus Torvalds .show = c_show 11171da177e4SLinus Torvalds }; 1118