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 272f159f4edSTony Lindgren static void __init feat_v6_fixup(void) 273f159f4edSTony Lindgren { 274f159f4edSTony Lindgren int id = read_cpuid_id(); 275f159f4edSTony Lindgren 276f159f4edSTony Lindgren if ((id & 0xff0f0000) != 0x41070000) 277f159f4edSTony Lindgren return; 278f159f4edSTony Lindgren 279f159f4edSTony Lindgren /* 280f159f4edSTony Lindgren * HWCAP_TLS is available only on 1136 r1p0 and later, 281f159f4edSTony Lindgren * see also kuser_get_tls_init. 282f159f4edSTony Lindgren */ 283f159f4edSTony Lindgren if ((((id >> 4) & 0xfff) == 0xb36) && (((id >> 20) & 3) == 0)) 284f159f4edSTony Lindgren elf_hwcap &= ~HWCAP_TLS; 285f159f4edSTony Lindgren } 286f159f4edSTony Lindgren 2871da177e4SLinus Torvalds static void __init setup_processor(void) 2881da177e4SLinus Torvalds { 2891da177e4SLinus Torvalds struct proc_info_list *list; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* 2921da177e4SLinus Torvalds * locate processor in the list of supported processor 2931da177e4SLinus Torvalds * types. The linker builds this table for us from the 2941da177e4SLinus Torvalds * entries in arch/arm/mm/proc-*.S 2951da177e4SLinus Torvalds */ 2960ba8b9b2SRussell King list = lookup_processor_type(read_cpuid_id()); 2971da177e4SLinus Torvalds if (!list) { 2981da177e4SLinus Torvalds printk("CPU configuration botched (ID %08x), unable " 2990ba8b9b2SRussell King "to continue.\n", read_cpuid_id()); 3001da177e4SLinus Torvalds while (1); 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds cpu_name = list->cpu_name; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds #ifdef MULTI_CPU 3061da177e4SLinus Torvalds processor = *list->proc; 3071da177e4SLinus Torvalds #endif 3081da177e4SLinus Torvalds #ifdef MULTI_TLB 3091da177e4SLinus Torvalds cpu_tlb = *list->tlb; 3101da177e4SLinus Torvalds #endif 3111da177e4SLinus Torvalds #ifdef MULTI_USER 3121da177e4SLinus Torvalds cpu_user = *list->user; 3131da177e4SLinus Torvalds #endif 3141da177e4SLinus Torvalds #ifdef MULTI_CACHE 3151da177e4SLinus Torvalds cpu_cache = *list->cache; 3161da177e4SLinus Torvalds #endif 3171da177e4SLinus Torvalds 3184e19025bSRussell King printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n", 3190ba8b9b2SRussell King cpu_name, read_cpuid_id(), read_cpuid_id() & 15, 320264edb35SRussell King proc_arch[cpu_architecture()], cr_alignment); 3211da177e4SLinus Torvalds 32296b644bdSSerge E. Hallyn sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); 3231da177e4SLinus Torvalds sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); 3241da177e4SLinus Torvalds elf_hwcap = list->elf_hwcap; 325adeff422SCatalin Marinas #ifndef CONFIG_ARM_THUMB 326adeff422SCatalin Marinas elf_hwcap &= ~HWCAP_THUMB; 327adeff422SCatalin Marinas #endif 3281da177e4SLinus Torvalds 329f159f4edSTony Lindgren feat_v6_fixup(); 330f159f4edSTony Lindgren 331c0e95878SRussell King cacheid_init(); 3321da177e4SLinus Torvalds cpu_proc_init(); 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 335ccea7a19SRussell King /* 336ccea7a19SRussell King * cpu_init - initialise one CPU. 337ccea7a19SRussell King * 33890f1e084SRussell King * cpu_init sets up the per-CPU stacks. 339ccea7a19SRussell King */ 34036c5ed23SRussell King void cpu_init(void) 341ccea7a19SRussell King { 342ccea7a19SRussell King unsigned int cpu = smp_processor_id(); 343ccea7a19SRussell King struct stack *stk = &stacks[cpu]; 344ccea7a19SRussell King 345ccea7a19SRussell King if (cpu >= NR_CPUS) { 346ccea7a19SRussell King printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); 347ccea7a19SRussell King BUG(); 348ccea7a19SRussell King } 349ccea7a19SRussell King 350ccea7a19SRussell King /* 351b86040a5SCatalin Marinas * Define the placement constraint for the inline asm directive below. 352b86040a5SCatalin Marinas * In Thumb-2, msr with an immediate value is not allowed. 353b86040a5SCatalin Marinas */ 354b86040a5SCatalin Marinas #ifdef CONFIG_THUMB2_KERNEL 355b86040a5SCatalin Marinas #define PLC "r" 356b86040a5SCatalin Marinas #else 357b86040a5SCatalin Marinas #define PLC "I" 358b86040a5SCatalin Marinas #endif 359b86040a5SCatalin Marinas 360b86040a5SCatalin Marinas /* 361ccea7a19SRussell King * setup stacks for re-entrant exception handlers 362ccea7a19SRussell King */ 363ccea7a19SRussell King __asm__ ( 364ccea7a19SRussell King "msr cpsr_c, %1\n\t" 365b86040a5SCatalin Marinas "add r14, %0, %2\n\t" 366b86040a5SCatalin Marinas "mov sp, r14\n\t" 367ccea7a19SRussell King "msr cpsr_c, %3\n\t" 368b86040a5SCatalin Marinas "add r14, %0, %4\n\t" 369b86040a5SCatalin Marinas "mov sp, r14\n\t" 370ccea7a19SRussell King "msr cpsr_c, %5\n\t" 371b86040a5SCatalin Marinas "add r14, %0, %6\n\t" 372b86040a5SCatalin Marinas "mov sp, r14\n\t" 373ccea7a19SRussell King "msr cpsr_c, %7" 374ccea7a19SRussell King : 375ccea7a19SRussell King : "r" (stk), 376b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), 377ccea7a19SRussell King "I" (offsetof(struct stack, irq[0])), 378b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), 379ccea7a19SRussell King "I" (offsetof(struct stack, abt[0])), 380b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), 381ccea7a19SRussell King "I" (offsetof(struct stack, und[0])), 382b86040a5SCatalin Marinas PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) 383aaaa3f9eSCatalin Marinas : "r14"); 384ccea7a19SRussell King } 385ccea7a19SRussell King 3861da177e4SLinus Torvalds static struct machine_desc * __init setup_machine(unsigned int nr) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds struct machine_desc *list; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds /* 3911da177e4SLinus Torvalds * locate machine in the list of supported machines. 3921da177e4SLinus Torvalds */ 3931da177e4SLinus Torvalds list = lookup_machine_type(nr); 3941da177e4SLinus Torvalds if (!list) { 3951da177e4SLinus Torvalds printk("Machine configuration botched (nr %d), unable " 3961da177e4SLinus Torvalds "to continue.\n", nr); 3971da177e4SLinus Torvalds while (1); 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds printk("Machine: %s\n", list->name); 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds return list; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 4054b5f32ceSNicolas Pitre static int __init arm_add_memory(unsigned long start, unsigned long size) 4063a669411SRussell King { 4074b5f32ceSNicolas Pitre struct membank *bank = &meminfo.bank[meminfo.nr_banks]; 4084b5f32ceSNicolas Pitre 4094b5f32ceSNicolas Pitre if (meminfo.nr_banks >= NR_BANKS) { 4104b5f32ceSNicolas Pitre printk(KERN_CRIT "NR_BANKS too low, " 4114b5f32ceSNicolas Pitre "ignoring memory at %#lx\n", start); 4124b5f32ceSNicolas Pitre return -EINVAL; 4134b5f32ceSNicolas Pitre } 41405f96ef1SRussell King 4153a669411SRussell King /* 4163a669411SRussell King * Ensure that start/size are aligned to a page boundary. 4173a669411SRussell King * Size is appropriately rounded down, start is rounded up. 4183a669411SRussell King */ 4193a669411SRussell King size -= start & ~PAGE_MASK; 42005f96ef1SRussell King bank->start = PAGE_ALIGN(start); 42105f96ef1SRussell King bank->size = size & PAGE_MASK; 42205f96ef1SRussell King bank->node = PHYS_TO_NID(start); 4234b5f32ceSNicolas Pitre 4244b5f32ceSNicolas Pitre /* 4254b5f32ceSNicolas Pitre * Check whether this memory region has non-zero size or 4264b5f32ceSNicolas Pitre * invalid node number. 4274b5f32ceSNicolas Pitre */ 4284b5f32ceSNicolas Pitre if (bank->size == 0 || bank->node >= MAX_NUMNODES) 4294b5f32ceSNicolas Pitre return -EINVAL; 4304b5f32ceSNicolas Pitre 4314b5f32ceSNicolas Pitre meminfo.nr_banks++; 4324b5f32ceSNicolas Pitre return 0; 4333a669411SRussell King } 4343a669411SRussell King 4351da177e4SLinus Torvalds /* 4361da177e4SLinus Torvalds * Pick out the memory size. We look for mem=size@start, 4371da177e4SLinus Torvalds * where start and size are "size[KkMm]" 4381da177e4SLinus Torvalds */ 4392b0d8c25SJeremy Kerr static int __init early_mem(char *p) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds static int usermem __initdata = 0; 4421da177e4SLinus Torvalds unsigned long size, start; 4432b0d8c25SJeremy Kerr char *endp; 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /* 4461da177e4SLinus Torvalds * If the user specifies memory size, we 4471da177e4SLinus Torvalds * blow away any automatically generated 4481da177e4SLinus Torvalds * size. 4491da177e4SLinus Torvalds */ 4501da177e4SLinus Torvalds if (usermem == 0) { 4511da177e4SLinus Torvalds usermem = 1; 4521da177e4SLinus Torvalds meminfo.nr_banks = 0; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds start = PHYS_OFFSET; 4562b0d8c25SJeremy Kerr size = memparse(p, &endp); 4572b0d8c25SJeremy Kerr if (*endp == '@') 4582b0d8c25SJeremy Kerr start = memparse(endp + 1, NULL); 4591da177e4SLinus Torvalds 4601c97b73eSAndrew Morton arm_add_memory(start, size); 4611da177e4SLinus Torvalds 4622b0d8c25SJeremy Kerr return 0; 4631da177e4SLinus Torvalds } 4642b0d8c25SJeremy Kerr early_param("mem", early_mem); 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds static void __init 4671da177e4SLinus Torvalds setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) 4681da177e4SLinus Torvalds { 4691da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_RAM 4701da177e4SLinus Torvalds extern int rd_size, rd_image_start, rd_prompt, rd_doload; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds rd_image_start = image_start; 4731da177e4SLinus Torvalds rd_prompt = prompt; 4741da177e4SLinus Torvalds rd_doload = doload; 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds if (rd_sz) 4771da177e4SLinus Torvalds rd_size = rd_sz; 4781da177e4SLinus Torvalds #endif 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds static void __init 4821da177e4SLinus Torvalds request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) 4831da177e4SLinus Torvalds { 4841da177e4SLinus Torvalds struct resource *res; 4851da177e4SLinus Torvalds int i; 4861da177e4SLinus Torvalds 48737efe642SRussell King kernel_code.start = virt_to_phys(_text); 48837efe642SRussell King kernel_code.end = virt_to_phys(_etext - 1); 48937efe642SRussell King kernel_data.start = virt_to_phys(_data); 49037efe642SRussell King kernel_data.end = virt_to_phys(_end - 1); 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds for (i = 0; i < mi->nr_banks; i++) { 4931da177e4SLinus Torvalds if (mi->bank[i].size == 0) 4941da177e4SLinus Torvalds continue; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds res = alloc_bootmem_low(sizeof(*res)); 4971da177e4SLinus Torvalds res->name = "System RAM"; 4983319f5e5SNicolas Pitre res->start = mi->bank[i].start; 4993319f5e5SNicolas Pitre res->end = mi->bank[i].start + mi->bank[i].size - 1; 5001da177e4SLinus Torvalds res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds request_resource(&iomem_resource, res); 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds if (kernel_code.start >= res->start && 5051da177e4SLinus Torvalds kernel_code.end <= res->end) 5061da177e4SLinus Torvalds request_resource(res, &kernel_code); 5071da177e4SLinus Torvalds if (kernel_data.start >= res->start && 5081da177e4SLinus Torvalds kernel_data.end <= res->end) 5091da177e4SLinus Torvalds request_resource(res, &kernel_data); 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds if (mdesc->video_start) { 5131da177e4SLinus Torvalds video_ram.start = mdesc->video_start; 5141da177e4SLinus Torvalds video_ram.end = mdesc->video_end; 5151da177e4SLinus Torvalds request_resource(&iomem_resource, &video_ram); 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds /* 5191da177e4SLinus Torvalds * Some machines don't have the possibility of ever 5201da177e4SLinus Torvalds * possessing lp0, lp1 or lp2 5211da177e4SLinus Torvalds */ 5221da177e4SLinus Torvalds if (mdesc->reserve_lp0) 5231da177e4SLinus Torvalds request_resource(&ioport_resource, &lp0); 5241da177e4SLinus Torvalds if (mdesc->reserve_lp1) 5251da177e4SLinus Torvalds request_resource(&ioport_resource, &lp1); 5261da177e4SLinus Torvalds if (mdesc->reserve_lp2) 5271da177e4SLinus Torvalds request_resource(&ioport_resource, &lp2); 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /* 5311da177e4SLinus Torvalds * Tag parsing. 5321da177e4SLinus Torvalds * 5331da177e4SLinus Torvalds * This is the new way of passing data to the kernel at boot time. Rather 5341da177e4SLinus Torvalds * than passing a fixed inflexible structure to the kernel, we pass a list 5351da177e4SLinus Torvalds * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE 5361da177e4SLinus Torvalds * tag for the list to be recognised (to distinguish the tagged list from 5371da177e4SLinus Torvalds * a param_struct). The list is terminated with a zero-length tag (this tag 5381da177e4SLinus Torvalds * is not parsed in any way). 5391da177e4SLinus Torvalds */ 5401da177e4SLinus Torvalds static int __init parse_tag_core(const struct tag *tag) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds if (tag->hdr.size > 2) { 5431da177e4SLinus Torvalds if ((tag->u.core.flags & 1) == 0) 5441da177e4SLinus Torvalds root_mountflags &= ~MS_RDONLY; 5451da177e4SLinus Torvalds ROOT_DEV = old_decode_dev(tag->u.core.rootdev); 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds return 0; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds __tagtable(ATAG_CORE, parse_tag_core); 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds static int __init parse_tag_mem32(const struct tag *tag) 5531da177e4SLinus Torvalds { 5544b5f32ceSNicolas Pitre return arm_add_memory(tag->u.mem.start, tag->u.mem.size); 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds __tagtable(ATAG_MEM, parse_tag_mem32); 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) 5601da177e4SLinus Torvalds struct screen_info screen_info = { 5611da177e4SLinus Torvalds .orig_video_lines = 30, 5621da177e4SLinus Torvalds .orig_video_cols = 80, 5631da177e4SLinus Torvalds .orig_video_mode = 0, 5641da177e4SLinus Torvalds .orig_video_ega_bx = 0, 5651da177e4SLinus Torvalds .orig_video_isVGA = 1, 5661da177e4SLinus Torvalds .orig_video_points = 8 5671da177e4SLinus Torvalds }; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds static int __init parse_tag_videotext(const struct tag *tag) 5701da177e4SLinus Torvalds { 5711da177e4SLinus Torvalds screen_info.orig_x = tag->u.videotext.x; 5721da177e4SLinus Torvalds screen_info.orig_y = tag->u.videotext.y; 5731da177e4SLinus Torvalds screen_info.orig_video_page = tag->u.videotext.video_page; 5741da177e4SLinus Torvalds screen_info.orig_video_mode = tag->u.videotext.video_mode; 5751da177e4SLinus Torvalds screen_info.orig_video_cols = tag->u.videotext.video_cols; 5761da177e4SLinus Torvalds screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; 5771da177e4SLinus Torvalds screen_info.orig_video_lines = tag->u.videotext.video_lines; 5781da177e4SLinus Torvalds screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; 5791da177e4SLinus Torvalds screen_info.orig_video_points = tag->u.videotext.video_points; 5801da177e4SLinus Torvalds return 0; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); 5841da177e4SLinus Torvalds #endif 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds static int __init parse_tag_ramdisk(const struct tag *tag) 5871da177e4SLinus Torvalds { 5881da177e4SLinus Torvalds setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, 5891da177e4SLinus Torvalds (tag->u.ramdisk.flags & 2) == 0, 5901da177e4SLinus Torvalds tag->u.ramdisk.start, tag->u.ramdisk.size); 5911da177e4SLinus Torvalds return 0; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds __tagtable(ATAG_RAMDISK, parse_tag_ramdisk); 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds static int __init parse_tag_serialnr(const struct tag *tag) 5971da177e4SLinus Torvalds { 5981da177e4SLinus Torvalds system_serial_low = tag->u.serialnr.low; 5991da177e4SLinus Torvalds system_serial_high = tag->u.serialnr.high; 6001da177e4SLinus Torvalds return 0; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds __tagtable(ATAG_SERIAL, parse_tag_serialnr); 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds static int __init parse_tag_revision(const struct tag *tag) 6061da177e4SLinus Torvalds { 6071da177e4SLinus Torvalds system_rev = tag->u.revision.rev; 6081da177e4SLinus Torvalds return 0; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds __tagtable(ATAG_REVISION, parse_tag_revision); 6121da177e4SLinus Torvalds 61392d2040dSAlexander Holler #ifndef CONFIG_CMDLINE_FORCE 6141da177e4SLinus Torvalds static int __init parse_tag_cmdline(const struct tag *tag) 6151da177e4SLinus Torvalds { 6161da177e4SLinus Torvalds strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); 6171da177e4SLinus Torvalds return 0; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds __tagtable(ATAG_CMDLINE, parse_tag_cmdline); 62192d2040dSAlexander Holler #endif /* CONFIG_CMDLINE_FORCE */ 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds /* 6241da177e4SLinus Torvalds * Scan the tag table for this tag, and call its parse function. 6251da177e4SLinus Torvalds * The tag table is built by the linker from all the __tagtable 6261da177e4SLinus Torvalds * declarations. 6271da177e4SLinus Torvalds */ 6281da177e4SLinus Torvalds static int __init parse_tag(const struct tag *tag) 6291da177e4SLinus Torvalds { 6301da177e4SLinus Torvalds extern struct tagtable __tagtable_begin, __tagtable_end; 6311da177e4SLinus Torvalds struct tagtable *t; 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds for (t = &__tagtable_begin; t < &__tagtable_end; t++) 6341da177e4SLinus Torvalds if (tag->hdr.tag == t->tag) { 6351da177e4SLinus Torvalds t->parse(tag); 6361da177e4SLinus Torvalds break; 6371da177e4SLinus Torvalds } 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds return t < &__tagtable_end; 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds /* 6431da177e4SLinus Torvalds * Parse all tags in the list, checking both the global and architecture 6441da177e4SLinus Torvalds * specific tag tables. 6451da177e4SLinus Torvalds */ 6461da177e4SLinus Torvalds static void __init parse_tags(const struct tag *t) 6471da177e4SLinus Torvalds { 6481da177e4SLinus Torvalds for (; t->hdr.size; t = tag_next(t)) 6491da177e4SLinus Torvalds if (!parse_tag(t)) 6501da177e4SLinus Torvalds printk(KERN_WARNING 6511da177e4SLinus Torvalds "Ignoring unrecognised tag 0x%08x\n", 6521da177e4SLinus Torvalds t->hdr.tag); 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds /* 6561da177e4SLinus Torvalds * This holds our defaults. 6571da177e4SLinus Torvalds */ 6581da177e4SLinus Torvalds static struct init_tags { 6591da177e4SLinus Torvalds struct tag_header hdr1; 6601da177e4SLinus Torvalds struct tag_core core; 6611da177e4SLinus Torvalds struct tag_header hdr2; 6621da177e4SLinus Torvalds struct tag_mem32 mem; 6631da177e4SLinus Torvalds struct tag_header hdr3; 6641da177e4SLinus Torvalds } init_tags __initdata = { 6651da177e4SLinus Torvalds { tag_size(tag_core), ATAG_CORE }, 6661da177e4SLinus Torvalds { 1, PAGE_SIZE, 0xff }, 6671da177e4SLinus Torvalds { tag_size(tag_mem32), ATAG_MEM }, 6681da177e4SLinus Torvalds { MEM_SIZE, PHYS_OFFSET }, 6691da177e4SLinus Torvalds { 0, ATAG_NONE } 6701da177e4SLinus Torvalds }; 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds static void (*init_machine)(void) __initdata; 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds static int __init customize_machine(void) 6751da177e4SLinus Torvalds { 6761da177e4SLinus Torvalds /* customizes platform devices, or adds new ones */ 6771da177e4SLinus Torvalds if (init_machine) 6781da177e4SLinus Torvalds init_machine(); 6791da177e4SLinus Torvalds return 0; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds arch_initcall(customize_machine); 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds void __init setup_arch(char **cmdline_p) 6841da177e4SLinus Torvalds { 6851da177e4SLinus Torvalds struct tag *tags = (struct tag *)&init_tags; 6861da177e4SLinus Torvalds struct machine_desc *mdesc; 6871da177e4SLinus Torvalds char *from = default_command_line; 6881da177e4SLinus Torvalds 689bff595c1SCatalin Marinas unwind_init(); 690bff595c1SCatalin Marinas 6911da177e4SLinus Torvalds setup_processor(); 6921da177e4SLinus Torvalds mdesc = setup_machine(machine_arch_type); 6931da177e4SLinus Torvalds machine_name = mdesc->name; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds if (mdesc->soft_reboot) 6961da177e4SLinus Torvalds reboot_setup("s"); 6971da177e4SLinus Torvalds 6989d20fdd5SBill Gatliff if (__atags_pointer) 6999d20fdd5SBill Gatliff tags = phys_to_virt(__atags_pointer); 7009d20fdd5SBill Gatliff else if (mdesc->boot_params) 701f9bd6ea4SRussell King tags = phys_to_virt(mdesc->boot_params); 7021da177e4SLinus Torvalds 7031da177e4SLinus Torvalds /* 7041da177e4SLinus Torvalds * If we have the old style parameters, convert them to 7051da177e4SLinus Torvalds * a tag list. 7061da177e4SLinus Torvalds */ 7071da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 7081da177e4SLinus Torvalds convert_to_tag_list(tags); 7091da177e4SLinus Torvalds if (tags->hdr.tag != ATAG_CORE) 7101da177e4SLinus Torvalds tags = (struct tag *)&init_tags; 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds if (mdesc->fixup) 7131da177e4SLinus Torvalds mdesc->fixup(mdesc, tags, &from, &meminfo); 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds if (tags->hdr.tag == ATAG_CORE) { 7161da177e4SLinus Torvalds if (meminfo.nr_banks != 0) 7171da177e4SLinus Torvalds squash_mem_tags(tags); 7184cd9d6f7SRichard Purdie save_atags(tags); 7191da177e4SLinus Torvalds parse_tags(tags); 7201da177e4SLinus Torvalds } 7211da177e4SLinus Torvalds 72237efe642SRussell King init_mm.start_code = (unsigned long) _text; 72337efe642SRussell King init_mm.end_code = (unsigned long) _etext; 72437efe642SRussell King init_mm.end_data = (unsigned long) _edata; 72537efe642SRussell King init_mm.brk = (unsigned long) _end; 7261da177e4SLinus Torvalds 7272b0d8c25SJeremy Kerr /* parse_early_param needs a boot_command_line */ 7282b0d8c25SJeremy Kerr strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); 7292b0d8c25SJeremy Kerr 73048ab7e09SJeremy Kerr /* populate cmd_line too for later use, preserving boot_command_line */ 73148ab7e09SJeremy Kerr strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); 73248ab7e09SJeremy Kerr *cmdline_p = cmd_line; 7332b0d8c25SJeremy Kerr 7342b0d8c25SJeremy Kerr parse_early_param(); 7352b0d8c25SJeremy Kerr 7364b5f32ceSNicolas Pitre paging_init(mdesc); 7371da177e4SLinus Torvalds request_standard_resources(&meminfo, mdesc); 7381da177e4SLinus Torvalds 7397bbb7940SRussell King #ifdef CONFIG_SMP 7407bbb7940SRussell King smp_init_cpus(); 7417bbb7940SRussell King #endif 7427bbb7940SRussell King 743ccea7a19SRussell King cpu_init(); 744bc581770SLinus Walleij tcm_init(); 745ccea7a19SRussell King 7461da177e4SLinus Torvalds /* 7471da177e4SLinus Torvalds * Set up various architecture-specific pointers 7481da177e4SLinus Torvalds */ 749354e6f72Seric miao arch_nr_irqs = mdesc->nr_irqs; 7501da177e4SLinus Torvalds init_arch_irq = mdesc->init_irq; 7511da177e4SLinus Torvalds system_timer = mdesc->timer; 7521da177e4SLinus Torvalds init_machine = mdesc->init_machine; 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds #ifdef CONFIG_VT 7551da177e4SLinus Torvalds #if defined(CONFIG_VGA_CONSOLE) 7561da177e4SLinus Torvalds conswitchp = &vga_con; 7571da177e4SLinus Torvalds #elif defined(CONFIG_DUMMY_CONSOLE) 7581da177e4SLinus Torvalds conswitchp = &dummy_con; 7591da177e4SLinus Torvalds #endif 7601da177e4SLinus Torvalds #endif 7615cbad0ebSJason Wessel early_trap_init(); 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds static int __init topology_init(void) 7661da177e4SLinus Torvalds { 7671da177e4SLinus Torvalds int cpu; 7681da177e4SLinus Torvalds 76966fb8bd2SRussell King for_each_possible_cpu(cpu) { 77066fb8bd2SRussell King struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); 77166fb8bd2SRussell King cpuinfo->cpu.hotpluggable = 1; 77266fb8bd2SRussell King register_cpu(&cpuinfo->cpu, cpu); 77366fb8bd2SRussell King } 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds return 0; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds subsys_initcall(topology_init); 7781da177e4SLinus Torvalds 779e119bfffSRussell King #ifdef CONFIG_HAVE_PROC_CPU 780e119bfffSRussell King static int __init proc_cpu_init(void) 781e119bfffSRussell King { 782e119bfffSRussell King struct proc_dir_entry *res; 783e119bfffSRussell King 784e119bfffSRussell King res = proc_mkdir("cpu", NULL); 785e119bfffSRussell King if (!res) 786e119bfffSRussell King return -ENOMEM; 787e119bfffSRussell King return 0; 788e119bfffSRussell King } 789e119bfffSRussell King fs_initcall(proc_cpu_init); 790e119bfffSRussell King #endif 791e119bfffSRussell King 7921da177e4SLinus Torvalds static const char *hwcap_str[] = { 7931da177e4SLinus Torvalds "swp", 7941da177e4SLinus Torvalds "half", 7951da177e4SLinus Torvalds "thumb", 7961da177e4SLinus Torvalds "26bit", 7971da177e4SLinus Torvalds "fastmult", 7981da177e4SLinus Torvalds "fpa", 7991da177e4SLinus Torvalds "vfp", 8001da177e4SLinus Torvalds "edsp", 8011da177e4SLinus Torvalds "java", 8028f7f9435SPaul Gortmaker "iwmmxt", 80399e4a6ddSLennert Buytenhek "crunch", 8044369ae16SCatalin Marinas "thumbee", 8052bedbdf4SCatalin Marinas "neon", 8067279dc3eSCatalin Marinas "vfpv3", 8077279dc3eSCatalin Marinas "vfpv3d16", 8081da177e4SLinus Torvalds NULL 8091da177e4SLinus Torvalds }; 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *v) 8121da177e4SLinus Torvalds { 8131da177e4SLinus Torvalds int i; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds seq_printf(m, "Processor\t: %s rev %d (%s)\n", 8160ba8b9b2SRussell King cpu_name, read_cpuid_id() & 15, elf_platform); 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds #if defined(CONFIG_SMP) 8191da177e4SLinus Torvalds for_each_online_cpu(i) { 82015559722SRussell King /* 82115559722SRussell King * glibc reads /proc/cpuinfo to determine the number of 82215559722SRussell King * online processors, looking for lines beginning with 82315559722SRussell King * "processor". Give glibc what it expects. 82415559722SRussell King */ 82515559722SRussell King seq_printf(m, "processor\t: %d\n", i); 8261da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", 8271da177e4SLinus Torvalds per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), 8281da177e4SLinus Torvalds (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds #else /* CONFIG_SMP */ 8311da177e4SLinus Torvalds seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", 8321da177e4SLinus Torvalds loops_per_jiffy / (500000/HZ), 8331da177e4SLinus Torvalds (loops_per_jiffy / (5000/HZ)) % 100); 8341da177e4SLinus Torvalds #endif 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds /* dump out the processor features */ 8371da177e4SLinus Torvalds seq_puts(m, "Features\t: "); 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds for (i = 0; hwcap_str[i]; i++) 8401da177e4SLinus Torvalds if (elf_hwcap & (1 << i)) 8411da177e4SLinus Torvalds seq_printf(m, "%s ", hwcap_str[i]); 8421da177e4SLinus Torvalds 8430ba8b9b2SRussell King seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); 8441da177e4SLinus Torvalds seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); 8451da177e4SLinus Torvalds 8460ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00000000) { 8471da177e4SLinus Torvalds /* pre-ARM7 */ 8480ba8b9b2SRussell King seq_printf(m, "CPU part\t: %07x\n", read_cpuid_id() >> 4); 8491da177e4SLinus Torvalds } else { 8500ba8b9b2SRussell King if ((read_cpuid_id() & 0x0008f000) == 0x00007000) { 8511da177e4SLinus Torvalds /* ARM7 */ 8521da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%02x\n", 8530ba8b9b2SRussell King (read_cpuid_id() >> 16) & 127); 8541da177e4SLinus Torvalds } else { 8551da177e4SLinus Torvalds /* post-ARM7 */ 8561da177e4SLinus Torvalds seq_printf(m, "CPU variant\t: 0x%x\n", 8570ba8b9b2SRussell King (read_cpuid_id() >> 20) & 15); 8581da177e4SLinus Torvalds } 8591da177e4SLinus Torvalds seq_printf(m, "CPU part\t: 0x%03x\n", 8600ba8b9b2SRussell King (read_cpuid_id() >> 4) & 0xfff); 8611da177e4SLinus Torvalds } 8620ba8b9b2SRussell King seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds seq_puts(m, "\n"); 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds seq_printf(m, "Hardware\t: %s\n", machine_name); 8671da177e4SLinus Torvalds seq_printf(m, "Revision\t: %04x\n", system_rev); 8681da177e4SLinus Torvalds seq_printf(m, "Serial\t\t: %08x%08x\n", 8691da177e4SLinus Torvalds system_serial_high, system_serial_low); 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds return 0; 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds static void *c_start(struct seq_file *m, loff_t *pos) 8751da177e4SLinus Torvalds { 8761da177e4SLinus Torvalds return *pos < 1 ? (void *)1 : NULL; 8771da177e4SLinus Torvalds } 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds static void *c_next(struct seq_file *m, void *v, loff_t *pos) 8801da177e4SLinus Torvalds { 8811da177e4SLinus Torvalds ++*pos; 8821da177e4SLinus Torvalds return NULL; 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds static void c_stop(struct seq_file *m, void *v) 8861da177e4SLinus Torvalds { 8871da177e4SLinus Torvalds } 8881da177e4SLinus Torvalds 8892ffd6e18SJan Engelhardt const struct seq_operations cpuinfo_op = { 8901da177e4SLinus Torvalds .start = c_start, 8911da177e4SLinus Torvalds .next = c_next, 8921da177e4SLinus Torvalds .stop = c_stop, 8931da177e4SLinus Torvalds .show = c_show 8941da177e4SLinus Torvalds }; 895