2011-01-19 15:32:15 +00:00
/*
* Support for Versatile FPGA - based IRQ controllers
*/
2012-10-27 01:05:06 +02:00
# include <linux/bitops.h>
2011-01-19 15:32:15 +00:00
# include <linux/irq.h>
# include <linux/io.h>
2015-07-07 17:11:46 -04:00
# include <linux/irqchip.h>
2012-10-31 22:04:31 +01:00
# include <linux/irqchip/versatile-fpga.h>
2012-04-28 14:33:47 +01:00
# include <linux/irqdomain.h>
# include <linux/module.h>
2012-09-06 09:07:57 +01:00
# include <linux/of.h>
# include <linux/of_address.h>
2013-10-04 15:15:35 +02:00
# include <linux/of_irq.h>
2011-01-19 15:32:15 +00:00
2012-04-28 14:33:47 +01:00
# include <asm/exception.h>
2011-01-19 15:32:15 +00:00
# include <asm/mach/irq.h>
# define IRQ_STATUS 0x00
# define IRQ_RAW_STATUS 0x04
# define IRQ_ENABLE_SET 0x08
# define IRQ_ENABLE_CLEAR 0x0c
2012-09-06 09:07:57 +01:00
# define INT_SOFT_SET 0x10
# define INT_SOFT_CLEAR 0x14
# define FIQ_STATUS 0x20
# define FIQ_RAW_STATUS 0x24
# define FIQ_ENABLE 0x28
# define FIQ_ENABLE_SET 0x28
# define FIQ_ENABLE_CLEAR 0x2C
2011-01-19 15:32:15 +00:00
2014-03-03 09:15:18 -06:00
# define PIC_ENABLES 0x20 /* set interrupt pass through bits */
2012-04-28 14:33:47 +01:00
/**
* struct fpga_irq_data - irq data container for the FPGA IRQ controller
* @ base : memory offset in virtual memory
* @ chip : chip container for this instance
* @ domain : IRQ domain for this instance
* @ valid : mask for valid IRQs on this controller
* @ used_irqs : number of active IRQs on this controller
*/
struct fpga_irq_data {
void __iomem * base ;
struct irq_chip chip ;
u32 valid ;
struct irq_domain * domain ;
u8 used_irqs ;
} ;
/* we cannot allocate memory when the controllers are initially registered */
2012-10-31 22:04:31 +01:00
static struct fpga_irq_data fpga_irq_devices [ CONFIG_VERSATILE_FPGA_IRQ_NR ] ;
2012-04-28 14:33:47 +01:00
static int fpga_irq_id ;
2011-01-19 15:32:15 +00:00
static void fpga_irq_mask ( struct irq_data * d )
{
struct fpga_irq_data * f = irq_data_get_irq_chip_data ( d ) ;
2012-04-28 14:33:47 +01:00
u32 mask = 1 < < d - > hwirq ;
2011-01-19 15:32:15 +00:00
writel ( mask , f - > base + IRQ_ENABLE_CLEAR ) ;
}
static void fpga_irq_unmask ( struct irq_data * d )
{
struct fpga_irq_data * f = irq_data_get_irq_chip_data ( d ) ;
2012-04-28 14:33:47 +01:00
u32 mask = 1 < < d - > hwirq ;
2011-01-19 15:32:15 +00:00
writel ( mask , f - > base + IRQ_ENABLE_SET ) ;
}
2015-09-14 10:42:37 +02:00
static void fpga_irq_handle ( struct irq_desc * desc )
2011-01-19 15:32:15 +00:00
{
2011-03-24 13:25:22 +01:00
struct fpga_irq_data * f = irq_desc_get_handler_data ( desc ) ;
2011-01-19 15:32:15 +00:00
u32 status = readl ( f - > base + IRQ_STATUS ) ;
if ( status = = 0 ) {
2015-09-14 10:42:37 +02:00
do_bad_IRQ ( desc ) ;
2011-01-19 15:32:15 +00:00
return ;
}
do {
2015-09-14 10:42:37 +02:00
unsigned int irq = ffs ( status ) - 1 ;
2011-01-19 15:32:15 +00:00
status & = ~ ( 1 < < irq ) ;
2012-04-28 14:33:47 +01:00
generic_handle_irq ( irq_find_mapping ( f - > domain , irq ) ) ;
2011-01-19 15:32:15 +00:00
} while ( status ) ;
}
2012-04-28 14:33:47 +01:00
/*
* Handle each interrupt in a single FPGA IRQ controller . Returns non - zero
* if we ' ve handled at least one interrupt . This does a single read of the
* status register and handles all interrupts in order from LSB first .
*/
static int handle_one_fpga ( struct fpga_irq_data * f , struct pt_regs * regs )
{
int handled = 0 ;
int irq ;
u32 status ;
while ( ( status = readl ( f - > base + IRQ_STATUS ) ) ) {
irq = ffs ( status ) - 1 ;
2014-08-26 11:03:29 +01:00
handle_domain_irq ( f - > domain , irq , regs ) ;
2012-04-28 14:33:47 +01:00
handled = 1 ;
}
return handled ;
}
/*
* Keep iterating over all registered FPGA IRQ controllers until there are
* no pending interrupts .
*/
asmlinkage void __exception_irq_entry fpga_handle_irq ( struct pt_regs * regs )
2011-01-19 15:32:15 +00:00
{
2012-04-28 14:33:47 +01:00
int i , handled ;
2011-01-19 15:32:15 +00:00
2012-04-28 14:33:47 +01:00
do {
for ( i = 0 , handled = 0 ; i < fpga_irq_id ; + + i )
handled | = handle_one_fpga ( & fpga_irq_devices [ i ] , regs ) ;
} while ( handled ) ;
}
static int fpga_irqdomain_map ( struct irq_domain * d , unsigned int irq ,
irq_hw_number_t hwirq )
{
struct fpga_irq_data * f = d - > host_data ;
/* Skip invalid IRQs, only register handlers for the real ones */
2012-10-27 01:05:06 +02:00
if ( ! ( f - > valid & BIT ( hwirq ) ) )
2013-06-06 14:11:38 +01:00
return - EPERM ;
2012-04-28 14:33:47 +01:00
irq_set_chip_data ( irq , f ) ;
irq_set_chip_and_handler ( irq , & f - > chip ,
handle_level_irq ) ;
2015-08-29 18:01:22 -05:00
irq_set_probe ( irq ) ;
2012-04-28 14:33:47 +01:00
return 0 ;
}
2015-04-27 21:54:24 +09:00
static const struct irq_domain_ops fpga_irqdomain_ops = {
2012-04-28 14:33:47 +01:00
. map = fpga_irqdomain_map ,
. xlate = irq_domain_xlate_onetwocell ,
} ;
2012-10-27 01:05:06 +02:00
void __init fpga_irq_init ( void __iomem * base , const char * name , int irq_start ,
int parent_irq , u32 valid , struct device_node * node )
{
2012-04-28 14:33:47 +01:00
struct fpga_irq_data * f ;
2012-10-27 01:05:06 +02:00
int i ;
2012-04-28 14:33:47 +01:00
if ( fpga_irq_id > = ARRAY_SIZE ( fpga_irq_devices ) ) {
2013-03-25 10:34:46 +01:00
pr_err ( " %s: too few FPGA IRQ controllers, increase CONFIG_VERSATILE_FPGA_IRQ_NR \n " , __func__ ) ;
2012-10-27 01:05:06 +02:00
return ;
2012-04-28 14:33:47 +01:00
}
f = & fpga_irq_devices [ fpga_irq_id ] ;
f - > base = base ;
f - > chip . name = name ;
2011-01-19 15:32:15 +00:00
f - > chip . irq_ack = fpga_irq_mask ;
f - > chip . irq_mask = fpga_irq_mask ;
f - > chip . irq_unmask = fpga_irq_unmask ;
2012-04-28 14:33:47 +01:00
f - > valid = valid ;
2011-01-19 15:32:15 +00:00
if ( parent_irq ! = - 1 ) {
irqchip/versatile: Consolidate chained IRQ handler install/remove
Chained irq handlers usually set up handler data as well. We now have
a function to set both under irq_desc->lock. Replace the two calls
with one.
Search and conversion was done with coccinelle:
@@
expression E1, E2, E3;
@@
(
-if (irq_set_handler_data(E1, E2) != 0)
- BUG();
|
-irq_set_handler_data(E1, E2);
)
-irq_set_chained_handler(E1, E3);
+irq_set_chained_handler_and_data(E1, E3, E2);
@@
expression E1, E2, E3;
@@
(
-if (irq_set_handler_data(E1, E2) != 0)
- BUG();
...
|
-irq_set_handler_data(E1, E2);
...
)
-irq_set_chained_handler(E1, E3);
+irq_set_chained_handler_and_data(E1, E3, E2);
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Julia Lawall <Julia.Lawall@lip6.fr>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
2015-06-21 21:11:00 +02:00
irq_set_chained_handler_and_data ( parent_irq , fpga_irq_handle ,
f ) ;
2011-01-19 15:32:15 +00:00
}
2012-10-27 01:05:06 +02:00
/* This will also allocate irq descriptors */
f - > domain = irq_domain_add_simple ( node , fls ( valid ) , irq_start ,
2012-04-28 14:33:47 +01:00
& fpga_irqdomain_ops , f ) ;
2012-10-27 01:05:06 +02:00
/* This will allocate all valid descriptors in the linear case */
for ( i = 0 ; i < fls ( valid ) ; i + + )
if ( valid & BIT ( i ) ) {
if ( ! irq_start )
irq_create_mapping ( f - > domain , i ) ;
f - > used_irqs + + ;
}
2013-10-04 15:15:35 +02:00
pr_info ( " FPGA IRQ chip %d \" %s \" @ %p, %u irqs " ,
2012-04-28 14:33:47 +01:00
fpga_irq_id , name , base , f - > used_irqs ) ;
2013-10-04 15:15:35 +02:00
if ( parent_irq ! = - 1 )
pr_cont ( " , parent IRQ: %d \n " , parent_irq ) ;
else
pr_cont ( " \n " ) ;
2012-10-27 01:05:06 +02:00
fpga_irq_id + + ;
2012-09-06 09:07:57 +01:00
}
2011-01-19 15:32:15 +00:00
2012-09-06 09:07:57 +01:00
# ifdef CONFIG_OF
int __init fpga_irq_of_init ( struct device_node * node ,
struct device_node * parent )
{
void __iomem * base ;
u32 clear_mask ;
u32 valid_mask ;
2013-10-04 15:15:35 +02:00
int parent_irq ;
2012-09-06 09:07:57 +01:00
if ( WARN_ON ( ! node ) )
return - ENODEV ;
base = of_iomap ( node , 0 ) ;
WARN ( ! base , " unable to map fpga irq registers \n " ) ;
if ( of_property_read_u32 ( node , " clear-mask " , & clear_mask ) )
clear_mask = 0 ;
if ( of_property_read_u32 ( node , " valid-mask " , & valid_mask ) )
valid_mask = 0 ;
2013-10-04 15:15:35 +02:00
/* Some chips are cascaded from a parent IRQ */
parent_irq = irq_of_parse_and_map ( node , 0 ) ;
2014-05-29 16:39:43 -05:00
if ( ! parent_irq ) {
set_handle_irq ( fpga_handle_irq ) ;
2013-10-04 15:15:35 +02:00
parent_irq = - 1 ;
2014-05-29 16:39:43 -05:00
}
2013-10-04 15:15:35 +02:00
fpga_irq_init ( base , node - > name , 0 , parent_irq , valid_mask , node ) ;
2012-09-06 09:07:57 +01:00
writel ( clear_mask , base + IRQ_ENABLE_CLEAR ) ;
writel ( clear_mask , base + FIQ_ENABLE_CLEAR ) ;
2014-03-03 09:15:18 -06:00
/*
* On Versatile AB / PB , some secondary interrupts have a direct
* pass - thru to the primary controller for IRQs 20 and 22 - 31 which need
* to be enabled . See section 3.10 of the Versatile AB user guide .
*/
if ( of_device_is_compatible ( node , " arm,versatile-sic " ) )
writel ( 0xffd00000 , base + PIC_ENABLES ) ;
2012-09-06 09:07:57 +01:00
return 0 ;
2011-01-19 15:32:15 +00:00
}
2014-05-29 16:39:43 -05:00
IRQCHIP_DECLARE ( arm_fpga , " arm,versatile-fpga-irq " , fpga_irq_of_init ) ;
2014-03-03 09:15:18 -06:00
IRQCHIP_DECLARE ( arm_fpga_sic , " arm,versatile-sic " , fpga_irq_of_init ) ;
2016-03-07 15:49:08 +01:00
IRQCHIP_DECLARE ( ox810se_rps , " oxsemi,ox810se-rps-irq " , fpga_irq_of_init ) ;
2012-09-06 09:07:57 +01:00
# endif