2006-06-20 20:15:20 +04:00
/*
* Copyright ( C ) 2006 Chris Dearman ( chris @ mips . com ) ,
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/mm.h>
# include <asm/mipsregs.h>
# include <asm/bcache.h>
# include <asm/cacheops.h>
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/mmu_context.h>
# include <asm/r4kcache.h>
/*
* MIPS32 / MIPS64 L2 cache handling
*/
/*
* Writeback and invalidate the secondary cache before DMA .
*/
static void mips_sc_wback_inv ( unsigned long addr , unsigned long size )
{
2006-06-22 14:42:43 +04:00
blast_scache_range ( addr , addr + size ) ;
2006-06-20 20:15:20 +04:00
}
/*
* Invalidate the secondary cache before DMA .
*/
static void mips_sc_inv ( unsigned long addr , unsigned long size )
{
2009-09-19 06:12:45 +04:00
unsigned long lsize = cpu_scache_line_size ( ) ;
unsigned long almask = ~ ( lsize - 1 ) ;
cache_op ( Hit_Writeback_Inv_SD , addr & almask ) ;
cache_op ( Hit_Writeback_Inv_SD , ( addr + size - 1 ) & almask ) ;
2006-06-22 14:42:43 +04:00
blast_inv_scache_range ( addr , addr + size ) ;
2006-06-20 20:15:20 +04:00
}
static void mips_sc_enable ( void )
{
/* L2 cache is permanently enabled */
}
static void mips_sc_disable ( void )
{
/* L2 cache is permanently enabled */
}
static struct bcache_ops mips_sc_ops = {
. bc_enable = mips_sc_enable ,
. bc_disable = mips_sc_disable ,
. bc_wback_inv = mips_sc_wback_inv ,
. bc_inv = mips_sc_inv
} ;
2010-10-21 07:05:42 +04:00
/*
* Check if the L2 cache controller is activated on a particular platform .
* MTI ' s L2 controller and the L2 cache controller of Broadcom ' s BMIPS
* cores both use c0_config2 ' s bit 12 as " L2 Bypass " bit , that is the
* cache being disabled . However there is no guarantee for this to be
* true on all platforms . In an act of stupidity the spec defined bits
* 12. .15 as implementation defined so below function will eventually have
* to be replaced by a platform specific probe .
*/
static inline int mips_sc_is_activated ( struct cpuinfo_mips * c )
{
2010-11-03 08:28:01 +03:00
unsigned int config2 = read_c0_config2 ( ) ;
unsigned int tmp ;
2010-10-21 07:05:42 +04:00
/* Check the bypass bit (L2B) */
switch ( c - > cputype ) {
case CPU_34K :
case CPU_74K :
case CPU_1004K :
case CPU_BMIPS5000 :
if ( config2 & ( 1 < < 12 ) )
return 0 ;
}
tmp = ( config2 > > 4 ) & 0x0f ;
if ( 0 < tmp & & tmp < = 7 )
c - > scache . linesz = 2 < < tmp ;
else
return 0 ;
2010-11-03 08:28:01 +03:00
return 1 ;
2010-10-21 07:05:42 +04:00
}
2006-06-20 20:15:20 +04:00
static inline int __init mips_sc_probe ( void )
{
struct cpuinfo_mips * c = & current_cpu_data ;
unsigned int config1 , config2 ;
unsigned int tmp ;
/* Mark as not present until probe completed */
c - > scache . flags | = MIPS_CACHE_NOT_PRESENT ;
/* Ignore anything but MIPSxx processors */
if ( c - > isa_level ! = MIPS_CPU_ISA_M32R1 & &
c - > isa_level ! = MIPS_CPU_ISA_M32R2 & &
c - > isa_level ! = MIPS_CPU_ISA_M64R1 & &
c - > isa_level ! = MIPS_CPU_ISA_M64R2 )
return 0 ;
/* Does this MIPS32/MIPS64 CPU have a config2 register? */
config1 = read_c0_config1 ( ) ;
if ( ! ( config1 & MIPS_CONF_M ) )
return 0 ;
config2 = read_c0_config2 ( ) ;
2010-10-21 07:05:42 +04:00
if ( ! mips_sc_is_activated ( c ) )
2006-06-20 20:15:20 +04:00
return 0 ;
tmp = ( config2 > > 8 ) & 0x0f ;
if ( 0 < = tmp & & tmp < = 7 )
c - > scache . sets = 64 < < tmp ;
else
return 0 ;
tmp = ( config2 > > 0 ) & 0x0f ;
if ( 0 < = tmp & & tmp < = 7 )
c - > scache . ways = tmp + 1 ;
else
return 0 ;
c - > scache . waysize = c - > scache . sets * c - > scache . linesz ;
2006-06-22 14:42:43 +04:00
c - > scache . waybit = __ffs ( c - > scache . waysize ) ;
2006-06-20 20:15:20 +04:00
c - > scache . flags & = ~ MIPS_CACHE_NOT_PRESENT ;
return 1 ;
}
2008-03-08 12:56:28 +03:00
int __cpuinit mips_sc_init ( void )
2006-06-20 20:15:20 +04:00
{
2007-10-12 02:46:15 +04:00
int found = mips_sc_probe ( ) ;
2006-06-20 20:15:20 +04:00
if ( found ) {
mips_sc_enable ( ) ;
bcops = & mips_sc_ops ;
}
return found ;
}