2010-10-05 17:10:30 +04:00
/*
* Common INTC2 register accessors
*
* Copyright ( C ) 2007 , 2008 Magnus Damm
* Copyright ( C ) 2009 , 2010 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
# include <linux/io.h>
# include "internals.h"
unsigned long intc_phys_to_virt ( struct intc_desc_int * d , unsigned long address )
{
struct intc_window * window ;
int k ;
/* scan through physical windows and convert address */
for ( k = 0 ; k < d - > nr_windows ; k + + ) {
window = d - > window + k ;
if ( address < window - > phys )
continue ;
if ( address > = ( window - > phys + window - > size ) )
continue ;
address - = window - > phys ;
address + = ( unsigned long ) window - > virt ;
return address ;
}
/* no windows defined, register must be 1:1 mapped virt:phys */
return address ;
}
unsigned int intc_get_reg ( struct intc_desc_int * d , unsigned long address )
{
unsigned int k ;
address = intc_phys_to_virt ( d , address ) ;
for ( k = 0 ; k < d - > nr_reg ; k + + ) {
if ( d - > reg [ k ] = = address )
return k ;
}
BUG ( ) ;
return 0 ;
}
unsigned int intc_set_field_from_handle ( unsigned int value ,
unsigned int field_value ,
unsigned int handle )
{
unsigned int width = _INTC_WIDTH ( handle ) ;
unsigned int shift = _INTC_SHIFT ( handle ) ;
value & = ~ ( ( ( 1 < < width ) - 1 ) < < shift ) ;
value | = field_value < < shift ;
return value ;
}
unsigned long intc_get_field_from_handle ( unsigned int value , unsigned int handle )
{
unsigned int width = _INTC_WIDTH ( handle ) ;
unsigned int shift = _INTC_SHIFT ( handle ) ;
unsigned int mask = ( ( 1 < < width ) - 1 ) < < shift ;
return ( value & mask ) > > shift ;
}
static unsigned long test_8 ( unsigned long addr , unsigned long h ,
unsigned long ignore )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
return intc_get_field_from_handle ( __raw_readb ( ptr ) , h ) ;
2010-10-05 17:10:30 +04:00
}
static unsigned long test_16 ( unsigned long addr , unsigned long h ,
unsigned long ignore )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
return intc_get_field_from_handle ( __raw_readw ( ptr ) , h ) ;
2010-10-05 17:10:30 +04:00
}
static unsigned long test_32 ( unsigned long addr , unsigned long h ,
unsigned long ignore )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
return intc_get_field_from_handle ( __raw_readl ( ptr ) , h ) ;
2010-10-05 17:10:30 +04:00
}
static unsigned long write_8 ( unsigned long addr , unsigned long h ,
unsigned long data )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
__raw_writeb ( intc_set_field_from_handle ( 0 , data , h ) , ptr ) ;
( void ) __raw_readb ( ptr ) ; /* Defeat write posting */
2010-10-05 17:10:30 +04:00
return 0 ;
}
static unsigned long write_16 ( unsigned long addr , unsigned long h ,
unsigned long data )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
__raw_writew ( intc_set_field_from_handle ( 0 , data , h ) , ptr ) ;
( void ) __raw_readw ( ptr ) ; /* Defeat write posting */
2010-10-05 17:10:30 +04:00
return 0 ;
}
static unsigned long write_32 ( unsigned long addr , unsigned long h ,
unsigned long data )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
__raw_writel ( intc_set_field_from_handle ( 0 , data , h ) , ptr ) ;
( void ) __raw_readl ( ptr ) ; /* Defeat write posting */
2010-10-05 17:10:30 +04:00
return 0 ;
}
static unsigned long modify_8 ( unsigned long addr , unsigned long h ,
unsigned long data )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
2010-10-05 17:10:30 +04:00
unsigned long flags ;
unsigned int value ;
local_irq_save ( flags ) ;
2012-10-15 09:08:48 +04:00
value = intc_set_field_from_handle ( __raw_readb ( ptr ) , data , h ) ;
__raw_writeb ( value , ptr ) ;
( void ) __raw_readb ( ptr ) ; /* Defeat write posting */
2010-10-05 17:10:30 +04:00
local_irq_restore ( flags ) ;
return 0 ;
}
static unsigned long modify_16 ( unsigned long addr , unsigned long h ,
unsigned long data )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
2010-10-05 17:10:30 +04:00
unsigned long flags ;
unsigned int value ;
local_irq_save ( flags ) ;
2012-10-15 09:08:48 +04:00
value = intc_set_field_from_handle ( __raw_readw ( ptr ) , data , h ) ;
__raw_writew ( value , ptr ) ;
( void ) __raw_readw ( ptr ) ; /* Defeat write posting */
2010-10-05 17:10:30 +04:00
local_irq_restore ( flags ) ;
return 0 ;
}
static unsigned long modify_32 ( unsigned long addr , unsigned long h ,
unsigned long data )
{
2012-10-15 09:08:48 +04:00
void __iomem * ptr = ( void __iomem * ) addr ;
2010-10-05 17:10:30 +04:00
unsigned long flags ;
unsigned int value ;
local_irq_save ( flags ) ;
2012-10-15 09:08:48 +04:00
value = intc_set_field_from_handle ( __raw_readl ( ptr ) , data , h ) ;
__raw_writel ( value , ptr ) ;
( void ) __raw_readl ( ptr ) ; /* Defeat write posting */
2010-10-05 17:10:30 +04:00
local_irq_restore ( flags ) ;
return 0 ;
}
static unsigned long intc_mode_field ( unsigned long addr ,
unsigned long handle ,
unsigned long ( * fn ) ( unsigned long ,
unsigned long ,
unsigned long ) ,
unsigned int irq )
{
return fn ( addr , handle , ( ( 1 < < _INTC_WIDTH ( handle ) ) - 1 ) ) ;
}
static unsigned long intc_mode_zero ( unsigned long addr ,
unsigned long handle ,
unsigned long ( * fn ) ( unsigned long ,
unsigned long ,
unsigned long ) ,
unsigned int irq )
{
return fn ( addr , handle , 0 ) ;
}
static unsigned long intc_mode_prio ( unsigned long addr ,
unsigned long handle ,
unsigned long ( * fn ) ( unsigned long ,
unsigned long ,
unsigned long ) ,
unsigned int irq )
{
return fn ( addr , handle , intc_get_prio_level ( irq ) ) ;
}
unsigned long ( * intc_reg_fns [ ] ) ( unsigned long addr ,
unsigned long h ,
unsigned long data ) = {
[ REG_FN_TEST_BASE + 0 ] = test_8 ,
[ REG_FN_TEST_BASE + 1 ] = test_16 ,
[ REG_FN_TEST_BASE + 3 ] = test_32 ,
[ REG_FN_WRITE_BASE + 0 ] = write_8 ,
[ REG_FN_WRITE_BASE + 1 ] = write_16 ,
[ REG_FN_WRITE_BASE + 3 ] = write_32 ,
[ REG_FN_MODIFY_BASE + 0 ] = modify_8 ,
[ REG_FN_MODIFY_BASE + 1 ] = modify_16 ,
[ REG_FN_MODIFY_BASE + 3 ] = modify_32 ,
} ;
unsigned long ( * intc_enable_fns [ ] ) ( unsigned long addr ,
unsigned long handle ,
unsigned long ( * fn ) ( unsigned long ,
unsigned long ,
unsigned long ) ,
unsigned int irq ) = {
[ MODE_ENABLE_REG ] = intc_mode_field ,
[ MODE_MASK_REG ] = intc_mode_zero ,
[ MODE_DUAL_REG ] = intc_mode_field ,
[ MODE_PRIO_REG ] = intc_mode_prio ,
[ MODE_PCLR_REG ] = intc_mode_prio ,
} ;
unsigned long ( * intc_disable_fns [ ] ) ( unsigned long addr ,
unsigned long handle ,
unsigned long ( * fn ) ( unsigned long ,
unsigned long ,
unsigned long ) ,
unsigned int irq ) = {
[ MODE_ENABLE_REG ] = intc_mode_zero ,
[ MODE_MASK_REG ] = intc_mode_field ,
[ MODE_DUAL_REG ] = intc_mode_field ,
[ MODE_PRIO_REG ] = intc_mode_zero ,
[ MODE_PCLR_REG ] = intc_mode_field ,
} ;
unsigned long ( * intc_enable_noprio_fns [ ] ) ( unsigned long addr ,
unsigned long handle ,
unsigned long ( * fn ) ( unsigned long ,
unsigned long ,
unsigned long ) ,
unsigned int irq ) = {
[ MODE_ENABLE_REG ] = intc_mode_field ,
[ MODE_MASK_REG ] = intc_mode_zero ,
[ MODE_DUAL_REG ] = intc_mode_field ,
[ MODE_PRIO_REG ] = intc_mode_field ,
[ MODE_PCLR_REG ] = intc_mode_field ,
} ;