diff options
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-bcm7120-l2.c | 123 |
1 files changed, 68 insertions, 55 deletions
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index e8441ee7454c..6a6285897df1 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -34,7 +34,7 @@ #define IRQSTAT 0x04 #define MAX_WORDS 4 -#define MAX_MAPPINGS MAX_WORDS +#define MAX_MAPPINGS (MAX_WORDS * 2) #define IRQS_PER_WORD 32 struct bcm7120_l2_intc_data { @@ -47,6 +47,8 @@ struct bcm7120_l2_intc_data { bool can_wake; u32 irq_fwd_mask[MAX_WORDS]; u32 irq_map_mask[MAX_WORDS]; + int num_parent_irqs; + const __be32 *map_mask_prop; }; static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) @@ -104,7 +106,7 @@ static void bcm7120_l2_intc_resume(struct irq_data *d) static int bcm7120_l2_intc_init_one(struct device_node *dn, struct bcm7120_l2_intc_data *data, - int irq, const __be32 *map_mask) + int irq) { int parent_irq; unsigned int idx; @@ -120,7 +122,8 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, */ for (idx = 0; idx < data->n_words; idx++) data->irq_map_mask[idx] |= - be32_to_cpup(map_mask + irq * data->n_words + idx); + be32_to_cpup(data->map_mask_prop + + irq * data->n_words + idx); irq_set_handler_data(parent_irq, data); irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); @@ -128,74 +131,76 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, return 0; } -int __init bcm7120_l2_intc_of_init(struct device_node *dn, - struct device_node *parent) +static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, + struct bcm7120_l2_intc_data *data) +{ + int ret; + + data->map_base[0] = of_iomap(dn, 0); + if (!data->map_base[0]) { + pr_err("unable to map registers\n"); + return -ENOMEM; + } + + data->pair_base[0] = data->map_base[0]; + data->en_offset[0] = IRQEN; + data->stat_offset[0] = IRQSTAT; + data->n_words = 1; + + ret = of_property_read_u32_array(dn, "brcm,int-fwd-mask", + data->irq_fwd_mask, data->n_words); + if (ret != 0 && ret != -EINVAL) { + /* property exists but has the wrong number of words */ + pr_err("invalid brcm,int-fwd-mask property\n"); + return -EINVAL; + } + + data->map_mask_prop = of_get_property(dn, "brcm,int-map-mask", &ret); + if (!data->map_mask_prop || + (ret != (sizeof(__be32) * data->num_parent_irqs * data->n_words))) { + pr_err("invalid brcm,int-map-mask property\n"); + return -EINVAL; + } + + return 0; +} + +int __init bcm7120_l2_intc_probe(struct device_node *dn, + struct device_node *parent, + int (*iomap_regs_fn)(struct device_node *, + struct bcm7120_l2_intc_data *), + const char *intc_name) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; struct bcm7120_l2_intc_data *data; struct irq_chip_generic *gc; struct irq_chip_type *ct; - const __be32 *map_mask; - int num_parent_irqs; - int ret = 0, len; + int ret = 0; unsigned int idx, irq, flags; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - for (idx = 0; idx < MAX_WORDS; idx++) { - data->map_base[idx] = of_iomap(dn, idx); - if (!data->map_base[idx]) - break; - - data->pair_base[idx] = data->map_base[idx]; - data->en_offset[idx] = IRQEN; - data->stat_offset[idx] = IRQSTAT; - - data->n_words = idx + 1; - } - if (!data->n_words) { - pr_err("failed to remap intc L2 registers\n"); - ret = -ENOMEM; - goto out_unmap; - } - - /* Enable all interrupts specified in the interrupt forward mask; - * disable all others. If the property doesn't exist (-EINVAL), - * assume all zeroes. - */ - ret = of_property_read_u32_array(dn, "brcm,int-fwd-mask", - data->irq_fwd_mask, data->n_words); - if (ret == 0 || ret == -EINVAL) { - for (idx = 0; idx < data->n_words; idx++) - __raw_writel(data->irq_fwd_mask[idx], - data->pair_base[idx] + - data->en_offset[idx]); - } else { - /* property exists but has the wrong number of words */ - pr_err("invalid int-fwd-mask property\n"); - ret = -EINVAL; - goto out_unmap; - } - - num_parent_irqs = of_irq_count(dn); - if (num_parent_irqs <= 0) { + data->num_parent_irqs = of_irq_count(dn); + if (data->num_parent_irqs <= 0) { pr_err("invalid number of parent interrupts\n"); ret = -ENOMEM; goto out_unmap; } - map_mask = of_get_property(dn, "brcm,int-map-mask", &len); - if (!map_mask || - (len != (sizeof(*map_mask) * num_parent_irqs * data->n_words))) { - pr_err("invalid brcm,int-map-mask property\n"); - ret = -EINVAL; + ret = iomap_regs_fn(dn, data); + if (ret < 0) goto out_unmap; + + for (idx = 0; idx < data->n_words; idx++) { + __raw_writel(data->irq_fwd_mask[idx], + data->pair_base[idx] + + data->en_offset[idx]); } - for (irq = 0; irq < num_parent_irqs; irq++) { - ret = bcm7120_l2_intc_init_one(dn, data, irq, map_mask); + for (irq = 0; irq < data->num_parent_irqs; irq++) { + ret = bcm7120_l2_intc_init_one(dn, data, irq); if (ret) goto out_unmap; } @@ -251,8 +256,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn, } } - pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n", - data->map_base[0], num_parent_irqs); + pr_info("registered %s intc (mem: 0x%p, parent IRQ(s): %d)\n", + intc_name, data->map_base[0], data->num_parent_irqs); return 0; @@ -266,5 +271,13 @@ out_unmap: kfree(data); return ret; } + +int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, + struct device_node *parent) +{ + return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, + "BCM7120 L2"); +} + IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc", - bcm7120_l2_intc_of_init); + bcm7120_l2_intc_probe_7120); |