2006-10-03 13:14:04 +09:00
/*
2006-12-25 10:19:56 +09:00
* arch / sh / kernel / setup . c
2005-04-16 15:20:36 -07:00
*
* This file handles the architecture - dependent parts of initialization
2006-12-25 10:19:56 +09:00
*
* Copyright ( C ) 1999 Niibe Yutaka
2007-03-28 16:38:13 +09:00
* Copyright ( C ) 2002 - 2007 Paul Mundt
2005-04-16 15:20:36 -07:00
*/
2006-07-10 04:44:13 -07:00
# include <linux/screen_info.h>
2005-04-16 15:20:36 -07:00
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/initrd.h>
# include <linux/bootmem.h>
# include <linux/console.h>
# include <linux/seq_file.h>
# include <linux/root_dev.h>
# include <linux/utsname.h>
2007-03-28 16:38:13 +09:00
# include <linux/nodemask.h>
2005-04-16 15:20:36 -07:00
# include <linux/cpu.h>
2006-03-27 01:16:04 -08:00
# include <linux/pfn.h>
2006-10-03 13:14:04 +09:00
# include <linux/fs.h>
2007-03-28 16:38:13 +09:00
# include <linux/mm.h>
2007-04-27 11:25:57 +09:00
# include <linux/kexec.h>
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
# include <asm/io.h>
2007-05-14 12:50:43 +09:00
# include <asm/page.h>
2005-04-16 15:20:36 -07:00
# include <asm/sections.h>
# include <asm/irq.h>
# include <asm/setup.h>
2006-02-01 03:06:02 -08:00
# include <asm/clock.h>
2007-03-28 16:38:13 +09:00
# include <asm/mmu_context.h>
2005-04-16 15:20:36 -07:00
extern void * __rd_start , * __rd_end ;
2007-03-08 17:27:37 +09:00
2005-04-16 15:20:36 -07:00
/*
* Machine setup . .
*/
/*
* Initialize loops_per_jiffy as 10000000 ( 1000 MIPS ) .
* This value will be used at the very early stage of serial setup .
* The bigger value means no problem .
*/
2006-02-01 03:06:02 -08:00
struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE , 10000000 , } ;
2007-05-15 15:19:34 +09:00
/*
* The machine vector . First entry in . machvec . init , or clobbered by
* sh_mv = on the command line , prior to . machvec . init teardown .
*/
struct sh_machine_vector sh_mv = { . mv_name = " Unknown " , } ;
2006-09-27 18:17:31 +09:00
# ifdef CONFIG_VT
2005-04-16 15:20:36 -07:00
struct screen_info screen_info ;
2006-09-27 18:17:31 +09:00
# endif
2005-04-16 15:20:36 -07:00
extern int root_mountflags ;
/*
* This is set up by the setup - routine at boot - time
*/
# define PARAM ((unsigned char *)empty_zero_page)
# define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000))
# define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004))
# define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008))
# define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c))
# define INITRD_START (*(unsigned long *) (PARAM+0x010))
# define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
/* ... */
# define COMMAND_LINE ((char *) (PARAM+0x100))
2005-11-07 00:58:24 -08:00
# define RAMDISK_IMAGE_START_MASK 0x07FF
2005-04-16 15:20:36 -07:00
# define RAMDISK_PROMPT_FLAG 0x8000
2005-11-07 00:58:24 -08:00
# define RAMDISK_LOAD_FLAG 0x4000
2005-04-16 15:20:36 -07:00
2007-02-12 00:54:19 -08:00
static char __initdata command_line [ COMMAND_LINE_SIZE ] = { 0 , } ;
2005-04-16 15:20:36 -07:00
2006-09-27 18:17:31 +09:00
static struct resource code_resource = { . name = " Kernel code " , } ;
static struct resource data_resource = { . name = " Kernel data " , } ;
2005-04-16 15:20:36 -07:00
unsigned long memory_start , memory_end ;
2007-05-14 15:59:09 +09:00
static int __init early_parse_mem ( char * p )
2005-04-16 15:20:36 -07:00
{
2007-05-14 15:59:09 +09:00
unsigned long size ;
2005-04-16 15:20:36 -07:00
memory_start = ( unsigned long ) PAGE_OFFSET + __MEMORY_START ;
2007-05-14 15:59:09 +09:00
size = memparse ( p , & p ) ;
memory_end = memory_start + size ;
2006-09-27 18:17:31 +09:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-05-14 15:59:09 +09:00
early_param ( " mem " , early_parse_mem ) ;
2005-04-16 15:20:36 -07:00
2007-03-28 16:38:13 +09:00
/*
* Register fully available low RAM pages with the bootmem allocator .
*/
static void __init register_bootmem_low_pages ( void )
2005-04-16 15:20:36 -07:00
{
2007-03-28 16:38:13 +09:00
unsigned long curr_pfn , last_pfn , pages ;
2006-12-12 09:00:47 +09:00
2005-04-16 15:20:36 -07:00
/*
2007-03-28 16:38:13 +09:00
* We are rounding up the start address of usable memory :
2005-04-16 15:20:36 -07:00
*/
2007-03-28 16:38:13 +09:00
curr_pfn = PFN_UP ( __MEMORY_START ) ;
2005-04-16 15:20:36 -07:00
/*
2007-03-28 16:38:13 +09:00
* . . . and at the end of the usable range downwards :
2005-04-16 15:20:36 -07:00
*/
2007-03-28 16:38:13 +09:00
last_pfn = PFN_DOWN ( __pa ( memory_end ) ) ;
2005-04-16 15:20:36 -07:00
2007-03-28 16:38:13 +09:00
if ( last_pfn > max_low_pfn )
last_pfn = max_low_pfn ;
pages = last_pfn - curr_pfn ;
free_bootmem ( PFN_PHYS ( curr_pfn ) , PFN_PHYS ( pages ) ) ;
}
void __init setup_bootmem_allocator ( unsigned long start_pfn )
{
unsigned long bootmap_size ;
2005-04-16 15:20:36 -07:00
/*
* Find a proper area for the bootmem bitmap . After this
* bootstrap step all allocations ( until the page allocator
* is intact ) must be done via bootmem_alloc ( ) .
*/
bootmap_size = init_bootmem_node ( NODE_DATA ( 0 ) , start_pfn ,
2007-03-28 16:38:13 +09:00
min_low_pfn , max_low_pfn ) ;
2005-04-16 15:20:36 -07:00
2007-03-28 16:38:13 +09:00
register_bootmem_low_pages ( ) ;
2005-04-16 15:20:36 -07:00
2007-03-28 16:38:13 +09:00
node_set_online ( 0 ) ;
2006-12-12 09:00:47 +09:00
2005-04-16 15:20:36 -07:00
/*
* Reserve the kernel text and
* Reserve the bootmem bitmap . We do this in two steps ( first step
* was init_bootmem ( ) ) , because this catches the ( definitely buggy )
* case of us accidentally initializing the bootmem allocator with
* an invalid RAM area .
*/
2007-03-28 16:38:13 +09:00
reserve_bootmem ( __MEMORY_START + PAGE_SIZE ,
2005-04-16 15:20:36 -07:00
( PFN_PHYS ( start_pfn ) + bootmap_size + PAGE_SIZE - 1 ) - __MEMORY_START ) ;
/*
* reserve physical page 0 - it ' s a special BIOS page on many boxes ,
* enabling clean reboots , SMP operation , laptop functions .
*/
2007-03-28 16:38:13 +09:00
reserve_bootmem ( __MEMORY_START , PAGE_SIZE ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_BLK_DEV_INITRD
2005-11-07 00:58:24 -08:00
ROOT_DEV = MKDEV ( RAMDISK_MAJOR , 0 ) ;
if ( & __rd_start ! = & __rd_end ) {
2005-04-16 15:20:36 -07:00
LOADER_TYPE = 1 ;
2006-12-11 20:28:03 +09:00
INITRD_START = PHYSADDR ( ( unsigned long ) & __rd_start ) -
__MEMORY_START ;
INITRD_SIZE = ( unsigned long ) & __rd_end -
( unsigned long ) & __rd_start ;
2005-11-07 00:58:24 -08:00
}
2005-04-16 15:20:36 -07:00
if ( LOADER_TYPE & & INITRD_START ) {
if ( INITRD_START + INITRD_SIZE < = ( max_low_pfn < < PAGE_SHIFT ) ) {
2007-03-28 16:38:13 +09:00
reserve_bootmem ( INITRD_START + __MEMORY_START ,
INITRD_SIZE ) ;
2006-12-11 20:28:03 +09:00
initrd_start = INITRD_START + PAGE_OFFSET +
__MEMORY_START ;
2005-04-16 15:20:36 -07:00
initrd_end = initrd_start + INITRD_SIZE ;
} else {
printk ( " initrd extends beyond end of memory "
" (0x%08lx > 0x%08lx) \n disabling initrd \n " ,
INITRD_START + INITRD_SIZE ,
max_low_pfn < < PAGE_SHIFT ) ;
initrd_start = 0 ;
}
}
# endif
2007-04-27 11:25:57 +09:00
# ifdef CONFIG_KEXEC
if ( crashk_res . start ! = crashk_res . end )
reserve_bootmem ( crashk_res . start ,
crashk_res . end - crashk_res . start + 1 ) ;
# endif
2007-03-28 16:38:13 +09:00
}
# ifndef CONFIG_NEED_MULTIPLE_NODES
static void __init setup_memory ( void )
{
unsigned long start_pfn ;
/*
* Partially used pages are not usable - thus
* we are rounding upwards :
*/
start_pfn = PFN_UP ( __pa ( _end ) ) ;
setup_bootmem_allocator ( start_pfn ) ;
}
# else
extern void __init setup_memory ( void ) ;
# endif
void __init setup_arch ( char * * cmdline_p )
{
enable_mmu ( ) ;
ROOT_DEV = old_decode_dev ( ORIG_ROOT_DEV ) ;
# ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK ;
rd_prompt = ( ( RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG ) ! = 0 ) ;
rd_doload = ( ( RAMDISK_FLAGS & RAMDISK_LOAD_FLAG ) ! = 0 ) ;
# endif
if ( ! MOUNT_ROOT_RDONLY )
root_mountflags & = ~ MS_RDONLY ;
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 ;
code_resource . start = virt_to_phys ( _text ) ;
code_resource . end = virt_to_phys ( _etext ) - 1 ;
data_resource . start = virt_to_phys ( _etext ) ;
data_resource . end = virt_to_phys ( _edata ) - 1 ;
2007-05-14 15:59:09 +09:00
memory_start = ( unsigned long ) PAGE_OFFSET + __MEMORY_START ;
memory_end = memory_start + __MEMORY_SIZE ;
2007-05-14 17:48:00 +09:00
# ifdef CONFIG_CMDLINE_BOOL
strlcpy ( command_line , CONFIG_CMDLINE , sizeof ( command_line ) ) ;
# else
strlcpy ( command_line , COMMAND_LINE , sizeof ( command_line ) ) ;
# endif
2007-05-14 15:59:09 +09:00
2007-05-14 17:48:00 +09:00
/* Save unparsed command line copy for /proc/cmdline */
memcpy ( boot_command_line , command_line , COMMAND_LINE_SIZE ) ;
2007-05-14 15:59:09 +09:00
* cmdline_p = command_line ;
2007-03-28 16:38:13 +09:00
parse_early_param ( ) ;
2007-05-14 15:59:09 +09:00
sh_mv_setup ( ) ;
2007-03-28 16:38:13 +09:00
/*
* Find the highest page frame number we have available
*/
max_pfn = PFN_DOWN ( __pa ( memory_end ) ) ;
/*
* Determine low and high memory ranges :
*/
max_low_pfn = max_pfn ;
min_low_pfn = __MEMORY_START > > PAGE_SHIFT ;
nodes_clear ( node_online_map ) ;
setup_memory ( ) ;
paging_init ( ) ;
sparse_init ( ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_DUMMY_CONSOLE
conswitchp = & dummy_con ;
# endif
/* Perform the machine specific initialisation */
2006-09-27 18:17:31 +09:00
if ( likely ( sh_mv . mv_setup ) )
sh_mv . mv_setup ( cmdline_p ) ;
2005-04-16 15:20:36 -07:00
}
static const char * cpu_name [ ] = {
2006-11-20 14:14:29 +09:00
[ CPU_SH7206 ] = " SH7206 " , [ CPU_SH7619 ] = " SH7619 " ,
2006-09-27 17:38:11 +09:00
[ CPU_SH7604 ] = " SH7604 " , [ CPU_SH7300 ] = " SH7300 " ,
[ CPU_SH7705 ] = " SH7705 " , [ CPU_SH7706 ] = " SH7706 " ,
[ CPU_SH7707 ] = " SH7707 " , [ CPU_SH7708 ] = " SH7708 " ,
[ CPU_SH7709 ] = " SH7709 " , [ CPU_SH7710 ] = " SH7710 " ,
2007-03-27 18:13:51 +09:00
[ CPU_SH7712 ] = " SH7712 " ,
2006-09-27 17:38:11 +09:00
[ CPU_SH7729 ] = " SH7729 " , [ CPU_SH7750 ] = " SH7750 " ,
[ CPU_SH7750S ] = " SH7750S " , [ CPU_SH7750R ] = " SH7750R " ,
[ CPU_SH7751 ] = " SH7751 " , [ CPU_SH7751R ] = " SH7751R " ,
[ CPU_SH7760 ] = " SH7760 " , [ CPU_SH73180 ] = " SH73180 " ,
[ CPU_ST40RA ] = " ST40RA " , [ CPU_ST40GX1 ] = " ST40GX1 " ,
[ CPU_SH4_202 ] = " SH4-202 " , [ CPU_SH4_501 ] = " SH4-501 " ,
[ CPU_SH7770 ] = " SH7770 " , [ CPU_SH7780 ] = " SH7780 " ,
[ CPU_SH7781 ] = " SH7781 " , [ CPU_SH7343 ] = " SH7343 " ,
2006-12-11 20:28:03 +09:00
[ CPU_SH7785 ] = " SH7785 " , [ CPU_SH7722 ] = " SH7722 " ,
2005-04-16 15:20:36 -07:00
[ CPU_SH_NONE ] = " Unknown "
} ;
2006-12-25 10:19:56 +09:00
const char * get_cpu_subtype ( struct sh_cpuinfo * c )
2005-04-16 15:20:36 -07:00
{
2006-12-25 10:19:56 +09:00
return cpu_name [ c - > type ] ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_PROC_FS
2006-09-27 18:24:28 +09:00
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
2005-04-16 15:20:36 -07:00
static const char * cpu_flags [ ] = {
2006-09-27 18:24:28 +09:00
" none " , " fpu " , " p2flush " , " mmuassoc " , " dsp " , " perfctr " ,
2007-05-08 15:45:33 +09:00
" ptea " , " llsc " , " l2 " , " op32 " , NULL
2005-04-16 15:20:36 -07:00
} ;
2006-12-25 10:19:56 +09:00
static void show_cpuflags ( struct seq_file * m , struct sh_cpuinfo * c )
2005-04-16 15:20:36 -07:00
{
unsigned long i ;
seq_printf ( m , " cpu flags \t : " ) ;
2006-12-25 10:19:56 +09:00
if ( ! c - > flags ) {
2005-04-16 15:20:36 -07:00
seq_printf ( m , " %s \n " , cpu_flags [ 0 ] ) ;
return ;
}
2006-02-01 03:06:02 -08:00
for ( i = 0 ; cpu_flags [ i ] ; i + + )
2006-12-25 10:19:56 +09:00
if ( ( c - > flags & ( 1 < < i ) ) )
2005-04-16 15:20:36 -07:00
seq_printf ( m , " %s " , cpu_flags [ i + 1 ] ) ;
seq_printf ( m , " \n " ) ;
}
2006-09-27 18:17:31 +09:00
static void show_cacheinfo ( struct seq_file * m , const char * type ,
struct cache_info info )
2005-04-16 15:20:36 -07:00
{
unsigned int cache_size ;
cache_size = info . ways * info . sets * info . linesz ;
2006-02-01 03:06:02 -08:00
seq_printf ( m , " %s size \t : %2dKiB (%d-way) \n " ,
type , cache_size > > 10 , info . ways ) ;
2005-04-16 15:20:36 -07:00
}
/*
* Get CPU information for use by the procfs .
*/
static int show_cpuinfo ( struct seq_file * m , void * v )
{
2006-12-25 10:19:56 +09:00
struct sh_cpuinfo * c = v ;
unsigned int cpu = c - cpu_data ;
if ( ! cpu_online ( cpu ) )
return 0 ;
2005-04-16 15:20:36 -07:00
2006-12-25 10:19:56 +09:00
if ( cpu = = 0 )
2005-04-16 15:20:36 -07:00
seq_printf ( m , " machine \t \t : %s \n " , get_system_type ( ) ) ;
seq_printf ( m , " processor \t : %d \n " , cpu ) ;
2006-10-02 02:18:13 -07:00
seq_printf ( m , " cpu family \t : %s \n " , init_utsname ( ) - > machine ) ;
2006-12-25 10:19:56 +09:00
seq_printf ( m , " cpu type \t : %s \n " , get_cpu_subtype ( c ) ) ;
2005-04-16 15:20:36 -07:00
2006-12-25 10:19:56 +09:00
show_cpuflags ( m , c ) ;
2005-04-16 15:20:36 -07:00
seq_printf ( m , " cache type \t : " ) ;
/*
* Check for what type of cache we have , we support both the
* unified cache on the SH - 2 and SH - 3 , as well as the harvard
* style cache on the SH - 4.
*/
2006-12-25 10:19:56 +09:00
if ( c - > icache . flags & SH_CACHE_COMBINED ) {
2005-04-16 15:20:36 -07:00
seq_printf ( m , " unified \n " ) ;
2006-12-25 10:19:56 +09:00
show_cacheinfo ( m , " cache " , c - > icache ) ;
2005-04-16 15:20:36 -07:00
} else {
seq_printf ( m , " split (harvard) \n " ) ;
2006-12-25 10:19:56 +09:00
show_cacheinfo ( m , " icache " , c - > icache ) ;
show_cacheinfo ( m , " dcache " , c - > dcache ) ;
2005-04-16 15:20:36 -07:00
}
2006-09-27 18:27:43 +09:00
/* Optional secondary cache */
2006-12-25 10:19:56 +09:00
if ( c - > flags & CPU_HAS_L2_CACHE )
show_cacheinfo ( m , " scache " , c - > scache ) ;
2006-09-27 18:27:43 +09:00
2005-04-16 15:20:36 -07:00
seq_printf ( m , " bogomips \t : %lu.%02lu \n " ,
2006-12-25 10:19:56 +09:00
c - > loops_per_jiffy / ( 500000 / HZ ) ,
( c - > loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
2005-04-16 15:20:36 -07:00
2007-04-26 12:17:20 +09:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
static void * c_start ( struct seq_file * m , loff_t * pos )
{
return * pos < NR_CPUS ? cpu_data + * pos : NULL ;
}
static void * c_next ( struct seq_file * m , void * v , loff_t * pos )
{
+ + * pos ;
return c_start ( m , pos ) ;
}
static void c_stop ( struct seq_file * m , void * v )
{
}
struct seq_operations cpuinfo_op = {
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = show_cpuinfo ,
} ;
# endif /* CONFIG_PROC_FS */