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> 24cea0bb1bSMika Westerberg #include <linux/crash_dump.h> 251da177e4SLinus Torvalds #include <linux/root_dev.h> 261da177e4SLinus Torvalds #include <linux/cpu.h> 271da177e4SLinus Torvalds #include <linux/interrupt.h> 287bbb7940SRussell King #include <linux/smp.h> 294e950f6fSAlexey Dobriyan #include <linux/fs.h> 30e119bfffSRussell King #include <linux/proc_fs.h> 312778f620SRussell King #include <linux/memblock.h> 322ecccf90SDave Martin #include <linux/bug.h> 332ecccf90SDave Martin #include <linux/compiler.h> 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> 551da177e4SLinus Torvalds 5673a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 570fc1c832SBen Dooks #include "compat.h" 5873a65b3fSUwe Kleine-König #endif 594cd9d6f7SRichard Purdie #include "atags.h" 60bc581770SLinus Walleij #include "tcm.h" 610fc1c832SBen Dooks 621da177e4SLinus Torvalds #ifndef MEM_SIZE 631da177e4SLinus Torvalds #define MEM_SIZE (16*1024*1024) 641da177e4SLinus Torvalds #endif 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) 671da177e4SLinus Torvalds char fpe_type[8]; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static int __init fpe_setup(char *line) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds memcpy(fpe_type, line, 8); 721da177e4SLinus Torvalds return 1; 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds __setup("fpe=", fpe_setup); 761da177e4SLinus Torvalds #endif 771da177e4SLinus Torvalds 784b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc); 790371d3f7SRussell King extern void sanity_check_meminfo(void); 801da177e4SLinus Torvalds extern void reboot_setup(char *str); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds unsigned int processor_id; 83c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id); 840385ebc0SRussell King unsigned int __machine_arch_type __read_mostly; 851da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type); 860385ebc0SRussell King unsigned int cacheid __read_mostly; 87c0e95878SRussell King EXPORT_SYMBOL(cacheid); 881da177e4SLinus Torvalds 899d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata; 909d20fdd5SBill Gatliff 911da177e4SLinus Torvalds unsigned int system_rev; 921da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds unsigned int system_serial_low; 951da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low); 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds unsigned int system_serial_high; 981da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high); 991da177e4SLinus Torvalds 1000385ebc0SRussell King unsigned int elf_hwcap __read_mostly; 1011da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap); 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds #ifdef MULTI_CPU 1050385ebc0SRussell King struct processor processor __read_mostly; 1061da177e4SLinus Torvalds #endif 1071da177e4SLinus Torvalds #ifdef MULTI_TLB 1080385ebc0SRussell King struct cpu_tlb_fns cpu_tlb __read_mostly; 1091da177e4SLinus Torvalds #endif 1101da177e4SLinus Torvalds #ifdef MULTI_USER 1110385ebc0SRussell King struct cpu_user_fns cpu_user __read_mostly; 1121da177e4SLinus Torvalds #endif 1131da177e4SLinus Torvalds #ifdef MULTI_CACHE 1140385ebc0SRussell King struct cpu_cache_fns cpu_cache __read_mostly; 1151da177e4SLinus Torvalds #endif 116953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE 1170385ebc0SRussell King struct outer_cache_fns outer_cache __read_mostly; 1186c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache); 119953233dcSCatalin Marinas #endif 1201da177e4SLinus Torvalds 1212ecccf90SDave Martin /* 1222ecccf90SDave Martin * Cached cpu_architecture() result for use by assembler code. 1232ecccf90SDave Martin * C code should use the cpu_architecture() function instead of accessing this 1242ecccf90SDave Martin * variable directly. 1252ecccf90SDave Martin */ 1262ecccf90SDave Martin int __cpu_architecture __read_mostly = CPU_ARCH_UNKNOWN; 1272ecccf90SDave Martin 128ccea7a19SRussell King struct stack { 129ccea7a19SRussell King u32 irq[3]; 130ccea7a19SRussell King u32 abt[3]; 131ccea7a19SRussell King u32 und[3]; 132ccea7a19SRussell King } ____cacheline_aligned; 133ccea7a19SRussell King 134ccea7a19SRussell King static struct stack stacks[NR_CPUS]; 135ccea7a19SRussell King 1361da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE]; 1371da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static const char *cpu_name; 1401da177e4SLinus Torvalds static const char *machine_name; 14148ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE]; 1428ff1443cSRussell King struct machine_desc *machine_desc __initdata; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; 1451da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; 1461da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l) 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* 1511da177e4SLinus Torvalds * Standard memory resources 1521da177e4SLinus Torvalds */ 1531da177e4SLinus Torvalds static struct resource mem_res[] = { 154740e518eSGreg Kroah-Hartman { 155740e518eSGreg Kroah-Hartman .name = "Video RAM", 156740e518eSGreg Kroah-Hartman .start = 0, 157740e518eSGreg Kroah-Hartman .end = 0, 158740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 159740e518eSGreg Kroah-Hartman }, 160740e518eSGreg Kroah-Hartman { 161740e518eSGreg Kroah-Hartman .name = "Kernel text", 162740e518eSGreg Kroah-Hartman .start = 0, 163740e518eSGreg Kroah-Hartman .end = 0, 164740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 165740e518eSGreg Kroah-Hartman }, 166740e518eSGreg Kroah-Hartman { 167740e518eSGreg Kroah-Hartman .name = "Kernel data", 168740e518eSGreg Kroah-Hartman .start = 0, 169740e518eSGreg Kroah-Hartman .end = 0, 170740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 171740e518eSGreg Kroah-Hartman } 1721da177e4SLinus Torvalds }; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds #define video_ram mem_res[0] 1751da177e4SLinus Torvalds #define kernel_code mem_res[1] 1761da177e4SLinus Torvalds #define kernel_data mem_res[2] 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds static struct resource io_res[] = { 179740e518eSGreg Kroah-Hartman { 180740e518eSGreg Kroah-Hartman .name = "reserved", 181740e518eSGreg Kroah-Hartman .start = 0x3bc, 182740e518eSGreg Kroah-Hartman .end = 0x3be, 183740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 184740e518eSGreg Kroah-Hartman }, 185740e518eSGreg Kroah-Hartman { 186740e518eSGreg Kroah-Hartman .name = "reserved", 187740e518eSGreg Kroah-Hartman .start = 0x378, 188740e518eSGreg Kroah-Hartman .end = 0x37f, 189740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 190740e518eSGreg Kroah-Hartman }, 191740e518eSGreg Kroah-Hartman { 192740e518eSGreg Kroah-Hartman .name = "reserved", 193740e518eSGreg Kroah-Hartman .start = 0x278, 194740e518eSGreg Kroah-Hartman .end = 0x27f, 195740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 196740e518eSGreg Kroah-Hartman } 1971da177e4SLinus Torvalds }; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds #define lp0 io_res[0] 2001da177e4SLinus Torvalds #define lp1 io_res[1] 2011da177e4SLinus Torvalds #define lp2 io_res[2] 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds static const char *proc_arch[] = { 2041da177e4SLinus Torvalds "undefined/unknown", 2051da177e4SLinus Torvalds "3", 2061da177e4SLinus Torvalds "4", 2071da177e4SLinus Torvalds "4T", 2081da177e4SLinus Torvalds "5", 2091da177e4SLinus Torvalds "5T", 2101da177e4SLinus Torvalds "5TE", 2111da177e4SLinus Torvalds "5TEJ", 2121da177e4SLinus Torvalds "6TEJ", 2136b090a25SCatalin Marinas "7", 2141da177e4SLinus Torvalds "?(11)", 2151da177e4SLinus Torvalds "?(12)", 2161da177e4SLinus Torvalds "?(13)", 2171da177e4SLinus Torvalds "?(14)", 2181da177e4SLinus Torvalds "?(15)", 2191da177e4SLinus Torvalds "?(16)", 2201da177e4SLinus Torvalds "?(17)", 2211da177e4SLinus Torvalds }; 2221da177e4SLinus Torvalds 2232ecccf90SDave Martin static int __get_cpu_architecture(void) 2241da177e4SLinus Torvalds { 2251da177e4SLinus Torvalds int cpu_arch; 2261da177e4SLinus Torvalds 2270ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0) { 2281da177e4SLinus Torvalds cpu_arch = CPU_ARCH_UNKNOWN; 2290ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 2300ba8b9b2SRussell King cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; 2310ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { 2320ba8b9b2SRussell King cpu_arch = (read_cpuid_id() >> 16) & 7; 2331da177e4SLinus Torvalds if (cpu_arch) 2341da177e4SLinus Torvalds cpu_arch += CPU_ARCH_ARMv3; 2350ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 236180005c4SCatalin Marinas unsigned int mmfr0; 237180005c4SCatalin Marinas 238180005c4SCatalin Marinas /* Revised CPUID format. Read the Memory Model Feature 239180005c4SCatalin Marinas * Register 0 and check for VMSAv7 or PMSAv7 */ 240180005c4SCatalin Marinas asm("mrc p15, 0, %0, c0, c1, 4" 241180005c4SCatalin Marinas : "=r" (mmfr0)); 242315cfe78SCatalin Marinas if ((mmfr0 & 0x0000000f) >= 0x00000003 || 243315cfe78SCatalin Marinas (mmfr0 & 0x000000f0) >= 0x00000030) 244180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv7; 245180005c4SCatalin Marinas else if ((mmfr0 & 0x0000000f) == 0x00000002 || 246180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000020) 247180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv6; 248180005c4SCatalin Marinas else 249180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 250180005c4SCatalin Marinas } else 251180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds return cpu_arch; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2562ecccf90SDave Martin int __pure cpu_architecture(void) 2572ecccf90SDave Martin { 2582ecccf90SDave Martin BUG_ON(__cpu_architecture == CPU_ARCH_UNKNOWN); 2592ecccf90SDave Martin 2602ecccf90SDave Martin return __cpu_architecture; 2612ecccf90SDave Martin } 2622ecccf90SDave Martin 2638925ec4cSWill Deacon static int cpu_has_aliasing_icache(unsigned int arch) 2648925ec4cSWill Deacon { 2658925ec4cSWill Deacon int aliasing_icache; 2668925ec4cSWill Deacon unsigned int id_reg, num_sets, line_size; 2678925ec4cSWill Deacon 2687f94e9ccSWill Deacon /* PIPT caches never alias. */ 2697f94e9ccSWill Deacon if (icache_is_pipt()) 2707f94e9ccSWill Deacon return 0; 2717f94e9ccSWill Deacon 2728925ec4cSWill Deacon /* arch specifies the register format */ 2738925ec4cSWill Deacon switch (arch) { 2748925ec4cSWill Deacon case CPU_ARCH_ARMv7: 2755fb31a96SLinus Walleij asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR" 2765fb31a96SLinus Walleij : /* No output operands */ 2778925ec4cSWill Deacon : "r" (1)); 2785fb31a96SLinus Walleij isb(); 2795fb31a96SLinus Walleij asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" 2805fb31a96SLinus Walleij : "=r" (id_reg)); 2818925ec4cSWill Deacon line_size = 4 << ((id_reg & 0x7) + 2); 2828925ec4cSWill Deacon num_sets = ((id_reg >> 13) & 0x7fff) + 1; 2838925ec4cSWill Deacon aliasing_icache = (line_size * num_sets) > PAGE_SIZE; 2848925ec4cSWill Deacon break; 2858925ec4cSWill Deacon case CPU_ARCH_ARMv6: 2868925ec4cSWill Deacon aliasing_icache = read_cpuid_cachetype() & (1 << 11); 2878925ec4cSWill Deacon break; 2888925ec4cSWill Deacon default: 2898925ec4cSWill Deacon /* I-cache aliases will be handled by D-cache aliasing code */ 2908925ec4cSWill Deacon aliasing_icache = 0; 2918925ec4cSWill Deacon } 2928925ec4cSWill Deacon 2938925ec4cSWill Deacon return aliasing_icache; 2948925ec4cSWill Deacon } 2958925ec4cSWill Deacon 296c0e95878SRussell King static void __init cacheid_init(void) 297c0e95878SRussell King { 298c0e95878SRussell King unsigned int cachetype = read_cpuid_cachetype(); 299c0e95878SRussell King unsigned int arch = cpu_architecture(); 300c0e95878SRussell King 301b57ee99fSCatalin Marinas if (arch >= CPU_ARCH_ARMv6) { 302b57ee99fSCatalin Marinas if ((cachetype & (7 << 29)) == 4 << 29) { 303b57ee99fSCatalin Marinas /* ARMv7 register format */ 30472dc53acSWill Deacon arch = CPU_ARCH_ARMv7; 305c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 3067f94e9ccSWill Deacon switch (cachetype & (3 << 14)) { 3077f94e9ccSWill Deacon case (1 << 14): 308c0e95878SRussell King cacheid |= CACHEID_ASID_TAGGED; 3097f94e9ccSWill Deacon break; 3107f94e9ccSWill Deacon case (3 << 14): 3117f94e9ccSWill Deacon cacheid |= CACHEID_PIPT; 3127f94e9ccSWill Deacon break; 3137f94e9ccSWill Deacon } 3148925ec4cSWill Deacon } else { 31572dc53acSWill Deacon arch = CPU_ARCH_ARMv6; 31672dc53acSWill Deacon if (cachetype & (1 << 23)) 31772dc53acSWill Deacon cacheid = CACHEID_VIPT_ALIASING; 31872dc53acSWill Deacon else 319c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 3208925ec4cSWill Deacon } 32172dc53acSWill Deacon if (cpu_has_aliasing_icache(arch)) 32272dc53acSWill Deacon cacheid |= CACHEID_VIPT_I_ALIASING; 323c0e95878SRussell King } else { 324c0e95878SRussell King cacheid = CACHEID_VIVT; 325c0e95878SRussell King } 3262b4ae1f1SRussell King 3272b4ae1f1SRussell King printk("CPU: %s data cache, %s instruction cache\n", 3282b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 3292b4ae1f1SRussell King cache_is_vipt_aliasing() ? "VIPT aliasing" : 3307f94e9ccSWill Deacon cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown", 3312b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 3322b4ae1f1SRussell King icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : 3338925ec4cSWill Deacon icache_is_vipt_aliasing() ? "VIPT aliasing" : 3347f94e9ccSWill Deacon icache_is_pipt() ? "PIPT" : 3352b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); 336c0e95878SRussell King } 337c0e95878SRussell King 3381da177e4SLinus Torvalds /* 3391da177e4SLinus Torvalds * These functions re-use the assembly code in head.S, which 3401da177e4SLinus Torvalds * already provide the required functionality. 3411da177e4SLinus Torvalds */ 3420f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int); 3436fc31d54SRussell King 34493c02ab4SGrant Likely void __init early_print(const char *str, ...) 3456fc31d54SRussell King { 3466fc31d54SRussell King extern void printascii(const char *); 3476fc31d54SRussell King char buf[256]; 3486fc31d54SRussell King va_list ap; 3496fc31d54SRussell King 3506fc31d54SRussell King va_start(ap, str); 3516fc31d54SRussell King vsnprintf(buf, sizeof(buf), str, ap); 3526fc31d54SRussell King va_end(ap); 3536fc31d54SRussell King 3546fc31d54SRussell King #ifdef CONFIG_DEBUG_LL 3556fc31d54SRussell King printascii(buf); 3566fc31d54SRussell King #endif 3576fc31d54SRussell King printk("%s", buf); 3586fc31d54SRussell King } 3596fc31d54SRussell King 360f159f4edSTony Lindgren static void __init feat_v6_fixup(void) 361f159f4edSTony Lindgren { 362f159f4edSTony Lindgren int id = read_cpuid_id(); 363f159f4edSTony Lindgren 364f159f4edSTony Lindgren if ((id & 0xff0f0000) != 0x41070000) 365f159f4edSTony Lindgren return; 366f159f4edSTony Lindgren 367f159f4edSTony Lindgren /* 368f159f4edSTony Lindgren * HWCAP_TLS is available only on 1136 r1p0 and later, 369f159f4edSTony Lindgren * see also kuser_get_tls_init. 370f159f4edSTony Lindgren */ 371f159f4edSTony Lindgren if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0)) 372f159f4edSTony Lindgren elf_hwcap &= ~HWCAP_TLS; 373f159f4edSTony Lindgren } 374f159f4edSTony Lindgren 375b69874e4SRussell King /* 376b69874e4SRussell King * cpu_init - initialise one CPU. 377b69874e4SRussell King * 378b69874e4SRussell King * cpu_init sets up the per-CPU stacks. 379b69874e4SRussell King */ 380b69874e4SRussell King void cpu_init(void) 381b69874e4SRussell King { 382b69874e4SRussell King unsigned int cpu = smp_processor_id(); 383b69874e4SRussell King struct stack *stk = &stacks[cpu]; 384b69874e4SRussell King 385b69874e4SRussell King if (cpu >= NR_CPUS) { 386b69874e4SRussell King printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); 387b69874e4SRussell King BUG(); 388b69874e4SRussell King } 389b69874e4SRussell King 390b69874e4SRussell King cpu_proc_init(); 391b69874e4SRussell King 392b69874e4SRussell King /* 393b69874e4SRussell King * Define the placement constraint for the inline asm directive below. 394b69874e4SRussell King * In Thumb-2, msr with an immediate value is not allowed. 395b69874e4SRussell King */ 396b69874e4SRussell King #ifdef CONFIG_THUMB2_KERNEL 397b69874e4SRussell King #define PLC "r" 398b69874e4SRussell King #else 399b69874e4SRussell King #define PLC "I" 400b69874e4SRussell King #endif 401b69874e4SRussell King 402b69874e4SRussell King /* 403b69874e4SRussell King * setup stacks for re-entrant exception handlers 404b69874e4SRussell King */ 405b69874e4SRussell King __asm__ ( 406b69874e4SRussell King "msr cpsr_c, %1\n\t" 407b69874e4SRussell King "add r14, %0, %2\n\t" 408b69874e4SRussell King "mov sp, r14\n\t" 409b69874e4SRussell King "msr cpsr_c, %3\n\t" 410b69874e4SRussell King "add r14, %0, %4\n\t" 411b69874e4SRussell King "mov sp, r14\n\t" 412b69874e4SRussell King "msr cpsr_c, %5\n\t" 413b69874e4SRussell King "add r14, %0, %6\n\t" 414b69874e4SRussell King "mov sp, r14\n\t" 415b69874e4SRussell King "msr cpsr_c, %7" 416b69874e4SRussell King : 417b69874e4SRussell King : "r" (stk), 418b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), 419b69874e4SRussell King "I" (offsetof(struct stack, irq[0])), 420b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), 421b69874e4SRussell King "I" (offsetof(struct stack, abt[0])), 422b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), 423b69874e4SRussell King "I" (offsetof(struct stack, und[0])), 424b69874e4SRussell King PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) 425b69874e4SRussell King : "r14"); 426b69874e4SRussell King } 427b69874e4SRussell King 4281da177e4SLinus Torvalds static void __init setup_processor(void) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds struct proc_info_list *list; 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds /* 4331da177e4SLinus Torvalds * locate processor in the list of supported processor 4341da177e4SLinus Torvalds * types. The linker builds this table for us from the 4351da177e4SLinus Torvalds * entries in arch/arm/mm/proc-*.S 4361da177e4SLinus Torvalds */ 4370ba8b9b2SRussell King list = lookup_processor_type(read_cpuid_id()); 4381da177e4SLinus Torvalds if (!list) { 4391da177e4SLinus Torvalds printk("CPU configuration botched (ID %08x), unable " 4400ba8b9b2SRussell King "to continue.\n", read_cpuid_id()); 4411da177e4SLinus Torvalds while (1); 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds cpu_name = list->cpu_name; 4452ecccf90SDave Martin __cpu_architecture = __get_cpu_architecture(); 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds #ifdef MULTI_CPU 4481da177e4SLinus Torvalds processor = *list->proc; 4491da177e4SLinus Torvalds #endif 4501da177e4SLinus Torvalds #ifdef MULTI_TLB 4511da177e4SLinus Torvalds cpu_tlb = *list->tlb; 4521da177e4SLinus Torvalds #endif 4531da177e4SLinus Torvalds #ifdef MULTI_USER 4541da177e4SLinus Torvalds cpu_user = *list->user; 4551da177e4SLinus Torvalds #endif 4561da177e4SLinus Torvalds #ifdef MULTI_CACHE 4571da177e4SLinus Torvalds cpu_cache = *list->cache; 4581da177e4SLinus Torvalds #endif 4591da177e4SLinus Torvalds 4604e19025bSRussell King printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 4610ba8b9b2SRussell King cpu_name, read_cpuid_id(), read_cpuid_id() & 15, 462264edb35SRussell King proc_arch[cpu_architecture()], cr_alignment); 4631da177e4SLinus Torvalds 464a34dbfb0SWill Deacon snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c", 465a34dbfb0SWill Deacon list->arch_name, ENDIANNESS); 466a34dbfb0SWill Deacon snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c", 467a34dbfb0SWill Deacon list->elf_name, ENDIANNESS); 4681da177e4SLinus Torvalds elf_hwcap = list->elf_hwcap; 469adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB 470adeff422SCatalin Marinas elf_hwcap &= ~HWCAP_THUMB; 471adeff422SCatalin Marinas #endif 4721da177e4SLinus Torvalds 473f159f4edSTony Lindgren feat_v6_fixup(); 474f159f4edSTony Lindgren 475c0e95878SRussell King cacheid_init(); 476b69874e4SRussell King cpu_init(); 477ccea7a19SRussell King } 478ccea7a19SRussell King 47993c02ab4SGrant Likely void __init dump_machine_table(void) 4801da177e4SLinus Torvalds { 481dce72dd0SNicolas Pitre struct machine_desc *p; 4821da177e4SLinus Torvalds 4836291319dSGrant Likely early_print("Available machine support:\n\nID (hex)\tNAME\n"); 4846291319dSGrant Likely for_each_machine_desc(p) 485dce72dd0SNicolas Pitre early_print("%08x\t%s\n", p->nr, p->name); 486dce72dd0SNicolas Pitre 487dce72dd0SNicolas Pitre early_print("\nPlease check your kernel config and/or bootloader.\n"); 488dce72dd0SNicolas Pitre 489dce72dd0SNicolas Pitre while (true) 490dce72dd0SNicolas Pitre /* can't use cpu_relax() here as it may require MMU setup */; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4939eb8f674SGrant Likely int __init arm_add_memory(phys_addr_t start, unsigned long size) 4943a669411SRussell King { 4954b5f32ceSNicolas Pitre struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 4964b5f32ceSNicolas Pitre 4974b5f32ceSNicolas Pitre if (meminfo.nr_banks >= NR_BANKS) { 4984b5f32ceSNicolas Pitre printk(KERN_CRIT "NR_BANKS too low, " 49929a38193SWill Deacon "ignoring memory at 0x%08llx\n", (long long)start); 5004b5f32ceSNicolas Pitre return -EINVAL; 5014b5f32ceSNicolas Pitre } 50205f96ef1SRussell King 5033a669411SRussell King /* 5043a669411SRussell King * Ensure that start/size are aligned to a page boundary. 5053a669411SRussell King * Size is appropriately rounded down, start is rounded up. 5063a669411SRussell King */ 5073a669411SRussell King size -= start & ~PAGE_MASK; 50805f96ef1SRussell King bank->start = PAGE_ALIGN(start); 50905f96ef1SRussell King bank->size = size & PAGE_MASK; 5104b5f32ceSNicolas Pitre 5114b5f32ceSNicolas Pitre /* 5124b5f32ceSNicolas Pitre * Check whether this memory region has non-zero size or 5134b5f32ceSNicolas Pitre * invalid node number. 5144b5f32ceSNicolas Pitre */ 515be370302SRussell King if (bank->size == 0) 5164b5f32ceSNicolas Pitre return -EINVAL; 5174b5f32ceSNicolas Pitre 5184b5f32ceSNicolas Pitre meminfo.nr_banks++; 5194b5f32ceSNicolas Pitre return 0; 5203a669411SRussell King } 5213a669411SRussell King 5221da177e4SLinus Torvalds /* 5231da177e4SLinus Torvalds * Pick out the memory size. We look for mem=size@start, 5241da177e4SLinus Torvalds * where start and size are "size[KkMm]" 5251da177e4SLinus Torvalds */ 5262b0d8c25SJeremy Kerr static int __init early_mem(char *p) 5271da177e4SLinus Torvalds { 5281da177e4SLinus Torvalds static int usermem __initdata = 0; 529f60892d3SWill Deacon unsigned long size; 530f60892d3SWill Deacon phys_addr_t start; 5312b0d8c25SJeremy Kerr char *endp; 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds /* 5341da177e4SLinus Torvalds * If the user specifies memory size, we 5351da177e4SLinus Torvalds * blow away any automatically generated 5361da177e4SLinus Torvalds * size. 5371da177e4SLinus Torvalds */ 5381da177e4SLinus Torvalds if (usermem == 0) { 5391da177e4SLinus Torvalds usermem = 1; 5401da177e4SLinus Torvalds meminfo.nr_banks = 0; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds start = PHYS_OFFSET; 5442b0d8c25SJeremy Kerr size = memparse(p, &endp); 5452b0d8c25SJeremy Kerr if (*endp == '@') 5462b0d8c25SJeremy Kerr start = memparse(endp + 1, NULL); 5471da177e4SLinus Torvalds 5481c97b73eSAndrew Morton arm_add_memory(start, size); 5491da177e4SLinus Torvalds 5502b0d8c25SJeremy Kerr return 0; 5511da177e4SLinus Torvalds } 5522b0d8c25SJeremy Kerr early_param("mem", early_mem); 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds static void __init 5551da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) 5561da177e4SLinus Torvalds { 5571da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM 5581da177e4SLinus Torvalds extern int rd_size, rd_image_start, rd_prompt, rd_doload; 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds rd_image_start = image_start; 5611da177e4SLinus Torvalds rd_prompt = prompt; 5621da177e4SLinus Torvalds rd_doload = doload; 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds if (rd_sz) 5651da177e4SLinus Torvalds rd_size = rd_sz; 5661da177e4SLinus Torvalds #endif 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 56911b9369cSDima Zavin static void __init request_standard_resources(struct machine_desc *mdesc) 5701da177e4SLinus Torvalds { 57111b9369cSDima Zavin struct memblock_region *region; 5721da177e4SLinus Torvalds struct resource *res; 5731da177e4SLinus Torvalds 57437efe642SRussell King kernel_code.start = virt_to_phys(_text); 57537efe642SRussell King kernel_code.end = virt_to_phys(_etext - 1); 576842eab40SRussell King kernel_data.start = virt_to_phys(_sdata); 57737efe642SRussell King kernel_data.end = virt_to_phys(_end - 1); 5781da177e4SLinus Torvalds 57911b9369cSDima Zavin for_each_memblock(memory, region) { 5801da177e4SLinus Torvalds res = alloc_bootmem_low(sizeof(*res)); 5811da177e4SLinus Torvalds res->name = "System RAM"; 58211b9369cSDima Zavin res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); 58311b9369cSDima Zavin res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; 5841da177e4SLinus Torvalds res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds request_resource(&iomem_resource, res); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds if (kernel_code.start >= res->start && 5891da177e4SLinus Torvalds kernel_code.end <= res->end) 5901da177e4SLinus Torvalds request_resource(res, &kernel_code); 5911da177e4SLinus Torvalds if (kernel_data.start >= res->start && 5921da177e4SLinus Torvalds kernel_data.end <= res->end) 5931da177e4SLinus Torvalds request_resource(res, &kernel_data); 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds if (mdesc->video_start) { 5971da177e4SLinus Torvalds video_ram.start = mdesc->video_start; 5981da177e4SLinus Torvalds video_ram.end = mdesc->video_end; 5991da177e4SLinus Torvalds request_resource(&iomem_resource, &video_ram); 6001da177e4SLinus Torvalds } 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* 6031da177e4SLinus Torvalds * Some machines don't have the possibility of ever 6041da177e4SLinus Torvalds * possessing lp0, lp1 or lp2 6051da177e4SLinus Torvalds */ 6061da177e4SLinus Torvalds if (mdesc->reserve_lp0) 6071da177e4SLinus Torvalds request_resource(&ioport_resource, &lp0); 6081da177e4SLinus Torvalds if (mdesc->reserve_lp1) 6091da177e4SLinus Torvalds request_resource(&ioport_resource, &lp1); 6101da177e4SLinus Torvalds if (mdesc->reserve_lp2) 6111da177e4SLinus Torvalds request_resource(&ioport_resource, &lp2); 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds /* 6151da177e4SLinus Torvalds * Tag parsing. 6161da177e4SLinus Torvalds * 6171da177e4SLinus Torvalds * This is the new way of passing data to the kernel at boot time. Rather 6181da177e4SLinus Torvalds * than passing a fixed inflexible structure to the kernel, we pass a list 6191da177e4SLinus Torvalds * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE 6201da177e4SLinus Torvalds * tag for the list to be recognised (to distinguish the tagged list from 6211da177e4SLinus Torvalds * a param_struct). The list is terminated with a zero-length tag (this tag 6221da177e4SLinus Torvalds * is not parsed in any way). 6231da177e4SLinus Torvalds */ 6241da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag) 6251da177e4SLinus Torvalds { 6261da177e4SLinus Torvalds if (tag->hdr.size > 2) { 6271da177e4SLinus Torvalds if ((tag->u.core.flags & 1) == 0) 6281da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY; 6291da177e4SLinus Torvalds ROOT_DEV = old_decode_dev(tag->u.core.rootdev); 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds return 0; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core); 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag) 6371da177e4SLinus Torvalds { 6384b5f32ceSNicolas Pitre return arm_add_memory(tag->u.mem.start, tag->u.mem.size); 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32); 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 6441da177e4SLinus Torvalds struct screen_info screen_info = { 6451da177e4SLinus Torvalds .orig_video_lines = 30, 6461da177e4SLinus Torvalds .orig_video_cols = 80, 6471da177e4SLinus Torvalds .orig_video_mode = 0, 6481da177e4SLinus Torvalds .orig_video_ega_bx = 0, 6491da177e4SLinus Torvalds .orig_video_isVGA = 1, 6501da177e4SLinus Torvalds .orig_video_points = 8 6511da177e4SLinus Torvalds }; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag) 6541da177e4SLinus Torvalds { 6551da177e4SLinus Torvalds screen_info.orig_x = tag->u.videotext.x; 6561da177e4SLinus Torvalds screen_info.orig_y = tag->u.videotext.y; 6571da177e4SLinus Torvalds screen_info.orig_video_page = tag->u.videotext.video_page; 6581da177e4SLinus Torvalds screen_info.orig_video_mode = tag->u.videotext.video_mode; 6591da177e4SLinus Torvalds screen_info.orig_video_cols = tag->u.videotext.video_cols; 6601da177e4SLinus Torvalds screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; 6611da177e4SLinus Torvalds screen_info.orig_video_lines = tag->u.videotext.video_lines; 6621da177e4SLinus Torvalds screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; 6631da177e4SLinus Torvalds screen_info.orig_video_points = tag->u.videotext.video_points; 6641da177e4SLinus Torvalds return 0; 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); 6681da177e4SLinus Torvalds #endif 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag) 6711da177e4SLinus Torvalds { 6721da177e4SLinus Torvalds setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, 6731da177e4SLinus Torvalds (tag->u.ramdisk.flags & 2) == 0, 6741da177e4SLinus Torvalds tag->u.ramdisk.start, tag->u.ramdisk.size); 6751da177e4SLinus Torvalds return 0; 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk); 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag) 6811da177e4SLinus Torvalds { 6821da177e4SLinus Torvalds system_serial_low = tag->u.serialnr.low; 6831da177e4SLinus Torvalds system_serial_high = tag->u.serialnr.high; 6841da177e4SLinus Torvalds return 0; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr); 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag) 6901da177e4SLinus Torvalds { 6911da177e4SLinus Torvalds system_rev = tag->u.revision.rev; 6921da177e4SLinus Torvalds return 0; 6931da177e4SLinus Torvalds } 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision); 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag) 6981da177e4SLinus Torvalds { 6994394c124SVictor Boivie #if defined(CONFIG_CMDLINE_EXTEND) 7004394c124SVictor Boivie strlcat(default_command_line, " ", COMMAND_LINE_SIZE); 7014394c124SVictor Boivie strlcat(default_command_line, tag->u.cmdline.cmdline, 7024394c124SVictor Boivie COMMAND_LINE_SIZE); 7034394c124SVictor Boivie #elif defined(CONFIG_CMDLINE_FORCE) 70422eeb8f6SAlexander Holler pr_warning("Ignoring tag cmdline (using the default kernel command line)\n"); 7054394c124SVictor Boivie #else 7064394c124SVictor Boivie strlcpy(default_command_line, tag->u.cmdline.cmdline, 7074394c124SVictor Boivie COMMAND_LINE_SIZE); 7084394c124SVictor Boivie #endif 7091da177e4SLinus Torvalds return 0; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline); 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds /* 7151da177e4SLinus Torvalds * Scan the tag table for this tag, and call its parse function. 7161da177e4SLinus Torvalds * The tag table is built by the linker from all the __tagtable 7171da177e4SLinus Torvalds * declarations. 7181da177e4SLinus Torvalds */ 7191da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag) 7201da177e4SLinus Torvalds { 7211da177e4SLinus Torvalds extern struct tagtable __tagtable_begin, __tagtable_end; 7221da177e4SLinus Torvalds struct tagtable *t; 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds for (t = &__tagtable_begin; t < &__tagtable_end; t++) 7251da177e4SLinus Torvalds if (tag->hdr.tag == t->tag) { 7261da177e4SLinus Torvalds t->parse(tag); 7271da177e4SLinus Torvalds break; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds return t < &__tagtable_end; 7311da177e4SLinus Torvalds } 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds /* 7341da177e4SLinus Torvalds * Parse all tags in the list, checking both the global and architecture 7351da177e4SLinus Torvalds * specific tag tables. 7361da177e4SLinus Torvalds */ 7371da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t) 7381da177e4SLinus Torvalds { 7391da177e4SLinus Torvalds for (; t->hdr.size; t = tag_next(t)) 7401da177e4SLinus Torvalds if (!parse_tag(t)) 7411da177e4SLinus Torvalds printk(KERN_WARNING 7421da177e4SLinus Torvalds "Ignoring unrecognised tag 0x%08x\n", 7431da177e4SLinus Torvalds t->hdr.tag); 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds /* 7471da177e4SLinus Torvalds * This holds our defaults. 7481da177e4SLinus Torvalds */ 7491da177e4SLinus Torvalds static struct init_tags { 7501da177e4SLinus Torvalds struct tag_header hdr1; 7511da177e4SLinus Torvalds struct tag_core core; 7521da177e4SLinus Torvalds struct tag_header hdr2; 7531da177e4SLinus Torvalds struct tag_mem32 mem; 7541da177e4SLinus Torvalds struct tag_header hdr3; 7551da177e4SLinus Torvalds } init_tags __initdata = { 7561da177e4SLinus Torvalds { tag_size(tag_core), ATAG_CORE }, 7571da177e4SLinus Torvalds { 1, PAGE_SIZE, 0xff }, 7581da177e4SLinus Torvalds { tag_size(tag_mem32), ATAG_MEM }, 759b75c178aSRussell King { MEM_SIZE }, 7601da177e4SLinus Torvalds { 0, ATAG_NONE } 7611da177e4SLinus Torvalds }; 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds static int __init customize_machine(void) 7641da177e4SLinus Torvalds { 7651da177e4SLinus Torvalds /* customizes platform devices, or adds new ones */ 7668ff1443cSRussell King if (machine_desc->init_machine) 7678ff1443cSRussell King machine_desc->init_machine(); 7681da177e4SLinus Torvalds return 0; 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds arch_initcall(customize_machine); 7711da177e4SLinus Torvalds 7723c57fb43SMika Westerberg #ifdef CONFIG_KEXEC 7733c57fb43SMika Westerberg static inline unsigned long long get_total_mem(void) 7743c57fb43SMika Westerberg { 7753c57fb43SMika Westerberg unsigned long total; 7763c57fb43SMika Westerberg 7773c57fb43SMika Westerberg total = max_low_pfn - min_low_pfn; 7783c57fb43SMika Westerberg return total << PAGE_SHIFT; 7793c57fb43SMika Westerberg } 7803c57fb43SMika Westerberg 7813c57fb43SMika Westerberg /** 7823c57fb43SMika Westerberg * reserve_crashkernel() - reserves memory are for crash kernel 7833c57fb43SMika Westerberg * 7843c57fb43SMika Westerberg * This function reserves memory area given in "crashkernel=" kernel command 7853c57fb43SMika Westerberg * line parameter. The memory reserved is used by a dump capture kernel when 7863c57fb43SMika Westerberg * primary kernel is crashing. 7873c57fb43SMika Westerberg */ 7883c57fb43SMika Westerberg static void __init reserve_crashkernel(void) 7893c57fb43SMika Westerberg { 7903c57fb43SMika Westerberg unsigned long long crash_size, crash_base; 7913c57fb43SMika Westerberg unsigned long long total_mem; 7923c57fb43SMika Westerberg int ret; 7933c57fb43SMika Westerberg 7943c57fb43SMika Westerberg total_mem = get_total_mem(); 7953c57fb43SMika Westerberg ret = parse_crashkernel(boot_command_line, total_mem, 7963c57fb43SMika Westerberg &crash_size, &crash_base); 7973c57fb43SMika Westerberg if (ret) 7983c57fb43SMika Westerberg return; 7993c57fb43SMika Westerberg 8003c57fb43SMika Westerberg ret = reserve_bootmem(crash_base, crash_size, BOOTMEM_EXCLUSIVE); 8013c57fb43SMika Westerberg if (ret < 0) { 8023c57fb43SMika Westerberg printk(KERN_WARNING "crashkernel reservation failed - " 8033c57fb43SMika Westerberg "memory is in use (0x%lx)\n", (unsigned long)crash_base); 8043c57fb43SMika Westerberg return; 8053c57fb43SMika Westerberg } 8063c57fb43SMika Westerberg 8073c57fb43SMika Westerberg printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " 8083c57fb43SMika Westerberg "for crashkernel (System RAM: %ldMB)\n", 8093c57fb43SMika Westerberg (unsigned long)(crash_size >> 20), 8103c57fb43SMika Westerberg (unsigned long)(crash_base >> 20), 8113c57fb43SMika Westerberg (unsigned long)(total_mem >> 20)); 8123c57fb43SMika Westerberg 8133c57fb43SMika Westerberg crashk_res.start = crash_base; 8143c57fb43SMika Westerberg crashk_res.end = crash_base + crash_size - 1; 8153c57fb43SMika Westerberg insert_resource(&iomem_resource, &crashk_res); 8163c57fb43SMika Westerberg } 8173c57fb43SMika Westerberg #else 8183c57fb43SMika Westerberg static inline void reserve_crashkernel(void) {} 8193c57fb43SMika Westerberg #endif /* CONFIG_KEXEC */ 8203c57fb43SMika Westerberg 82173a65b3fSUwe Kleine-König static void __init squash_mem_tags(struct tag *tag) 82273a65b3fSUwe Kleine-König { 82373a65b3fSUwe Kleine-König for (; tag->hdr.size; tag = tag_next(tag)) 82473a65b3fSUwe Kleine-König if (tag->hdr.tag == ATAG_MEM) 82573a65b3fSUwe Kleine-König tag->hdr.tag = ATAG_NONE; 82673a65b3fSUwe Kleine-König } 82773a65b3fSUwe Kleine-König 8286291319dSGrant Likely static struct machine_desc * __init setup_machine_tags(unsigned int nr) 8291da177e4SLinus Torvalds { 8301da177e4SLinus Torvalds struct tag *tags = (struct tag *)&init_tags; 8316291319dSGrant Likely struct machine_desc *mdesc = NULL, *p; 8321da177e4SLinus Torvalds char *from = default_command_line; 8331da177e4SLinus Torvalds 834b75c178aSRussell King init_tags.mem.start = PHYS_OFFSET; 835b75c178aSRussell King 8366291319dSGrant Likely /* 8376291319dSGrant Likely * locate machine in the list of supported machines. 8386291319dSGrant Likely */ 8396291319dSGrant Likely for_each_machine_desc(p) 8406291319dSGrant Likely if (nr == p->nr) { 8416291319dSGrant Likely printk("Machine: %s\n", p->name); 8426291319dSGrant Likely mdesc = p; 8436291319dSGrant Likely break; 8446291319dSGrant Likely } 845bff595c1SCatalin Marinas 8466291319dSGrant Likely if (!mdesc) { 8476291319dSGrant Likely early_print("\nError: unrecognized/unsupported machine ID" 8486291319dSGrant Likely " (r1 = 0x%08x).\n\n", nr); 8496291319dSGrant Likely dump_machine_table(); /* does not return */ 8506291319dSGrant Likely } 8511da177e4SLinus Torvalds 8529d20fdd5SBill Gatliff if (__atags_pointer) 8539d20fdd5SBill Gatliff tags = phys_to_virt(__atags_pointer); 8542bb9839eSNicolas Pitre else if (mdesc->atag_offset) 8552bb9839eSNicolas Pitre tags = (void *)(PAGE_OFFSET + mdesc->atag_offset); 8561da177e4SLinus Torvalds 85773a65b3fSUwe Kleine-König #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 8581da177e4SLinus Torvalds /* 8591da177e4SLinus Torvalds * If we have the old style parameters, convert them to 8601da177e4SLinus Torvalds * a tag list. 8611da177e4SLinus Torvalds */ 8621da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 8631da177e4SLinus Torvalds convert_to_tag_list(tags); 86473a65b3fSUwe Kleine-König #endif 86593c02ab4SGrant Likely 86693c02ab4SGrant Likely if (tags->hdr.tag != ATAG_CORE) { 86793c02ab4SGrant Likely #if defined(CONFIG_OF) 86893c02ab4SGrant Likely /* 86993c02ab4SGrant Likely * If CONFIG_OF is set, then assume this is a reasonably 87093c02ab4SGrant Likely * modern system that should pass boot parameters 87193c02ab4SGrant Likely */ 87293c02ab4SGrant Likely early_print("Warning: Neither atags nor dtb found\n"); 87393c02ab4SGrant Likely #endif 8741da177e4SLinus Torvalds tags = (struct tag *)&init_tags; 87593c02ab4SGrant Likely } 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds if (mdesc->fixup) 8780744a3eeSRussell King mdesc->fixup(tags, &from, &meminfo); 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds if (tags->hdr.tag == ATAG_CORE) { 8811da177e4SLinus Torvalds if (meminfo.nr_banks != 0) 8821da177e4SLinus Torvalds squash_mem_tags(tags); 8834cd9d6f7SRichard Purdie save_atags(tags); 8841da177e4SLinus Torvalds parse_tags(tags); 8851da177e4SLinus Torvalds } 8861da177e4SLinus Torvalds 8876291319dSGrant Likely /* parse_early_param needs a boot_command_line */ 8886291319dSGrant Likely strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); 8896291319dSGrant Likely 8906291319dSGrant Likely return mdesc; 8916291319dSGrant Likely } 8926291319dSGrant Likely 8936291319dSGrant Likely 8946291319dSGrant Likely void __init setup_arch(char **cmdline_p) 8956291319dSGrant Likely { 8966291319dSGrant Likely struct machine_desc *mdesc; 8976291319dSGrant Likely 8986291319dSGrant Likely setup_processor(); 89993c02ab4SGrant Likely mdesc = setup_machine_fdt(__atags_pointer); 90093c02ab4SGrant Likely if (!mdesc) 9016291319dSGrant Likely mdesc = setup_machine_tags(machine_arch_type); 9026291319dSGrant Likely machine_desc = mdesc; 9036291319dSGrant Likely machine_name = mdesc->name; 9046291319dSGrant Likely 9059811ccdfSArnaud Patard #ifdef CONFIG_ZONE_DMA 9069811ccdfSArnaud Patard if (mdesc->dma_zone_size) { 9079811ccdfSArnaud Patard extern unsigned long arm_dma_zone_size; 9089811ccdfSArnaud Patard arm_dma_zone_size = mdesc->dma_zone_size; 9099811ccdfSArnaud Patard } 9109811ccdfSArnaud Patard #endif 9116291319dSGrant Likely if (mdesc->soft_reboot) 9126291319dSGrant Likely reboot_setup("s"); 9136291319dSGrant Likely 91437efe642SRussell King init_mm.start_code = (unsigned long) _text; 91537efe642SRussell King init_mm.end_code = (unsigned long) _etext; 91637efe642SRussell King init_mm.end_data = (unsigned long) _edata; 91737efe642SRussell King init_mm.brk = (unsigned long) _end; 9181da177e4SLinus Torvalds 91948ab7e09SJeremy Kerr /* populate cmd_line too for later use, preserving boot_command_line */ 92048ab7e09SJeremy Kerr strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 92148ab7e09SJeremy Kerr *cmdline_p = cmd_line; 9222b0d8c25SJeremy Kerr 9232b0d8c25SJeremy Kerr parse_early_param(); 9242b0d8c25SJeremy Kerr 9250371d3f7SRussell King sanity_check_meminfo(); 9268d717a52SRussell King arm_memblock_init(&meminfo, mdesc); 9272778f620SRussell King 9284b5f32ceSNicolas Pitre paging_init(mdesc); 92911b9369cSDima Zavin request_standard_resources(mdesc); 9301da177e4SLinus Torvalds 93193c02ab4SGrant Likely unflatten_device_tree(); 93293c02ab4SGrant Likely 9337bbb7940SRussell King #ifdef CONFIG_SMP 934f00ec48fSRussell King if (is_smp()) 9357bbb7940SRussell King smp_init_cpus(); 9367bbb7940SRussell King #endif 9373c57fb43SMika Westerberg reserve_crashkernel(); 9387bbb7940SRussell King 939bc581770SLinus Walleij tcm_init(); 940ccea7a19SRussell King 94152108641Seric miao #ifdef CONFIG_MULTI_IRQ_HANDLER 94252108641Seric miao handle_arch_irq = mdesc->handle_irq; 94352108641Seric miao #endif 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds #ifdef CONFIG_VT 9461da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) 9471da177e4SLinus Torvalds conswitchp = &vga_con; 9481da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE) 9491da177e4SLinus Torvalds conswitchp = &dummy_con; 9501da177e4SLinus Torvalds #endif 9511da177e4SLinus Torvalds #endif 9525cbad0ebSJason Wessel early_trap_init(); 953dec12e62SRussell King 954dec12e62SRussell King if (mdesc->init_early) 955dec12e62SRussell King mdesc->init_early(); 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds static int __init topology_init(void) 9601da177e4SLinus Torvalds { 9611da177e4SLinus Torvalds int cpu; 9621da177e4SLinus Torvalds 96366fb8bd2SRussell King for_each_possible_cpu(cpu) { 96466fb8bd2SRussell King struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); 96566fb8bd2SRussell King cpuinfo->cpu.hotpluggable = 1; 96666fb8bd2SRussell King register_cpu(&cpuinfo->cpu, cpu); 96766fb8bd2SRussell King } 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds return 0; 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds subsys_initcall(topology_init); 9721da177e4SLinus Torvalds 973e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU 974e119bfffSRussell King static int __init proc_cpu_init(void) 975e119bfffSRussell King { 976e119bfffSRussell King struct proc_dir_entry *res; 977e119bfffSRussell King 978e119bfffSRussell King res = proc_mkdir("cpu", NULL); 979e119bfffSRussell King if (!res) 980e119bfffSRussell King return -ENOMEM; 981e119bfffSRussell King return 0; 982e119bfffSRussell King } 983e119bfffSRussell King fs_initcall(proc_cpu_init); 984e119bfffSRussell King #endif 985e119bfffSRussell King 9861da177e4SLinus Torvalds static const char *hwcap_str[] = { 9871da177e4SLinus Torvalds "swp", 9881da177e4SLinus Torvalds "half", 9891da177e4SLinus Torvalds "thumb", 9901da177e4SLinus Torvalds "26bit", 9911da177e4SLinus Torvalds "fastmult", 9921da177e4SLinus Torvalds "fpa", 9931da177e4SLinus Torvalds "vfp", 9941da177e4SLinus Torvalds "edsp", 9951da177e4SLinus Torvalds "java", 9968f7f9435SPaul Gortmaker "iwmmxt", 99799e4a6ddSLennert Buytenhek "crunch", 9984369ae16SCatalin Marinas "thumbee", 9992bedbdf4SCatalin Marinas "neon", 10007279dc3eSCatalin Marinas "vfpv3", 10017279dc3eSCatalin Marinas "vfpv3d16", 1002254cdf8eSWill Deacon "tls", 1003254cdf8eSWill Deacon "vfpv4", 1004254cdf8eSWill Deacon "idiva", 1005254cdf8eSWill Deacon "idivt", 10061da177e4SLinus Torvalds NULL 10071da177e4SLinus Torvalds }; 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v) 10101da177e4SLinus Torvalds { 10111da177e4SLinus Torvalds int i; 10121da177e4SLinus Torvalds 10131da177e4SLinus Torvalds seq_printf(m, "Processor\t: %s rev %d (%s)\n", 10140ba8b9b2SRussell King cpu_name, read_cpuid_id() & 15, elf_platform); 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds #if defined(CONFIG_SMP) 10171da177e4SLinus Torvalds for_each_online_cpu(i) { 101815559722SRussell King /* 101915559722SRussell King * glibc reads /proc/cpuinfo to determine the number of 102015559722SRussell King * online processors, looking for lines beginning with 102115559722SRussell King * "processor". Give glibc what it expects. 102215559722SRussell King */ 102315559722SRussell King seq_printf(m, "processor\t: %d\n", i); 10241da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 10251da177e4SLinus Torvalds per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), 10261da177e4SLinus Torvalds (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); 10271da177e4SLinus Torvalds } 10281da177e4SLinus Torvalds #else /* CONFIG_SMP */ 10291da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", 10301da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ), 10311da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100); 10321da177e4SLinus Torvalds #endif 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds /* dump out the processor features */ 10351da177e4SLinus Torvalds seq_puts(m, "Features\t: "); 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds for (i = 0; hwcap_str[i]; i++) 10381da177e4SLinus Torvalds if (elf_hwcap & (1 << i)) 10391da177e4SLinus Torvalds seq_printf(m, "%s ", hwcap_str[i]); 10401da177e4SLinus Torvalds 10410ba8b9b2SRussell King seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 10421da177e4SLinus Torvalds seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); 10431da177e4SLinus Torvalds 10440ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00000000) { 10451da177e4SLinus Torvalds /* pre-ARM7 */ 10460ba8b9b2SRussell King seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4); 10471da177e4SLinus Torvalds } else { 10480ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 10491da177e4SLinus Torvalds /* ARM7 */ 10501da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%02x\n", 10510ba8b9b2SRussell King (read_cpuid_id() >> 16) & 127); 10521da177e4SLinus Torvalds } else { 10531da177e4SLinus Torvalds /* post-ARM7 */ 10541da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%x\n", 10550ba8b9b2SRussell King (read_cpuid_id() >> 20) & 15); 10561da177e4SLinus Torvalds } 10571da177e4SLinus Torvalds seq_printf(m, "CPU part\t: 0x%03x\n", 10580ba8b9b2SRussell King (read_cpuid_id() >> 4) & 0xfff); 10591da177e4SLinus Torvalds } 10600ba8b9b2SRussell King seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds seq_puts(m, "\n"); 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds seq_printf(m, "Hardware\t: %s\n", machine_name); 10651da177e4SLinus Torvalds seq_printf(m, "Revision\t: %04x\n", system_rev); 10661da177e4SLinus Torvalds seq_printf(m, "Serial\t\t: %08x%08x\n", 10671da177e4SLinus Torvalds system_serial_high, system_serial_low); 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds return 0; 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 10731da177e4SLinus Torvalds { 10741da177e4SLinus Torvalds return *pos < 1 ? (void *)1 : NULL; 10751da177e4SLinus Torvalds } 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 10781da177e4SLinus Torvalds { 10791da177e4SLinus Torvalds ++*pos; 10801da177e4SLinus Torvalds return NULL; 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 10841da177e4SLinus Torvalds { 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds 10872ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = { 10881da177e4SLinus Torvalds .start = c_start, 10891da177e4SLinus Torvalds .next = c_next, 10901da177e4SLinus Torvalds .stop = c_stop, 10911da177e4SLinus Torvalds .show = c_show 10921da177e4SLinus Torvalds }; 1093