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> 221da177e4SLinus Torvalds #include <linux/root_dev.h> 231da177e4SLinus Torvalds #include <linux/cpu.h> 241da177e4SLinus Torvalds #include <linux/interrupt.h> 257bbb7940SRussell King #include <linux/smp.h> 264e950f6fSAlexey Dobriyan #include <linux/fs.h> 27e119bfffSRussell King #include <linux/proc_fs.h> 281da177e4SLinus Torvalds 29b86040a5SCatalin Marinas #include <asm/unified.h> 301da177e4SLinus Torvalds #include <asm/cpu.h> 310ba8b9b2SRussell King #include <asm/cputype.h> 321da177e4SLinus Torvalds #include <asm/elf.h> 331da177e4SLinus Torvalds #include <asm/procinfo.h> 3437efe642SRussell King #include <asm/sections.h> 351da177e4SLinus Torvalds #include <asm/setup.h> 361da177e4SLinus Torvalds #include <asm/mach-types.h> 371da177e4SLinus Torvalds #include <asm/cacheflush.h> 3846097c7dSRussell King #include <asm/cachetype.h> 391da177e4SLinus Torvalds #include <asm/tlbflush.h> 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds #include <asm/mach/arch.h> 421da177e4SLinus Torvalds #include <asm/mach/irq.h> 431da177e4SLinus Torvalds #include <asm/mach/time.h> 445cbad0ebSJason Wessel #include <asm/traps.h> 45bff595c1SCatalin Marinas #include <asm/unwind.h> 461da177e4SLinus Torvalds 470fc1c832SBen Dooks #include "compat.h" 484cd9d6f7SRichard Purdie #include "atags.h" 49bc581770SLinus Walleij #include "tcm.h" 500fc1c832SBen Dooks 511da177e4SLinus Torvalds #ifndef MEM_SIZE 521da177e4SLinus Torvalds #define MEM_SIZE (16*1024*1024) 531da177e4SLinus Torvalds #endif 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE) 561da177e4SLinus Torvalds char fpe_type[8]; 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static int __init fpe_setup(char *line) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds memcpy(fpe_type, line, 8); 611da177e4SLinus Torvalds return 1; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds __setup("fpe=", fpe_setup); 651da177e4SLinus Torvalds #endif 661da177e4SLinus Torvalds 674b5f32ceSNicolas Pitre extern void paging_init(struct machine_desc *desc); 681da177e4SLinus Torvalds extern void reboot_setup(char *str); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds unsigned int processor_id; 71c18f6581SKrzysztof Halasa EXPORT_SYMBOL(processor_id); 721da177e4SLinus Torvalds unsigned int __machine_arch_type; 731da177e4SLinus Torvalds EXPORT_SYMBOL(__machine_arch_type); 74c0e95878SRussell King unsigned int cacheid; 75c0e95878SRussell King EXPORT_SYMBOL(cacheid); 761da177e4SLinus Torvalds 779d20fdd5SBill Gatliff unsigned int __atags_pointer __initdata; 789d20fdd5SBill Gatliff 791da177e4SLinus Torvalds unsigned int system_rev; 801da177e4SLinus Torvalds EXPORT_SYMBOL(system_rev); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds unsigned int system_serial_low; 831da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_low); 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds unsigned int system_serial_high; 861da177e4SLinus Torvalds EXPORT_SYMBOL(system_serial_high); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds unsigned int elf_hwcap; 891da177e4SLinus Torvalds EXPORT_SYMBOL(elf_hwcap); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds #ifdef MULTI_CPU 931da177e4SLinus Torvalds struct processor processor; 941da177e4SLinus Torvalds #endif 951da177e4SLinus Torvalds #ifdef MULTI_TLB 961da177e4SLinus Torvalds struct cpu_tlb_fns cpu_tlb; 971da177e4SLinus Torvalds #endif 981da177e4SLinus Torvalds #ifdef MULTI_USER 991da177e4SLinus Torvalds struct cpu_user_fns cpu_user; 1001da177e4SLinus Torvalds #endif 1011da177e4SLinus Torvalds #ifdef MULTI_CACHE 1021da177e4SLinus Torvalds struct cpu_cache_fns cpu_cache; 1031da177e4SLinus Torvalds #endif 104953233dcSCatalin Marinas #ifdef CONFIG_OUTER_CACHE 105953233dcSCatalin Marinas struct outer_cache_fns outer_cache; 1066c09f09dSSantosh Shilimkar EXPORT_SYMBOL(outer_cache); 107953233dcSCatalin Marinas #endif 1081da177e4SLinus Torvalds 109ccea7a19SRussell King struct stack { 110ccea7a19SRussell King u32 irq[3]; 111ccea7a19SRussell King u32 abt[3]; 112ccea7a19SRussell King u32 und[3]; 113ccea7a19SRussell King } ____cacheline_aligned; 114ccea7a19SRussell King 115ccea7a19SRussell King static struct stack stacks[NR_CPUS]; 116ccea7a19SRussell King 1171da177e4SLinus Torvalds char elf_platform[ELF_PLATFORM_SIZE]; 1181da177e4SLinus Torvalds EXPORT_SYMBOL(elf_platform); 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static const char *cpu_name; 1211da177e4SLinus Torvalds static const char *machine_name; 12248ab7e09SJeremy Kerr static char __initdata cmd_line[COMMAND_LINE_SIZE]; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; 1251da177e4SLinus Torvalds static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; 1261da177e4SLinus Torvalds #define ENDIANNESS ((char)endian_test.l) 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds /* 1311da177e4SLinus Torvalds * Standard memory resources 1321da177e4SLinus Torvalds */ 1331da177e4SLinus Torvalds static struct resource mem_res[] = { 134740e518eSGreg Kroah-Hartman { 135740e518eSGreg Kroah-Hartman .name = "Video RAM", 136740e518eSGreg Kroah-Hartman .start = 0, 137740e518eSGreg Kroah-Hartman .end = 0, 138740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 139740e518eSGreg Kroah-Hartman }, 140740e518eSGreg Kroah-Hartman { 141740e518eSGreg Kroah-Hartman .name = "Kernel text", 142740e518eSGreg Kroah-Hartman .start = 0, 143740e518eSGreg Kroah-Hartman .end = 0, 144740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 145740e518eSGreg Kroah-Hartman }, 146740e518eSGreg Kroah-Hartman { 147740e518eSGreg Kroah-Hartman .name = "Kernel data", 148740e518eSGreg Kroah-Hartman .start = 0, 149740e518eSGreg Kroah-Hartman .end = 0, 150740e518eSGreg Kroah-Hartman .flags = IORESOURCE_MEM 151740e518eSGreg Kroah-Hartman } 1521da177e4SLinus Torvalds }; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds #define video_ram mem_res[0] 1551da177e4SLinus Torvalds #define kernel_code mem_res[1] 1561da177e4SLinus Torvalds #define kernel_data mem_res[2] 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds static struct resource io_res[] = { 159740e518eSGreg Kroah-Hartman { 160740e518eSGreg Kroah-Hartman .name = "reserved", 161740e518eSGreg Kroah-Hartman .start = 0x3bc, 162740e518eSGreg Kroah-Hartman .end = 0x3be, 163740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 164740e518eSGreg Kroah-Hartman }, 165740e518eSGreg Kroah-Hartman { 166740e518eSGreg Kroah-Hartman .name = "reserved", 167740e518eSGreg Kroah-Hartman .start = 0x378, 168740e518eSGreg Kroah-Hartman .end = 0x37f, 169740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 170740e518eSGreg Kroah-Hartman }, 171740e518eSGreg Kroah-Hartman { 172740e518eSGreg Kroah-Hartman .name = "reserved", 173740e518eSGreg Kroah-Hartman .start = 0x278, 174740e518eSGreg Kroah-Hartman .end = 0x27f, 175740e518eSGreg Kroah-Hartman .flags = IORESOURCE_IO | IORESOURCE_BUSY 176740e518eSGreg Kroah-Hartman } 1771da177e4SLinus Torvalds }; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds #define lp0 io_res[0] 1801da177e4SLinus Torvalds #define lp1 io_res[1] 1811da177e4SLinus Torvalds #define lp2 io_res[2] 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static const char *proc_arch[] = { 1841da177e4SLinus Torvalds "undefined/unknown", 1851da177e4SLinus Torvalds "3", 1861da177e4SLinus Torvalds "4", 1871da177e4SLinus Torvalds "4T", 1881da177e4SLinus Torvalds "5", 1891da177e4SLinus Torvalds "5T", 1901da177e4SLinus Torvalds "5TE", 1911da177e4SLinus Torvalds "5TEJ", 1921da177e4SLinus Torvalds "6TEJ", 1936b090a25SCatalin Marinas "7", 1941da177e4SLinus Torvalds "?(11)", 1951da177e4SLinus Torvalds "?(12)", 1961da177e4SLinus Torvalds "?(13)", 1971da177e4SLinus Torvalds "?(14)", 1981da177e4SLinus Torvalds "?(15)", 1991da177e4SLinus Torvalds "?(16)", 2001da177e4SLinus Torvalds "?(17)", 2011da177e4SLinus Torvalds }; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds int cpu_architecture(void) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds int cpu_arch; 2061da177e4SLinus Torvalds 2070ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0) { 2081da177e4SLinus Torvalds cpu_arch = CPU_ARCH_UNKNOWN; 2090ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 2100ba8b9b2SRussell King cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; 2110ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) { 2120ba8b9b2SRussell King cpu_arch = (read_cpuid_id() >> 16) & 7; 2131da177e4SLinus Torvalds if (cpu_arch) 2141da177e4SLinus Torvalds cpu_arch += CPU_ARCH_ARMv3; 2150ba8b9b2SRussell King } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 216180005c4SCatalin Marinas unsigned int mmfr0; 217180005c4SCatalin Marinas 218180005c4SCatalin Marinas /* Revised CPUID format. Read the Memory Model Feature 219180005c4SCatalin Marinas * Register 0 and check for VMSAv7 or PMSAv7 */ 220180005c4SCatalin Marinas asm("mrc p15, 0, %0, c0, c1, 4" 221180005c4SCatalin Marinas : "=r" (mmfr0)); 222180005c4SCatalin Marinas if ((mmfr0 & 0x0000000f) == 0x00000003 || 223180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000030) 224180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv7; 225180005c4SCatalin Marinas else if ((mmfr0 & 0x0000000f) == 0x00000002 || 226180005c4SCatalin Marinas (mmfr0 & 0x000000f0) == 0x00000020) 227180005c4SCatalin Marinas cpu_arch = CPU_ARCH_ARMv6; 228180005c4SCatalin Marinas else 229180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 230180005c4SCatalin Marinas } else 231180005c4SCatalin Marinas cpu_arch = CPU_ARCH_UNKNOWN; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds return cpu_arch; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 236c0e95878SRussell King static void __init cacheid_init(void) 237c0e95878SRussell King { 238c0e95878SRussell King unsigned int cachetype = read_cpuid_cachetype(); 239c0e95878SRussell King unsigned int arch = cpu_architecture(); 240c0e95878SRussell King 241b57ee99fSCatalin Marinas if (arch >= CPU_ARCH_ARMv6) { 242b57ee99fSCatalin Marinas if ((cachetype & (7 << 29)) == 4 << 29) { 243b57ee99fSCatalin Marinas /* ARMv7 register format */ 244c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 245c0e95878SRussell King if ((cachetype & (3 << 14)) == 1 << 14) 246c0e95878SRussell King cacheid |= CACHEID_ASID_TAGGED; 247b57ee99fSCatalin Marinas } else if (cachetype & (1 << 23)) 248c0e95878SRussell King cacheid = CACHEID_VIPT_ALIASING; 249c0e95878SRussell King else 250c0e95878SRussell King cacheid = CACHEID_VIPT_NONALIASING; 251c0e95878SRussell King } else { 252c0e95878SRussell King cacheid = CACHEID_VIVT; 253c0e95878SRussell King } 2542b4ae1f1SRussell King 2552b4ae1f1SRussell King printk("CPU: %s data cache, %s instruction cache\n", 2562b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 2572b4ae1f1SRussell King cache_is_vipt_aliasing() ? "VIPT aliasing" : 2582b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", 2592b4ae1f1SRussell King cache_is_vivt() ? "VIVT" : 2602b4ae1f1SRussell King icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : 2612b4ae1f1SRussell King cache_is_vipt_aliasing() ? "VIPT aliasing" : 2622b4ae1f1SRussell King cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); 263c0e95878SRussell King } 264c0e95878SRussell King 2651da177e4SLinus Torvalds /* 2661da177e4SLinus Torvalds * These functions re-use the assembly code in head.S, which 2671da177e4SLinus Torvalds * already provide the required functionality. 2681da177e4SLinus Torvalds */ 2690f44ba1dSRussell King extern struct proc_info_list *lookup_processor_type(unsigned int); 2701da177e4SLinus Torvalds extern struct machine_desc *lookup_machine_type(unsigned int); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds static void __init setup_processor(void) 2731da177e4SLinus Torvalds { 2741da177e4SLinus Torvalds struct proc_info_list *list; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds /* 2771da177e4SLinus Torvalds * locate processor in the list of supported processor 2781da177e4SLinus Torvalds * types. The linker builds this table for us from the 2791da177e4SLinus Torvalds * entries in arch/arm/mm/proc-*.S 2801da177e4SLinus Torvalds */ 2810ba8b9b2SRussell King list = lookup_processor_type(read_cpuid_id()); 2821da177e4SLinus Torvalds if (!list) { 2831da177e4SLinus Torvalds printk("CPU configuration botched (ID %08x), unable " 2840ba8b9b2SRussell King "to continue.\n", read_cpuid_id()); 2851da177e4SLinus Torvalds while (1); 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds cpu_name = list->cpu_name; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds #ifdef MULTI_CPU 2911da177e4SLinus Torvalds processor = *list->proc; 2921da177e4SLinus Torvalds #endif 2931da177e4SLinus Torvalds #ifdef MULTI_TLB 2941da177e4SLinus Torvalds cpu_tlb = *list->tlb; 2951da177e4SLinus Torvalds #endif 2961da177e4SLinus Torvalds #ifdef MULTI_USER 2971da177e4SLinus Torvalds cpu_user = *list->user; 2981da177e4SLinus Torvalds #endif 2991da177e4SLinus Torvalds #ifdef MULTI_CACHE 3001da177e4SLinus Torvalds cpu_cache = *list->cache; 3011da177e4SLinus Torvalds #endif 3021da177e4SLinus Torvalds 3034e19025bSRussell King printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 3040ba8b9b2SRussell King cpu_name, read_cpuid_id(), read_cpuid_id() & 15, 305264edb35SRussell King proc_arch[cpu_architecture()], cr_alignment); 3061da177e4SLinus Torvalds 30796b644bdSSerge E. Hallyn sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); 3081da177e4SLinus Torvalds sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); 3091da177e4SLinus Torvalds elf_hwcap = list->elf_hwcap; 310adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB 311adeff422SCatalin Marinas elf_hwcap &= ~HWCAP_THUMB; 312adeff422SCatalin Marinas #endif 3131da177e4SLinus Torvalds 314c0e95878SRussell King cacheid_init(); 3151da177e4SLinus Torvalds cpu_proc_init(); 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 318ccea7a19SRussell King /* 319ccea7a19SRussell King * cpu_init - initialise one CPU. 320ccea7a19SRussell King * 32190f1e084SRussell King * cpu_init sets up the per-CPU stacks. 322ccea7a19SRussell King */ 32336c5ed23SRussell King void cpu_init(void) 324ccea7a19SRussell King { 325ccea7a19SRussell King unsigned int cpu = smp_processor_id(); 326ccea7a19SRussell King struct stack *stk = &stacks[cpu]; 327ccea7a19SRussell King 328ccea7a19SRussell King if (cpu >= NR_CPUS) { 329ccea7a19SRussell King printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); 330ccea7a19SRussell King BUG(); 331ccea7a19SRussell King } 332ccea7a19SRussell King 333ccea7a19SRussell King /* 334b86040a5SCatalin Marinas * Define the placement constraint for the inline asm directive below. 335b86040a5SCatalin Marinas * In Thumb-2, msr with an immediate value is not allowed. 336b86040a5SCatalin Marinas */ 337b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL 338b86040a5SCatalin Marinas #define PLC "r" 339b86040a5SCatalin Marinas #else 340b86040a5SCatalin Marinas #define PLC "I" 341b86040a5SCatalin Marinas #endif 342b86040a5SCatalin Marinas 343b86040a5SCatalin Marinas /* 344ccea7a19SRussell King * setup stacks for re-entrant exception handlers 345ccea7a19SRussell King */ 346ccea7a19SRussell King __asm__ ( 347ccea7a19SRussell King "msr cpsr_c, %1\n\t" 348b86040a5SCatalin Marinas "add r14, %0, %2\n\t" 349b86040a5SCatalin Marinas "mov sp, r14\n\t" 350ccea7a19SRussell King "msr cpsr_c, %3\n\t" 351b86040a5SCatalin Marinas "add r14, %0, %4\n\t" 352b86040a5SCatalin Marinas "mov sp, r14\n\t" 353ccea7a19SRussell King "msr cpsr_c, %5\n\t" 354b86040a5SCatalin Marinas "add r14, %0, %6\n\t" 355b86040a5SCatalin Marinas "mov sp, r14\n\t" 356ccea7a19SRussell King "msr cpsr_c, %7" 357ccea7a19SRussell King : 358ccea7a19SRussell King : "r" (stk), 359b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), 360ccea7a19SRussell King "I" (offsetof(struct stack, irq[0])), 361b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), 362ccea7a19SRussell King "I" (offsetof(struct stack, abt[0])), 363b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), 364ccea7a19SRussell King "I" (offsetof(struct stack, und[0])), 365b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) 366aaaa3f9eSCatalin Marinas : "r14"); 367ccea7a19SRussell King } 368ccea7a19SRussell King 3691da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr) 3701da177e4SLinus Torvalds { 3711da177e4SLinus Torvalds struct machine_desc *list; 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds /* 3741da177e4SLinus Torvalds * locate machine in the list of supported machines. 3751da177e4SLinus Torvalds */ 3761da177e4SLinus Torvalds list = lookup_machine_type(nr); 3771da177e4SLinus Torvalds if (!list) { 3781da177e4SLinus Torvalds printk("Machine configuration botched (nr %d), unable " 3791da177e4SLinus Torvalds "to continue.\n", nr); 3801da177e4SLinus Torvalds while (1); 3811da177e4SLinus Torvalds } 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds printk("Machine: %s\n", list->name); 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds return list; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3884b5f32ceSNicolas Pitre static int __init arm_add_memory(unsigned long start, unsigned long size) 3893a669411SRussell King { 3904b5f32ceSNicolas Pitre struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 3914b5f32ceSNicolas Pitre 3924b5f32ceSNicolas Pitre if (meminfo.nr_banks >= NR_BANKS) { 3934b5f32ceSNicolas Pitre printk(KERN_CRIT "NR_BANKS too low, " 3944b5f32ceSNicolas Pitre "ignoring memory at %#lx\n", start); 3954b5f32ceSNicolas Pitre return -EINVAL; 3964b5f32ceSNicolas Pitre } 39705f96ef1SRussell King 3983a669411SRussell King /* 3993a669411SRussell King * Ensure that start/size are aligned to a page boundary. 4003a669411SRussell King * Size is appropriately rounded down, start is rounded up. 4013a669411SRussell King */ 4023a669411SRussell King size -= start & ~PAGE_MASK; 40305f96ef1SRussell King bank->start = PAGE_ALIGN(start); 40405f96ef1SRussell King bank->size = size & PAGE_MASK; 40505f96ef1SRussell King bank->node = PHYS_TO_NID(start); 4064b5f32ceSNicolas Pitre 4074b5f32ceSNicolas Pitre /* 4084b5f32ceSNicolas Pitre * Check whether this memory region has non-zero size or 4094b5f32ceSNicolas Pitre * invalid node number. 4104b5f32ceSNicolas Pitre */ 4114b5f32ceSNicolas Pitre if (bank->size == 0 || bank->node >= MAX_NUMNODES) 4124b5f32ceSNicolas Pitre return -EINVAL; 4134b5f32ceSNicolas Pitre 4144b5f32ceSNicolas Pitre meminfo.nr_banks++; 4154b5f32ceSNicolas Pitre return 0; 4163a669411SRussell King } 4173a669411SRussell King 4181da177e4SLinus Torvalds /* 4191da177e4SLinus Torvalds * Pick out the memory size. We look for mem=size@start, 4201da177e4SLinus Torvalds * where start and size are "size[KkMm]" 4211da177e4SLinus Torvalds */ 4222b0d8c25SJeremy Kerr static int __init early_mem(char *p) 4231da177e4SLinus Torvalds { 4241da177e4SLinus Torvalds static int usermem __initdata = 0; 4251da177e4SLinus Torvalds unsigned long size, start; 4262b0d8c25SJeremy Kerr char *endp; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* 4291da177e4SLinus Torvalds * If the user specifies memory size, we 4301da177e4SLinus Torvalds * blow away any automatically generated 4311da177e4SLinus Torvalds * size. 4321da177e4SLinus Torvalds */ 4331da177e4SLinus Torvalds if (usermem == 0) { 4341da177e4SLinus Torvalds usermem = 1; 4351da177e4SLinus Torvalds meminfo.nr_banks = 0; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds start = PHYS_OFFSET; 4392b0d8c25SJeremy Kerr size = memparse(p, &endp); 4402b0d8c25SJeremy Kerr if (*endp == '@') 4412b0d8c25SJeremy Kerr start = memparse(endp + 1, NULL); 4421da177e4SLinus Torvalds 4431c97b73eSAndrew Morton arm_add_memory(start, size); 4441da177e4SLinus Torvalds 4452b0d8c25SJeremy Kerr return 0; 4461da177e4SLinus Torvalds } 4472b0d8c25SJeremy Kerr early_param("mem", early_mem); 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds static void __init 4501da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) 4511da177e4SLinus Torvalds { 4521da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM 4531da177e4SLinus Torvalds extern int rd_size, rd_image_start, rd_prompt, rd_doload; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds rd_image_start = image_start; 4561da177e4SLinus Torvalds rd_prompt = prompt; 4571da177e4SLinus Torvalds rd_doload = doload; 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds if (rd_sz) 4601da177e4SLinus Torvalds rd_size = rd_sz; 4611da177e4SLinus Torvalds #endif 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds static void __init 4651da177e4SLinus Torvalds request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) 4661da177e4SLinus Torvalds { 4671da177e4SLinus Torvalds struct resource *res; 4681da177e4SLinus Torvalds int i; 4691da177e4SLinus Torvalds 47037efe642SRussell King kernel_code.start = virt_to_phys(_text); 47137efe642SRussell King kernel_code.end = virt_to_phys(_etext - 1); 47237efe642SRussell King kernel_data.start = virt_to_phys(_data); 47337efe642SRussell King kernel_data.end = virt_to_phys(_end - 1); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds for (i = 0; i < mi->nr_banks; i++) { 4761da177e4SLinus Torvalds if (mi->bank[i].size == 0) 4771da177e4SLinus Torvalds continue; 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds res = alloc_bootmem_low(sizeof(*res)); 4801da177e4SLinus Torvalds res->name = "System RAM"; 4813319f5e5SNicolas Pitre res->start = mi->bank[i].start; 4823319f5e5SNicolas Pitre res->end = mi->bank[i].start + mi->bank[i].size - 1; 4831da177e4SLinus Torvalds res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds request_resource(&iomem_resource, res); 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds if (kernel_code.start >= res->start && 4881da177e4SLinus Torvalds kernel_code.end <= res->end) 4891da177e4SLinus Torvalds request_resource(res, &kernel_code); 4901da177e4SLinus Torvalds if (kernel_data.start >= res->start && 4911da177e4SLinus Torvalds kernel_data.end <= res->end) 4921da177e4SLinus Torvalds request_resource(res, &kernel_data); 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds if (mdesc->video_start) { 4961da177e4SLinus Torvalds video_ram.start = mdesc->video_start; 4971da177e4SLinus Torvalds video_ram.end = mdesc->video_end; 4981da177e4SLinus Torvalds request_resource(&iomem_resource, &video_ram); 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds /* 5021da177e4SLinus Torvalds * Some machines don't have the possibility of ever 5031da177e4SLinus Torvalds * possessing lp0, lp1 or lp2 5041da177e4SLinus Torvalds */ 5051da177e4SLinus Torvalds if (mdesc->reserve_lp0) 5061da177e4SLinus Torvalds request_resource(&ioport_resource, &lp0); 5071da177e4SLinus Torvalds if (mdesc->reserve_lp1) 5081da177e4SLinus Torvalds request_resource(&ioport_resource, &lp1); 5091da177e4SLinus Torvalds if (mdesc->reserve_lp2) 5101da177e4SLinus Torvalds request_resource(&ioport_resource, &lp2); 5111da177e4SLinus Torvalds } 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds /* 5141da177e4SLinus Torvalds * Tag parsing. 5151da177e4SLinus Torvalds * 5161da177e4SLinus Torvalds * This is the new way of passing data to the kernel at boot time. Rather 5171da177e4SLinus Torvalds * than passing a fixed inflexible structure to the kernel, we pass a list 5181da177e4SLinus Torvalds * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE 5191da177e4SLinus Torvalds * tag for the list to be recognised (to distinguish the tagged list from 5201da177e4SLinus Torvalds * a param_struct). The list is terminated with a zero-length tag (this tag 5211da177e4SLinus Torvalds * is not parsed in any way). 5221da177e4SLinus Torvalds */ 5231da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds if (tag->hdr.size > 2) { 5261da177e4SLinus Torvalds if ((tag->u.core.flags & 1) == 0) 5271da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY; 5281da177e4SLinus Torvalds ROOT_DEV = old_decode_dev(tag->u.core.rootdev); 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds return 0; 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core); 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag) 5361da177e4SLinus Torvalds { 5374b5f32ceSNicolas Pitre return arm_add_memory(tag->u.mem.start, tag->u.mem.size); 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32); 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 5431da177e4SLinus Torvalds struct screen_info screen_info = { 5441da177e4SLinus Torvalds .orig_video_lines = 30, 5451da177e4SLinus Torvalds .orig_video_cols = 80, 5461da177e4SLinus Torvalds .orig_video_mode = 0, 5471da177e4SLinus Torvalds .orig_video_ega_bx = 0, 5481da177e4SLinus Torvalds .orig_video_isVGA = 1, 5491da177e4SLinus Torvalds .orig_video_points = 8 5501da177e4SLinus Torvalds }; 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag) 5531da177e4SLinus Torvalds { 5541da177e4SLinus Torvalds screen_info.orig_x = tag->u.videotext.x; 5551da177e4SLinus Torvalds screen_info.orig_y = tag->u.videotext.y; 5561da177e4SLinus Torvalds screen_info.orig_video_page = tag->u.videotext.video_page; 5571da177e4SLinus Torvalds screen_info.orig_video_mode = tag->u.videotext.video_mode; 5581da177e4SLinus Torvalds screen_info.orig_video_cols = tag->u.videotext.video_cols; 5591da177e4SLinus Torvalds screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; 5601da177e4SLinus Torvalds screen_info.orig_video_lines = tag->u.videotext.video_lines; 5611da177e4SLinus Torvalds screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; 5621da177e4SLinus Torvalds screen_info.orig_video_points = tag->u.videotext.video_points; 5631da177e4SLinus Torvalds return 0; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); 5671da177e4SLinus Torvalds #endif 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag) 5701da177e4SLinus Torvalds { 5711da177e4SLinus Torvalds setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, 5721da177e4SLinus Torvalds (tag->u.ramdisk.flags & 2) == 0, 5731da177e4SLinus Torvalds tag->u.ramdisk.start, tag->u.ramdisk.size); 5741da177e4SLinus Torvalds return 0; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk); 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag) 5801da177e4SLinus Torvalds { 5811da177e4SLinus Torvalds system_serial_low = tag->u.serialnr.low; 5821da177e4SLinus Torvalds system_serial_high = tag->u.serialnr.high; 5831da177e4SLinus Torvalds return 0; 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds system_rev = tag->u.revision.rev; 5911da177e4SLinus Torvalds return 0; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision); 5951da177e4SLinus Torvalds 59692d2040dSAlexander Holler #ifndef CONFIG_CMDLINE_FORCE 5971da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag) 5981da177e4SLinus Torvalds { 5991da177e4SLinus Torvalds strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); 6001da177e4SLinus Torvalds return 0; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline); 60492d2040dSAlexander Holler #endif /* CONFIG_CMDLINE_FORCE */ 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds /* 6071da177e4SLinus Torvalds * Scan the tag table for this tag, and call its parse function. 6081da177e4SLinus Torvalds * The tag table is built by the linker from all the __tagtable 6091da177e4SLinus Torvalds * declarations. 6101da177e4SLinus Torvalds */ 6111da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag) 6121da177e4SLinus Torvalds { 6131da177e4SLinus Torvalds extern struct tagtable __tagtable_begin, __tagtable_end; 6141da177e4SLinus Torvalds struct tagtable *t; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds for (t = &__tagtable_begin; t < &__tagtable_end; t++) 6171da177e4SLinus Torvalds if (tag->hdr.tag == t->tag) { 6181da177e4SLinus Torvalds t->parse(tag); 6191da177e4SLinus Torvalds break; 6201da177e4SLinus Torvalds } 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds return t < &__tagtable_end; 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds /* 6261da177e4SLinus Torvalds * Parse all tags in the list, checking both the global and architecture 6271da177e4SLinus Torvalds * specific tag tables. 6281da177e4SLinus Torvalds */ 6291da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t) 6301da177e4SLinus Torvalds { 6311da177e4SLinus Torvalds for (; t->hdr.size; t = tag_next(t)) 6321da177e4SLinus Torvalds if (!parse_tag(t)) 6331da177e4SLinus Torvalds printk(KERN_WARNING 6341da177e4SLinus Torvalds "Ignoring unrecognised tag 0x%08x\n", 6351da177e4SLinus Torvalds t->hdr.tag); 6361da177e4SLinus Torvalds } 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds /* 6391da177e4SLinus Torvalds * This holds our defaults. 6401da177e4SLinus Torvalds */ 6411da177e4SLinus Torvalds static struct init_tags { 6421da177e4SLinus Torvalds struct tag_header hdr1; 6431da177e4SLinus Torvalds struct tag_core core; 6441da177e4SLinus Torvalds struct tag_header hdr2; 6451da177e4SLinus Torvalds struct tag_mem32 mem; 6461da177e4SLinus Torvalds struct tag_header hdr3; 6471da177e4SLinus Torvalds } init_tags __initdata = { 6481da177e4SLinus Torvalds { tag_size(tag_core), ATAG_CORE }, 6491da177e4SLinus Torvalds { 1, PAGE_SIZE, 0xff }, 6501da177e4SLinus Torvalds { tag_size(tag_mem32), ATAG_MEM }, 6511da177e4SLinus Torvalds { MEM_SIZE, PHYS_OFFSET }, 6521da177e4SLinus Torvalds { 0, ATAG_NONE } 6531da177e4SLinus Torvalds }; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds static void (*init_machine)(void) __initdata; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds static int __init customize_machine(void) 6581da177e4SLinus Torvalds { 6591da177e4SLinus Torvalds /* customizes platform devices, or adds new ones */ 6601da177e4SLinus Torvalds if (init_machine) 6611da177e4SLinus Torvalds init_machine(); 6621da177e4SLinus Torvalds return 0; 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds arch_initcall(customize_machine); 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p) 6671da177e4SLinus Torvalds { 6681da177e4SLinus Torvalds struct tag *tags = (struct tag *)&init_tags; 6691da177e4SLinus Torvalds struct machine_desc *mdesc; 6701da177e4SLinus Torvalds char *from = default_command_line; 6711da177e4SLinus Torvalds 672bff595c1SCatalin Marinas unwind_init(); 673bff595c1SCatalin Marinas 6741da177e4SLinus Torvalds setup_processor(); 6751da177e4SLinus Torvalds mdesc = setup_machine(machine_arch_type); 6761da177e4SLinus Torvalds machine_name = mdesc->name; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds if (mdesc->soft_reboot) 6791da177e4SLinus Torvalds reboot_setup("s"); 6801da177e4SLinus Torvalds 6819d20fdd5SBill Gatliff if (__atags_pointer) 6829d20fdd5SBill Gatliff tags = phys_to_virt(__atags_pointer); 6839d20fdd5SBill Gatliff else if (mdesc->boot_params) 684f9bd6ea4SRussell King tags = phys_to_virt(mdesc->boot_params); 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds /* 6871da177e4SLinus Torvalds * If we have the old style parameters, convert them to 6881da177e4SLinus Torvalds * a tag list. 6891da177e4SLinus Torvalds */ 6901da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 6911da177e4SLinus Torvalds convert_to_tag_list(tags); 6921da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 6931da177e4SLinus Torvalds tags = (struct tag *)&init_tags; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds if (mdesc->fixup) 6961da177e4SLinus Torvalds mdesc->fixup(mdesc, tags, &from, &meminfo); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds if (tags->hdr.tag == ATAG_CORE) { 6991da177e4SLinus Torvalds if (meminfo.nr_banks != 0) 7001da177e4SLinus Torvalds squash_mem_tags(tags); 7014cd9d6f7SRichard Purdie save_atags(tags); 7021da177e4SLinus Torvalds parse_tags(tags); 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 70537efe642SRussell King init_mm.start_code = (unsigned long) _text; 70637efe642SRussell King init_mm.end_code = (unsigned long) _etext; 70737efe642SRussell King init_mm.end_data = (unsigned long) _edata; 70837efe642SRussell King init_mm.brk = (unsigned long) _end; 7091da177e4SLinus Torvalds 7102b0d8c25SJeremy Kerr /* parse_early_param needs a boot_command_line */ 7112b0d8c25SJeremy Kerr strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); 7122b0d8c25SJeremy Kerr 71348ab7e09SJeremy Kerr /* populate cmd_line too for later use, preserving boot_command_line */ 71448ab7e09SJeremy Kerr strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 71548ab7e09SJeremy Kerr *cmdline_p = cmd_line; 7162b0d8c25SJeremy Kerr 7172b0d8c25SJeremy Kerr parse_early_param(); 7182b0d8c25SJeremy Kerr 7194b5f32ceSNicolas Pitre paging_init(mdesc); 7201da177e4SLinus Torvalds request_standard_resources(&meminfo, mdesc); 7211da177e4SLinus Torvalds 7227bbb7940SRussell King #ifdef CONFIG_SMP 7237bbb7940SRussell King smp_init_cpus(); 7247bbb7940SRussell King #endif 7257bbb7940SRussell King 726ccea7a19SRussell King cpu_init(); 727bc581770SLinus Walleij tcm_init(); 728ccea7a19SRussell King 7291da177e4SLinus Torvalds /* 7301da177e4SLinus Torvalds * Set up various architecture-specific pointers 7311da177e4SLinus Torvalds */ 732354e6f72Seric miao arch_nr_irqs = mdesc->nr_irqs; 7331da177e4SLinus Torvalds init_arch_irq = mdesc->init_irq; 7341da177e4SLinus Torvalds system_timer = mdesc->timer; 7351da177e4SLinus Torvalds init_machine = mdesc->init_machine; 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds #ifdef CONFIG_VT 7381da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) 7391da177e4SLinus Torvalds conswitchp = &vga_con; 7401da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE) 7411da177e4SLinus Torvalds conswitchp = &dummy_con; 7421da177e4SLinus Torvalds #endif 7431da177e4SLinus Torvalds #endif 7445cbad0ebSJason Wessel early_trap_init(); 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds static int __init topology_init(void) 7491da177e4SLinus Torvalds { 7501da177e4SLinus Torvalds int cpu; 7511da177e4SLinus Torvalds 75266fb8bd2SRussell King for_each_possible_cpu(cpu) { 75366fb8bd2SRussell King struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); 75466fb8bd2SRussell King cpuinfo->cpu.hotpluggable = 1; 75566fb8bd2SRussell King register_cpu(&cpuinfo->cpu, cpu); 75666fb8bd2SRussell King } 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds return 0; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds subsys_initcall(topology_init); 7611da177e4SLinus Torvalds 762e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU 763e119bfffSRussell King static int __init proc_cpu_init(void) 764e119bfffSRussell King { 765e119bfffSRussell King struct proc_dir_entry *res; 766e119bfffSRussell King 767e119bfffSRussell King res = proc_mkdir("cpu", NULL); 768e119bfffSRussell King if (!res) 769e119bfffSRussell King return -ENOMEM; 770e119bfffSRussell King return 0; 771e119bfffSRussell King } 772e119bfffSRussell King fs_initcall(proc_cpu_init); 773e119bfffSRussell King #endif 774e119bfffSRussell King 7751da177e4SLinus Torvalds static const char *hwcap_str[] = { 7761da177e4SLinus Torvalds "swp", 7771da177e4SLinus Torvalds "half", 7781da177e4SLinus Torvalds "thumb", 7791da177e4SLinus Torvalds "26bit", 7801da177e4SLinus Torvalds "fastmult", 7811da177e4SLinus Torvalds "fpa", 7821da177e4SLinus Torvalds "vfp", 7831da177e4SLinus Torvalds "edsp", 7841da177e4SLinus Torvalds "java", 7858f7f9435SPaul Gortmaker "iwmmxt", 78699e4a6ddSLennert Buytenhek "crunch", 7874369ae16SCatalin Marinas "thumbee", 7882bedbdf4SCatalin Marinas "neon", 7897279dc3eSCatalin Marinas "vfpv3", 7907279dc3eSCatalin Marinas "vfpv3d16", 7911da177e4SLinus Torvalds NULL 7921da177e4SLinus Torvalds }; 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v) 7951da177e4SLinus Torvalds { 7961da177e4SLinus Torvalds int i; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds seq_printf(m, "Processor\t: %s rev %d (%s)\n", 7990ba8b9b2SRussell King cpu_name, read_cpuid_id() & 15, elf_platform); 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds #if defined(CONFIG_SMP) 8021da177e4SLinus Torvalds for_each_online_cpu(i) { 80315559722SRussell King /* 80415559722SRussell King * glibc reads /proc/cpuinfo to determine the number of 80515559722SRussell King * online processors, looking for lines beginning with 80615559722SRussell King * "processor". Give glibc what it expects. 80715559722SRussell King */ 80815559722SRussell King seq_printf(m, "processor\t: %d\n", i); 8091da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 8101da177e4SLinus Torvalds per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), 8111da177e4SLinus Torvalds (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds #else /* CONFIG_SMP */ 8141da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", 8151da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ), 8161da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100); 8171da177e4SLinus Torvalds #endif 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds /* dump out the processor features */ 8201da177e4SLinus Torvalds seq_puts(m, "Features\t: "); 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds for (i = 0; hwcap_str[i]; i++) 8231da177e4SLinus Torvalds if (elf_hwcap & (1 << i)) 8241da177e4SLinus Torvalds seq_printf(m, "%s ", hwcap_str[i]); 8251da177e4SLinus Torvalds 8260ba8b9b2SRussell King seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 8271da177e4SLinus Torvalds seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); 8281da177e4SLinus Torvalds 8290ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00000000) { 8301da177e4SLinus Torvalds /* pre-ARM7 */ 8310ba8b9b2SRussell King seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4); 8321da177e4SLinus Torvalds } else { 8330ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 8341da177e4SLinus Torvalds /* ARM7 */ 8351da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%02x\n", 8360ba8b9b2SRussell King (read_cpuid_id() >> 16) & 127); 8371da177e4SLinus Torvalds } else { 8381da177e4SLinus Torvalds /* post-ARM7 */ 8391da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%x\n", 8400ba8b9b2SRussell King (read_cpuid_id() >> 20) & 15); 8411da177e4SLinus Torvalds } 8421da177e4SLinus Torvalds seq_printf(m, "CPU part\t: 0x%03x\n", 8430ba8b9b2SRussell King (read_cpuid_id() >> 4) & 0xfff); 8441da177e4SLinus Torvalds } 8450ba8b9b2SRussell King seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds seq_puts(m, "\n"); 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds seq_printf(m, "Hardware\t: %s\n", machine_name); 8501da177e4SLinus Torvalds seq_printf(m, "Revision\t: %04x\n", system_rev); 8511da177e4SLinus Torvalds seq_printf(m, "Serial\t\t: %08x%08x\n", 8521da177e4SLinus Torvalds system_serial_high, system_serial_low); 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds return 0; 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds 8571da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 8581da177e4SLinus Torvalds { 8591da177e4SLinus Torvalds return *pos < 1 ? (void *)1 : NULL; 8601da177e4SLinus Torvalds } 8611da177e4SLinus Torvalds 8621da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 8631da177e4SLinus Torvalds { 8641da177e4SLinus Torvalds ++*pos; 8651da177e4SLinus Torvalds return NULL; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 8691da177e4SLinus Torvalds { 8701da177e4SLinus Torvalds } 8711da177e4SLinus Torvalds 8722ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = { 8731da177e4SLinus Torvalds .start = c_start, 8741da177e4SLinus Torvalds .next = c_next, 8751da177e4SLinus Torvalds .stop = c_stop, 8761da177e4SLinus Torvalds .show = c_show 8771da177e4SLinus Torvalds }; 878