.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> |
---|
3 | | - * JZ4740 platform IRQ support |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify it |
---|
6 | | - * under the terms of the GNU General Public License as published by the |
---|
7 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
8 | | - * option) any later version. |
---|
9 | | - * |
---|
10 | | - * You should have received a copy of the GNU General Public License along |
---|
11 | | - * with this program; if not, write to the Free Software Foundation, Inc., |
---|
12 | | - * 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
13 | | - * |
---|
| 4 | + * Ingenic XBurst platform IRQ support |
---|
14 | 5 | */ |
---|
15 | 6 | |
---|
16 | 7 | #include <linux/errno.h> |
---|
.. | .. |
---|
19 | 10 | #include <linux/interrupt.h> |
---|
20 | 11 | #include <linux/ioport.h> |
---|
21 | 12 | #include <linux/irqchip.h> |
---|
22 | | -#include <linux/irqchip/ingenic.h> |
---|
23 | 13 | #include <linux/of_address.h> |
---|
24 | 14 | #include <linux/of_irq.h> |
---|
25 | 15 | #include <linux/timex.h> |
---|
.. | .. |
---|
27 | 17 | #include <linux/delay.h> |
---|
28 | 18 | |
---|
29 | 19 | #include <asm/io.h> |
---|
30 | | -#include <asm/mach-jz4740/irq.h> |
---|
31 | 20 | |
---|
32 | 21 | struct ingenic_intc_data { |
---|
33 | 22 | void __iomem *base; |
---|
| 23 | + struct irq_domain *domain; |
---|
34 | 24 | unsigned num_chips; |
---|
35 | 25 | }; |
---|
36 | 26 | |
---|
.. | .. |
---|
44 | 34 | static irqreturn_t intc_cascade(int irq, void *data) |
---|
45 | 35 | { |
---|
46 | 36 | struct ingenic_intc_data *intc = irq_get_handler_data(irq); |
---|
47 | | - uint32_t irq_reg; |
---|
| 37 | + struct irq_domain *domain = intc->domain; |
---|
| 38 | + struct irq_chip_generic *gc; |
---|
| 39 | + uint32_t pending; |
---|
48 | 40 | unsigned i; |
---|
49 | 41 | |
---|
50 | 42 | for (i = 0; i < intc->num_chips; i++) { |
---|
51 | | - irq_reg = readl(intc->base + (i * CHIP_SIZE) + |
---|
52 | | - JZ_REG_INTC_PENDING); |
---|
53 | | - if (!irq_reg) |
---|
| 43 | + gc = irq_get_domain_generic_chip(domain, i * 32); |
---|
| 44 | + |
---|
| 45 | + pending = irq_reg_readl(gc, JZ_REG_INTC_PENDING); |
---|
| 46 | + if (!pending) |
---|
54 | 47 | continue; |
---|
55 | 48 | |
---|
56 | | - generic_handle_irq(__fls(irq_reg) + (i * 32) + JZ4740_IRQ_BASE); |
---|
| 49 | + while (pending) { |
---|
| 50 | + int bit = __fls(pending); |
---|
| 51 | + |
---|
| 52 | + irq = irq_linear_revmap(domain, bit + (i * 32)); |
---|
| 53 | + generic_handle_irq(irq); |
---|
| 54 | + pending &= ~BIT(bit); |
---|
| 55 | + } |
---|
57 | 56 | } |
---|
58 | 57 | |
---|
59 | 58 | return IRQ_HANDLED; |
---|
60 | 59 | } |
---|
61 | | - |
---|
62 | | -static void intc_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask) |
---|
63 | | -{ |
---|
64 | | - struct irq_chip_regs *regs = &gc->chip_types->regs; |
---|
65 | | - |
---|
66 | | - writel(mask, gc->reg_base + regs->enable); |
---|
67 | | - writel(~mask, gc->reg_base + regs->disable); |
---|
68 | | -} |
---|
69 | | - |
---|
70 | | -void ingenic_intc_irq_suspend(struct irq_data *data) |
---|
71 | | -{ |
---|
72 | | - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); |
---|
73 | | - intc_irq_set_mask(gc, gc->wake_active); |
---|
74 | | -} |
---|
75 | | - |
---|
76 | | -void ingenic_intc_irq_resume(struct irq_data *data) |
---|
77 | | -{ |
---|
78 | | - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); |
---|
79 | | - intc_irq_set_mask(gc, gc->mask_cache); |
---|
80 | | -} |
---|
81 | | - |
---|
82 | | -static struct irqaction intc_cascade_action = { |
---|
83 | | - .handler = intc_cascade, |
---|
84 | | - .name = "SoC intc cascade interrupt", |
---|
85 | | -}; |
---|
86 | 60 | |
---|
87 | 61 | static int __init ingenic_intc_of_init(struct device_node *node, |
---|
88 | 62 | unsigned num_chips) |
---|
.. | .. |
---|
117 | 91 | goto out_unmap_irq; |
---|
118 | 92 | } |
---|
119 | 93 | |
---|
120 | | - domain = irq_domain_add_legacy(node, num_chips * 32, |
---|
121 | | - JZ4740_IRQ_BASE, 0, |
---|
122 | | - &irq_domain_simple_ops, NULL); |
---|
| 94 | + domain = irq_domain_add_linear(node, num_chips * 32, |
---|
| 95 | + &irq_generic_chip_ops, NULL); |
---|
123 | 96 | if (!domain) { |
---|
124 | 97 | err = -ENOMEM; |
---|
125 | 98 | goto out_unmap_base; |
---|
126 | 99 | } |
---|
127 | 100 | |
---|
128 | | - for (i = 0; i < num_chips; i++) { |
---|
129 | | - /* Mask all irqs */ |
---|
130 | | - writel(0xffffffff, intc->base + (i * CHIP_SIZE) + |
---|
131 | | - JZ_REG_INTC_SET_MASK); |
---|
| 101 | + intc->domain = domain; |
---|
132 | 102 | |
---|
133 | | - gc = irq_alloc_generic_chip("INTC", 1, |
---|
134 | | - JZ4740_IRQ_BASE + (i * 32), |
---|
135 | | - intc->base + (i * CHIP_SIZE), |
---|
136 | | - handle_level_irq); |
---|
| 103 | + err = irq_alloc_domain_generic_chips(domain, 32, 1, "INTC", |
---|
| 104 | + handle_level_irq, 0, |
---|
| 105 | + IRQ_NOPROBE | IRQ_LEVEL, 0); |
---|
| 106 | + if (err) |
---|
| 107 | + goto out_domain_remove; |
---|
| 108 | + |
---|
| 109 | + for (i = 0; i < num_chips; i++) { |
---|
| 110 | + gc = irq_get_domain_generic_chip(domain, i * 32); |
---|
137 | 111 | |
---|
138 | 112 | gc->wake_enabled = IRQ_MSK(32); |
---|
| 113 | + gc->reg_base = intc->base + (i * CHIP_SIZE); |
---|
139 | 114 | |
---|
140 | 115 | ct = gc->chip_types; |
---|
141 | 116 | ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; |
---|
.. | .. |
---|
144 | 119 | ct->chip.irq_mask = irq_gc_mask_disable_reg; |
---|
145 | 120 | ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; |
---|
146 | 121 | ct->chip.irq_set_wake = irq_gc_set_wake; |
---|
147 | | - ct->chip.irq_suspend = ingenic_intc_irq_suspend; |
---|
148 | | - ct->chip.irq_resume = ingenic_intc_irq_resume; |
---|
| 122 | + ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND; |
---|
149 | 123 | |
---|
150 | | - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, |
---|
151 | | - IRQ_NOPROBE | IRQ_LEVEL); |
---|
| 124 | + /* Mask all irqs */ |
---|
| 125 | + irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK); |
---|
152 | 126 | } |
---|
153 | 127 | |
---|
154 | | - setup_irq(parent_irq, &intc_cascade_action); |
---|
| 128 | + if (request_irq(parent_irq, intc_cascade, IRQF_NO_SUSPEND, |
---|
| 129 | + "SoC intc cascade interrupt", NULL)) |
---|
| 130 | + pr_err("Failed to register SoC intc cascade interrupt\n"); |
---|
155 | 131 | return 0; |
---|
156 | 132 | |
---|
| 133 | +out_domain_remove: |
---|
| 134 | + irq_domain_remove(domain); |
---|
157 | 135 | out_unmap_base: |
---|
158 | 136 | iounmap(intc->base); |
---|
159 | 137 | out_unmap_irq: |
---|
.. | .. |
---|
177 | 155 | { |
---|
178 | 156 | return ingenic_intc_of_init(node, 2); |
---|
179 | 157 | } |
---|
| 158 | +IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc", intc_2chip_of_init); |
---|
180 | 159 | IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init); |
---|
181 | 160 | IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init); |
---|
182 | 161 | IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init); |
---|