2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / kernel / setup . c
*
* Copyright ( C ) 1995 - 2001 Russell King
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/stddef.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/utsname.h>
# include <linux/initrd.h>
# include <linux/console.h>
# include <linux/bootmem.h>
# include <linux/seq_file.h>
2006-07-10 15:44:13 +04:00
# include <linux/screen_info.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/root_dev.h>
# include <linux/cpu.h>
# include <linux/interrupt.h>
2006-02-16 14:08:09 +03:00
# include <linux/smp.h>
2007-07-30 02:36:13 +04:00
# include <linux/fs.h>
2010-01-10 20:23:29 +03:00
# include <linux/proc_fs.h>
2010-07-09 19:27:52 +04:00
# include <linux/memblock.h>
2005-04-17 02:20:36 +04:00
2009-07-24 15:32:54 +04:00
# include <asm/unified.h>
2005-04-17 02:20:36 +04:00
# include <asm/cpu.h>
2008-08-10 21:08:10 +04:00
# include <asm/cputype.h>
2005-04-17 02:20:36 +04:00
# include <asm/elf.h>
# include <asm/procinfo.h>
2008-12-01 14:53:07 +03:00
# include <asm/sections.h>
2005-04-17 02:20:36 +04:00
# include <asm/setup.h>
# include <asm/mach-types.h>
# include <asm/cacheflush.h>
2008-08-10 21:10:19 +04:00
# include <asm/cachetype.h>
2005-04-17 02:20:36 +04:00
# include <asm/tlbflush.h>
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/time.h>
2008-02-20 22:33:40 +03:00
# include <asm/traps.h>
2009-02-16 13:41:36 +03:00
# include <asm/unwind.h>
2005-04-17 02:20:36 +04:00
2006-03-16 02:17:30 +03:00
# include "compat.h"
2008-01-02 02:56:46 +03:00
# include "atags.h"
2009-09-15 20:30:37 +04:00
# include "tcm.h"
2006-03-16 02:17:30 +03:00
2005-04-17 02:20:36 +04:00
# ifndef MEM_SIZE
# define MEM_SIZE (16*1024*1024)
# endif
# if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
char fpe_type [ 8 ] ;
static int __init fpe_setup ( char * line )
{
memcpy ( fpe_type , line , 8 ) ;
return 1 ;
}
__setup ( " fpe= " , fpe_setup ) ;
# endif
2008-10-06 21:24:40 +04:00
extern void paging_init ( struct machine_desc * desc ) ;
2005-04-17 02:20:36 +04:00
extern void reboot_setup ( char * str ) ;
unsigned int processor_id ;
2007-12-18 05:53:27 +03:00
EXPORT_SYMBOL ( processor_id ) ;
2005-04-17 02:20:36 +04:00
unsigned int __machine_arch_type ;
EXPORT_SYMBOL ( __machine_arch_type ) ;
2008-09-25 18:35:28 +04:00
unsigned int cacheid ;
EXPORT_SYMBOL ( cacheid ) ;
2005-04-17 02:20:36 +04:00
2007-06-01 01:02:22 +04:00
unsigned int __atags_pointer __initdata ;
2005-04-17 02:20:36 +04:00
unsigned int system_rev ;
EXPORT_SYMBOL ( system_rev ) ;
unsigned int system_serial_low ;
EXPORT_SYMBOL ( system_serial_low ) ;
unsigned int system_serial_high ;
EXPORT_SYMBOL ( system_serial_high ) ;
unsigned int elf_hwcap ;
EXPORT_SYMBOL ( elf_hwcap ) ;
# ifdef MULTI_CPU
struct processor processor ;
# endif
# ifdef MULTI_TLB
struct cpu_tlb_fns cpu_tlb ;
# endif
# ifdef MULTI_USER
struct cpu_user_fns cpu_user ;
# endif
# ifdef MULTI_CACHE
struct cpu_cache_fns cpu_cache ;
# endif
2007-02-05 16:48:08 +03:00
# ifdef CONFIG_OUTER_CACHE
struct outer_cache_fns outer_cache ;
2010-02-16 09:57:43 +03:00
EXPORT_SYMBOL ( outer_cache ) ;
2007-02-05 16:48:08 +03:00
# endif
2005-04-17 02:20:36 +04:00
2005-06-01 01:22:32 +04:00
struct stack {
u32 irq [ 3 ] ;
u32 abt [ 3 ] ;
u32 und [ 3 ] ;
} ____cacheline_aligned ;
static struct stack stacks [ NR_CPUS ] ;
2005-04-17 02:20:36 +04:00
char elf_platform [ ELF_PLATFORM_SIZE ] ;
EXPORT_SYMBOL ( elf_platform ) ;
static const char * cpu_name ;
static const char * machine_name ;
2010-01-27 03:13:31 +03:00
static char __initdata cmd_line [ COMMAND_LINE_SIZE ] ;
2005-04-17 02:20:36 +04:00
static char default_command_line [ COMMAND_LINE_SIZE ] __initdata = CONFIG_CMDLINE ;
static union { char c [ 4 ] ; unsigned long l ; } endian_test __initdata = { { ' l ' , ' ? ' , ' ? ' , ' b ' } } ;
# define ENDIANNESS ((char)endian_test.l)
DEFINE_PER_CPU ( struct cpuinfo_arm , cpu_data ) ;
/*
* Standard memory resources
*/
static struct resource mem_res [ ] = {
2006-06-13 01:47:06 +04:00
{
. name = " Video RAM " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_MEM
} ,
{
. name = " Kernel text " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_MEM
} ,
{
. name = " Kernel data " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_MEM
}
2005-04-17 02:20:36 +04:00
} ;
# define video_ram mem_res[0]
# define kernel_code mem_res[1]
# define kernel_data mem_res[2]
static struct resource io_res [ ] = {
2006-06-13 01:47:06 +04:00
{
. name = " reserved " ,
. start = 0x3bc ,
. end = 0x3be ,
. flags = IORESOURCE_IO | IORESOURCE_BUSY
} ,
{
. name = " reserved " ,
. start = 0x378 ,
. end = 0x37f ,
. flags = IORESOURCE_IO | IORESOURCE_BUSY
} ,
{
. name = " reserved " ,
. start = 0x278 ,
. end = 0x27f ,
. flags = IORESOURCE_IO | IORESOURCE_BUSY
}
2005-04-17 02:20:36 +04:00
} ;
# define lp0 io_res[0]
# define lp1 io_res[1]
# define lp2 io_res[2]
static const char * proc_arch [ ] = {
" undefined/unknown " ,
" 3 " ,
" 4 " ,
" 4T " ,
" 5 " ,
" 5T " ,
" 5TE " ,
" 5TEJ " ,
" 6TEJ " ,
2006-01-12 19:28:16 +03:00
" 7 " ,
2005-04-17 02:20:36 +04:00
" ?(11) " ,
" ?(12) " ,
" ?(13) " ,
" ?(14) " ,
" ?(15) " ,
" ?(16) " ,
" ?(17) " ,
} ;
int cpu_architecture ( void )
{
int cpu_arch ;
2008-08-10 21:08:10 +04:00
if ( ( read_cpuid_id ( ) & 0x0008f000 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
cpu_arch = CPU_ARCH_UNKNOWN ;
2008-08-10 21:08:10 +04:00
} else if ( ( read_cpuid_id ( ) & 0x0008f000 ) = = 0x00007000 ) {
cpu_arch = ( read_cpuid_id ( ) & ( 1 < < 23 ) ) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3 ;
} else if ( ( read_cpuid_id ( ) & 0x00080000 ) = = 0x00000000 ) {
cpu_arch = ( read_cpuid_id ( ) > > 16 ) & 7 ;
2005-04-17 02:20:36 +04:00
if ( cpu_arch )
cpu_arch + = CPU_ARCH_ARMv3 ;
2008-08-10 21:08:10 +04:00
} else if ( ( read_cpuid_id ( ) & 0x000f0000 ) = = 0x000f0000 ) {
2007-09-25 19:49:45 +04:00
unsigned int mmfr0 ;
/* Revised CPUID format. Read the Memory Model Feature
* Register 0 and check for VMSAv7 or PMSAv7 */
asm ( " mrc p15, 0, %0, c0, c1, 4 "
: " =r " ( mmfr0 ) ) ;
if ( ( mmfr0 & 0x0000000f ) = = 0x00000003 | |
( mmfr0 & 0x000000f0 ) = = 0x00000030 )
cpu_arch = CPU_ARCH_ARMv7 ;
else if ( ( mmfr0 & 0x0000000f ) = = 0x00000002 | |
( mmfr0 & 0x000000f0 ) = = 0x00000020 )
cpu_arch = CPU_ARCH_ARMv6 ;
else
cpu_arch = CPU_ARCH_UNKNOWN ;
} else
cpu_arch = CPU_ARCH_UNKNOWN ;
2005-04-17 02:20:36 +04:00
return cpu_arch ;
}
2008-09-25 18:35:28 +04:00
static void __init cacheid_init ( void )
{
unsigned int cachetype = read_cpuid_cachetype ( ) ;
unsigned int arch = cpu_architecture ( ) ;
2009-03-03 13:44:12 +03:00
if ( arch > = CPU_ARCH_ARMv6 ) {
if ( ( cachetype & ( 7 < < 29 ) ) = = 4 < < 29 ) {
/* ARMv7 register format */
cacheid = CACHEID_VIPT_NONALIASING ;
if ( ( cachetype & ( 3 < < 14 ) ) = = 1 < < 14 )
cacheid | = CACHEID_ASID_TAGGED ;
} else if ( cachetype & ( 1 < < 23 ) )
2008-09-25 18:35:28 +04:00
cacheid = CACHEID_VIPT_ALIASING ;
else
cacheid = CACHEID_VIPT_NONALIASING ;
} else {
cacheid = CACHEID_VIVT ;
}
2008-09-25 18:39:20 +04:00
printk ( " CPU: %s data cache, %s instruction cache \n " ,
cache_is_vivt ( ) ? " VIVT " :
cache_is_vipt_aliasing ( ) ? " VIPT aliasing " :
cache_is_vipt_nonaliasing ( ) ? " VIPT nonaliasing " : " unknown " ,
cache_is_vivt ( ) ? " VIVT " :
icache_is_vivt_asid_tagged ( ) ? " VIVT ASID tagged " :
cache_is_vipt_aliasing ( ) ? " VIPT aliasing " :
cache_is_vipt_nonaliasing ( ) ? " VIPT nonaliasing " : " unknown " ) ;
2008-09-25 18:35:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* These functions re - use the assembly code in head . S , which
* already provide the required functionality .
*/
2006-02-25 00:04:56 +03:00
extern struct proc_info_list * lookup_processor_type ( unsigned int ) ;
2005-04-17 02:20:36 +04:00
extern struct machine_desc * lookup_machine_type ( unsigned int ) ;
static void __init setup_processor ( void )
{
struct proc_info_list * list ;
/*
* locate processor in the list of supported processor
* types . The linker builds this table for us from the
* entries in arch / arm / mm / proc - * . S
*/
2008-08-10 21:08:10 +04:00
list = lookup_processor_type ( read_cpuid_id ( ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! list ) {
printk ( " CPU configuration botched (ID %08x), unable "
2008-08-10 21:08:10 +04:00
" to continue. \n " , read_cpuid_id ( ) ) ;
2005-04-17 02:20:36 +04:00
while ( 1 ) ;
}
cpu_name = list - > cpu_name ;
# ifdef MULTI_CPU
processor = * list - > proc ;
# endif
# ifdef MULTI_TLB
cpu_tlb = * list - > tlb ;
# endif
# ifdef MULTI_USER
cpu_user = * list - > user ;
# endif
# ifdef MULTI_CACHE
cpu_cache = * list - > cache ;
# endif
2006-07-03 16:29:38 +04:00
printk ( " CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx \n " ,
2008-08-10 21:08:10 +04:00
cpu_name , read_cpuid_id ( ) , read_cpuid_id ( ) & 15 ,
2006-06-29 18:03:09 +04:00
proc_arch [ cpu_architecture ( ) ] , cr_alignment ) ;
2005-04-17 02:20:36 +04:00
2006-10-02 13:18:13 +04:00
sprintf ( init_utsname ( ) - > machine , " %s%c " , list - > arch_name , ENDIANNESS ) ;
2005-04-17 02:20:36 +04:00
sprintf ( elf_platform , " %s%c " , list - > elf_name , ENDIANNESS ) ;
elf_hwcap = list - > elf_hwcap ;
2006-04-11 00:32:35 +04:00
# ifndef CONFIG_ARM_THUMB
elf_hwcap & = ~ HWCAP_THUMB ;
# endif
2005-04-17 02:20:36 +04:00
2008-09-25 18:35:28 +04:00
cacheid_init ( ) ;
2005-04-17 02:20:36 +04:00
cpu_proc_init ( ) ;
}
2005-06-01 01:22:32 +04:00
/*
* cpu_init - initialise one CPU .
*
2008-09-25 17:45:02 +04:00
* cpu_init sets up the per - CPU stacks .
2005-06-01 01:22:32 +04:00
*/
2005-06-19 21:39:33 +04:00
void cpu_init ( void )
2005-06-01 01:22:32 +04:00
{
unsigned int cpu = smp_processor_id ( ) ;
struct stack * stk = & stacks [ cpu ] ;
if ( cpu > = NR_CPUS ) {
printk ( KERN_CRIT " CPU%u: bad primary CPU number \n " , cpu ) ;
BUG ( ) ;
}
2009-07-24 15:32:54 +04:00
/*
* Define the placement constraint for the inline asm directive below .
* In Thumb - 2 , msr with an immediate value is not allowed .
*/
# ifdef CONFIG_THUMB2_KERNEL
# define PLC "r"
# else
# define PLC "I"
# endif
2005-06-01 01:22:32 +04:00
/*
* setup stacks for re - entrant exception handlers
*/
__asm__ (
" msr cpsr_c, %1 \n \t "
2009-07-24 15:32:54 +04:00
" add r14, %0, %2 \n \t "
" mov sp, r14 \n \t "
2005-06-01 01:22:32 +04:00
" msr cpsr_c, %3 \n \t "
2009-07-24 15:32:54 +04:00
" add r14, %0, %4 \n \t "
" mov sp, r14 \n \t "
2005-06-01 01:22:32 +04:00
" msr cpsr_c, %5 \n \t "
2009-07-24 15:32:54 +04:00
" add r14, %0, %6 \n \t "
" mov sp, r14 \n \t "
2005-06-01 01:22:32 +04:00
" msr cpsr_c, %7 "
:
: " r " ( stk ) ,
2009-07-24 15:32:54 +04:00
PLC ( PSR_F_BIT | PSR_I_BIT | IRQ_MODE ) ,
2005-06-01 01:22:32 +04:00
" I " ( offsetof ( struct stack , irq [ 0 ] ) ) ,
2009-07-24 15:32:54 +04:00
PLC ( PSR_F_BIT | PSR_I_BIT | ABT_MODE ) ,
2005-06-01 01:22:32 +04:00
" I " ( offsetof ( struct stack , abt [ 0 ] ) ) ,
2009-07-24 15:32:54 +04:00
PLC ( PSR_F_BIT | PSR_I_BIT | UND_MODE ) ,
2005-06-01 01:22:32 +04:00
" I " ( offsetof ( struct stack , und [ 0 ] ) ) ,
2009-07-24 15:32:54 +04:00
PLC ( PSR_F_BIT | PSR_I_BIT | SVC_MODE )
2005-06-29 18:34:39 +04:00
: " r14 " ) ;
2005-06-01 01:22:32 +04:00
}
2005-04-17 02:20:36 +04:00
static struct machine_desc * __init setup_machine ( unsigned int nr )
{
struct machine_desc * list ;
/*
* locate machine in the list of supported machines .
*/
list = lookup_machine_type ( nr ) ;
if ( ! list ) {
printk ( " Machine configuration botched (nr %d), unable "
" to continue. \n " , nr ) ;
while ( 1 ) ;
}
printk ( " Machine: %s \n " , list - > name ) ;
return list ;
}
2008-10-06 21:24:40 +04:00
static int __init arm_add_memory ( unsigned long start , unsigned long size )
2005-06-23 00:43:10 +04:00
{
2008-10-06 21:24:40 +04:00
struct membank * bank = & meminfo . bank [ meminfo . nr_banks ] ;
if ( meminfo . nr_banks > = NR_BANKS ) {
printk ( KERN_CRIT " NR_BANKS too low, "
" ignoring memory at %#lx \n " , start ) ;
return - EINVAL ;
}
2006-11-30 23:44:49 +03:00
2005-06-23 00:43:10 +04:00
/*
* Ensure that start / size are aligned to a page boundary .
* Size is appropriately rounded down , start is rounded up .
*/
size - = start & ~ PAGE_MASK ;
2006-11-30 23:44:49 +03:00
bank - > start = PAGE_ALIGN ( start ) ;
bank - > size = size & PAGE_MASK ;
2008-10-06 21:24:40 +04:00
/*
* Check whether this memory region has non - zero size or
* invalid node number .
*/
2010-05-07 20:40:33 +04:00
if ( bank - > size = = 0 )
2008-10-06 21:24:40 +04:00
return - EINVAL ;
meminfo . nr_banks + + ;
return 0 ;
2005-06-23 00:43:10 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Pick out the memory size . We look for mem = size @ start ,
* where start and size are " size[KkMm] "
*/
2010-01-12 01:17:34 +03:00
static int __init early_mem ( char * p )
2005-04-17 02:20:36 +04:00
{
static int usermem __initdata = 0 ;
unsigned long size , start ;
2010-01-12 01:17:34 +03:00
char * endp ;
2005-04-17 02:20:36 +04:00
/*
* If the user specifies memory size , we
* blow away any automatically generated
* size .
*/
if ( usermem = = 0 ) {
usermem = 1 ;
meminfo . nr_banks = 0 ;
}
start = PHYS_OFFSET ;
2010-01-12 01:17:34 +03:00
size = memparse ( p , & endp ) ;
if ( * endp = = ' @ ' )
start = memparse ( endp + 1 , NULL ) ;
2005-04-17 02:20:36 +04:00
2006-04-21 00:41:18 +04:00
arm_add_memory ( start , size ) ;
2005-04-17 02:20:36 +04:00
2010-01-12 01:17:34 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-01-12 01:17:34 +03:00
early_param ( " mem " , early_mem ) ;
2005-04-17 02:20:36 +04:00
static void __init
setup_ramdisk ( int doload , int prompt , int image_start , unsigned int rd_sz )
{
# ifdef CONFIG_BLK_DEV_RAM
extern int rd_size , rd_image_start , rd_prompt , rd_doload ;
rd_image_start = image_start ;
rd_prompt = prompt ;
rd_doload = doload ;
if ( rd_sz )
rd_size = rd_sz ;
# endif
}
static void __init
request_standard_resources ( struct meminfo * mi , struct machine_desc * mdesc )
{
struct resource * res ;
int i ;
2008-12-01 14:53:07 +03:00
kernel_code . start = virt_to_phys ( _text ) ;
kernel_code . end = virt_to_phys ( _etext - 1 ) ;
kernel_data . start = virt_to_phys ( _data ) ;
kernel_data . end = virt_to_phys ( _end - 1 ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < mi - > nr_banks ; i + + ) {
if ( mi - > bank [ i ] . size = = 0 )
continue ;
res = alloc_bootmem_low ( sizeof ( * res ) ) ;
res - > name = " System RAM " ;
2008-10-02 06:29:22 +04:00
res - > start = mi - > bank [ i ] . start ;
res - > end = mi - > bank [ i ] . start + mi - > bank [ i ] . size - 1 ;
2005-04-17 02:20:36 +04:00
res - > flags = IORESOURCE_MEM | IORESOURCE_BUSY ;
request_resource ( & iomem_resource , res ) ;
if ( kernel_code . start > = res - > start & &
kernel_code . end < = res - > end )
request_resource ( res , & kernel_code ) ;
if ( kernel_data . start > = res - > start & &
kernel_data . end < = res - > end )
request_resource ( res , & kernel_data ) ;
}
if ( mdesc - > video_start ) {
video_ram . start = mdesc - > video_start ;
video_ram . end = mdesc - > video_end ;
request_resource ( & iomem_resource , & video_ram ) ;
}
/*
* Some machines don ' t have the possibility of ever
* possessing lp0 , lp1 or lp2
*/
if ( mdesc - > reserve_lp0 )
request_resource ( & ioport_resource , & lp0 ) ;
if ( mdesc - > reserve_lp1 )
request_resource ( & ioport_resource , & lp1 ) ;
if ( mdesc - > reserve_lp2 )
request_resource ( & ioport_resource , & lp2 ) ;
}
/*
* Tag parsing .
*
* This is the new way of passing data to the kernel at boot time . Rather
* than passing a fixed inflexible structure to the kernel , we pass a list
* of variable - sized tags to the kernel . The first tag must be a ATAG_CORE
* tag for the list to be recognised ( to distinguish the tagged list from
* a param_struct ) . The list is terminated with a zero - length tag ( this tag
* is not parsed in any way ) .
*/
static int __init parse_tag_core ( const struct tag * tag )
{
if ( tag - > hdr . size > 2 ) {
if ( ( tag - > u . core . flags & 1 ) = = 0 )
root_mountflags & = ~ MS_RDONLY ;
ROOT_DEV = old_decode_dev ( tag - > u . core . rootdev ) ;
}
return 0 ;
}
__tagtable ( ATAG_CORE , parse_tag_core ) ;
static int __init parse_tag_mem32 ( const struct tag * tag )
{
2008-10-06 21:24:40 +04:00
return arm_add_memory ( tag - > u . mem . start , tag - > u . mem . size ) ;
2005-04-17 02:20:36 +04:00
}
__tagtable ( ATAG_MEM , parse_tag_mem32 ) ;
# if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
struct screen_info screen_info = {
. orig_video_lines = 30 ,
. orig_video_cols = 80 ,
. orig_video_mode = 0 ,
. orig_video_ega_bx = 0 ,
. orig_video_isVGA = 1 ,
. orig_video_points = 8
} ;
static int __init parse_tag_videotext ( const struct tag * tag )
{
screen_info . orig_x = tag - > u . videotext . x ;
screen_info . orig_y = tag - > u . videotext . y ;
screen_info . orig_video_page = tag - > u . videotext . video_page ;
screen_info . orig_video_mode = tag - > u . videotext . video_mode ;
screen_info . orig_video_cols = tag - > u . videotext . video_cols ;
screen_info . orig_video_ega_bx = tag - > u . videotext . video_ega_bx ;
screen_info . orig_video_lines = tag - > u . videotext . video_lines ;
screen_info . orig_video_isVGA = tag - > u . videotext . video_isvga ;
screen_info . orig_video_points = tag - > u . videotext . video_points ;
return 0 ;
}
__tagtable ( ATAG_VIDEOTEXT , parse_tag_videotext ) ;
# endif
static int __init parse_tag_ramdisk ( const struct tag * tag )
{
setup_ramdisk ( ( tag - > u . ramdisk . flags & 1 ) = = 0 ,
( tag - > u . ramdisk . flags & 2 ) = = 0 ,
tag - > u . ramdisk . start , tag - > u . ramdisk . size ) ;
return 0 ;
}
__tagtable ( ATAG_RAMDISK , parse_tag_ramdisk ) ;
static int __init parse_tag_serialnr ( const struct tag * tag )
{
system_serial_low = tag - > u . serialnr . low ;
system_serial_high = tag - > u . serialnr . high ;
return 0 ;
}
__tagtable ( ATAG_SERIAL , parse_tag_serialnr ) ;
static int __init parse_tag_revision ( const struct tag * tag )
{
system_rev = tag - > u . revision . rev ;
return 0 ;
}
__tagtable ( ATAG_REVISION , parse_tag_revision ) ;
2010-02-16 21:04:53 +03:00
# ifndef CONFIG_CMDLINE_FORCE
2005-04-17 02:20:36 +04:00
static int __init parse_tag_cmdline ( const struct tag * tag )
{
strlcpy ( default_command_line , tag - > u . cmdline . cmdline , COMMAND_LINE_SIZE ) ;
return 0 ;
}
__tagtable ( ATAG_CMDLINE , parse_tag_cmdline ) ;
2010-02-16 21:04:53 +03:00
# endif /* CONFIG_CMDLINE_FORCE */
2005-04-17 02:20:36 +04:00
/*
* Scan the tag table for this tag , and call its parse function .
* The tag table is built by the linker from all the __tagtable
* declarations .
*/
static int __init parse_tag ( const struct tag * tag )
{
extern struct tagtable __tagtable_begin , __tagtable_end ;
struct tagtable * t ;
for ( t = & __tagtable_begin ; t < & __tagtable_end ; t + + )
if ( tag - > hdr . tag = = t - > tag ) {
t - > parse ( tag ) ;
break ;
}
return t < & __tagtable_end ;
}
/*
* Parse all tags in the list , checking both the global and architecture
* specific tag tables .
*/
static void __init parse_tags ( const struct tag * t )
{
for ( ; t - > hdr . size ; t = tag_next ( t ) )
if ( ! parse_tag ( t ) )
printk ( KERN_WARNING
" Ignoring unrecognised tag 0x%08x \n " ,
t - > hdr . tag ) ;
}
/*
* This holds our defaults .
*/
static struct init_tags {
struct tag_header hdr1 ;
struct tag_core core ;
struct tag_header hdr2 ;
struct tag_mem32 mem ;
struct tag_header hdr3 ;
} init_tags __initdata = {
{ tag_size ( tag_core ) , ATAG_CORE } ,
{ 1 , PAGE_SIZE , 0xff } ,
{ tag_size ( tag_mem32 ) , ATAG_MEM } ,
{ MEM_SIZE , PHYS_OFFSET } ,
{ 0 , ATAG_NONE }
} ;
static void ( * init_machine ) ( void ) __initdata ;
static int __init customize_machine ( void )
{
/* customizes platform devices, or adds new ones */
if ( init_machine )
init_machine ( ) ;
return 0 ;
}
arch_initcall ( customize_machine ) ;
void __init setup_arch ( char * * cmdline_p )
{
struct tag * tags = ( struct tag * ) & init_tags ;
struct machine_desc * mdesc ;
char * from = default_command_line ;
2009-02-16 13:41:36 +03:00
unwind_init ( ) ;
2005-04-17 02:20:36 +04:00
setup_processor ( ) ;
mdesc = setup_machine ( machine_arch_type ) ;
machine_name = mdesc - > name ;
if ( mdesc - > soft_reboot )
reboot_setup ( " s " ) ;
2007-06-01 01:02:22 +04:00
if ( __atags_pointer )
tags = phys_to_virt ( __atags_pointer ) ;
else if ( mdesc - > boot_params )
2005-07-04 13:43:36 +04:00
tags = phys_to_virt ( mdesc - > boot_params ) ;
2005-04-17 02:20:36 +04:00
/*
* If we have the old style parameters , convert them to
* a tag list .
*/
if ( tags - > hdr . tag ! = ATAG_CORE )
convert_to_tag_list ( tags ) ;
if ( tags - > hdr . tag ! = ATAG_CORE )
tags = ( struct tag * ) & init_tags ;
if ( mdesc - > fixup )
mdesc - > fixup ( mdesc , tags , & from , & meminfo ) ;
if ( tags - > hdr . tag = = ATAG_CORE ) {
if ( meminfo . nr_banks ! = 0 )
squash_mem_tags ( tags ) ;
2008-01-02 02:56:46 +03:00
save_atags ( tags ) ;
2005-04-17 02:20:36 +04:00
parse_tags ( tags ) ;
}
2008-12-01 14:53:07 +03:00
init_mm . start_code = ( unsigned long ) _text ;
init_mm . end_code = ( unsigned long ) _etext ;
init_mm . end_data = ( unsigned long ) _edata ;
init_mm . brk = ( unsigned long ) _end ;
2005-04-17 02:20:36 +04:00
2010-01-12 01:17:34 +03:00
/* parse_early_param needs a boot_command_line */
strlcpy ( boot_command_line , from , COMMAND_LINE_SIZE ) ;
2010-01-27 03:13:31 +03:00
/* populate cmd_line too for later use, preserving boot_command_line */
strlcpy ( cmd_line , boot_command_line , COMMAND_LINE_SIZE ) ;
* cmdline_p = cmd_line ;
2010-01-12 01:17:34 +03:00
parse_early_param ( ) ;
2010-07-09 19:27:52 +04:00
arm_memblock_init ( & meminfo ) ;
2008-10-06 21:24:40 +04:00
paging_init ( mdesc ) ;
2005-04-17 02:20:36 +04:00
request_standard_resources ( & meminfo , mdesc ) ;
2006-02-16 14:08:09 +03:00
# ifdef CONFIG_SMP
smp_init_cpus ( ) ;
# endif
2005-06-01 01:22:32 +04:00
cpu_init ( ) ;
2009-09-15 20:30:37 +04:00
tcm_init ( ) ;
2005-06-01 01:22:32 +04:00
2005-04-17 02:20:36 +04:00
/*
* Set up various architecture - specific pointers
*/
init_arch_irq = mdesc - > init_irq ;
system_timer = mdesc - > timer ;
init_machine = mdesc - > init_machine ;
# ifdef CONFIG_VT
# if defined(CONFIG_VGA_CONSOLE)
conswitchp = & vga_con ;
# elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = & dummy_con ;
# endif
# endif
2008-02-20 22:33:40 +03:00
early_trap_init ( ) ;
2005-04-17 02:20:36 +04:00
}
static int __init topology_init ( void )
{
int cpu ;
2007-03-13 12:54:21 +03:00
for_each_possible_cpu ( cpu ) {
struct cpuinfo_arm * cpuinfo = & per_cpu ( cpu_data , cpu ) ;
cpuinfo - > cpu . hotpluggable = 1 ;
register_cpu ( & cpuinfo - > cpu , cpu ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
subsys_initcall ( topology_init ) ;
2010-01-10 20:23:29 +03:00
# ifdef CONFIG_HAVE_PROC_CPU
static int __init proc_cpu_init ( void )
{
struct proc_dir_entry * res ;
res = proc_mkdir ( " cpu " , NULL ) ;
if ( ! res )
return - ENOMEM ;
return 0 ;
}
fs_initcall ( proc_cpu_init ) ;
# endif
2005-04-17 02:20:36 +04:00
static const char * hwcap_str [ ] = {
" swp " ,
" half " ,
" thumb " ,
" 26bit " ,
" fastmult " ,
" fpa " ,
" vfp " ,
" edsp " ,
" java " ,
2006-10-27 08:13:19 +04:00
" iwmmxt " ,
2006-12-18 02:59:10 +03:00
" crunch " ,
2008-11-06 16:23:06 +03:00
" thumbee " ,
2008-11-06 16:23:07 +03:00
" neon " ,
2009-02-11 15:13:56 +03:00
" vfpv3 " ,
" vfpv3d16 " ,
2005-04-17 02:20:36 +04:00
NULL
} ;
static int c_show ( struct seq_file * m , void * v )
{
int i ;
seq_printf ( m , " Processor \t : %s rev %d (%s) \n " ,
2008-08-10 21:08:10 +04:00
cpu_name , read_cpuid_id ( ) & 15 , elf_platform ) ;
2005-04-17 02:20:36 +04:00
# if defined(CONFIG_SMP)
for_each_online_cpu ( i ) {
2005-11-07 00:41:08 +03:00
/*
* glibc reads / proc / cpuinfo to determine the number of
* online processors , looking for lines beginning with
* " processor " . Give glibc what it expects .
*/
seq_printf ( m , " processor \t : %d \n " , i ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( m , " BogoMIPS \t : %lu.%02lu \n \n " ,
per_cpu ( cpu_data , i ) . loops_per_jiffy / ( 500000UL / HZ ) ,
( per_cpu ( cpu_data , i ) . loops_per_jiffy / ( 5000UL / HZ ) ) % 100 ) ;
}
# else /* CONFIG_SMP */
seq_printf ( m , " BogoMIPS \t : %lu.%02lu \n " ,
loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
# endif
/* dump out the processor features */
seq_puts ( m , " Features \t : " ) ;
for ( i = 0 ; hwcap_str [ i ] ; i + + )
if ( elf_hwcap & ( 1 < < i ) )
seq_printf ( m , " %s " , hwcap_str [ i ] ) ;
2008-08-10 21:08:10 +04:00
seq_printf ( m , " \n CPU implementer \t : 0x%02x \n " , read_cpuid_id ( ) > > 24 ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( m , " CPU architecture: %s \n " , proc_arch [ cpu_architecture ( ) ] ) ;
2008-08-10 21:08:10 +04:00
if ( ( read_cpuid_id ( ) & 0x0008f000 ) = = 0x00000000 ) {
2005-04-17 02:20:36 +04:00
/* pre-ARM7 */
2008-08-10 21:08:10 +04:00
seq_printf ( m , " CPU part \t : %07x \n " , read_cpuid_id ( ) > > 4 ) ;
2005-04-17 02:20:36 +04:00
} else {
2008-08-10 21:08:10 +04:00
if ( ( read_cpuid_id ( ) & 0x0008f000 ) = = 0x00007000 ) {
2005-04-17 02:20:36 +04:00
/* ARM7 */
seq_printf ( m , " CPU variant \t : 0x%02x \n " ,
2008-08-10 21:08:10 +04:00
( read_cpuid_id ( ) > > 16 ) & 127 ) ;
2005-04-17 02:20:36 +04:00
} else {
/* post-ARM7 */
seq_printf ( m , " CPU variant \t : 0x%x \n " ,
2008-08-10 21:08:10 +04:00
( read_cpuid_id ( ) > > 20 ) & 15 ) ;
2005-04-17 02:20:36 +04:00
}
seq_printf ( m , " CPU part \t : 0x%03x \n " ,
2008-08-10 21:08:10 +04:00
( read_cpuid_id ( ) > > 4 ) & 0xfff ) ;
2005-04-17 02:20:36 +04:00
}
2008-08-10 21:08:10 +04:00
seq_printf ( m , " CPU revision \t : %d \n " , read_cpuid_id ( ) & 15 ) ;
2005-04-17 02:20:36 +04:00
seq_puts ( m , " \n " ) ;
seq_printf ( m , " Hardware \t : %s \n " , machine_name ) ;
seq_printf ( m , " Revision \t : %04x \n " , system_rev ) ;
seq_printf ( m , " Serial \t \t : %08x%08x \n " ,
system_serial_high , system_serial_low ) ;
return 0 ;
}
static void * c_start ( struct seq_file * m , loff_t * pos )
{
return * pos < 1 ? ( void * ) 1 : NULL ;
}
static void * c_next ( struct seq_file * m , void * v , loff_t * pos )
{
+ + * pos ;
return NULL ;
}
static void c_stop ( struct seq_file * m , void * v )
{
}
2008-01-22 22:41:07 +03:00
const struct seq_operations cpuinfo_op = {
2005-04-17 02:20:36 +04:00
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = c_show
} ;