1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2015 - Ben Herrenschmidt, IBM Corp. |
4 | * |
5 | * Driver for Aspeed "new" VIC as found in SoC generation 3 and later |
6 | * |
7 | * Based on irq-vic.c: |
8 | * |
9 | * Copyright (C) 1999 - 2003 ARM Limited |
10 | * Copyright (C) 2000 Deep Blue Solutions Ltd |
11 | */ |
12 | |
13 | #include <linux/export.h> |
14 | #include <linux/init.h> |
15 | #include <linux/list.h> |
16 | #include <linux/io.h> |
17 | #include <linux/irq.h> |
18 | #include <linux/irqchip.h> |
19 | #include <linux/irqchip/chained_irq.h> |
20 | #include <linux/irqdomain.h> |
21 | #include <linux/of.h> |
22 | #include <linux/of_address.h> |
23 | #include <linux/of_irq.h> |
24 | #include <linux/syscore_ops.h> |
25 | #include <linux/device.h> |
26 | #include <linux/slab.h> |
27 | |
28 | #include <asm/exception.h> |
29 | #include <asm/irq.h> |
30 | |
31 | /* These definitions correspond to the "new mapping" of the |
32 | * register set that interleaves "high" and "low". The offsets |
33 | * below are for the "low" register, add 4 to get to the high one |
34 | */ |
35 | #define AVIC_IRQ_STATUS 0x00 |
36 | #define AVIC_FIQ_STATUS 0x08 |
37 | #define AVIC_RAW_STATUS 0x10 |
38 | #define AVIC_INT_SELECT 0x18 |
39 | #define AVIC_INT_ENABLE 0x20 |
40 | #define AVIC_INT_ENABLE_CLR 0x28 |
41 | #define AVIC_INT_TRIGGER 0x30 |
42 | #define AVIC_INT_TRIGGER_CLR 0x38 |
43 | #define AVIC_INT_SENSE 0x40 |
44 | #define AVIC_INT_DUAL_EDGE 0x48 |
45 | #define AVIC_INT_EVENT 0x50 |
46 | #define AVIC_EDGE_CLR 0x58 |
47 | #define AVIC_EDGE_STATUS 0x60 |
48 | |
49 | #define NUM_IRQS 64 |
50 | |
51 | struct aspeed_vic { |
52 | void __iomem *base; |
53 | u32 edge_sources[2]; |
54 | struct irq_domain *dom; |
55 | }; |
56 | static struct aspeed_vic *system_avic; |
57 | |
58 | static void vic_init_hw(struct aspeed_vic *vic) |
59 | { |
60 | u32 sense; |
61 | |
62 | /* Disable all interrupts */ |
63 | writel(val: 0xffffffff, addr: vic->base + AVIC_INT_ENABLE_CLR); |
64 | writel(val: 0xffffffff, addr: vic->base + AVIC_INT_ENABLE_CLR + 4); |
65 | |
66 | /* Make sure no soft trigger is on */ |
67 | writel(val: 0xffffffff, addr: vic->base + AVIC_INT_TRIGGER_CLR); |
68 | writel(val: 0xffffffff, addr: vic->base + AVIC_INT_TRIGGER_CLR + 4); |
69 | |
70 | /* Set everything to be IRQ */ |
71 | writel(val: 0, addr: vic->base + AVIC_INT_SELECT); |
72 | writel(val: 0, addr: vic->base + AVIC_INT_SELECT + 4); |
73 | |
74 | /* Some interrupts have a programmable high/low level trigger |
75 | * (4 GPIO direct inputs), for now we assume this was configured |
76 | * by firmware. We read which ones are edge now. |
77 | */ |
78 | sense = readl(addr: vic->base + AVIC_INT_SENSE); |
79 | vic->edge_sources[0] = ~sense; |
80 | sense = readl(addr: vic->base + AVIC_INT_SENSE + 4); |
81 | vic->edge_sources[1] = ~sense; |
82 | |
83 | /* Clear edge detection latches */ |
84 | writel(val: 0xffffffff, addr: vic->base + AVIC_EDGE_CLR); |
85 | writel(val: 0xffffffff, addr: vic->base + AVIC_EDGE_CLR + 4); |
86 | } |
87 | |
88 | static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs) |
89 | { |
90 | struct aspeed_vic *vic = system_avic; |
91 | u32 stat, irq; |
92 | |
93 | for (;;) { |
94 | irq = 0; |
95 | stat = readl_relaxed(vic->base + AVIC_IRQ_STATUS); |
96 | if (!stat) { |
97 | stat = readl_relaxed(vic->base + AVIC_IRQ_STATUS + 4); |
98 | irq = 32; |
99 | } |
100 | if (stat == 0) |
101 | break; |
102 | irq += ffs(stat) - 1; |
103 | generic_handle_domain_irq(vic->dom, irq); |
104 | } |
105 | } |
106 | |
107 | static void avic_ack_irq(struct irq_data *d) |
108 | { |
109 | struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); |
110 | unsigned int sidx = d->hwirq >> 5; |
111 | unsigned int sbit = 1u << (d->hwirq & 0x1f); |
112 | |
113 | /* Clear edge latch for edge interrupts, nop for level */ |
114 | if (vic->edge_sources[sidx] & sbit) |
115 | writel(val: sbit, addr: vic->base + AVIC_EDGE_CLR + sidx * 4); |
116 | } |
117 | |
118 | static void avic_mask_irq(struct irq_data *d) |
119 | { |
120 | struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); |
121 | unsigned int sidx = d->hwirq >> 5; |
122 | unsigned int sbit = 1u << (d->hwirq & 0x1f); |
123 | |
124 | writel(val: sbit, addr: vic->base + AVIC_INT_ENABLE_CLR + sidx * 4); |
125 | } |
126 | |
127 | static void avic_unmask_irq(struct irq_data *d) |
128 | { |
129 | struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); |
130 | unsigned int sidx = d->hwirq >> 5; |
131 | unsigned int sbit = 1u << (d->hwirq & 0x1f); |
132 | |
133 | writel(val: sbit, addr: vic->base + AVIC_INT_ENABLE + sidx * 4); |
134 | } |
135 | |
136 | /* For level irq, faster than going through a nop "ack" and mask */ |
137 | static void avic_mask_ack_irq(struct irq_data *d) |
138 | { |
139 | struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); |
140 | unsigned int sidx = d->hwirq >> 5; |
141 | unsigned int sbit = 1u << (d->hwirq & 0x1f); |
142 | |
143 | /* First mask */ |
144 | writel(val: sbit, addr: vic->base + AVIC_INT_ENABLE_CLR + sidx * 4); |
145 | |
146 | /* Then clear edge latch for edge interrupts */ |
147 | if (vic->edge_sources[sidx] & sbit) |
148 | writel(val: sbit, addr: vic->base + AVIC_EDGE_CLR + sidx * 4); |
149 | } |
150 | |
151 | static struct irq_chip avic_chip = { |
152 | .name = "AVIC" , |
153 | .irq_ack = avic_ack_irq, |
154 | .irq_mask = avic_mask_irq, |
155 | .irq_unmask = avic_unmask_irq, |
156 | .irq_mask_ack = avic_mask_ack_irq, |
157 | }; |
158 | |
159 | static int avic_map(struct irq_domain *d, unsigned int irq, |
160 | irq_hw_number_t hwirq) |
161 | { |
162 | struct aspeed_vic *vic = d->host_data; |
163 | unsigned int sidx = hwirq >> 5; |
164 | unsigned int sbit = 1u << (hwirq & 0x1f); |
165 | |
166 | /* Check if interrupt exists */ |
167 | if (sidx > 1) |
168 | return -EPERM; |
169 | |
170 | if (vic->edge_sources[sidx] & sbit) |
171 | irq_set_chip_and_handler(irq, chip: &avic_chip, handle: handle_edge_irq); |
172 | else |
173 | irq_set_chip_and_handler(irq, chip: &avic_chip, handle: handle_level_irq); |
174 | irq_set_chip_data(irq, data: vic); |
175 | irq_set_probe(irq); |
176 | return 0; |
177 | } |
178 | |
179 | static const struct irq_domain_ops avic_dom_ops = { |
180 | .map = avic_map, |
181 | .xlate = irq_domain_xlate_onetwocell, |
182 | }; |
183 | |
184 | static int __init avic_of_init(struct device_node *node, |
185 | struct device_node *parent) |
186 | { |
187 | void __iomem *regs; |
188 | struct aspeed_vic *vic; |
189 | |
190 | if (WARN(parent, "non-root Aspeed VIC not supported" )) |
191 | return -EINVAL; |
192 | if (WARN(system_avic, "duplicate Aspeed VIC not supported" )) |
193 | return -EINVAL; |
194 | |
195 | regs = of_iomap(node, index: 0); |
196 | if (WARN_ON(!regs)) |
197 | return -EIO; |
198 | |
199 | vic = kzalloc(size: sizeof(struct aspeed_vic), GFP_KERNEL); |
200 | if (WARN_ON(!vic)) { |
201 | iounmap(addr: regs); |
202 | return -ENOMEM; |
203 | } |
204 | vic->base = regs; |
205 | |
206 | /* Initialize sources, all masked */ |
207 | vic_init_hw(vic); |
208 | |
209 | /* Ready to receive interrupts */ |
210 | system_avic = vic; |
211 | set_handle_irq(avic_handle_irq); |
212 | |
213 | /* Register our domain */ |
214 | vic->dom = irq_domain_add_simple(of_node: node, NUM_IRQS, first_irq: 0, |
215 | ops: &avic_dom_ops, host_data: vic); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | IRQCHIP_DECLARE(ast2400_vic, "aspeed,ast2400-vic" , avic_of_init); |
221 | IRQCHIP_DECLARE(ast2500_vic, "aspeed,ast2500-vic" , avic_of_init); |
222 | |