2014-11-06 15:20:06 +08:00
/*
* Copyright ( C ) 2013 Altera Corporation
* Copyright ( C ) 2011 Tobias Klauser < tklauser @ distanz . ch >
*
* Based on cpuinfo . c from microblaze
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/seq_file.h>
# include <linux/string.h>
# include <linux/of.h>
# include <asm/cpuinfo.h>
struct cpuinfo cpuinfo ;
# define err_cpu(x) \
pr_err ( " ERROR: Nios II " x " different for kernel and DTS \n " )
static inline u32 fcpu ( struct device_node * cpu , const char * n )
{
u32 val = 0 ;
of_property_read_u32 ( cpu , n , & val ) ;
return val ;
}
static inline u32 fcpu_has ( struct device_node * cpu , const char * n )
{
return of_get_property ( cpu , n , NULL ) ? 1 : 0 ;
}
void __init setup_cpuinfo ( void )
{
struct device_node * cpu ;
const char * str ;
int len ;
cpu = of_find_node_by_type ( NULL , " cpu " ) ;
if ( ! cpu )
panic ( " %s: No CPU found in devicetree! \n " , __func__ ) ;
if ( ! fcpu_has ( cpu , " altr,has-initda " ) )
panic ( " initda instruction is unimplemented. Please update your "
" hardware system to have more than 4-byte line data "
" cache \n " ) ;
cpuinfo . cpu_clock_freq = fcpu ( cpu , " clock-frequency " ) ;
str = of_get_property ( cpu , " altr,implementation " , & len ) ;
if ( str )
strlcpy ( cpuinfo . cpu_impl , str , sizeof ( cpuinfo . cpu_impl ) ) ;
else
strcpy ( cpuinfo . cpu_impl , " <unknown> " ) ;
cpuinfo . has_div = fcpu_has ( cpu , " altr,has-div " ) ;
cpuinfo . has_mul = fcpu_has ( cpu , " altr,has-mul " ) ;
cpuinfo . has_mulx = fcpu_has ( cpu , " altr,has-mulx " ) ;
2014-12-31 09:29:07 +08:00
cpuinfo . mmu = fcpu_has ( cpu , " altr,has-mmu " ) ;
2014-11-06 15:20:06 +08:00
2014-11-17 18:30:37 +08:00
if ( IS_ENABLED ( CONFIG_NIOS2_HW_DIV_SUPPORT ) & & ! cpuinfo . has_div )
2014-11-06 15:20:06 +08:00
err_cpu ( " DIV " ) ;
2014-11-17 18:30:37 +08:00
if ( IS_ENABLED ( CONFIG_NIOS2_HW_MUL_SUPPORT ) & & ! cpuinfo . has_mul )
2014-11-06 15:20:06 +08:00
err_cpu ( " MUL " ) ;
2014-11-17 18:30:37 +08:00
if ( IS_ENABLED ( CONFIG_NIOS2_HW_MULX_SUPPORT ) & & ! cpuinfo . has_mulx )
2014-11-06 15:20:06 +08:00
err_cpu ( " MULX " ) ;
cpuinfo . tlb_num_ways = fcpu ( cpu , " altr,tlb-num-ways " ) ;
if ( ! cpuinfo . tlb_num_ways )
panic ( " altr,tlb-num-ways can't be 0. Please check your hardware "
" system \n " ) ;
cpuinfo . icache_line_size = fcpu ( cpu , " icache-line-size " ) ;
cpuinfo . icache_size = fcpu ( cpu , " icache-size " ) ;
if ( CONFIG_NIOS2_ICACHE_SIZE ! = cpuinfo . icache_size )
pr_warn ( " Warning: icache size configuration mismatch "
" (0x%x vs 0x%x) of CONFIG_NIOS2_ICACHE_SIZE vs "
" device tree icache-size \n " ,
CONFIG_NIOS2_ICACHE_SIZE , cpuinfo . icache_size ) ;
cpuinfo . dcache_line_size = fcpu ( cpu , " dcache-line-size " ) ;
if ( CONFIG_NIOS2_DCACHE_LINE_SIZE ! = cpuinfo . dcache_line_size )
pr_warn ( " Warning: dcache line size configuration mismatch "
" (0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_LINE_SIZE vs "
" device tree dcache-line-size \n " ,
CONFIG_NIOS2_DCACHE_LINE_SIZE , cpuinfo . dcache_line_size ) ;
cpuinfo . dcache_size = fcpu ( cpu , " dcache-size " ) ;
if ( CONFIG_NIOS2_DCACHE_SIZE ! = cpuinfo . dcache_size )
pr_warn ( " Warning: dcache size configuration mismatch "
" (0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_SIZE vs "
" device tree dcache-size \n " ,
CONFIG_NIOS2_DCACHE_SIZE , cpuinfo . dcache_size ) ;
cpuinfo . tlb_pid_num_bits = fcpu ( cpu , " altr,pid-num-bits " ) ;
cpuinfo . tlb_num_ways_log2 = ilog2 ( cpuinfo . tlb_num_ways ) ;
cpuinfo . tlb_num_entries = fcpu ( cpu , " altr,tlb-num-entries " ) ;
cpuinfo . tlb_num_lines = cpuinfo . tlb_num_entries / cpuinfo . tlb_num_ways ;
cpuinfo . tlb_ptr_sz = fcpu ( cpu , " altr,tlb-ptr-sz " ) ;
cpuinfo . reset_addr = fcpu ( cpu , " altr,reset-addr " ) ;
cpuinfo . exception_addr = fcpu ( cpu , " altr,exception-addr " ) ;
cpuinfo . fast_tlb_miss_exc_addr = fcpu ( cpu , " altr,fast-tlb-miss-addr " ) ;
}
# ifdef CONFIG_PROC_FS
/*
* Get CPU information for use by the procfs .
*/
static int show_cpuinfo ( struct seq_file * m , void * v )
{
const u32 clockfreq = cpuinfo . cpu_clock_freq ;
2015-04-15 16:18:00 -07:00
seq_printf ( m ,
" CPU: \t \t Nios II/%s \n "
" MMU: \t \t %s \n "
" FPU: \t \t none \n "
" Clocking: \t %u.%02u MHz \n "
" BogoMips: \t %lu.%02lu \n "
" Calibration: \t %lu loops \n " ,
cpuinfo . cpu_impl ,
cpuinfo . mmu ? " present " : " none " ,
clockfreq / 1000000 , ( clockfreq / 100000 ) % 10 ,
( loops_per_jiffy * HZ ) / 500000 ,
( ( loops_per_jiffy * HZ ) / 5000 ) % 100 ,
( loops_per_jiffy * HZ ) ) ;
seq_printf ( m ,
" HW: \n "
" MUL: \t \t %s \n "
" MULX: \t \t %s \n "
" DIV: \t \t %s \n " ,
cpuinfo . has_mul ? " yes " : " no " ,
cpuinfo . has_mulx ? " yes " : " no " ,
cpuinfo . has_div ? " yes " : " no " ) ;
seq_printf ( m ,
" Icache: \t \t %ukB, line length: %u \n " ,
cpuinfo . icache_size > > 10 ,
cpuinfo . icache_line_size ) ;
seq_printf ( m ,
" Dcache: \t \t %ukB, line length: %u \n " ,
cpuinfo . dcache_size > > 10 ,
cpuinfo . dcache_line_size ) ;
seq_printf ( m ,
" TLB: \t \t %u ways, %u entries, %u PID bits \n " ,
cpuinfo . tlb_num_ways ,
cpuinfo . tlb_num_entries ,
cpuinfo . tlb_pid_num_bits ) ;
2014-11-06 15:20:06 +08:00
return 0 ;
}
static void * cpuinfo_start ( struct seq_file * m , loff_t * pos )
{
unsigned long i = * pos ;
return i < num_possible_cpus ( ) ? ( void * ) ( i + 1 ) : NULL ;
}
static void * cpuinfo_next ( struct seq_file * m , void * v , loff_t * pos )
{
+ + * pos ;
return cpuinfo_start ( m , pos ) ;
}
static void cpuinfo_stop ( struct seq_file * m , void * v )
{
}
const struct seq_operations cpuinfo_op = {
. start = cpuinfo_start ,
. next = cpuinfo_next ,
. stop = cpuinfo_stop ,
. show = show_cpuinfo
} ;
# endif /* CONFIG_PROC_FS */