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 */ 101da177e4SLinus Torvalds #include <linux/module.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> 23cea0bb1bSMika Westerberg #include <linux/crash_dump.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> 311da177e4SLinus Torvalds 32b86040a5SCatalin Marinas #include <asm/unified.h> 331da177e4SLinus Torvalds #include <asm/cpu.h> 340ba8b9b2SRussell King #include <asm/cputype.h> 351da177e4SLinus Torvalds #include <asm/elf.h> 361da177e4SLinus Torvalds #include <asm/procinfo.h> 3737efe642SRussell King #include <asm/sections.h> 381da177e4SLinus Torvalds #include <asm/setup.h> 39f00ec48fSRussell King #include <asm/smp_plat.h> 401da177e4SLinus Torvalds #include <asm/mach-types.h> 411da177e4SLinus Torvalds #include <asm/cacheflush.h> 4246097c7dSRussell King #include <asm/cachetype.h> 431da177e4SLinus Torvalds #include <asm/tlbflush.h> 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #include <asm/mach/arch.h> 461da177e4SLinus Torvalds #include <asm/mach/irq.h> 471da177e4SLinus Torvalds #include <asm/mach/time.h> 485cbad0ebSJason Wessel #include <asm/traps.h> 49bff595c1SCatalin Marinas #include <asm/unwind.h> 501da177e4SLinus Torvalds 5173a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 520fc1c832SBen Dooks #include "compat.h" 5373a65b3fSUwe Kleine-König #endif 544cd9d6f7SRichard Purdie #include "atags.h" 55bc581770SLinus Walleij #include "tcm.h" 560fc1c832SBen Dooks 571da177e4SLinus Torvalds #ifndef MEM_SIZE 581da177e4SLinus Torvalds #define MEM_SIZE (16*1024*1024) 591da177e4SLinus Torvalds #endif 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) 621da177e4SLinus Torvalds char fpe_type[8]; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds static int __init fpe_setup(char *line) 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds memcpy(fpe_type, line, 8); 671da177e4SLinus Torvalds return 1; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds __setup("fpe=", fpe_setup); 711da177e4SLinus Torvalds #endif 721da177e4SLinus Torvalds 734b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc); 741da177e4SLinus Torvalds extern void reboot_setup(char *str); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds unsigned int processor_id; 77c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id); 780385ebc0SRussell King unsigned int __machine_arch_type __read_mostly; 791da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type); 800385ebc0SRussell King unsigned int cacheid __read_mostly; 81c0e95878SRussell King EXPORT_SYMBOL(cacheid); 821da177e4SLinus Torvalds 839d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata; 849d20fdd5SBill Gatliff 851da177e4SLinus Torvalds unsigned int system_rev; 861da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds unsigned int system_serial_low; 891da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds unsigned int system_serial_high; 921da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high); 931da177e4SLinus Torvalds 940385ebc0SRussell King unsigned int elf_hwcap __read_mostly; 951da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds #ifdef MULTI_CPU 990385ebc0SRussell King struct processor processor __read_mostly; 1001da177e4SLinus Torvalds #endif 1011da177e4SLinus Torvalds #ifdef MULTI_TLB 1020385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly; 1031da177e4SLinus Torvalds #endif 1041da177e4SLinus Torvalds #ifdef MULTI_USER 1050385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly; 1061da177e4SLinus Torvalds #endif 1071da177e4SLinus Torvalds #ifdef MULTI_CACHE 1080385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly; 1091da177e4SLinus Torvalds #endif 110953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE 1110385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly; 1126c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache); 113953233dcSCatalin Marinas #endif 1141da177e4SLinus Torvalds 115ccea7a19SRussell King struct stack { 116ccea7a19SRussell King u32 irq[3]; 117ccea7a19SRussell King u32 abt[3]; 118ccea7a19SRussell King u32 und[3]; 119ccea7a19SRussell King } ____cacheline_aligned; 120ccea7a19SRussell King 121ccea7a19SRussell King static struct stack stacks[NR_CPUS]; 122ccea7a19SRussell King 1231da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE]; 1241da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds static const char *cpu_name; 1271da177e4SLinus Torvalds static const char *machine_name; 12848ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE]; 1298ff1443cSRussell King struct machine_desc *machine_desc __initdata; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; 1321da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; 1331da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l) 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds /* 1381da177e4SLinus Torvalds * Standard memory resources 1391da177e4SLinus Torvalds */ 1401da177e4SLinus Torvalds static struct resource mem_res[] = { 141740e518eSGreg Kroah-Hartman { 142740e518eSGreg Kroah-Hartman .name = "Video RAM", 143740e518eSGreg Kroah-Hartman .start = 0, 144740e518eSGreg Kroah-Hartman .end = 0, 145740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 146740e518eSGreg Kroah-Hartman }, 147740e518eSGreg Kroah-Hartman { 148740e518eSGreg Kroah-Hartman .name = "Kernel text", 149740e518eSGreg Kroah-Hartman .start = 0, 150740e518eSGreg Kroah-Hartman .end = 0, 151740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 152740e518eSGreg Kroah-Hartman }, 153740e518eSGreg Kroah-Hartman { 154740e518eSGreg Kroah-Hartman .name = "Kernel data", 155740e518eSGreg Kroah-Hartman .start = 0, 156740e518eSGreg Kroah-Hartman .end = 0, 157740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 158740e518eSGreg Kroah-Hartman } 1591da177e4SLinus Torvalds }; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds #define video_ram mem_res[0] 1621da177e4SLinus Torvalds #define kernel_code mem_res[1] 1631da177e4SLinus Torvalds #define kernel_data mem_res[2] 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds static struct resource io_res[] = { 166740e518eSGreg Kroah-Hartman { 167740e518eSGreg Kroah-Hartman .name = "reserved", 168740e518eSGreg Kroah-Hartman .start = 0x3bc, 169740e518eSGreg Kroah-Hartman .end = 0x3be, 170740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 171740e518eSGreg Kroah-Hartman }, 172740e518eSGreg Kroah-Hartman { 173740e518eSGreg Kroah-Hartman .name = "reserved", 174740e518eSGreg Kroah-Hartman .start = 0x378, 175740e518eSGreg Kroah-Hartman .end = 0x37f, 176740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 177740e518eSGreg Kroah-Hartman }, 178740e518eSGreg Kroah-Hartman { 179740e518eSGreg Kroah-Hartman .name = "reserved", 180740e518eSGreg Kroah-Hartman .start = 0x278, 181740e518eSGreg Kroah-Hartman .end = 0x27f, 182740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 183740e518eSGreg Kroah-Hartman } 1841da177e4SLinus Torvalds }; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds #define lp0 io_res[0] 1871da177e4SLinus Torvalds #define lp1 io_res[1] 1881da177e4SLinus Torvalds #define lp2 io_res[2] 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static const char *proc_arch[] = { 1911da177e4SLinus Torvalds "undefined/unknown", 1921da177e4SLinus Torvalds "3", 1931da177e4SLinus Torvalds "4", 1941da177e4SLinus Torvalds "4T", 1951da177e4SLinus Torvalds "5", 1961da177e4SLinus Torvalds "5T", 1971da177e4SLinus Torvalds "5TE", 1981da177e4SLinus Torvalds "5TEJ", 1991da177e4SLinus Torvalds "6TEJ", 2006b090a25SCatalin Marinas "7", 2011da177e4SLinus Torvalds "?(11)", 2021da177e4SLinus Torvalds "?(12)", 2031da177e4SLinus Torvalds "?(13)", 2041da177e4SLinus Torvalds "?(14)", 2051da177e4SLinus Torvalds "?(15)", 2061da177e4SLinus Torvalds "?(16)", 2071da177e4SLinus Torvalds "?(17)", 2081da177e4SLinus Torvalds }; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds int cpu_architecture(void) 2111da177e4SLinus Torvalds { 2121da177e4SLinus Torvalds int cpu_arch; 2131da177e4SLinus Torvalds 2140ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0) { 2151da177e4SLinus Torvalds cpu_arch = CPU_ARCH_UNKNOWN; 2160ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 2170ba8b9b2SRussell King cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; 2180ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { 2190ba8b9b2SRussell King cpu_arch = (read_cpuid_id() >> 16) & 7; 2201da177e4SLinus Torvalds if (cpu_arch) 2211da177e4SLinus Torvalds cpu_arch += CPU_ARCH_ARMv3; 2220ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 223180005c4SCatalin Marinas unsigned int mmfr0; 224180005c4SCatalin Marinas 225180005c4SCatalin Marinas /* Revised CPUID format. Read the Memory Model Feature 226180005c4SCatalin Marinas * Register 0 and check for VMSAv7 or PMSAv7 */ 227180005c4SCatalin Marinas asm("mrc p15, 0, %0, c0, c1, 4" 228180005c4SCatalin Marinas : "=r" (mmfr0)); 229315cfe78SCatalin Marinas if ((mmfr0 & 0x0000000f) >= 0x00000003 || 230315cfe78SCatalin Marinas (mmfr0 & 0x000000f0) >= 0x00000030) 231180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv7; 232180005c4SCatalin Marinas else if ((mmfr0 & 0x0000000f) == 0x00000002 || 233180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000020) 234180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv6; 235180005c4SCatalin Marinas else 236180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 237180005c4SCatalin Marinas } else 238180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds return cpu_arch; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2438925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch) 2448925ec4cSWill Deacon { 2458925ec4cSWill Deacon int aliasing_icache; 2468925ec4cSWill Deacon unsigned int id_reg, num_sets, line_size; 2478925ec4cSWill Deacon 2488925ec4cSWill Deacon /* arch specifies the register format */ 2498925ec4cSWill Deacon switch (arch) { 2508925ec4cSWill Deacon case CPU_ARCH_ARMv7: 2515fb31a96SLinus Walleij asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR" 2525fb31a96SLinus Walleij : /* No output operands */ 2538925ec4cSWill Deacon : "r" (1)); 2545fb31a96SLinus Walleij isb(); 2555fb31a96SLinus Walleij asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" 2565fb31a96SLinus Walleij : "=r" (id_reg)); 2578925ec4cSWill Deacon line_size = 4 << ((id_reg & 0x7) + 2); 2588925ec4cSWill Deacon num_sets = ((id_reg >> 13) & 0x7fff) + 1; 2598925ec4cSWill Deacon aliasing_icache = (line_size * num_sets) > PAGE_SIZE; 2608925ec4cSWill Deacon break; 2618925ec4cSWill Deacon case CPU_ARCH_ARMv6: 2628925ec4cSWill Deacon aliasing_icache = read_cpuid_cachetype() & (1 << 11); 2638925ec4cSWill Deacon break; 2648925ec4cSWill Deacon default: 2658925ec4cSWill Deacon /* I-cache aliases will be handled by D-cache aliasing code */ 2668925ec4cSWill Deacon aliasing_icache = 0; 2678925ec4cSWill Deacon } 2688925ec4cSWill Deacon 2698925ec4cSWill Deacon return aliasing_icache; 2708925ec4cSWill Deacon } 2718925ec4cSWill Deacon 272c0e95878SRussell King static void __init cacheid_init(void) 273c0e95878SRussell King { 274c0e95878SRussell King unsigned int cachetype = read_cpuid_cachetype(); 275c0e95878SRussell King unsigned int arch = cpu_architecture(); 276c0e95878SRussell King 277b57ee99fSCatalin Marinas if (arch >= CPU_ARCH_ARMv6) { 278b57ee99fSCatalin Marinas if ((cachetype & (7 << 29)) == 4 << 29) { 279b57ee99fSCatalin Marinas /* ARMv7 register format */ 280c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 281c0e95878SRussell King if ((cachetype & (3 << 14)) == 1 << 14) 282c0e95878SRussell King cacheid |= CACHEID_ASID_TAGGED; 2838925ec4cSWill Deacon else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7)) 2848925ec4cSWill Deacon cacheid |= CACHEID_VIPT_I_ALIASING; 2858925ec4cSWill Deacon } else if (cachetype & (1 << 23)) { 286c0e95878SRussell King cacheid = CACHEID_VIPT_ALIASING; 2878925ec4cSWill Deacon } else { 288c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 2898925ec4cSWill Deacon if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6)) 2908925ec4cSWill Deacon cacheid |= CACHEID_VIPT_I_ALIASING; 2918925ec4cSWill Deacon } 292c0e95878SRussell King } else { 293c0e95878SRussell King cacheid = CACHEID_VIVT; 294c0e95878SRussell King } 2952b4ae1f1SRussell King 2962b4ae1f1SRussell King printk("CPU: %s data cache, %s instruction cache\n", 2972b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 2982b4ae1f1SRussell King cache_is_vipt_aliasing() ? "VIPT aliasing" : 2992b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", 3002b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 3012b4ae1f1SRussell King icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : 3028925ec4cSWill Deacon icache_is_vipt_aliasing() ? "VIPT aliasing" : 3032b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); 304c0e95878SRussell King } 305c0e95878SRussell King 3061da177e4SLinus Torvalds /* 3071da177e4SLinus Torvalds * These functions re-use the assembly code in head.S, which 3081da177e4SLinus Torvalds * already provide the required functionality. 3091da177e4SLinus Torvalds */ 3100f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int); 3116fc31d54SRussell King 3126fc31d54SRussell King static void __init early_print(const char *str, ...) 3136fc31d54SRussell King { 3146fc31d54SRussell King extern void printascii(const char *); 3156fc31d54SRussell King char buf[256]; 3166fc31d54SRussell King va_list ap; 3176fc31d54SRussell King 3186fc31d54SRussell King va_start(ap, str); 3196fc31d54SRussell King vsnprintf(buf, sizeof(buf), str, ap); 3206fc31d54SRussell King va_end(ap); 3216fc31d54SRussell King 3226fc31d54SRussell King #ifdef CONFIG_DEBUG_LL 3236fc31d54SRussell King printascii(buf); 3246fc31d54SRussell King #endif 3256fc31d54SRussell King printk("%s", buf); 3266fc31d54SRussell King } 3276fc31d54SRussell King 328f159f4edSTony Lindgren static void __init feat_v6_fixup(void) 329f159f4edSTony Lindgren { 330f159f4edSTony Lindgren int id = read_cpuid_id(); 331f159f4edSTony Lindgren 332f159f4edSTony Lindgren if ((id & 0xff0f0000) != 0x41070000) 333f159f4edSTony Lindgren return; 334f159f4edSTony Lindgren 335f159f4edSTony Lindgren /* 336f159f4edSTony Lindgren * HWCAP_TLS is available only on 1136 r1p0 and later, 337f159f4edSTony Lindgren * see also kuser_get_tls_init. 338f159f4edSTony Lindgren */ 339f159f4edSTony Lindgren if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0)) 340f159f4edSTony Lindgren elf_hwcap &= ~HWCAP_TLS; 341f159f4edSTony Lindgren } 342f159f4edSTony Lindgren 3431da177e4SLinus Torvalds static void __init setup_processor(void) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds struct proc_info_list *list; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* 3481da177e4SLinus Torvalds * locate processor in the list of supported processor 3491da177e4SLinus Torvalds * types. The linker builds this table for us from the 3501da177e4SLinus Torvalds * entries in arch/arm/mm/proc-*.S 3511da177e4SLinus Torvalds */ 3520ba8b9b2SRussell King list = lookup_processor_type(read_cpuid_id()); 3531da177e4SLinus Torvalds if (!list) { 3541da177e4SLinus Torvalds printk("CPU configuration botched (ID %08x), unable " 3550ba8b9b2SRussell King "to continue.\n", read_cpuid_id()); 3561da177e4SLinus Torvalds while (1); 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds cpu_name = list->cpu_name; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds #ifdef MULTI_CPU 3621da177e4SLinus Torvalds processor = *list->proc; 3631da177e4SLinus Torvalds #endif 3641da177e4SLinus Torvalds #ifdef MULTI_TLB 3651da177e4SLinus Torvalds cpu_tlb = *list->tlb; 3661da177e4SLinus Torvalds #endif 3671da177e4SLinus Torvalds #ifdef MULTI_USER 3681da177e4SLinus Torvalds cpu_user = *list->user; 3691da177e4SLinus Torvalds #endif 3701da177e4SLinus Torvalds #ifdef MULTI_CACHE 3711da177e4SLinus Torvalds cpu_cache = *list->cache; 3721da177e4SLinus Torvalds #endif 3731da177e4SLinus Torvalds 3744e19025bSRussell King printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 3750ba8b9b2SRussell King cpu_name, read_cpuid_id(), read_cpuid_id() & 15, 376264edb35SRussell King proc_arch[cpu_architecture()], cr_alignment); 3771da177e4SLinus Torvalds 37896b644bdSSerge E. Hallyn sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); 3791da177e4SLinus Torvalds sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); 3801da177e4SLinus Torvalds elf_hwcap = list->elf_hwcap; 381adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB 382adeff422SCatalin Marinas elf_hwcap &= ~HWCAP_THUMB; 383adeff422SCatalin Marinas #endif 3841da177e4SLinus Torvalds 385f159f4edSTony Lindgren feat_v6_fixup(); 386f159f4edSTony Lindgren 387c0e95878SRussell King cacheid_init(); 3881da177e4SLinus Torvalds cpu_proc_init(); 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 391ccea7a19SRussell King /* 392ccea7a19SRussell King * cpu_init - initialise one CPU. 393ccea7a19SRussell King * 39490f1e084SRussell King * cpu_init sets up the per-CPU stacks. 395ccea7a19SRussell King */ 39636c5ed23SRussell King void cpu_init(void) 397ccea7a19SRussell King { 398ccea7a19SRussell King unsigned int cpu = smp_processor_id(); 399ccea7a19SRussell King struct stack *stk = &stacks[cpu]; 400ccea7a19SRussell King 401ccea7a19SRussell King if (cpu >= NR_CPUS) { 402ccea7a19SRussell King printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); 403ccea7a19SRussell King BUG(); 404ccea7a19SRussell King } 405ccea7a19SRussell King 406ccea7a19SRussell King /* 407b86040a5SCatalin Marinas * Define the placement constraint for the inline asm directive below. 408b86040a5SCatalin Marinas * In Thumb-2, msr with an immediate value is not allowed. 409b86040a5SCatalin Marinas */ 410b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL 411b86040a5SCatalin Marinas #define PLC "r" 412b86040a5SCatalin Marinas #else 413b86040a5SCatalin Marinas #define PLC "I" 414b86040a5SCatalin Marinas #endif 415b86040a5SCatalin Marinas 416b86040a5SCatalin Marinas /* 417ccea7a19SRussell King * setup stacks for re-entrant exception handlers 418ccea7a19SRussell King */ 419ccea7a19SRussell King __asm__ ( 420ccea7a19SRussell King "msr cpsr_c, %1\n\t" 421b86040a5SCatalin Marinas "add r14, %0, %2\n\t" 422b86040a5SCatalin Marinas "mov sp, r14\n\t" 423ccea7a19SRussell King "msr cpsr_c, %3\n\t" 424b86040a5SCatalin Marinas "add r14, %0, %4\n\t" 425b86040a5SCatalin Marinas "mov sp, r14\n\t" 426ccea7a19SRussell King "msr cpsr_c, %5\n\t" 427b86040a5SCatalin Marinas "add r14, %0, %6\n\t" 428b86040a5SCatalin Marinas "mov sp, r14\n\t" 429ccea7a19SRussell King "msr cpsr_c, %7" 430ccea7a19SRussell King : 431ccea7a19SRussell King : "r" (stk), 432b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), 433ccea7a19SRussell King "I" (offsetof(struct stack, irq[0])), 434b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), 435ccea7a19SRussell King "I" (offsetof(struct stack, abt[0])), 436b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), 437ccea7a19SRussell King "I" (offsetof(struct stack, und[0])), 438b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) 439aaaa3f9eSCatalin Marinas : "r14"); 440ccea7a19SRussell King } 441ccea7a19SRussell King 4421da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr) 4431da177e4SLinus Torvalds { 444dce72dd0SNicolas Pitre extern struct machine_desc __arch_info_begin[], __arch_info_end[]; 445dce72dd0SNicolas Pitre struct machine_desc *p; 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds /* 4481da177e4SLinus Torvalds * locate machine in the list of supported machines. 4491da177e4SLinus Torvalds */ 450dce72dd0SNicolas Pitre for (p = __arch_info_begin; p < __arch_info_end; p++) 451dce72dd0SNicolas Pitre if (nr == p->nr) { 452dce72dd0SNicolas Pitre printk("Machine: %s\n", p->name); 453dce72dd0SNicolas Pitre return p; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 456dce72dd0SNicolas Pitre early_print("\n" 457dce72dd0SNicolas Pitre "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n" 458dce72dd0SNicolas Pitre "Available machine support:\n\nID (hex)\tNAME\n", nr); 4591da177e4SLinus Torvalds 460dce72dd0SNicolas Pitre for (p = __arch_info_begin; p < __arch_info_end; p++) 461dce72dd0SNicolas Pitre early_print("%08x\t%s\n", p->nr, p->name); 462dce72dd0SNicolas Pitre 463dce72dd0SNicolas Pitre early_print("\nPlease check your kernel config and/or bootloader.\n"); 464dce72dd0SNicolas Pitre 465dce72dd0SNicolas Pitre while (true) 466dce72dd0SNicolas Pitre /* can't use cpu_relax() here as it may require MMU setup */; 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 469f60892d3SWill Deacon static int __init arm_add_memory(phys_addr_t start, unsigned long size) 4703a669411SRussell King { 4714b5f32ceSNicolas Pitre struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 4724b5f32ceSNicolas Pitre 4734b5f32ceSNicolas Pitre if (meminfo.nr_banks >= NR_BANKS) { 4744b5f32ceSNicolas Pitre printk(KERN_CRIT "NR_BANKS too low, " 47529a38193SWill Deacon "ignoring memory at 0x%08llx\n", (long long)start); 4764b5f32ceSNicolas Pitre return -EINVAL; 4774b5f32ceSNicolas Pitre } 47805f96ef1SRussell King 4793a669411SRussell King /* 4803a669411SRussell King * Ensure that start/size are aligned to a page boundary. 4813a669411SRussell King * Size is appropriately rounded down, start is rounded up. 4823a669411SRussell King */ 4833a669411SRussell King size -= start & ~PAGE_MASK; 48405f96ef1SRussell King bank->start = PAGE_ALIGN(start); 48505f96ef1SRussell King bank->size = size & PAGE_MASK; 4864b5f32ceSNicolas Pitre 4874b5f32ceSNicolas Pitre /* 4884b5f32ceSNicolas Pitre * Check whether this memory region has non-zero size or 4894b5f32ceSNicolas Pitre * invalid node number. 4904b5f32ceSNicolas Pitre */ 491be370302SRussell King if (bank->size == 0) 4924b5f32ceSNicolas Pitre return -EINVAL; 4934b5f32ceSNicolas Pitre 4944b5f32ceSNicolas Pitre meminfo.nr_banks++; 4954b5f32ceSNicolas Pitre return 0; 4963a669411SRussell King } 4973a669411SRussell King 4981da177e4SLinus Torvalds /* 4991da177e4SLinus Torvalds * Pick out the memory size. We look for mem=size@start, 5001da177e4SLinus Torvalds * where start and size are "size[KkMm]" 5011da177e4SLinus Torvalds */ 5022b0d8c25SJeremy Kerr static int __init early_mem(char *p) 5031da177e4SLinus Torvalds { 5041da177e4SLinus Torvalds static int usermem __initdata = 0; 505f60892d3SWill Deacon unsigned long size; 506f60892d3SWill Deacon phys_addr_t start; 5072b0d8c25SJeremy Kerr char *endp; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /* 5101da177e4SLinus Torvalds * If the user specifies memory size, we 5111da177e4SLinus Torvalds * blow away any automatically generated 5121da177e4SLinus Torvalds * size. 5131da177e4SLinus Torvalds */ 5141da177e4SLinus Torvalds if (usermem == 0) { 5151da177e4SLinus Torvalds usermem = 1; 5161da177e4SLinus Torvalds meminfo.nr_banks = 0; 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds start = PHYS_OFFSET; 5202b0d8c25SJeremy Kerr size = memparse(p, &endp); 5212b0d8c25SJeremy Kerr if (*endp == '@') 5222b0d8c25SJeremy Kerr start = memparse(endp + 1, NULL); 5231da177e4SLinus Torvalds 5241c97b73eSAndrew Morton arm_add_memory(start, size); 5251da177e4SLinus Torvalds 5262b0d8c25SJeremy Kerr return 0; 5271da177e4SLinus Torvalds } 5282b0d8c25SJeremy Kerr early_param("mem", early_mem); 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds static void __init 5311da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM 5341da177e4SLinus Torvalds extern int rd_size, rd_image_start, rd_prompt, rd_doload; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds rd_image_start = image_start; 5371da177e4SLinus Torvalds rd_prompt = prompt; 5381da177e4SLinus Torvalds rd_doload = doload; 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds if (rd_sz) 5411da177e4SLinus Torvalds rd_size = rd_sz; 5421da177e4SLinus Torvalds #endif 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 54511b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc) 5461da177e4SLinus Torvalds { 54711b9369cSDima Zavin struct memblock_region *region; 5481da177e4SLinus Torvalds struct resource *res; 5491da177e4SLinus Torvalds 55037efe642SRussell King kernel_code.start = virt_to_phys(_text); 55137efe642SRussell King kernel_code.end = virt_to_phys(_etext - 1); 552842eab40SRussell King kernel_data.start = virt_to_phys(_sdata); 55337efe642SRussell King kernel_data.end = virt_to_phys(_end - 1); 5541da177e4SLinus Torvalds 55511b9369cSDima Zavin for_each_memblock(memory, region) { 5561da177e4SLinus Torvalds res = alloc_bootmem_low(sizeof(*res)); 5571da177e4SLinus Torvalds res->name = "System RAM"; 55811b9369cSDima Zavin res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 55911b9369cSDima Zavin res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 5601da177e4SLinus Torvalds res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds request_resource(&iomem_resource, res); 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds if (kernel_code.start >= res->start && 5651da177e4SLinus Torvalds kernel_code.end <= res->end) 5661da177e4SLinus Torvalds request_resource(res, &kernel_code); 5671da177e4SLinus Torvalds if (kernel_data.start >= res->start && 5681da177e4SLinus Torvalds kernel_data.end <= res->end) 5691da177e4SLinus Torvalds request_resource(res, &kernel_data); 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds if (mdesc->video_start) { 5731da177e4SLinus Torvalds video_ram.start = mdesc->video_start; 5741da177e4SLinus Torvalds video_ram.end = mdesc->video_end; 5751da177e4SLinus Torvalds request_resource(&iomem_resource, &video_ram); 5761da177e4SLinus Torvalds } 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds /* 5791da177e4SLinus Torvalds * Some machines don't have the possibility of ever 5801da177e4SLinus Torvalds * possessing lp0, lp1 or lp2 5811da177e4SLinus Torvalds */ 5821da177e4SLinus Torvalds if (mdesc->reserve_lp0) 5831da177e4SLinus Torvalds request_resource(&ioport_resource, &lp0); 5841da177e4SLinus Torvalds if (mdesc->reserve_lp1) 5851da177e4SLinus Torvalds request_resource(&ioport_resource, &lp1); 5861da177e4SLinus Torvalds if (mdesc->reserve_lp2) 5871da177e4SLinus Torvalds request_resource(&ioport_resource, &lp2); 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds /* 5911da177e4SLinus Torvalds * Tag parsing. 5921da177e4SLinus Torvalds * 5931da177e4SLinus Torvalds * This is the new way of passing data to the kernel at boot time. Rather 5941da177e4SLinus Torvalds * than passing a fixed inflexible structure to the kernel, we pass a list 5951da177e4SLinus Torvalds * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE 5961da177e4SLinus Torvalds * tag for the list to be recognised (to distinguish the tagged list from 5971da177e4SLinus Torvalds * a param_struct). The list is terminated with a zero-length tag (this tag 5981da177e4SLinus Torvalds * is not parsed in any way). 5991da177e4SLinus Torvalds */ 6001da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag) 6011da177e4SLinus Torvalds { 6021da177e4SLinus Torvalds if (tag->hdr.size > 2) { 6031da177e4SLinus Torvalds if ((tag->u.core.flags & 1) == 0) 6041da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY; 6051da177e4SLinus Torvalds ROOT_DEV = old_decode_dev(tag->u.core.rootdev); 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds return 0; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core); 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag) 6131da177e4SLinus Torvalds { 6144b5f32ceSNicolas Pitre return arm_add_memory(tag->u.mem.start, tag->u.mem.size); 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32); 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 6201da177e4SLinus Torvalds struct screen_info screen_info = { 6211da177e4SLinus Torvalds .orig_video_lines = 30, 6221da177e4SLinus Torvalds .orig_video_cols = 80, 6231da177e4SLinus Torvalds .orig_video_mode = 0, 6241da177e4SLinus Torvalds .orig_video_ega_bx = 0, 6251da177e4SLinus Torvalds .orig_video_isVGA = 1, 6261da177e4SLinus Torvalds .orig_video_points = 8 6271da177e4SLinus Torvalds }; 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag) 6301da177e4SLinus Torvalds { 6311da177e4SLinus Torvalds screen_info.orig_x = tag->u.videotext.x; 6321da177e4SLinus Torvalds screen_info.orig_y = tag->u.videotext.y; 6331da177e4SLinus Torvalds screen_info.orig_video_page = tag->u.videotext.video_page; 6341da177e4SLinus Torvalds screen_info.orig_video_mode = tag->u.videotext.video_mode; 6351da177e4SLinus Torvalds screen_info.orig_video_cols = tag->u.videotext.video_cols; 6361da177e4SLinus Torvalds screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; 6371da177e4SLinus Torvalds screen_info.orig_video_lines = tag->u.videotext.video_lines; 6381da177e4SLinus Torvalds screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; 6391da177e4SLinus Torvalds screen_info.orig_video_points = tag->u.videotext.video_points; 6401da177e4SLinus Torvalds return 0; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); 6441da177e4SLinus Torvalds #endif 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag) 6471da177e4SLinus Torvalds { 6481da177e4SLinus Torvalds setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, 6491da177e4SLinus Torvalds (tag->u.ramdisk.flags & 2) == 0, 6501da177e4SLinus Torvalds tag->u.ramdisk.start, tag->u.ramdisk.size); 6511da177e4SLinus Torvalds return 0; 6521da177e4SLinus Torvalds } 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk); 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag) 6571da177e4SLinus Torvalds { 6581da177e4SLinus Torvalds system_serial_low = tag->u.serialnr.low; 6591da177e4SLinus Torvalds system_serial_high = tag->u.serialnr.high; 6601da177e4SLinus Torvalds return 0; 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr); 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag) 6661da177e4SLinus Torvalds { 6671da177e4SLinus Torvalds system_rev = tag->u.revision.rev; 6681da177e4SLinus Torvalds return 0; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision); 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag) 6741da177e4SLinus Torvalds { 6754394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND) 6764394c124SVictor Boivie strlcat(default_command_line, " ", COMMAND_LINE_SIZE); 6774394c124SVictor Boivie strlcat(default_command_line, tag->u.cmdline.cmdline, 6784394c124SVictor Boivie COMMAND_LINE_SIZE); 6794394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE) 68022eeb8f6SAlexander Holler pr_warning("Ignoring tag cmdline (using the default kernel command line)\n"); 6814394c124SVictor Boivie #else 6824394c124SVictor Boivie strlcpy(default_command_line, tag->u.cmdline.cmdline, 6834394c124SVictor Boivie COMMAND_LINE_SIZE); 6844394c124SVictor Boivie #endif 6851da177e4SLinus Torvalds return 0; 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline); 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* 6911da177e4SLinus Torvalds * Scan the tag table for this tag, and call its parse function. 6921da177e4SLinus Torvalds * The tag table is built by the linker from all the __tagtable 6931da177e4SLinus Torvalds * declarations. 6941da177e4SLinus Torvalds */ 6951da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag) 6961da177e4SLinus Torvalds { 6971da177e4SLinus Torvalds extern struct tagtable __tagtable_begin, __tagtable_end; 6981da177e4SLinus Torvalds struct tagtable *t; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds for (t = &__tagtable_begin; t < &__tagtable_end; t++) 7011da177e4SLinus Torvalds if (tag->hdr.tag == t->tag) { 7021da177e4SLinus Torvalds t->parse(tag); 7031da177e4SLinus Torvalds break; 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds return t < &__tagtable_end; 7071da177e4SLinus Torvalds } 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds /* 7101da177e4SLinus Torvalds * Parse all tags in the list, checking both the global and architecture 7111da177e4SLinus Torvalds * specific tag tables. 7121da177e4SLinus Torvalds */ 7131da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t) 7141da177e4SLinus Torvalds { 7151da177e4SLinus Torvalds for (; t->hdr.size; t = tag_next(t)) 7161da177e4SLinus Torvalds if (!parse_tag(t)) 7171da177e4SLinus Torvalds printk(KERN_WARNING 7181da177e4SLinus Torvalds "Ignoring unrecognised tag 0x%08x\n", 7191da177e4SLinus Torvalds t->hdr.tag); 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds /* 7231da177e4SLinus Torvalds * This holds our defaults. 7241da177e4SLinus Torvalds */ 7251da177e4SLinus Torvalds static struct init_tags { 7261da177e4SLinus Torvalds struct tag_header hdr1; 7271da177e4SLinus Torvalds struct tag_core core; 7281da177e4SLinus Torvalds struct tag_header hdr2; 7291da177e4SLinus Torvalds struct tag_mem32 mem; 7301da177e4SLinus Torvalds struct tag_header hdr3; 7311da177e4SLinus Torvalds } init_tags __initdata = { 7321da177e4SLinus Torvalds { tag_size(tag_core), ATAG_CORE }, 7331da177e4SLinus Torvalds { 1, PAGE_SIZE, 0xff }, 7341da177e4SLinus Torvalds { tag_size(tag_mem32), ATAG_MEM }, 735b75c178aSRussell King { MEM_SIZE }, 7361da177e4SLinus Torvalds { 0, ATAG_NONE } 7371da177e4SLinus Torvalds }; 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds static int __init customize_machine(void) 7401da177e4SLinus Torvalds { 7411da177e4SLinus Torvalds /* customizes platform devices, or adds new ones */ 7428ff1443cSRussell King if (machine_desc->init_machine) 7438ff1443cSRussell King machine_desc->init_machine(); 7441da177e4SLinus Torvalds return 0; 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds arch_initcall(customize_machine); 7471da177e4SLinus Torvalds 7483c57fb43SMika Westerberg #ifdef CONFIG_KEXEC 7493c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void) 7503c57fb43SMika Westerberg { 7513c57fb43SMika Westerberg unsigned long total; 7523c57fb43SMika Westerberg 7533c57fb43SMika Westerberg total = max_low_pfn - min_low_pfn; 7543c57fb43SMika Westerberg return total << PAGE_SHIFT; 7553c57fb43SMika Westerberg } 7563c57fb43SMika Westerberg 7573c57fb43SMika Westerberg /** 7583c57fb43SMika Westerberg * reserve_crashkernel() - reserves memory are for crash kernel 7593c57fb43SMika Westerberg * 7603c57fb43SMika Westerberg * This function reserves memory area given in "crashkernel=" kernel command 7613c57fb43SMika Westerberg * line parameter. The memory reserved is used by a dump capture kernel when 7623c57fb43SMika Westerberg * primary kernel is crashing. 7633c57fb43SMika Westerberg */ 7643c57fb43SMika Westerberg static void __init reserve_crashkernel(void) 7653c57fb43SMika Westerberg { 7663c57fb43SMika Westerberg unsigned long long crash_size, crash_base; 7673c57fb43SMika Westerberg unsigned long long total_mem; 7683c57fb43SMika Westerberg int ret; 7693c57fb43SMika Westerberg 7703c57fb43SMika Westerberg total_mem = get_total_mem(); 7713c57fb43SMika Westerberg ret = parse_crashkernel(boot_command_line, total_mem, 7723c57fb43SMika Westerberg &crash_size, &crash_base); 7733c57fb43SMika Westerberg if (ret) 7743c57fb43SMika Westerberg return; 7753c57fb43SMika Westerberg 7763c57fb43SMika Westerberg ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE); 7773c57fb43SMika Westerberg if (ret < 0) { 7783c57fb43SMika Westerberg printk(KERN_WARNING "crashkernel reservation failed - " 7793c57fb43SMika Westerberg "memory is in use (0x%lx)\n", (unsigned long)crash_base); 7803c57fb43SMika Westerberg return; 7813c57fb43SMika Westerberg } 7823c57fb43SMika Westerberg 7833c57fb43SMika Westerberg printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " 7843c57fb43SMika Westerberg "for crashkernel (System RAM: %ldMB)\n", 7853c57fb43SMika Westerberg (unsigned long)(crash_size >> 20), 7863c57fb43SMika Westerberg (unsigned long)(crash_base >> 20), 7873c57fb43SMika Westerberg (unsigned long)(total_mem >> 20)); 7883c57fb43SMika Westerberg 7893c57fb43SMika Westerberg crashk_res.start = crash_base; 7903c57fb43SMika Westerberg crashk_res.end = crash_base + crash_size - 1; 7913c57fb43SMika Westerberg insert_resource(&iomem_resource, &crashk_res); 7923c57fb43SMika Westerberg } 7933c57fb43SMika Westerberg #else 7943c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {} 7953c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */ 7963c57fb43SMika Westerberg 79773a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag) 79873a65b3fSUwe Kleine-König { 79973a65b3fSUwe Kleine-König for (; tag->hdr.size; tag = tag_next(tag)) 80073a65b3fSUwe Kleine-König if (tag->hdr.tag == ATAG_MEM) 80173a65b3fSUwe Kleine-König tag->hdr.tag = ATAG_NONE; 80273a65b3fSUwe Kleine-König } 80373a65b3fSUwe Kleine-König 8041da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p) 8051da177e4SLinus Torvalds { 8061da177e4SLinus Torvalds struct tag *tags = (struct tag *)&init_tags; 8071da177e4SLinus Torvalds struct machine_desc *mdesc; 8081da177e4SLinus Torvalds char *from = default_command_line; 8091da177e4SLinus Torvalds 810b75c178aSRussell King init_tags.mem.start = PHYS_OFFSET; 811b75c178aSRussell King 812bff595c1SCatalin Marinas unwind_init(); 813bff595c1SCatalin Marinas 8141da177e4SLinus Torvalds setup_processor(); 8151da177e4SLinus Torvalds mdesc = setup_machine(machine_arch_type); 8168ff1443cSRussell King machine_desc = mdesc; 8171da177e4SLinus Torvalds machine_name = mdesc->name; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds if (mdesc->soft_reboot) 8201da177e4SLinus Torvalds reboot_setup("s"); 8211da177e4SLinus Torvalds 8229d20fdd5SBill Gatliff if (__atags_pointer) 8239d20fdd5SBill Gatliff tags = phys_to_virt(__atags_pointer); 8243572bea8SNicolas Pitre else if (mdesc->boot_params) { 8253572bea8SNicolas Pitre #ifdef CONFIG_MMU 8263572bea8SNicolas Pitre /* 8273572bea8SNicolas Pitre * We still are executing with a minimal MMU mapping created 8283572bea8SNicolas Pitre * with the presumption that the machine default for this 8293572bea8SNicolas Pitre * is located in the first MB of RAM. Anything else will 8303572bea8SNicolas Pitre * fault and silently hang the kernel at this point. 8313572bea8SNicolas Pitre */ 8323572bea8SNicolas Pitre if (mdesc->boot_params < PHYS_OFFSET || 8333572bea8SNicolas Pitre mdesc->boot_params >= PHYS_OFFSET + SZ_1M) { 8343572bea8SNicolas Pitre printk(KERN_WARNING 8353572bea8SNicolas Pitre "Default boot params at physical 0x%08lx out of reach\n", 8363572bea8SNicolas Pitre mdesc->boot_params); 8373572bea8SNicolas Pitre } else 8383572bea8SNicolas Pitre #endif 8393572bea8SNicolas Pitre { 840f9bd6ea4SRussell King tags = phys_to_virt(mdesc->boot_params); 8413572bea8SNicolas Pitre } 8423572bea8SNicolas Pitre } 8431da177e4SLinus Torvalds 84473a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 8451da177e4SLinus Torvalds /* 8461da177e4SLinus Torvalds * If we have the old style parameters, convert them to 8471da177e4SLinus Torvalds * a tag list. 8481da177e4SLinus Torvalds */ 8491da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 8501da177e4SLinus Torvalds convert_to_tag_list(tags); 85173a65b3fSUwe Kleine-König #endif 8521da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 8531da177e4SLinus Torvalds tags = (struct tag *)&init_tags; 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds if (mdesc->fixup) 8561da177e4SLinus Torvalds mdesc->fixup(mdesc, tags, &from, &meminfo); 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds if (tags->hdr.tag == ATAG_CORE) { 8591da177e4SLinus Torvalds if (meminfo.nr_banks != 0) 8601da177e4SLinus Torvalds squash_mem_tags(tags); 8614cd9d6f7SRichard Purdie save_atags(tags); 8621da177e4SLinus Torvalds parse_tags(tags); 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds 86537efe642SRussell King init_mm.start_code = (unsigned long) _text; 86637efe642SRussell King init_mm.end_code = (unsigned long) _etext; 86737efe642SRussell King init_mm.end_data = (unsigned long) _edata; 86837efe642SRussell King init_mm.brk = (unsigned long) _end; 8691da177e4SLinus Torvalds 8702b0d8c25SJeremy Kerr /* parse_early_param needs a boot_command_line */ 8712b0d8c25SJeremy Kerr strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); 8722b0d8c25SJeremy Kerr 87348ab7e09SJeremy Kerr /* populate cmd_line too for later use, preserving boot_command_line */ 87448ab7e09SJeremy Kerr strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 87548ab7e09SJeremy Kerr *cmdline_p = cmd_line; 8762b0d8c25SJeremy Kerr 8772b0d8c25SJeremy Kerr parse_early_param(); 8782b0d8c25SJeremy Kerr 8798d717a52SRussell King arm_memblock_init(&meminfo, mdesc); 8802778f620SRussell King 8814b5f32ceSNicolas Pitre paging_init(mdesc); 88211b9369cSDima Zavin request_standard_resources(mdesc); 8831da177e4SLinus Torvalds 8847bbb7940SRussell King #ifdef CONFIG_SMP 885f00ec48fSRussell King if (is_smp()) 8867bbb7940SRussell King smp_init_cpus(); 8877bbb7940SRussell King #endif 8883c57fb43SMika Westerberg reserve_crashkernel(); 8897bbb7940SRussell King 890ccea7a19SRussell King cpu_init(); 891bc581770SLinus Walleij tcm_init(); 892ccea7a19SRussell King 89352108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER 89452108641Seric miao handle_arch_irq = mdesc->handle_irq; 89552108641Seric miao #endif 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds #ifdef CONFIG_VT 8981da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) 8991da177e4SLinus Torvalds conswitchp = &vga_con; 9001da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE) 9011da177e4SLinus Torvalds conswitchp = &dummy_con; 9021da177e4SLinus Torvalds #endif 9031da177e4SLinus Torvalds #endif 9045cbad0ebSJason Wessel early_trap_init(); 905dec12e62SRussell King 906dec12e62SRussell King if (mdesc->init_early) 907dec12e62SRussell King mdesc->init_early(); 9081da177e4SLinus Torvalds } 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds static int __init topology_init(void) 9121da177e4SLinus Torvalds { 9131da177e4SLinus Torvalds int cpu; 9141da177e4SLinus Torvalds 91566fb8bd2SRussell King for_each_possible_cpu(cpu) { 91666fb8bd2SRussell King struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); 91766fb8bd2SRussell King cpuinfo->cpu.hotpluggable = 1; 91866fb8bd2SRussell King register_cpu(&cpuinfo->cpu, cpu); 91966fb8bd2SRussell King } 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds return 0; 9221da177e4SLinus Torvalds } 9231da177e4SLinus Torvalds subsys_initcall(topology_init); 9241da177e4SLinus Torvalds 925e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU 926e119bfffSRussell King static int __init proc_cpu_init(void) 927e119bfffSRussell King { 928e119bfffSRussell King struct proc_dir_entry *res; 929e119bfffSRussell King 930e119bfffSRussell King res = proc_mkdir("cpu", NULL); 931e119bfffSRussell King if (!res) 932e119bfffSRussell King return -ENOMEM; 933e119bfffSRussell King return 0; 934e119bfffSRussell King } 935e119bfffSRussell King fs_initcall(proc_cpu_init); 936e119bfffSRussell King #endif 937e119bfffSRussell King 9381da177e4SLinus Torvalds static const char *hwcap_str[] = { 9391da177e4SLinus Torvalds "swp", 9401da177e4SLinus Torvalds "half", 9411da177e4SLinus Torvalds "thumb", 9421da177e4SLinus Torvalds "26bit", 9431da177e4SLinus Torvalds "fastmult", 9441da177e4SLinus Torvalds "fpa", 9451da177e4SLinus Torvalds "vfp", 9461da177e4SLinus Torvalds "edsp", 9471da177e4SLinus Torvalds "java", 9488f7f9435SPaul Gortmaker "iwmmxt", 94999e4a6ddSLennert Buytenhek "crunch", 9504369ae16SCatalin Marinas "thumbee", 9512bedbdf4SCatalin Marinas "neon", 9527279dc3eSCatalin Marinas "vfpv3", 9537279dc3eSCatalin Marinas "vfpv3d16", 9541da177e4SLinus Torvalds NULL 9551da177e4SLinus Torvalds }; 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v) 9581da177e4SLinus Torvalds { 9591da177e4SLinus Torvalds int i; 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds seq_printf(m, "Processor\t: %s rev %d (%s)\n", 9620ba8b9b2SRussell King cpu_name, read_cpuid_id() & 15, elf_platform); 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds #if defined(CONFIG_SMP) 9651da177e4SLinus Torvalds for_each_online_cpu(i) { 96615559722SRussell King /* 96715559722SRussell King * glibc reads /proc/cpuinfo to determine the number of 96815559722SRussell King * online processors, looking for lines beginning with 96915559722SRussell King * "processor". Give glibc what it expects. 97015559722SRussell King */ 97115559722SRussell King seq_printf(m, "processor\t: %d\n", i); 9721da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 9731da177e4SLinus Torvalds per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), 9741da177e4SLinus Torvalds (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds #else /* CONFIG_SMP */ 9771da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", 9781da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ), 9791da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100); 9801da177e4SLinus Torvalds #endif 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds /* dump out the processor features */ 9831da177e4SLinus Torvalds seq_puts(m, "Features\t: "); 9841da177e4SLinus Torvalds 9851da177e4SLinus Torvalds for (i = 0; hwcap_str[i]; i++) 9861da177e4SLinus Torvalds if (elf_hwcap & (1 << i)) 9871da177e4SLinus Torvalds seq_printf(m, "%s ", hwcap_str[i]); 9881da177e4SLinus Torvalds 9890ba8b9b2SRussell King seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 9901da177e4SLinus Torvalds seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); 9911da177e4SLinus Torvalds 9920ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00000000) { 9931da177e4SLinus Torvalds /* pre-ARM7 */ 9940ba8b9b2SRussell King seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4); 9951da177e4SLinus Torvalds } else { 9960ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 9971da177e4SLinus Torvalds /* ARM7 */ 9981da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%02x\n", 9990ba8b9b2SRussell King (read_cpuid_id() >> 16) & 127); 10001da177e4SLinus Torvalds } else { 10011da177e4SLinus Torvalds /* post-ARM7 */ 10021da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%x\n", 10030ba8b9b2SRussell King (read_cpuid_id() >> 20) & 15); 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds seq_printf(m, "CPU part\t: 0x%03x\n", 10060ba8b9b2SRussell King (read_cpuid_id() >> 4) & 0xfff); 10071da177e4SLinus Torvalds } 10080ba8b9b2SRussell King seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds seq_puts(m, "\n"); 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds seq_printf(m, "Hardware\t: %s\n", machine_name); 10131da177e4SLinus Torvalds seq_printf(m, "Revision\t: %04x\n", system_rev); 10141da177e4SLinus Torvalds seq_printf(m, "Serial\t\t: %08x%08x\n", 10151da177e4SLinus Torvalds system_serial_high, system_serial_low); 10161da177e4SLinus Torvalds 10171da177e4SLinus Torvalds return 0; 10181da177e4SLinus Torvalds } 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 10211da177e4SLinus Torvalds { 10221da177e4SLinus Torvalds return *pos < 1 ? (void *)1 : NULL; 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 10261da177e4SLinus Torvalds { 10271da177e4SLinus Torvalds ++*pos; 10281da177e4SLinus Torvalds return NULL; 10291da177e4SLinus Torvalds } 10301da177e4SLinus Torvalds 10311da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 10321da177e4SLinus Torvalds { 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds 10352ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = { 10361da177e4SLinus Torvalds .start = c_start, 10371da177e4SLinus Torvalds .next = c_next, 10381da177e4SLinus Torvalds .stop = c_stop, 10391da177e4SLinus Torvalds .show = c_show 10401da177e4SLinus Torvalds }; 1041