2013-01-18 15:12:20 +05:30
/*
* Copyright ( C ) 2004 , 2007 - 2010 , 2011 - 2012 Synopsys , Inc . ( www . synopsys . com )
*
* 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/seq_file.h>
# include <linux/fs.h>
# include <linux/delay.h>
# include <linux/root_dev.h>
# include <linux/console.h>
# include <linux/module.h>
# include <linux/cpu.h>
2013-01-22 17:00:52 +05:30
# include <linux/of_fdt.h>
# include <asm/sections.h>
2013-01-18 15:12:20 +05:30
# include <asm/arcregs.h>
# include <asm/tlb.h>
# include <asm/cache.h>
# include <asm/setup.h>
# include <asm/page.h>
# include <asm/irq.h>
# include <asm/arcregs.h>
2013-01-22 17:00:52 +05:30
# include <asm/prom.h>
2013-01-22 17:03:19 +05:30
# include <asm/unwind.h>
2013-01-18 15:12:24 +05:30
# include <asm/clk.h>
2013-01-18 15:12:20 +05:30
# define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
int running_on_hw = 1 ; /* vs. on ISS */
char __initdata command_line [ COMMAND_LINE_SIZE ] ;
struct task_struct * _current_task [ NR_CPUS ] ; /* For stack switching */
struct cpuinfo_arc cpuinfo_arc700 [ NR_CPUS ] ;
2013-01-18 15:12:24 +05:30
2013-01-18 15:12:20 +05:30
void __init read_arc_build_cfg_regs ( void )
{
2013-01-18 15:12:24 +05:30
struct bcr_perip uncached_space ;
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ smp_processor_id ( ) ] ;
FIX_PTR ( cpu ) ;
READ_BCR ( AUX_IDENTITY , cpu - > core ) ;
cpu - > timers = read_aux_reg ( ARC_REG_TIMERS_BCR ) ;
cpu - > vec_base = read_aux_reg ( AUX_INTR_VEC_BASE ) ;
if ( cpu - > vec_base = = 0 )
cpu - > vec_base = ( unsigned int ) _int_vec_base_lds ;
READ_BCR ( ARC_REG_D_UNCACH_BCR , uncached_space ) ;
cpu - > uncached_base = uncached_space . start < < 24 ;
cpu - > extn . mul = read_aux_reg ( ARC_REG_MUL_BCR ) ;
cpu - > extn . swap = read_aux_reg ( ARC_REG_SWAP_BCR ) ;
cpu - > extn . norm = read_aux_reg ( ARC_REG_NORM_BCR ) ;
cpu - > extn . minmax = read_aux_reg ( ARC_REG_MIXMAX_BCR ) ;
cpu - > extn . barrel = read_aux_reg ( ARC_REG_BARREL_BCR ) ;
READ_BCR ( ARC_REG_MAC_BCR , cpu - > extn_mac_mul ) ;
cpu - > extn . ext_arith = read_aux_reg ( ARC_REG_EXTARITH_BCR ) ;
cpu - > extn . crc = read_aux_reg ( ARC_REG_CRC_BCR ) ;
READ_BCR ( ARC_REG_XY_MEM_BCR , cpu - > extn_xymem ) ;
2013-01-18 15:12:20 +05:30
read_decode_mmu_bcr ( ) ;
read_decode_cache_bcr ( ) ;
2013-01-18 15:12:24 +05:30
READ_BCR ( ARC_REG_FP_BCR , cpu - > fp ) ;
READ_BCR ( ARC_REG_DPFP_BCR , cpu - > dpfp ) ;
}
static const struct cpuinfo_data arc_cpu_tbl [ ] = {
{ { 0x10 , " ARCTangent A5 " } , 0x1F } ,
{ { 0x20 , " ARC 600 " } , 0x2F } ,
{ { 0x30 , " ARC 700 " } , 0x33 } ,
{ { 0x34 , " ARC 700 R4.10 " } , 0x34 } ,
{ { 0x00 , NULL } }
} ;
char * arc_cpu_mumbojumbo ( int cpu_id , char * buf , int len )
{
int n = 0 ;
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ cpu_id ] ;
struct bcr_identity * core = & cpu - > core ;
const struct cpuinfo_data * tbl ;
int be = 0 ;
# ifdef CONFIG_CPU_BIG_ENDIAN
be = 1 ;
# endif
FIX_PTR ( cpu ) ;
n + = scnprintf ( buf + n , len - n ,
" \n ARC IDENTITY \t : Family [%#02x] "
" Cpu-id [%#02x] Chip-id [%#4x] \n " ,
core - > family , core - > cpu_id ,
core - > chip_id ) ;
for ( tbl = & arc_cpu_tbl [ 0 ] ; tbl - > info . id ! = 0 ; tbl + + ) {
if ( ( core - > family > = tbl - > info . id ) & &
( core - > family < = tbl - > up_range ) ) {
n + = scnprintf ( buf + n , len - n ,
" processor \t : %s %s \n " ,
tbl - > info . str ,
be ? " [Big Endian] " : " " ) ;
break ;
}
}
if ( tbl - > info . id = = 0 )
n + = scnprintf ( buf + n , len - n , " UNKNOWN ARC Processor \n " ) ;
n + = scnprintf ( buf + n , len - n , " CPU speed \t : %u.%02u Mhz \n " ,
( unsigned int ) ( arc_get_core_freq ( ) / 1000000 ) ,
( unsigned int ) ( arc_get_core_freq ( ) / 10000 ) % 100 ) ;
n + = scnprintf ( buf + n , len - n , " Timers \t \t : %s %s \n " ,
( cpu - > timers & 0x200 ) ? " TIMER1 " : " " ,
( cpu - > timers & 0x100 ) ? " TIMER0 " : " " ) ;
n + = scnprintf ( buf + n , len - n , " Vect Tbl Base \t : %#x \n " ,
cpu - > vec_base ) ;
n + = scnprintf ( buf + n , len - n , " UNCACHED Base \t : %#x \n " ,
cpu - > uncached_base ) ;
return buf ;
}
static const struct id_to_str mul_type_nm [ ] = {
{ 0x0 , " N/A " } ,
{ 0x1 , " 32x32 (spl Result Reg) " } ,
{ 0x2 , " 32x32 (ANY Result Reg) " }
} ;
static const struct id_to_str mac_mul_nm [ ] = {
{ 0x0 , " N/A " } ,
{ 0x1 , " N/A " } ,
{ 0x2 , " Dual 16 x 16 " } ,
{ 0x3 , " N/A " } ,
{ 0x4 , " 32x16 " } ,
{ 0x5 , " N/A " } ,
{ 0x6 , " Dual 16x16 and 32x16 " }
} ;
char * arc_extn_mumbojumbo ( int cpu_id , char * buf , int len )
{
int n = 0 ;
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ cpu_id ] ;
FIX_PTR ( cpu ) ;
# define IS_AVAIL1(var, str) ((var) ? str : "")
# define IS_AVAIL2(var, str) ((var == 0x2) ? str : "")
# define IS_USED(var) ((var) ? "(in-use)" : "(not used)")
n + = scnprintf ( buf + n , len - n ,
" Extn [700-Base] \t : %s %s %s %s %s %s \n " ,
IS_AVAIL2 ( cpu - > extn . norm , " norm, " ) ,
IS_AVAIL2 ( cpu - > extn . barrel , " barrel-shift, " ) ,
IS_AVAIL1 ( cpu - > extn . swap , " swap, " ) ,
IS_AVAIL2 ( cpu - > extn . minmax , " minmax, " ) ,
IS_AVAIL1 ( cpu - > extn . crc , " crc, " ) ,
IS_AVAIL2 ( cpu - > extn . ext_arith , " ext-arith " ) ) ;
n + = scnprintf ( buf + n , len - n , " Extn [700-MPY] \t : %s " ,
mul_type_nm [ cpu - > extn . mul ] . str ) ;
n + = scnprintf ( buf + n , len - n , " MAC MPY: %s \n " ,
mac_mul_nm [ cpu - > extn_mac_mul . type ] . str ) ;
if ( cpu - > core . family = = 0x34 ) {
n + = scnprintf ( buf + n , len - n ,
" Extn [700-4.10] \t : LLOCK/SCOND %s, SWAPE %s, RTSC %s \n " ,
IS_USED ( __CONFIG_ARC_HAS_LLSC_VAL ) ,
IS_USED ( __CONFIG_ARC_HAS_SWAPE_VAL ) ,
IS_USED ( __CONFIG_ARC_HAS_RTSC_VAL ) ) ;
}
n + = scnprintf ( buf + n , len - n , " Extn [CCM] \t : %s " ,
! ( cpu - > dccm . sz | | cpu - > iccm . sz ) ? " N/A " : " " ) ;
if ( cpu - > dccm . sz )
n + = scnprintf ( buf + n , len - n , " DCCM: @ %x, %d KB " ,
cpu - > dccm . base_addr , TO_KB ( cpu - > dccm . sz ) ) ;
if ( cpu - > iccm . sz )
n + = scnprintf ( buf + n , len - n , " ICCM: @ %x, %d KB " ,
cpu - > iccm . base_addr , TO_KB ( cpu - > iccm . sz ) ) ;
n + = scnprintf ( buf + n , len - n , " \n Extn [FPU] \t : %s " ,
! ( cpu - > fp . ver | | cpu - > dpfp . ver ) ? " N/A " : " " ) ;
if ( cpu - > fp . ver )
n + = scnprintf ( buf + n , len - n , " SP [v%d] %s " ,
cpu - > fp . ver , cpu - > fp . fast ? " (fast) " : " " ) ;
if ( cpu - > dpfp . ver )
n + = scnprintf ( buf + n , len - n , " DP [v%d] %s " ,
cpu - > dpfp . ver , cpu - > dpfp . fast ? " (fast) " : " " ) ;
n + = scnprintf ( buf + n , len - n , " \n " ) ;
# ifdef _ASM_GENERIC_UNISTD_H
n + = scnprintf ( buf + n , len - n ,
" OS ABI [v2] \t : asm-generic/{unistd,stat,fcntl} \n " ) ;
# endif
return buf ;
}
/*
* Ensure that FP hardware and kernel config match
* - If hardware contains DPFP , kernel needs to save / restore FPU state
* across context switches
* - If hardware lacks DPFP , but kernel configured to save FPU state then
* kernel trying to access non - existant DPFP regs will crash
*
* We only check for Dbl precision Floating Point , because only DPFP
* hardware has dedicated regs which need to be saved / restored on ctx - sw
* ( Single Precision uses core regs ) , thus kernel is kind of oblivious to it
*/
void __init arc_chk_fpu ( void )
{
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ smp_processor_id ( ) ] ;
if ( cpu - > dpfp . ver ) {
# ifndef CONFIG_ARC_FPU_SAVE_RESTORE
pr_warn ( " DPFP support broken in this kernel... \n " ) ;
# endif
} else {
# ifdef CONFIG_ARC_FPU_SAVE_RESTORE
panic ( " H/w lacks DPFP support, apps won't work \n " ) ;
# endif
}
2013-01-18 15:12:20 +05:30
}
/*
* Initialize and setup the processor core
* This is called by all the CPUs thus should not do special case stuff
* such as only for boot CPU etc
*/
void __init setup_processor ( void )
{
2013-01-18 15:12:24 +05:30
char str [ 512 ] ;
int cpu_id = smp_processor_id ( ) ;
2013-01-18 15:12:20 +05:30
read_arc_build_cfg_regs ( ) ;
arc_init_IRQ ( ) ;
2013-01-18 15:12:24 +05:30
printk ( arc_cpu_mumbojumbo ( cpu_id , str , sizeof ( str ) ) ) ;
2013-01-18 15:12:20 +05:30
arc_mmu_init ( ) ;
arc_cache_init ( ) ;
2013-01-18 15:12:24 +05:30
printk ( arc_extn_mumbojumbo ( cpu_id , str , sizeof ( str ) ) ) ;
# ifdef CONFIG_SMP
printk ( arc_platform_smp_cpuinfo ( ) ) ;
# endif
arc_chk_fpu ( ) ;
2013-01-18 15:12:20 +05:30
}
void __init __attribute__ ( ( weak ) ) arc_platform_early_init ( void )
{
}
void __init setup_arch ( char * * cmdline_p )
{
2013-01-22 17:00:52 +05:30
int rc ;
2013-01-18 15:12:20 +05:30
# ifdef CONFIG_CMDLINE_UBOOT
/* Make sure that a whitespace is inserted before */
strlcat ( command_line , " " , sizeof ( command_line ) ) ;
# endif
/*
* Append . config cmdline to base command line , which might already
* contain u - boot " bootargs " ( handled by head . S , if so configured )
*/
strlcat ( command_line , CONFIG_CMDLINE , sizeof ( command_line ) ) ;
/* Save unparsed command line copy for /proc/cmdline */
strlcpy ( boot_command_line , command_line , COMMAND_LINE_SIZE ) ;
* cmdline_p = command_line ;
2013-01-22 17:00:52 +05:30
rc = setup_machine_fdt ( __dtb_start ) ;
2013-01-18 15:12:20 +05:30
/* To force early parsing of things like mem=xxx */
parse_early_param ( ) ;
/* Platform/board specific: e.g. early console registration */
arc_platform_early_init ( ) ;
setup_processor ( ) ;
2013-01-18 15:12:23 +05:30
# ifdef CONFIG_SMP
smp_init_cpus ( ) ;
# endif
2013-01-18 15:12:20 +05:30
setup_arch_memory ( ) ;
2013-01-22 17:00:52 +05:30
unflatten_device_tree ( ) ;
2013-01-18 15:12:20 +05:30
/* Can be issue if someone passes cmd line arg "ro"
* But that is unlikely so keeping it as it is
*/
root_mountflags & = ~ MS_RDONLY ;
console_verbose ( ) ;
# if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
conswitchp = & dummy_con ;
# endif
2013-01-22 17:03:19 +05:30
arc_unwind_init ( ) ;
arc_unwind_setup ( ) ;
2013-01-18 15:12:20 +05:30
}
/*
* Get CPU information for use by the procfs .
*/
# define cpu_to_ptr(c) ((void *)(0xFFFF0000 | (unsigned int)(c)))
# define ptr_to_cpu(p) (~0xFFFF0000UL & (unsigned int)(p))
static int show_cpuinfo ( struct seq_file * m , void * v )
{
char * str ;
int cpu_id = ptr_to_cpu ( v ) ;
str = ( char * ) __get_free_page ( GFP_TEMPORARY ) ;
if ( ! str )
goto done ;
2013-01-18 15:12:24 +05:30
seq_printf ( m , arc_cpu_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
2013-01-18 15:12:20 +05:30
seq_printf ( m , " Bogo MIPS : \t %lu.%02lu \n " ,
loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
2013-01-18 15:12:24 +05:30
seq_printf ( m , arc_mmu_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
seq_printf ( m , arc_cache_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
seq_printf ( m , arc_extn_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
# ifdef CONFIG_SMP
seq_printf ( m , arc_platform_smp_cpuinfo ( ) ) ;
# endif
2013-01-18 15:12:20 +05:30
free_page ( ( unsigned long ) str ) ;
done :
seq_printf ( m , " \n \n " ) ;
return 0 ;
}
static void * c_start ( struct seq_file * m , loff_t * pos )
{
/*
* Callback returns cpu - id to iterator for show routine , NULL to stop .
* However since NULL is also a valid cpu - id ( 0 ) , we use a round - about
* way to pass it w / o having to kmalloc / free a 2 byte string .
* Encode cpu - id as 0xFFcccc , which is decoded by show routine .
*/
return * pos < num_possible_cpus ( ) ? cpu_to_ptr ( * 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 )
{
}
const struct seq_operations cpuinfo_op = {
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = show_cpuinfo
} ;
static DEFINE_PER_CPU ( struct cpu , cpu_topology ) ;
static int __init topology_init ( void )
{
int cpu ;
for_each_present_cpu ( cpu )
register_cpu ( & per_cpu ( cpu_topology , cpu ) , cpu ) ;
return 0 ;
}
subsys_initcall ( topology_init ) ;