2005-06-24 09:01:16 +04:00
/*
* arch / xtensa / setup . c
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1995 Linus Torvalds
* Copyright ( C ) 2001 - 2005 Tensilica Inc .
*
* Chris Zankel < chris @ zankel . net >
* Joe Taylor < joe @ tensilica . com , joetylr @ yahoo . com >
* Kevin Chea
* Marc Gauthier < marc @ tensilica . com > < marc @ alumni . uwaterloo . ca >
*/
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/proc_fs.h>
2006-07-10 15:44:13 +04:00
# include <linux/screen_info.h>
2005-06-24 09:01:16 +04:00
# include <linux/bootmem.h>
# include <linux/kernel.h>
# if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
# include <linux / console.h>
# endif
# ifdef CONFIG_RTC
# include <linux / timex.h>
# endif
# ifdef CONFIG_PROC_FS
# include <linux / seq_file.h>
# endif
# include <asm/system.h>
# include <asm/bootparam.h>
# include <asm/pgtable.h>
# include <asm/processor.h>
# include <asm/timex.h>
# include <asm/platform.h>
# include <asm/page.h>
# include <asm/setup.h>
# include <xtensa/config/system.h>
# if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
struct screen_info screen_info = { 0 , 24 , 0 , 0 , 0 , 80 , 0 , 0 , 0 , 24 , 1 , 16 } ;
# endif
# ifdef CONFIG_BLK_DEV_FD
extern struct fd_ops no_fd_ops ;
struct fd_ops * fd_ops ;
# endif
# if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
extern struct ide_ops no_ide_ops ;
struct ide_ops * ide_ops ;
# endif
extern struct rtc_ops no_rtc_ops ;
struct rtc_ops * rtc_ops ;
# ifdef CONFIG_PC_KEYB
extern struct kbd_ops no_kbd_ops ;
struct kbd_ops * kbd_ops ;
# endif
# ifdef CONFIG_BLK_DEV_INITRD
extern void * initrd_start ;
extern void * initrd_end ;
extern void * __initrd_start ;
extern void * __initrd_end ;
int initrd_is_mapped = 0 ;
extern int initrd_below_start_ok ;
# endif
unsigned char aux_device_present ;
extern unsigned long loops_per_jiffy ;
/* Command line specified as configuration option. */
static char command_line [ COMMAND_LINE_SIZE ] ;
# ifdef CONFIG_CMDLINE_BOOL
static char default_command_line [ COMMAND_LINE_SIZE ] __initdata = CONFIG_CMDLINE ;
# endif
sysmem_info_t __initdata sysmem ;
# ifdef CONFIG_BLK_DEV_INITRD
int initrd_is_mapped ;
# endif
extern void init_mmu ( void ) ;
/*
* Boot parameter parsing .
*
* The Xtensa port uses a list of variable - sized tags to pass data to
* the kernel . The first tag must be a BP_TAG_FIRST tag for the list
* to be recognised . The list is terminated with a zero - sized
* BP_TAG_LAST tag .
*/
typedef struct tagtable {
u32 tag ;
int ( * parse ) ( const bp_tag_t * ) ;
} tagtable_t ;
# define __tagtable(tag, fn) static tagtable_t __tagtable_##fn \
__attribute__ ( ( unused , __section__ ( " .taglist " ) ) ) = { tag , fn }
/* parse current tag */
static int __init parse_tag_mem ( const bp_tag_t * tag )
{
meminfo_t * mi = ( meminfo_t * ) ( tag - > data ) ;
if ( mi - > type ! = MEMORY_TYPE_CONVENTIONAL )
return - 1 ;
if ( sysmem . nr_banks > = SYSMEM_BANKS_MAX ) {
printk ( KERN_WARNING
" Ignoring memory bank 0x%08lx size %ldKB \n " ,
( unsigned long ) mi - > start ,
( unsigned long ) mi - > end - ( unsigned long ) mi - > start ) ;
return - EINVAL ;
}
sysmem . bank [ sysmem . nr_banks ] . type = mi - > type ;
sysmem . bank [ sysmem . nr_banks ] . start = PAGE_ALIGN ( mi - > start ) ;
sysmem . bank [ sysmem . nr_banks ] . end = mi - > end & PAGE_SIZE ;
sysmem . nr_banks + + ;
return 0 ;
}
__tagtable ( BP_TAG_MEMORY , parse_tag_mem ) ;
# ifdef CONFIG_BLK_DEV_INITRD
static int __init parse_tag_initrd ( const bp_tag_t * tag )
{
meminfo_t * mi ;
mi = ( meminfo_t * ) ( tag - > data ) ;
initrd_start = ( void * ) ( mi - > start ) ;
initrd_end = ( void * ) ( mi - > end ) ;
return 0 ;
}
__tagtable ( BP_TAG_INITRD , parse_tag_initrd ) ;
# endif /* CONFIG_BLK_DEV_INITRD */
static int __init parse_tag_cmdline ( const bp_tag_t * tag )
{
strncpy ( command_line , ( char * ) ( tag - > data ) , COMMAND_LINE_SIZE ) ;
command_line [ COMMAND_LINE_SIZE - 1 ] = ' \0 ' ;
return 0 ;
}
__tagtable ( BP_TAG_COMMAND_LINE , parse_tag_cmdline ) ;
static int __init parse_bootparam ( const bp_tag_t * tag )
{
extern tagtable_t __tagtable_begin , __tagtable_end ;
tagtable_t * t ;
/* Boot parameters must start with a BP_TAG_FIRST tag. */
if ( tag - > id ! = BP_TAG_FIRST ) {
printk ( KERN_WARNING " Invalid boot parameters! \n " ) ;
return 0 ;
}
tag = ( bp_tag_t * ) ( ( unsigned long ) tag + sizeof ( bp_tag_t ) + tag - > size ) ;
/* Parse all tags. */
while ( tag ! = NULL & & tag - > id ! = BP_TAG_LAST ) {
for ( t = & __tagtable_begin ; t < & __tagtable_end ; t + + ) {
if ( tag - > id = = t - > tag ) {
t - > parse ( tag ) ;
break ;
}
}
if ( t = = & __tagtable_end )
printk ( KERN_WARNING " Ignoring tag "
" 0x%08x \n " , tag - > id ) ;
tag = ( bp_tag_t * ) ( ( unsigned long ) ( tag + 1 ) + tag - > size ) ;
}
return 0 ;
}
/*
* Initialize architecture . ( Early stage )
*/
void __init init_arch ( bp_tag_t * bp_start )
{
# ifdef CONFIG_BLK_DEV_INITRD
initrd_start = & __initrd_start ;
initrd_end = & __initrd_end ;
# endif
sysmem . nr_banks = 0 ;
# ifdef CONFIG_CMDLINE_BOOL
strcpy ( command_line , default_command_line ) ;
# endif
/* Parse boot parameters */
if ( bp_start )
parse_bootparam ( bp_start ) ;
if ( sysmem . nr_banks = = 0 ) {
sysmem . nr_banks = 1 ;
sysmem . bank [ 0 ] . start = PLATFORM_DEFAULT_MEM_START ;
sysmem . bank [ 0 ] . end = PLATFORM_DEFAULT_MEM_START
+ PLATFORM_DEFAULT_MEM_SIZE ;
}
/* Early hook for platforms */
platform_init ( bp_start ) ;
/* Initialize MMU. */
init_mmu ( ) ;
}
/*
* Initialize system . Setup memory and reserve regions .
*/
extern char _end ;
extern char _stext ;
extern char _WindowVectors_text_start ;
extern char _WindowVectors_text_end ;
extern char _DebugInterruptVector_literal_start ;
extern char _DebugInterruptVector_text_end ;
extern char _KernelExceptionVector_literal_start ;
extern char _KernelExceptionVector_text_end ;
extern char _UserExceptionVector_literal_start ;
extern char _UserExceptionVector_text_end ;
extern char _DoubleExceptionVector_literal_start ;
extern char _DoubleExceptionVector_text_end ;
void __init setup_arch ( char * * cmdline_p )
{
extern int mem_reserve ( unsigned long , unsigned long , int ) ;
extern void bootmem_init ( void ) ;
memcpy ( saved_command_line , command_line , COMMAND_LINE_SIZE ) ;
saved_command_line [ COMMAND_LINE_SIZE - 1 ] = ' \0 ' ;
* cmdline_p = command_line ;
/* Reserve some memory regions */
# ifdef CONFIG_BLK_DEV_INITRD
if ( initrd_start < initrd_end ) {
initrd_is_mapped = mem_reserve ( __pa ( initrd_start ) ,
__pa ( initrd_end ) , 0 ) ;
initrd_below_start_ok = 1 ;
} else {
initrd_start = 0 ;
}
# endif
mem_reserve ( __pa ( & _stext ) , __pa ( & _end ) , 1 ) ;
mem_reserve ( __pa ( & _WindowVectors_text_start ) ,
__pa ( & _WindowVectors_text_end ) , 0 ) ;
mem_reserve ( __pa ( & _DebugInterruptVector_literal_start ) ,
__pa ( & _DebugInterruptVector_text_end ) , 0 ) ;
mem_reserve ( __pa ( & _KernelExceptionVector_literal_start ) ,
__pa ( & _KernelExceptionVector_text_end ) , 0 ) ;
mem_reserve ( __pa ( & _UserExceptionVector_literal_start ) ,
__pa ( & _UserExceptionVector_text_end ) , 0 ) ;
mem_reserve ( __pa ( & _DoubleExceptionVector_literal_start ) ,
__pa ( & _DoubleExceptionVector_text_end ) , 0 ) ;
bootmem_init ( ) ;
platform_setup ( cmdline_p ) ;
paging_init ( ) ;
# ifdef CONFIG_VT
# if defined(CONFIG_VGA_CONSOLE)
conswitchp = & vga_con ;
# elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = & dummy_con ;
# endif
# endif
2005-09-23 08:44:23 +04:00
# ifdef CONFIG_PCI
2005-06-24 09:01:16 +04:00
platform_pcibios_init ( ) ;
# endif
}
void machine_restart ( char * cmd )
{
platform_restart ( ) ;
}
void machine_halt ( void )
{
platform_halt ( ) ;
while ( 1 ) ;
}
void machine_power_off ( void )
{
platform_power_off ( ) ;
while ( 1 ) ;
}
# ifdef CONFIG_PROC_FS
/*
* Display some core information through / proc / cpuinfo .
*/
static int
c_show ( struct seq_file * f , void * slot )
{
/* high-level stuff */
seq_printf ( f , " processor \t : 0 \n "
" vendor_id \t : Tensilica \n "
" model \t \t : Xtensa " XCHAL_HW_RELEASE_NAME " \n "
" core ID \t \t : " XCHAL_CORE_ID " \n "
" build ID \t : 0x%x \n "
" byte order \t : %s \n "
" cpu MHz \t \t : %lu.%02lu \n "
" bogomips \t : %lu.%02lu \n " ,
XCHAL_BUILD_UNIQUE_ID ,
XCHAL_HAVE_BE ? " big " : " little " ,
CCOUNT_PER_JIFFY / ( 1000000 / HZ ) ,
( CCOUNT_PER_JIFFY / ( 10000 / HZ ) ) % 100 ,
loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
seq_printf ( f , " flags \t \t : "
# if XCHAL_HAVE_NMI
" nmi "
# endif
# if XCHAL_HAVE_DEBUG
" debug "
# if XCHAL_HAVE_OCD
" ocd "
# endif
# endif
# if XCHAL_HAVE_DENSITY
" density "
# endif
# if XCHAL_HAVE_BOOLEANS
" boolean "
# endif
# if XCHAL_HAVE_LOOPS
" loop "
# endif
# if XCHAL_HAVE_NSA
" nsa "
# endif
# if XCHAL_HAVE_MINMAX
" minmax "
# endif
# if XCHAL_HAVE_SEXT
" sext "
# endif
# if XCHAL_HAVE_CLAMPS
" clamps "
# endif
# if XCHAL_HAVE_MAC16
" mac16 "
# endif
# if XCHAL_HAVE_MUL16
" mul16 "
# endif
# if XCHAL_HAVE_MUL32
" mul32 "
# endif
# if XCHAL_HAVE_MUL32_HIGH
" mul32h "
# endif
# if XCHAL_HAVE_FP
" fpu "
# endif
" \n " ) ;
/* Registers. */
seq_printf ( f , " physical aregs \t : %d \n "
" misc regs \t : %d \n "
" ibreak \t \t : %d \n "
" dbreak \t \t : %d \n " ,
XCHAL_NUM_AREGS ,
XCHAL_NUM_MISC_REGS ,
XCHAL_NUM_IBREAK ,
XCHAL_NUM_DBREAK ) ;
/* Interrupt. */
seq_printf ( f , " num ints \t : %d \n "
" ext ints \t : %d \n "
" int levels \t : %d \n "
" timers \t \t : %d \n "
" debug level \t : %d \n " ,
XCHAL_NUM_INTERRUPTS ,
XCHAL_NUM_EXTINTERRUPTS ,
XCHAL_NUM_INTLEVELS ,
XCHAL_NUM_TIMERS ,
XCHAL_DEBUGLEVEL ) ;
/* Coprocessors */
# if XCHAL_HAVE_CP
seq_printf ( f , " coprocessors \t : %d \n " , XCHAL_CP_NUM ) ;
# else
seq_printf ( f , " coprocessors \t : none \n " ) ;
# endif
/* {I,D}{RAM,ROM} and XLMI */
seq_printf ( f , " inst ROMs \t : %d \n "
" inst RAMs \t : %d \n "
" data ROMs \t : %d \n "
" data RAMs \t : %d \n "
" XLMI ports \t : %d \n " ,
XCHAL_NUM_IROM ,
XCHAL_NUM_IRAM ,
XCHAL_NUM_DROM ,
XCHAL_NUM_DRAM ,
XCHAL_NUM_XLMI ) ;
/* Cache */
seq_printf ( f , " icache line size: %d \n "
" icache ways \t : %d \n "
" icache size \t : %d \n "
" icache flags \t : "
# if XCHAL_ICACHE_LINE_LOCKABLE
" lock "
# endif
" \n "
" dcache line size: %d \n "
" dcache ways \t : %d \n "
" dcache size \t : %d \n "
" dcache flags \t : "
# if XCHAL_DCACHE_IS_WRITEBACK
" writeback "
# endif
# if XCHAL_DCACHE_LINE_LOCKABLE
" lock "
# endif
" \n " ,
XCHAL_ICACHE_LINESIZE ,
XCHAL_ICACHE_WAYS ,
XCHAL_ICACHE_SIZE ,
XCHAL_DCACHE_LINESIZE ,
XCHAL_DCACHE_WAYS ,
XCHAL_DCACHE_SIZE ) ;
/* MMU */
seq_printf ( f , " ASID bits \t : %d \n "
" ASID invalid \t : %d \n "
" ASID kernel \t : %d \n "
" rings \t \t : %d \n "
" itlb ways \t : %d \n "
" itlb AR ways \t : %d \n "
" dtlb ways \t : %d \n "
" dtlb AR ways \t : %d \n " ,
XCHAL_MMU_ASID_BITS ,
XCHAL_MMU_ASID_INVALID ,
XCHAL_MMU_ASID_KERNEL ,
XCHAL_MMU_RINGS ,
XCHAL_ITLB_WAYS ,
XCHAL_ITLB_ARF_WAYS ,
XCHAL_DTLB_WAYS ,
XCHAL_DTLB_ARF_WAYS ) ;
return 0 ;
}
/*
* We show only CPU # 0 info .
*/
static void *
c_start ( struct seq_file * f , loff_t * pos )
{
return ( void * ) ( ( * pos = = 0 ) ? ( void * ) 1 : NULL ) ;
}
static void *
c_next ( struct seq_file * f , void * v , loff_t * pos )
{
return NULL ;
}
static void
c_stop ( struct seq_file * f , void * v )
{
}
struct seq_operations cpuinfo_op =
{
start : c_start ,
next : c_next ,
stop : c_stop ,
show : c_show
} ;
# endif /* CONFIG_PROC_FS */