WIP FPC-III support
[linux/fpc-iii.git] / drivers / irqchip / irq-litex-vexriscv.c
bloba4fe688dd81986c8ba2ddc25bbbf6de389063c0f
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * VexRiscv interrupt controller driver
5 * Copyright (C) 2019 Antmicro Ltd. <www.antmicro.com>
6 */
8 #include <linux/irq.h>
9 #include <linux/irqchip.h>
10 #include <linux/irqdesc.h>
11 #include <linux/of.h>
12 #include <linux/of_irq.h>
13 #include <linux/of_address.h>
15 #define IRQ_MASK CONFIG_LITEX_VEXRISCV_CSR_MASK
16 #define IRQ_PENDING CONFIG_LITEX_VEXRISCV_CSR_PENDING
17 #define IRQ_VEC_SZ 32
19 static struct irq_domain *root_domain;
21 struct litex_vexriscv_intc {
22 struct irq_chip chip;
23 irq_flow_handler_t handle;
24 unsigned long flags;
27 static unsigned int litex_vexriscv_irq_getie(void)
29 return (csr_read(sstatus) & IE_SIE) != 0;
32 static void litex_vexriscv_irq_setie(unsigned int ie)
34 if (ie)
35 csr_write(sstatus, IE_SIE);
36 else
37 csr_clear(sstatus, IE_SIE);
40 static unsigned int litex_vexriscv_irq_getmask(void)
42 u32 mask;
44 __asm__ __volatile__ ("csrr %0, %1" : "=r"(mask) : "i"(IRQ_MASK));
45 return mask;
48 static void litex_vexriscv_irq_setmask(unsigned int mask)
50 __asm__ volatile ("csrw %0, %1" :: "i"(IRQ_MASK), "r"(mask));
53 static unsigned int litex_vexriscv_irq_pending(void)
55 u32 pending;
57 __asm__ __volatile__ ("csrr %0, %1" : "=r"(pending) : "i"(IRQ_PENDING));
58 return pending;
61 static int litex_vexriscv_intc_map(struct irq_domain *d, unsigned int irq,
62 irq_hw_number_t hw)
64 struct litex_vexriscv_intc *intc = d->host_data;
66 pr_debug("irqchip: LiteX Vexriscv irqmap: %d\n", irq);
67 irq_set_chip_and_handler(irq, &intc->chip, intc->handle);
68 irq_set_status_flags(irq, intc->flags);
70 pr_debug("irqchip: mapcount: %d\n", d->mapcount);
72 return 0;
75 static void litex_vexriscv_intc_mask(struct irq_data *data)
77 unsigned int mask = litex_vexriscv_irq_getmask();
78 unsigned int irqbit = BIT(data->hwirq);
80 pr_debug("irqchip: LiteX VexRiscv irqchip mask: 0x%08x -> 0x%08x",
81 mask, mask & ~irqbit);
82 mask &= ~irqbit;
83 litex_vexriscv_irq_setmask(mask);
85 if (!mask)
86 litex_vexriscv_irq_setie(0);
89 static void litex_vexriscv_intc_unmask(struct irq_data *data)
91 unsigned int mask = litex_vexriscv_irq_getmask();
92 unsigned int irqbit = BIT(data->hwirq);
94 pr_debug("irqchip: LiteX VexRiscv irqchip mask: 0x%08x -> 0x%08x",
95 mask, mask | irqbit);
96 mask |= irqbit;
97 litex_vexriscv_irq_setmask(mask);
99 if (!litex_vexriscv_irq_getie())
100 litex_vexriscv_irq_setie(1);
103 static void litex_vexriscv_intc_ack(struct irq_data *data)
105 /* no need to ack IRQs */
108 static void litex_vexriscv_intc_handle_irq(struct pt_regs *regs)
110 unsigned int irq;
111 int i;
113 irq = litex_vexriscv_irq_pending() & litex_vexriscv_irq_getmask();
114 pr_debug("irqchip: Litex Vexriscv irqchip mask: 0x%08x pending: 0x%08x",
115 litex_vexriscv_irq_getmask(),
116 litex_vexriscv_irq_pending());
118 for (i = 0; i < IRQ_VEC_SZ; i++) {
119 pr_debug("irqchip: i %d, irq 0x%08x, trying 0x%08lx\n", i, irq, BIT(i));
121 if (irq & BIT(i)) {
122 pr_debug("irqchip: handling at i = %d\n", i);
123 handle_domain_irq(root_domain, i, regs);
128 static const struct irq_domain_ops litex_vexriscv_domain_ops = {
129 .xlate = irq_domain_xlate_onecell,
130 .map = litex_vexriscv_intc_map,
133 static struct litex_vexriscv_intc litex_vexriscv_intc0 = {
134 .handle = handle_edge_irq,
135 .flags = IRQ_TYPE_DEFAULT | IRQ_TYPE_PROBE,
136 .chip = {
137 .name = "litex-vexriscv-intc0",
138 .irq_mask = litex_vexriscv_intc_mask,
139 .irq_unmask = litex_vexriscv_intc_unmask,
140 .irq_ack = litex_vexriscv_intc_ack,
144 static int __init litex_vexriscv_intc_init(struct device_node *node, struct device_node *parent)
146 /* clear interrupts for init */
147 litex_vexriscv_irq_setie(0);
148 litex_vexriscv_irq_setmask(0);
150 root_domain = irq_domain_add_linear(node, IRQ_VEC_SZ,
151 &litex_vexriscv_domain_ops,
152 &litex_vexriscv_intc0);
153 irq_set_default_host(root_domain);
154 set_handle_irq(litex_vexriscv_intc_handle_irq);
156 /* print device info */
157 pr_info("irqchip: LiteX VexRiscv irqchip driver initialized. "
158 "IE: %d, mask: 0x%08x, pending: 0x%08x\n",
159 litex_vexriscv_irq_getie(),
160 litex_vexriscv_irq_getmask(),
161 litex_vexriscv_irq_pending());
162 pr_info("irqchip: LiteX VexRiscv irqchip settings: "
163 "mask CSR 0x%03x, pending CSR 0x%03x\n", IRQ_MASK,
164 IRQ_PENDING);
166 return 0;
169 IRQCHIP_DECLARE(litex_vexriscv_intc0, "vexriscv,intc0", litex_vexriscv_intc_init);