2006-01-14 00:30:48 +03:00
/*
* linux / arch / arm / common / vic . c
*
* Copyright ( C ) 1999 - 2003 ARM Limited
* Copyright ( C ) 2000 Deep Blue Solutions Ltd
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2010-01-12 21:09:12 +03:00
2011-09-27 14:00:46 +04:00
# include <linux/export.h>
2006-01-14 00:30:48 +03:00
# include <linux/init.h>
# include <linux/list.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2013-04-03 02:07:37 +04:00
# include <linux/irq.h>
2014-04-15 12:28:04 +04:00
# include <linux/irqchip/chained_irq.h>
2011-09-27 14:00:46 +04:00
# include <linux/irqdomain.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
2011-04-23 00:02:33 +04:00
# include <linux/syscore_ops.h>
2009-09-14 15:25:34 +04:00
# include <linux/device.h>
2009-08-04 04:01:02 +04:00
# include <linux/amba/bus.h>
2013-01-07 19:45:59 +04:00
# include <linux/irqchip/arm-vic.h>
2006-01-14 00:30:48 +03:00
2011-09-28 12:40:11 +04:00
# include <asm/exception.h>
2013-01-18 19:20:06 +04:00
# include <asm/irq.h>
2006-01-14 00:30:48 +03:00
2012-10-28 02:25:26 +04:00
# include "irqchip.h"
2012-11-06 23:14:26 +04:00
# define VIC_IRQ_STATUS 0x00
# define VIC_FIQ_STATUS 0x04
# define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */
# define VIC_INT_SOFT 0x18
# define VIC_INT_SOFT_CLEAR 0x1c
# define VIC_PROTECT 0x20
# define VIC_PL190_VECT_ADDR 0x30 /* PL190 only */
# define VIC_PL190_DEF_VECT_ADDR 0x34 /* PL190 only */
# define VIC_VECT_ADDR0 0x100 /* 0 to 15 (0..31 PL192) */
# define VIC_VECT_CNTL0 0x200 /* 0 to 15 (0..31 PL192) */
# define VIC_ITCR 0x300 /* VIC test control register */
# define VIC_VECT_CNTL_ENABLE (1 << 5)
# define VIC_PL192_VECT_ADDR 0xF00
2009-03-24 18:30:07 +03:00
/**
* struct vic_device - VIC PM device
2013-11-22 02:11:29 +04:00
* @ parent_irq : The parent IRQ number of the VIC if cascaded , or 0.
2009-03-24 18:30:07 +03:00
* @ irq : The IRQ number for the base of the VIC .
* @ base : The register base for the VIC .
2012-04-20 11:02:36 +04:00
* @ valid_sources : A bitmask of valid interrupts
2009-03-24 18:30:07 +03:00
* @ resume_sources : A bitmask of interrupts for resume .
* @ resume_irqs : The IRQs enabled for resume .
* @ int_select : Save for VIC_INT_SELECT .
* @ int_enable : Save for VIC_INT_ENABLE .
* @ soft_int : Save for VIC_INT_SOFT .
* @ protect : Save for VIC_PROTECT .
2011-09-27 14:00:46 +04:00
* @ domain : The IRQ domain for the VIC .
2009-03-24 18:30:07 +03:00
*/
struct vic_device {
void __iomem * base ;
int irq ;
2012-04-20 11:02:36 +04:00
u32 valid_sources ;
2009-03-24 18:30:07 +03:00
u32 resume_sources ;
u32 resume_irqs ;
u32 int_select ;
u32 int_enable ;
u32 soft_int ;
u32 protect ;
2012-02-15 01:06:57 +04:00
struct irq_domain * domain ;
2009-03-24 18:30:07 +03:00
} ;
/* we cannot allocate memory when VICs are initially registered */
static struct vic_device vic_devices [ CONFIG_ARM_VIC_NR ] ;
2010-01-12 21:09:12 +03:00
static int vic_id ;
2009-03-24 18:30:07 +03:00
2012-11-06 02:32:29 +04:00
static void vic_handle_irq ( struct pt_regs * regs ) ;
2010-01-12 21:09:12 +03:00
/**
* vic_init2 - common initialisation code
* @ base : Base of the VIC .
*
tree-wide: fix comment/printk typos
"gadget", "through", "command", "maintain", "maintain", "controller", "address",
"between", "initiali[zs]e", "instead", "function", "select", "already",
"equal", "access", "management", "hierarchy", "registration", "interest",
"relative", "memory", "offset", "already",
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2010-11-01 22:38:34 +03:00
* Common initialisation code for registration
2010-01-12 21:09:12 +03:00
* and resume .
*/
static void vic_init2 ( void __iomem * base )
{
int i ;
for ( i = 0 ; i < 16 ; i + + ) {
void __iomem * reg = base + VIC_VECT_CNTL0 + ( i * 4 ) ;
writel ( VIC_VECT_CNTL_ENABLE | i , reg ) ;
}
writel ( 32 , base + VIC_PL190_DEF_VECT_ADDR ) ;
}
2009-03-24 18:30:07 +03:00
2011-04-23 00:02:33 +04:00
# ifdef CONFIG_PM
static void resume_one_vic ( struct vic_device * vic )
2009-03-24 18:30:07 +03:00
{
void __iomem * base = vic - > base ;
printk ( KERN_DEBUG " %s: resuming vic at %p \n " , __func__ , base ) ;
/* re-initialise static settings */
vic_init2 ( base ) ;
writel ( vic - > int_select , base + VIC_INT_SELECT ) ;
writel ( vic - > protect , base + VIC_PROTECT ) ;
/* set the enabled ints and then clear the non-enabled */
writel ( vic - > int_enable , base + VIC_INT_ENABLE ) ;
writel ( ~ vic - > int_enable , base + VIC_INT_ENABLE_CLEAR ) ;
/* and the same for the soft-int register */
writel ( vic - > soft_int , base + VIC_INT_SOFT ) ;
writel ( ~ vic - > soft_int , base + VIC_INT_SOFT_CLEAR ) ;
2011-04-23 00:02:33 +04:00
}
2009-03-24 18:30:07 +03:00
2011-04-23 00:02:33 +04:00
static void vic_resume ( void )
{
int id ;
for ( id = vic_id - 1 ; id > = 0 ; id - - )
resume_one_vic ( vic_devices + id ) ;
2009-03-24 18:30:07 +03:00
}
2011-04-23 00:02:33 +04:00
static void suspend_one_vic ( struct vic_device * vic )
2009-03-24 18:30:07 +03:00
{
void __iomem * base = vic - > base ;
printk ( KERN_DEBUG " %s: suspending vic at %p \n " , __func__ , base ) ;
vic - > int_select = readl ( base + VIC_INT_SELECT ) ;
vic - > int_enable = readl ( base + VIC_INT_ENABLE ) ;
vic - > soft_int = readl ( base + VIC_INT_SOFT ) ;
vic - > protect = readl ( base + VIC_PROTECT ) ;
/* set the interrupts (if any) that are used for
* resuming the system */
writel ( vic - > resume_irqs , base + VIC_INT_ENABLE ) ;
writel ( ~ vic - > resume_irqs , base + VIC_INT_ENABLE_CLEAR ) ;
2011-04-23 00:02:33 +04:00
}
static int vic_suspend ( void )
{
int id ;
for ( id = 0 ; id < vic_id ; id + + )
suspend_one_vic ( vic_devices + id ) ;
2009-03-24 18:30:07 +03:00
return 0 ;
}
2011-04-23 00:02:33 +04:00
struct syscore_ops vic_syscore_ops = {
. suspend = vic_suspend ,
. resume = vic_resume ,
2009-03-24 18:30:07 +03:00
} ;
/**
* vic_pm_init - initicall to register VIC pm
*
* This is called via late_initcall ( ) to register
* the resources for the VICs due to the early
* nature of the VIC ' s registration .
*/
static int __init vic_pm_init ( void )
{
2011-04-23 00:02:33 +04:00
if ( vic_id > 0 )
register_syscore_ops ( & vic_syscore_ops ) ;
2009-03-24 18:30:07 +03:00
return 0 ;
}
late_initcall ( vic_pm_init ) ;
2011-09-27 14:00:46 +04:00
# endif /* CONFIG_PM */
2009-03-24 18:30:07 +03:00
2012-04-20 11:02:36 +04:00
static struct irq_chip vic_chip ;
static int vic_irqdomain_map ( struct irq_domain * d , unsigned int irq ,
irq_hw_number_t hwirq )
{
struct vic_device * v = d - > host_data ;
/* Skip invalid IRQs, only register handlers for the real ones */
if ( ! ( v - > valid_sources & ( 1 < < hwirq ) ) )
2013-06-06 17:11:38 +04:00
return - EPERM ;
2012-04-20 11:02:36 +04:00
irq_set_chip_and_handler ( irq , & vic_chip , handle_level_irq ) ;
irq_set_chip_data ( irq , v - > base ) ;
set_irq_flags ( irq , IRQF_VALID | IRQF_PROBE ) ;
return 0 ;
}
2012-11-06 02:32:29 +04:00
/*
* Handle each interrupt in a single VIC . Returns non - zero if we ' ve
* handled at least one interrupt . This reads the status register
* before handling each interrupt , which is necessary given that
* handle_IRQ may briefly re - enable interrupts for soft IRQ handling .
*/
static int handle_one_vic ( struct vic_device * vic , struct pt_regs * regs )
{
u32 stat , irq ;
int handled = 0 ;
while ( ( stat = readl_relaxed ( vic - > base + VIC_IRQ_STATUS ) ) ) {
irq = ffs ( stat ) - 1 ;
handle_IRQ ( irq_find_mapping ( vic - > domain , irq ) , regs ) ;
handled = 1 ;
}
return handled ;
}
2013-11-22 02:11:29 +04:00
static void vic_handle_irq_cascaded ( unsigned int irq , struct irq_desc * desc )
{
u32 stat , hwirq ;
2014-04-15 12:28:04 +04:00
struct irq_chip * host_chip = irq_desc_get_chip ( desc ) ;
2013-11-22 02:11:29 +04:00
struct vic_device * vic = irq_desc_get_handler_data ( desc ) ;
2014-04-15 12:28:04 +04:00
chained_irq_enter ( host_chip , desc ) ;
2013-11-22 02:11:29 +04:00
while ( ( stat = readl_relaxed ( vic - > base + VIC_IRQ_STATUS ) ) ) {
hwirq = ffs ( stat ) - 1 ;
generic_handle_irq ( irq_find_mapping ( vic - > domain , hwirq ) ) ;
}
2014-04-15 12:28:04 +04:00
chained_irq_exit ( host_chip , desc ) ;
2013-11-22 02:11:29 +04:00
}
2012-11-06 02:32:29 +04:00
/*
* Keep iterating over all registered VIC ' s until there are no pending
* interrupts .
*/
2014-03-05 04:40:30 +04:00
static void __exception_irq_entry vic_handle_irq ( struct pt_regs * regs )
2012-11-06 02:32:29 +04:00
{
int i , handled ;
do {
for ( i = 0 , handled = 0 ; i < vic_id ; + + i )
handled | = handle_one_vic ( & vic_devices [ i ] , regs ) ;
} while ( handled ) ;
}
2012-04-20 11:02:36 +04:00
static struct irq_domain_ops vic_irqdomain_ops = {
. map = vic_irqdomain_map ,
. xlate = irq_domain_xlate_onetwocell ,
} ;
2010-01-12 21:09:12 +03:00
/**
2011-09-27 14:00:46 +04:00
* vic_register ( ) - Register a VIC .
2010-01-12 21:09:12 +03:00
* @ base : The base address of the VIC .
2013-11-22 02:11:29 +04:00
* @ parent_irq : The parent IRQ if cascaded , else 0.
2010-01-12 21:09:12 +03:00
* @ irq : The base IRQ for the VIC .
2012-04-20 11:02:03 +04:00
* @ valid_sources : bitmask of valid interrupts
2010-01-12 21:09:12 +03:00
* @ resume_sources : bitmask of interrupts allowed for resume sources .
2011-09-27 14:00:46 +04:00
* @ node : The device tree node associated with the VIC .
2010-01-12 21:09:12 +03:00
*
* Register the VIC with the system device tree so that it can be notified
* of suspend and resume requests and ensure that the correct actions are
* taken to re - instate the settings on resume .
2011-09-27 14:00:46 +04:00
*
* This also configures the IRQ domain for the VIC .
2010-01-12 21:09:12 +03:00
*/
2013-11-22 02:11:29 +04:00
static void __init vic_register ( void __iomem * base , unsigned int parent_irq ,
unsigned int irq ,
2012-04-20 11:02:03 +04:00
u32 valid_sources , u32 resume_sources ,
struct device_node * node )
2010-01-12 21:09:12 +03:00
{
struct vic_device * v ;
2012-12-26 04:39:16 +04:00
int i ;
2010-01-12 21:09:12 +03:00
2011-09-27 14:00:46 +04:00
if ( vic_id > = ARRAY_SIZE ( vic_devices ) ) {
2010-01-12 21:09:12 +03:00
printk ( KERN_ERR " %s: too few VICs, increase CONFIG_ARM_VIC_NR \n " , __func__ ) ;
2011-09-27 14:00:46 +04:00
return ;
2010-01-12 21:09:12 +03:00
}
2011-09-27 14:00:46 +04:00
v = & vic_devices [ vic_id ] ;
v - > base = base ;
2012-04-20 11:02:36 +04:00
v - > valid_sources = valid_sources ;
2011-09-27 14:00:46 +04:00
v - > resume_sources = resume_sources ;
2012-11-21 05:55:27 +04:00
set_handle_irq ( vic_handle_irq ) ;
2011-09-27 14:00:46 +04:00
vic_id + + ;
2013-11-22 02:11:29 +04:00
if ( parent_irq ) {
irq_set_handler_data ( parent_irq , v ) ;
irq_set_chained_handler ( parent_irq , vic_handle_irq_cascaded ) ;
}
2012-10-16 21:50:00 +04:00
v - > domain = irq_domain_add_simple ( node , fls ( valid_sources ) , irq ,
2012-04-20 11:02:03 +04:00
& vic_irqdomain_ops , v ) ;
2012-12-26 04:39:16 +04:00
/* create an IRQ mapping for each valid IRQ */
for ( i = 0 ; i < fls ( valid_sources ) ; i + + )
if ( valid_sources & ( 1 < < i ) )
irq_create_mapping ( v - > domain , i ) ;
2013-11-24 23:18:57 +04:00
/* If no base IRQ was passed, figure out our allocated base */
if ( irq )
v - > irq = irq ;
else
v - > irq = irq_find_mapping ( v - > domain , 0 ) ;
2010-01-12 21:09:12 +03:00
}
2010-11-29 12:20:21 +03:00
static void vic_ack_irq ( struct irq_data * d )
2010-01-12 21:09:12 +03:00
{
2010-11-29 12:20:21 +03:00
void __iomem * base = irq_data_get_irq_chip_data ( d ) ;
2011-09-27 14:00:46 +04:00
unsigned int irq = d - > hwirq ;
2010-01-12 21:09:12 +03:00
writel ( 1 < < irq , base + VIC_INT_ENABLE_CLEAR ) ;
/* moreover, clear the soft-triggered, in case it was the reason */
writel ( 1 < < irq , base + VIC_INT_SOFT_CLEAR ) ;
}
2010-11-29 12:20:21 +03:00
static void vic_mask_irq ( struct irq_data * d )
2010-01-12 21:09:12 +03:00
{
2010-11-29 12:20:21 +03:00
void __iomem * base = irq_data_get_irq_chip_data ( d ) ;
2011-09-27 14:00:46 +04:00
unsigned int irq = d - > hwirq ;
2010-01-12 21:09:12 +03:00
writel ( 1 < < irq , base + VIC_INT_ENABLE_CLEAR ) ;
}
2010-11-29 12:20:21 +03:00
static void vic_unmask_irq ( struct irq_data * d )
2010-01-12 21:09:12 +03:00
{
2010-11-29 12:20:21 +03:00
void __iomem * base = irq_data_get_irq_chip_data ( d ) ;
2011-09-27 14:00:46 +04:00
unsigned int irq = d - > hwirq ;
2010-01-12 21:09:12 +03:00
writel ( 1 < < irq , base + VIC_INT_ENABLE ) ;
}
# if defined(CONFIG_PM)
2009-03-24 18:30:07 +03:00
static struct vic_device * vic_from_irq ( unsigned int irq )
{
struct vic_device * v = vic_devices ;
unsigned int base_irq = irq & ~ 31 ;
int id ;
for ( id = 0 ; id < vic_id ; id + + , v + + ) {
if ( v - > irq = = base_irq )
return v ;
}
return NULL ;
}
2010-11-29 12:20:21 +03:00
static int vic_set_wake ( struct irq_data * d , unsigned int on )
2009-03-24 18:30:07 +03:00
{
2010-11-29 12:20:21 +03:00
struct vic_device * v = vic_from_irq ( d - > irq ) ;
2011-09-27 14:00:46 +04:00
unsigned int off = d - > hwirq ;
2009-06-02 12:31:03 +04:00
u32 bit = 1 < < off ;
2009-03-24 18:30:07 +03:00
if ( ! v )
return - EINVAL ;
2009-06-02 12:31:03 +04:00
if ( ! ( bit & v - > resume_sources ) )
return - EINVAL ;
2009-03-24 18:30:07 +03:00
if ( on )
2009-06-02 12:31:03 +04:00
v - > resume_irqs | = bit ;
2009-03-24 18:30:07 +03:00
else
2009-06-02 12:31:03 +04:00
v - > resume_irqs & = ~ bit ;
2009-03-24 18:30:07 +03:00
return 0 ;
}
# else
# define vic_set_wake NULL
# endif /* CONFIG_PM */
2006-08-02 01:26:25 +04:00
static struct irq_chip vic_chip = {
2010-04-02 21:04:47 +04:00
. name = " VIC " ,
2010-11-29 12:20:21 +03:00
. irq_ack = vic_ack_irq ,
. irq_mask = vic_mask_irq ,
. irq_unmask = vic_unmask_irq ,
. irq_set_wake = vic_set_wake ,
2006-01-14 00:30:48 +03:00
} ;
2010-04-02 21:04:47 +04:00
static void __init vic_disable ( void __iomem * base )
{
writel ( 0 , base + VIC_INT_SELECT ) ;
writel ( 0 , base + VIC_INT_ENABLE ) ;
writel ( ~ 0 , base + VIC_INT_ENABLE_CLEAR ) ;
writel ( 0 , base + VIC_ITCR ) ;
writel ( ~ 0 , base + VIC_INT_SOFT_CLEAR ) ;
}
static void __init vic_clear_interrupts ( void __iomem * base )
{
unsigned int i ;
writel ( 0 , base + VIC_PL190_VECT_ADDR ) ;
for ( i = 0 ; i < 19 ; i + + ) {
unsigned int value ;
value = readl ( base + VIC_PL190_VECT_ADDR ) ;
writel ( value , base + VIC_PL190_VECT_ADDR ) ;
}
}
2010-01-12 21:09:12 +03:00
/*
* The PL190 cell from ARM has been modified by ST to handle 64 interrupts .
* The original cell has 32 interrupts , while the modified one has 64 ,
* replocating two blocks 0x00 . .0 x1f in 0x20 . .0 x3f . In that case
* the probe function is called twice , with base set to offset 000
* and 020 within the page . We call this " second block " .
*/
static void __init vic_init_st ( void __iomem * base , unsigned int irq_start ,
2011-12-01 14:16:46 +04:00
u32 vic_sources , struct device_node * node )
2010-01-12 21:09:12 +03:00
{
unsigned int i ;
int vic_2nd_block = ( ( unsigned long ) base & ~ PAGE_MASK ) ! = 0 ;
/* Disable all interrupts initially. */
2010-04-02 21:04:47 +04:00
vic_disable ( base ) ;
2010-01-12 21:09:12 +03:00
/*
* Make sure we clear all existing interrupts . The vector registers
* in this cell are after the second block of general registers ,
* so we can address them using standard offsets , but only from
* the second base address , which is 0x20 in the page
*/
if ( vic_2nd_block ) {
2010-04-02 21:04:47 +04:00
vic_clear_interrupts ( base ) ;
2010-01-12 21:09:12 +03:00
/* ST has 16 vectors as well, but we don't enable them by now */
for ( i = 0 ; i < 16 ; i + + ) {
void __iomem * reg = base + VIC_VECT_CNTL0 + ( i * 4 ) ;
writel ( 0 , reg ) ;
}
writel ( 32 , base + VIC_PL190_DEF_VECT_ADDR ) ;
}
2013-11-22 02:11:29 +04:00
vic_register ( base , 0 , irq_start , vic_sources , 0 , node ) ;
2010-01-12 21:09:12 +03:00
}
2009-07-02 18:28:41 +04:00
2013-11-22 02:11:29 +04:00
void __init __vic_init ( void __iomem * base , int parent_irq , int irq_start ,
2011-09-27 14:00:46 +04:00
u32 vic_sources , u32 resume_sources ,
struct device_node * node )
2006-01-14 00:30:48 +03:00
{
unsigned int i ;
2009-07-02 18:28:41 +04:00
u32 cellid = 0 ;
2009-08-04 04:01:02 +04:00
enum amba_vendor vendor ;
2009-07-02 18:28:41 +04:00
/* Identify which VIC cell this one is, by reading the ID */
for ( i = 0 ; i < 4 ; i + + ) {
2011-09-23 12:13:49 +04:00
void __iomem * addr ;
addr = ( void __iomem * ) ( ( u32 ) base & PAGE_MASK ) + 0xfe0 + ( i * 4 ) ;
2009-07-02 18:28:41 +04:00
cellid | = ( readl ( addr ) & 0xff ) < < ( 8 * i ) ;
}
vendor = ( cellid > > 12 ) & 0xff ;
printk ( KERN_INFO " VIC @%p: id 0x%08x, vendor 0x%02x \n " ,
base , cellid , vendor ) ;
switch ( vendor ) {
2009-08-04 04:01:02 +04:00
case AMBA_VENDOR_ST :
2011-12-01 14:16:46 +04:00
vic_init_st ( base , irq_start , vic_sources , node ) ;
2009-07-02 18:28:41 +04:00
return ;
default :
printk ( KERN_WARNING " VIC: unknown vendor, continuing anyways \n " ) ;
/* fall through */
2009-08-04 04:01:02 +04:00
case AMBA_VENDOR_ARM :
2009-07-02 18:28:41 +04:00
break ;
}
2006-01-14 00:30:48 +03:00
/* Disable all interrupts initially. */
2010-04-02 21:04:47 +04:00
vic_disable ( base ) ;
2006-01-14 00:30:48 +03:00
2010-04-02 21:04:47 +04:00
/* Make sure we clear all existing interrupts */
vic_clear_interrupts ( base ) ;
2006-01-14 00:30:48 +03:00
2009-03-24 18:30:07 +03:00
vic_init2 ( base ) ;
2006-01-14 00:30:48 +03:00
2013-11-22 02:11:29 +04:00
vic_register ( base , parent_irq , irq_start , vic_sources , resume_sources , node ) ;
2011-09-27 14:00:46 +04:00
}
/**
* vic_init ( ) - initialise a vectored interrupt controller
* @ base : iomem base address
* @ irq_start : starting interrupt number , must be muliple of 32
* @ vic_sources : bitmask of interrupt sources to allow
* @ resume_sources : bitmask of interrupt sources to allow for resume
*/
void __init vic_init ( void __iomem * base , unsigned int irq_start ,
u32 vic_sources , u32 resume_sources )
{
2013-11-22 02:11:29 +04:00
__vic_init ( base , 0 , irq_start , vic_sources , resume_sources , NULL ) ;
}
/**
* vic_init_cascaded ( ) - initialise a cascaded vectored interrupt controller
* @ base : iomem base address
* @ parent_irq : the parent IRQ we ' re cascaded off
* @ irq_start : starting interrupt number , must be muliple of 32
* @ vic_sources : bitmask of interrupt sources to allow
* @ resume_sources : bitmask of interrupt sources to allow for resume
*
* This returns the base for the new interrupts or negative on error .
*/
int __init vic_init_cascaded ( void __iomem * base , unsigned int parent_irq ,
u32 vic_sources , u32 resume_sources )
{
struct vic_device * v ;
v = & vic_devices [ vic_id ] ;
__vic_init ( base , parent_irq , 0 , vic_sources , resume_sources , NULL ) ;
/* Return out acquired base */
return v - > irq ;
2011-09-27 14:00:46 +04:00
}
2014-02-25 01:19:24 +04:00
EXPORT_SYMBOL_GPL ( vic_init_cascaded ) ;
2011-09-27 14:00:46 +04:00
# ifdef CONFIG_OF
int __init vic_of_init ( struct device_node * node , struct device_node * parent )
{
void __iomem * regs ;
2013-08-25 21:37:24 +04:00
u32 interrupt_mask = ~ 0 ;
u32 wakeup_mask = ~ 0 ;
2011-09-27 14:00:46 +04:00
if ( WARN ( parent , " non-root VICs are not supported " ) )
return - EINVAL ;
regs = of_iomap ( node , 0 ) ;
if ( WARN_ON ( ! regs ) )
return - EIO ;
2013-08-25 21:37:24 +04:00
of_property_read_u32 ( node , " valid-mask " , & interrupt_mask ) ;
of_property_read_u32 ( node , " valid-wakeup-mask " , & wakeup_mask ) ;
2012-10-16 21:50:00 +04:00
/*
2012-12-26 04:39:16 +04:00
* Passing 0 as first IRQ makes the simple domain allocate descriptors
2012-10-16 21:50:00 +04:00
*/
2013-11-22 02:11:29 +04:00
__vic_init ( regs , 0 , 0 , interrupt_mask , wakeup_mask , node ) ;
2011-09-27 14:00:46 +04:00
return 0 ;
2006-01-14 00:30:48 +03:00
}
2012-10-28 02:25:26 +04:00
IRQCHIP_DECLARE ( arm_pl190_vic , " arm,pl190-vic " , vic_of_init ) ;
IRQCHIP_DECLARE ( arm_pl192_vic , " arm,pl192-vic " , vic_of_init ) ;
IRQCHIP_DECLARE ( arm_versatile_vic , " arm,versatile-vic " , vic_of_init ) ;
2011-09-27 14:00:46 +04:00
# endif /* CONFIG OF */