2008-08-04 16:33:47 +09:00
/*
* arch / sh / mm / cache - sh2a . c
*
* Copyright ( C ) 2008 Yoshinori Sato
*
* Released under the terms of the GNU GPL v2 .0 .
*/
# include <linux/init.h>
# include <linux/mm.h>
# include <asm/cache.h>
# include <asm/addrspace.h>
# include <asm/processor.h>
# include <asm/cacheflush.h>
# include <asm/io.h>
2009-08-15 12:38:29 +09:00
static void sh2a__flush_wback_region ( void * start , int size )
2008-08-04 16:33:47 +09:00
{
unsigned long v ;
unsigned long begin , end ;
unsigned long flags ;
begin = ( unsigned long ) start & ~ ( L1_CACHE_BYTES - 1 ) ;
end = ( ( unsigned long ) start + size + L1_CACHE_BYTES - 1 )
& ~ ( L1_CACHE_BYTES - 1 ) ;
local_irq_save ( flags ) ;
jump_to_uncached ( ) ;
for ( v = begin ; v < end ; v + = L1_CACHE_BYTES ) {
unsigned long addr = CACHE_OC_ADDRESS_ARRAY | ( v & 0x000007f0 ) ;
int way ;
for ( way = 0 ; way < 4 ; way + + ) {
unsigned long data = ctrl_inl ( addr | ( way < < 11 ) ) ;
if ( ( data & CACHE_PHYSADDR_MASK ) = = ( v & CACHE_PHYSADDR_MASK ) ) {
data & = ~ SH_CACHE_UPDATED ;
ctrl_outl ( data , addr | ( way < < 11 ) ) ;
}
}
}
back_to_cached ( ) ;
local_irq_restore ( flags ) ;
}
2009-08-15 12:38:29 +09:00
static void sh2a__flush_purge_region ( void * start , int size )
2008-08-04 16:33:47 +09:00
{
unsigned long v ;
unsigned long begin , end ;
unsigned long flags ;
begin = ( unsigned long ) start & ~ ( L1_CACHE_BYTES - 1 ) ;
end = ( ( unsigned long ) start + size + L1_CACHE_BYTES - 1 )
& ~ ( L1_CACHE_BYTES - 1 ) ;
local_irq_save ( flags ) ;
jump_to_uncached ( ) ;
for ( v = begin ; v < end ; v + = L1_CACHE_BYTES ) {
ctrl_outl ( ( v & CACHE_PHYSADDR_MASK ) ,
2008-08-07 13:54:59 +09:00
CACHE_OC_ADDRESS_ARRAY | ( v & 0x000007f0 ) | 0x00000008 ) ;
2008-08-04 16:33:47 +09:00
}
back_to_cached ( ) ;
local_irq_restore ( flags ) ;
}
2009-08-15 12:38:29 +09:00
static void sh2a__flush_invalidate_region ( void * start , int size )
2008-08-04 16:33:47 +09:00
{
unsigned long v ;
unsigned long begin , end ;
unsigned long flags ;
begin = ( unsigned long ) start & ~ ( L1_CACHE_BYTES - 1 ) ;
end = ( ( unsigned long ) start + size + L1_CACHE_BYTES - 1 )
& ~ ( L1_CACHE_BYTES - 1 ) ;
local_irq_save ( flags ) ;
jump_to_uncached ( ) ;
# ifdef CONFIG_CACHE_WRITEBACK
ctrl_outl ( ctrl_inl ( CCR ) | CCR_OCACHE_INVALIDATE , CCR ) ;
/* I-cache invalidate */
for ( v = begin ; v < end ; v + = L1_CACHE_BYTES ) {
ctrl_outl ( ( v & CACHE_PHYSADDR_MASK ) ,
2008-08-07 13:54:59 +09:00
CACHE_IC_ADDRESS_ARRAY | ( v & 0x000007f0 ) | 0x00000008 ) ;
2008-08-04 16:33:47 +09:00
}
# else
for ( v = begin ; v < end ; v + = L1_CACHE_BYTES ) {
ctrl_outl ( ( v & CACHE_PHYSADDR_MASK ) ,
2008-08-07 13:54:59 +09:00
CACHE_IC_ADDRESS_ARRAY | ( v & 0x000007f0 ) | 0x00000008 ) ;
2008-08-04 16:33:47 +09:00
ctrl_outl ( ( v & CACHE_PHYSADDR_MASK ) ,
2008-08-07 13:54:59 +09:00
CACHE_OC_ADDRESS_ARRAY | ( v & 0x000007f0 ) | 0x00000008 ) ;
2008-08-04 16:33:47 +09:00
}
# endif
back_to_cached ( ) ;
local_irq_restore ( flags ) ;
}
/* WBack O-Cache and flush I-Cache */
2009-08-21 17:23:14 +09:00
static void sh2a_flush_icache_range ( void * args )
2008-08-04 16:33:47 +09:00
{
2009-08-21 17:23:14 +09:00
struct flusher_data * data = args ;
unsigned long start , end ;
2008-08-04 16:33:47 +09:00
unsigned long v ;
2009-09-01 21:12:55 +09:00
unsigned long flags ;
2008-08-04 16:33:47 +09:00
2009-08-21 17:23:14 +09:00
start = data - > addr1 & ~ ( L1_CACHE_BYTES - 1 ) ;
end = ( data - > addr2 + L1_CACHE_BYTES - 1 ) & ~ ( L1_CACHE_BYTES - 1 ) ;
2008-08-04 16:33:47 +09:00
2009-09-01 21:12:55 +09:00
local_irq_save ( flags ) ;
2008-08-04 16:33:47 +09:00
jump_to_uncached ( ) ;
for ( v = start ; v < end ; v + = L1_CACHE_BYTES ) {
unsigned long addr = ( v & 0x000007f0 ) ;
int way ;
/* O-Cache writeback */
for ( way = 0 ; way < 4 ; way + + ) {
unsigned long data = ctrl_inl ( CACHE_OC_ADDRESS_ARRAY | addr | ( way < < 11 ) ) ;
if ( ( data & CACHE_PHYSADDR_MASK ) = = ( v & CACHE_PHYSADDR_MASK ) ) {
data & = ~ SH_CACHE_UPDATED ;
ctrl_outl ( data , CACHE_OC_ADDRESS_ARRAY | addr | ( way < < 11 ) ) ;
}
}
/* I-Cache invalidate */
2009-09-01 21:12:55 +09:00
ctrl_outl ( addr ,
CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008 ) ;
2008-08-04 16:33:47 +09:00
}
back_to_cached ( ) ;
2009-09-01 21:12:55 +09:00
local_irq_restore ( flags ) ;
2008-08-04 16:33:47 +09:00
}
2009-08-15 12:38:29 +09:00
void __init sh2a_cache_init ( void )
{
2009-08-21 17:23:14 +09:00
local_flush_icache_range = sh2a_flush_icache_range ;
2009-08-15 12:38:29 +09:00
__flush_wback_region = sh2a__flush_wback_region ;
__flush_purge_region = sh2a__flush_purge_region ;
__flush_invalidate_region = sh2a__flush_invalidate_region ;
}