2005-04-17 02:20:36 +04:00
/*
* sc - rm7k . c : RM7000 cache management functions .
*
* Copyright ( C ) 1997 , 2001 , 2003 , 2004 Ralf Baechle ( ralf @ linux - mips . org )
*/
# undef DEBUG
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/mm.h>
2006-02-15 12:25:48 +03:00
# include <linux/bitops.h>
2005-04-17 02:20:36 +04:00
# include <asm/addrspace.h>
# include <asm/bcache.h>
# include <asm/cacheops.h>
# include <asm/mipsregs.h>
# include <asm/processor.h>
2005-04-25 20:36:23 +04:00
# include <asm/cacheflush.h> /* for run_uncached() */
2005-04-17 02:20:36 +04:00
/* Primary cache parameters. */
# define sc_lsize 32
# define tc_pagesize (32*128)
/* Secondary cache parameters. */
# define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */
extern unsigned long icache_way_size , dcache_way_size ;
# include <asm/r4kcache.h>
2009-03-30 23:53:23 +04:00
static int rm7k_tcache_enabled ;
2005-04-17 02:20:36 +04:00
/*
* Writeback and invalidate the primary cache dcache before DMA .
* ( XXX These need to be fixed . . . )
*/
static void rm7k_sc_wback_inv ( unsigned long addr , unsigned long size )
{
unsigned long end , a ;
pr_debug ( " rm7k_sc_wback_inv[%08lx,%08lx] " , addr , size ) ;
/* Catch bad driver code */
BUG_ON ( size = = 0 ) ;
2006-02-15 12:25:48 +03:00
blast_scache_range ( addr , addr + size ) ;
2005-04-17 02:20:36 +04:00
if ( ! rm7k_tcache_enabled )
return ;
a = addr & ~ ( tc_pagesize - 1 ) ;
end = ( addr + size - 1 ) & ~ ( tc_pagesize - 1 ) ;
while ( 1 ) {
invalidate_tcache_page ( a ) ; /* Page_Invalidate_T */
if ( a = = end )
break ;
a + = tc_pagesize ;
}
}
static void rm7k_sc_inv ( unsigned long addr , unsigned long size )
{
unsigned long end , a ;
pr_debug ( " rm7k_sc_inv[%08lx,%08lx] " , addr , size ) ;
/* Catch bad driver code */
BUG_ON ( size = = 0 ) ;
2006-02-15 12:25:48 +03:00
blast_inv_scache_range ( addr , addr + size ) ;
2005-04-17 02:20:36 +04:00
if ( ! rm7k_tcache_enabled )
return ;
a = addr & ~ ( tc_pagesize - 1 ) ;
end = ( addr + size - 1 ) & ~ ( tc_pagesize - 1 ) ;
while ( 1 ) {
invalidate_tcache_page ( a ) ; /* Page_Invalidate_T */
if ( a = = end )
break ;
a + = tc_pagesize ;
}
}
/*
2005-04-25 20:36:23 +04:00
* This function is executed in uncached address space .
2005-04-17 02:20:36 +04:00
*/
2008-07-06 03:19:42 +04:00
static __cpuinit void __rm7k_sc_enable ( void )
2005-04-17 02:20:36 +04:00
{
int i ;
2005-06-20 17:09:49 +04:00
set_c0_config ( RM7K_CONF_SE ) ;
2005-04-17 02:20:36 +04:00
write_c0_taglo ( 0 ) ;
write_c0_taghi ( 0 ) ;
for ( i = 0 ; i < scache_size ; i + = sc_lsize ) {
__asm__ __volatile__ (
" .set noreorder \n \t "
" .set mips3 \n \t "
" cache %1, (%0) \n \t "
" .set mips0 \n \t "
" .set reorder "
:
2005-04-25 20:36:23 +04:00
: " r " ( CKSEG0ADDR ( i ) ) , " i " ( Index_Store_Tag_SD ) ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-06 03:19:42 +04:00
static __cpuinit void rm7k_sc_enable ( void )
2005-04-17 02:20:36 +04:00
{
2005-06-20 17:09:49 +04:00
if ( read_c0_config ( ) & RM7K_CONF_SE )
2005-04-17 02:20:36 +04:00
return ;
2005-06-20 17:09:49 +04:00
printk ( KERN_INFO " Enabling secondary cache... \n " ) ;
2005-04-25 20:36:23 +04:00
run_uncached ( __rm7k_sc_enable ) ;
2005-04-17 02:20:36 +04:00
}
static void rm7k_sc_disable ( void )
{
2005-06-20 17:09:49 +04:00
clear_c0_config ( RM7K_CONF_SE ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-30 23:53:23 +04:00
static struct bcache_ops rm7k_sc_ops = {
2005-04-17 02:20:36 +04:00
. bc_enable = rm7k_sc_enable ,
. bc_disable = rm7k_sc_disable ,
. bc_wback_inv = rm7k_sc_wback_inv ,
. bc_inv = rm7k_sc_inv
} ;
2008-03-08 12:56:28 +03:00
void __cpuinit rm7k_sc_init ( void )
2005-04-17 02:20:36 +04:00
{
2006-02-15 12:25:48 +03:00
struct cpuinfo_mips * c = & current_cpu_data ;
2005-04-17 02:20:36 +04:00
unsigned int config = read_c0_config ( ) ;
2005-06-20 17:09:49 +04:00
if ( ( config & RM7K_CONF_SC ) )
2005-04-17 02:20:36 +04:00
return ;
2006-02-15 12:25:48 +03:00
c - > scache . linesz = sc_lsize ;
c - > scache . ways = 4 ;
2006-04-07 20:33:31 +04:00
c - > scache . waybit = __ffs ( scache_size / c - > scache . ways ) ;
2006-02-15 12:25:48 +03:00
c - > scache . waysize = scache_size / c - > scache . ways ;
c - > scache . sets = scache_size / ( c - > scache . linesz * c - > scache . ways ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " Secondary cache size %dK, linesize %d bytes. \n " ,
( scache_size > > 10 ) , sc_lsize ) ;
2005-06-20 17:09:49 +04:00
if ( ! ( config & RM7K_CONF_SE ) )
2005-04-17 02:20:36 +04:00
rm7k_sc_enable ( ) ;
/*
* While we ' re at it let ' s deal with the tertiary cache .
*/
2005-06-20 17:09:49 +04:00
if ( ! ( config & RM7K_CONF_TC ) ) {
2005-04-17 02:20:36 +04:00
/*
* We can ' t enable the L3 cache yet . There may be board - specific
* magic necessary to turn it on , and blindly asking the CPU to
* start using it would may give cache errors .
*
* Also , board - specific knowledge may allow us to use the
* CACHE Flash_Invalidate_T instruction if the tag RAM supports
* it , and may specify the size of the L3 cache so we don ' t have
* to probe it .
*/
printk ( KERN_INFO " Tertiary cache present, %s enabled \n " ,
2005-06-20 17:09:49 +04:00
( config & RM7K_CONF_TE ) ? " already " : " not (yet) " ) ;
2005-04-17 02:20:36 +04:00
2005-06-20 17:09:49 +04:00
if ( ( config & RM7K_CONF_TE ) )
2005-04-17 02:20:36 +04:00
rm7k_tcache_enabled = 1 ;
}
bcops = & rm7k_sc_ops ;
}