irqchip/loongson-liointc: Fix build error for LoongArch
[platform/kernel/linux-starfive.git] / drivers / irqchip / irq-loongson-liointc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
4  *  Loongson Local IO Interrupt Controller support
5  */
6
7 #include <linux/errno.h>
8 #include <linux/init.h>
9 #include <linux/types.h>
10 #include <linux/interrupt.h>
11 #include <linux/ioport.h>
12 #include <linux/irqchip.h>
13 #include <linux/of_address.h>
14 #include <linux/of_irq.h>
15 #include <linux/io.h>
16 #include <linux/smp.h>
17 #include <linux/irqchip/chained_irq.h>
18
19 #ifdef CONFIG_MIPS
20 #include <loongson.h>
21 #else
22 #include <asm/loongson.h>
23 #endif
24
25 #define LIOINTC_CHIP_IRQ        32
26 #define LIOINTC_NUM_PARENT 4
27 #define LIOINTC_NUM_CORES       4
28
29 #define LIOINTC_INTC_CHIP_START 0x20
30
31 #define LIOINTC_REG_INTC_STATUS (LIOINTC_INTC_CHIP_START + 0x20)
32 #define LIOINTC_REG_INTC_EN_STATUS      (LIOINTC_INTC_CHIP_START + 0x04)
33 #define LIOINTC_REG_INTC_ENABLE (LIOINTC_INTC_CHIP_START + 0x08)
34 #define LIOINTC_REG_INTC_DISABLE        (LIOINTC_INTC_CHIP_START + 0x0c)
35 #define LIOINTC_REG_INTC_POL    (LIOINTC_INTC_CHIP_START + 0x10)
36 #define LIOINTC_REG_INTC_EDGE   (LIOINTC_INTC_CHIP_START + 0x14)
37
38 #define LIOINTC_SHIFT_INTx      4
39
40 #define LIOINTC_ERRATA_IRQ      10
41
42 struct liointc_handler_data {
43         struct liointc_priv     *priv;
44         u32                     parent_int_map;
45 };
46
47 struct liointc_priv {
48         struct irq_chip_generic         *gc;
49         struct liointc_handler_data     handler[LIOINTC_NUM_PARENT];
50         void __iomem                    *core_isr[LIOINTC_NUM_CORES];
51         u8                              map_cache[LIOINTC_CHIP_IRQ];
52         bool                            has_lpc_irq_errata;
53 };
54
55 static void liointc_chained_handle_irq(struct irq_desc *desc)
56 {
57         struct liointc_handler_data *handler = irq_desc_get_handler_data(desc);
58         struct irq_chip *chip = irq_desc_get_chip(desc);
59         struct irq_chip_generic *gc = handler->priv->gc;
60         int core = cpu_logical_map(smp_processor_id()) % LIOINTC_NUM_CORES;
61         u32 pending;
62
63         chained_irq_enter(chip, desc);
64
65         pending = readl(handler->priv->core_isr[core]);
66
67         if (!pending) {
68                 /* Always blame LPC IRQ if we have that bug */
69                 if (handler->priv->has_lpc_irq_errata &&
70                         (handler->parent_int_map & gc->mask_cache &
71                         BIT(LIOINTC_ERRATA_IRQ)))
72                         pending = BIT(LIOINTC_ERRATA_IRQ);
73                 else
74                         spurious_interrupt();
75         }
76
77         while (pending) {
78                 int bit = __ffs(pending);
79
80                 generic_handle_domain_irq(gc->domain, bit);
81                 pending &= ~BIT(bit);
82         }
83
84         chained_irq_exit(chip, desc);
85 }
86
87 static void liointc_set_bit(struct irq_chip_generic *gc,
88                                 unsigned int offset,
89                                 u32 mask, bool set)
90 {
91         if (set)
92                 writel(readl(gc->reg_base + offset) | mask,
93                                 gc->reg_base + offset);
94         else
95                 writel(readl(gc->reg_base + offset) & ~mask,
96                                 gc->reg_base + offset);
97 }
98
99 static int liointc_set_type(struct irq_data *data, unsigned int type)
100 {
101         struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
102         u32 mask = data->mask;
103         unsigned long flags;
104
105         irq_gc_lock_irqsave(gc, flags);
106         switch (type) {
107         case IRQ_TYPE_LEVEL_HIGH:
108                 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
109                 liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
110                 break;
111         case IRQ_TYPE_LEVEL_LOW:
112                 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
113                 liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
114                 break;
115         case IRQ_TYPE_EDGE_RISING:
116                 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true);
117                 liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
118                 break;
119         case IRQ_TYPE_EDGE_FALLING:
120                 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true);
121                 liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
122                 break;
123         default:
124                 irq_gc_unlock_irqrestore(gc, flags);
125                 return -EINVAL;
126         }
127         irq_gc_unlock_irqrestore(gc, flags);
128
129         irqd_set_trigger_type(data, type);
130         return 0;
131 }
132
133 static void liointc_resume(struct irq_chip_generic *gc)
134 {
135         struct liointc_priv *priv = gc->private;
136         unsigned long flags;
137         int i;
138
139         irq_gc_lock_irqsave(gc, flags);
140         /* Disable all at first */
141         writel(0xffffffff, gc->reg_base + LIOINTC_REG_INTC_DISABLE);
142         /* Restore map cache */
143         for (i = 0; i < LIOINTC_CHIP_IRQ; i++)
144                 writeb(priv->map_cache[i], gc->reg_base + i);
145         /* Restore mask cache */
146         writel(gc->mask_cache, gc->reg_base + LIOINTC_REG_INTC_ENABLE);
147         irq_gc_unlock_irqrestore(gc, flags);
148 }
149
150 static const char * const parent_names[] = {"int0", "int1", "int2", "int3"};
151 static const char * const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"};
152
153 static void __iomem *liointc_get_reg_byname(struct device_node *node,
154                                                 const char *name)
155 {
156         int index = of_property_match_string(node, "reg-names", name);
157
158         if (index < 0)
159                 return NULL;
160
161         return of_iomap(node, index);
162 }
163
164 static int __init liointc_of_init(struct device_node *node,
165                                   struct device_node *parent)
166 {
167         struct irq_chip_generic *gc;
168         struct irq_domain *domain;
169         struct irq_chip_type *ct;
170         struct liointc_priv *priv;
171         void __iomem *base;
172         u32 of_parent_int_map[LIOINTC_NUM_PARENT];
173         int parent_irq[LIOINTC_NUM_PARENT];
174         bool have_parent = FALSE;
175         int sz, i, err = 0;
176
177         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
178         if (!priv)
179                 return -ENOMEM;
180
181         if (of_device_is_compatible(node, "loongson,liointc-2.0")) {
182                 base = liointc_get_reg_byname(node, "main");
183                 if (!base) {
184                         err = -ENODEV;
185                         goto out_free_priv;
186                 }
187
188                 for (i = 0; i < LIOINTC_NUM_CORES; i++)
189                         priv->core_isr[i] = liointc_get_reg_byname(node, core_reg_names[i]);
190                 if (!priv->core_isr[0]) {
191                         err = -ENODEV;
192                         goto out_iounmap_base;
193                 }
194         } else {
195                 base = of_iomap(node, 0);
196                 if (!base) {
197                         err = -ENODEV;
198                         goto out_free_priv;
199                 }
200
201                 for (i = 0; i < LIOINTC_NUM_CORES; i++)
202                         priv->core_isr[i] = base + LIOINTC_REG_INTC_STATUS;
203         }
204
205         for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
206                 parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
207                 if (parent_irq[i] > 0)
208                         have_parent = TRUE;
209         }
210         if (!have_parent) {
211                 err = -ENODEV;
212                 goto out_iounmap_isr;
213         }
214
215         sz = of_property_read_variable_u32_array(node,
216                                                 "loongson,parent_int_map",
217                                                 &of_parent_int_map[0],
218                                                 LIOINTC_NUM_PARENT,
219                                                 LIOINTC_NUM_PARENT);
220         if (sz < 4) {
221                 pr_err("loongson-liointc: No parent_int_map\n");
222                 err = -ENODEV;
223                 goto out_iounmap_isr;
224         }
225
226         for (i = 0; i < LIOINTC_NUM_PARENT; i++)
227                 priv->handler[i].parent_int_map = of_parent_int_map[i];
228
229         /* Setup IRQ domain */
230         domain = irq_domain_add_linear(node, 32,
231                                         &irq_generic_chip_ops, priv);
232         if (!domain) {
233                 pr_err("loongson-liointc: cannot add IRQ domain\n");
234                 err = -EINVAL;
235                 goto out_iounmap_isr;
236         }
237
238         err = irq_alloc_domain_generic_chips(domain, 32, 1,
239                                         node->full_name, handle_level_irq,
240                                         IRQ_NOPROBE, 0, 0);
241         if (err) {
242                 pr_err("loongson-liointc: unable to register IRQ domain\n");
243                 goto out_free_domain;
244         }
245
246
247         /* Disable all IRQs */
248         writel(0xffffffff, base + LIOINTC_REG_INTC_DISABLE);
249         /* Set to level triggered */
250         writel(0x0, base + LIOINTC_REG_INTC_EDGE);
251
252         /* Generate parent INT part of map cache */
253         for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
254                 u32 pending = priv->handler[i].parent_int_map;
255
256                 while (pending) {
257                         int bit = __ffs(pending);
258
259                         priv->map_cache[bit] = BIT(i) << LIOINTC_SHIFT_INTx;
260                         pending &= ~BIT(bit);
261                 }
262         }
263
264         for (i = 0; i < LIOINTC_CHIP_IRQ; i++) {
265                 /* Generate core part of map cache */
266                 priv->map_cache[i] |= BIT(loongson_sysconf.boot_cpu_id);
267                 writeb(priv->map_cache[i], base + i);
268         }
269
270         gc = irq_get_domain_generic_chip(domain, 0);
271         gc->private = priv;
272         gc->reg_base = base;
273         gc->domain = domain;
274         gc->resume = liointc_resume;
275
276         ct = gc->chip_types;
277         ct->regs.enable = LIOINTC_REG_INTC_ENABLE;
278         ct->regs.disable = LIOINTC_REG_INTC_DISABLE;
279         ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
280         ct->chip.irq_mask = irq_gc_mask_disable_reg;
281         ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
282         ct->chip.irq_set_type = liointc_set_type;
283
284         gc->mask_cache = 0;
285         priv->gc = gc;
286
287         for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
288                 if (parent_irq[i] <= 0)
289                         continue;
290
291                 priv->handler[i].priv = priv;
292                 irq_set_chained_handler_and_data(parent_irq[i],
293                                 liointc_chained_handle_irq, &priv->handler[i]);
294         }
295
296         return 0;
297
298 out_free_domain:
299         irq_domain_remove(domain);
300 out_iounmap_isr:
301         for (i = 0; i < LIOINTC_NUM_CORES; i++) {
302                 if (!priv->core_isr[i])
303                         continue;
304                 iounmap(priv->core_isr[i]);
305         }
306 out_iounmap_base:
307         iounmap(base);
308 out_free_priv:
309         kfree(priv);
310
311         return err;
312 }
313
314 IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init);
315 IRQCHIP_DECLARE(loongson_liointc_1_0a, "loongson,liointc-1.0a", liointc_of_init);
316 IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);