1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2017 SiFive
4 * Copyright (C) 2018 Christoph Hellwig
6 #define pr_fmt(fmt) "plic: " fmt
7 #include <linux/interrupt.h>
10 #include <linux/irqchip.h>
11 #include <linux/irqdomain.h>
12 #include <linux/module.h>
14 #include <linux/of_address.h>
15 #include <linux/of_irq.h>
16 #include <linux/platform_device.h>
17 #include <linux/spinlock.h>
20 * This driver implements a version of the RISC-V PLIC with the actual layout
21 * specified in chapter 8 of the SiFive U5 Coreplex Series Manual:
23 * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf
25 * The largest number supported by devices marked as 'sifive,plic-1.0.0', is
26 * 1024, of which device 0 is defined as non-existent by the RISC-V Privileged
30 #define MAX_DEVICES 1024
31 #define MAX_CONTEXTS 15872
34 * Each interrupt source has a priority register associated with it.
35 * We always hardwire it to one in Linux.
37 #define PRIORITY_BASE 0
38 #define PRIORITY_PER_ID 4
41 * Each hart context has a vector of interrupt enable bits associated with it.
42 * There's one bit for each interrupt source.
44 #define ENABLE_BASE 0x2000
45 #define ENABLE_PER_HART 0x80
48 * Each hart context has a set of control registers associated with it. Right
49 * now there's only two: a source priority threshold over which the hart will
50 * take an interrupt, and a register to claim interrupts.
52 #define CONTEXT_BASE 0x200000
53 #define CONTEXT_PER_HART 0x1000
54 #define CONTEXT_THRESHOLD 0x00
55 #define CONTEXT_CLAIM 0x04
57 static void __iomem
*plic_regs
;
63 static DEFINE_PER_CPU(struct plic_handler
, plic_handlers
);
65 static inline void __iomem
*plic_hart_offset(int ctxid
)
67 return plic_regs
+ CONTEXT_BASE
+ ctxid
* CONTEXT_PER_HART
;
70 static inline u32 __iomem
*plic_enable_base(int ctxid
)
72 return plic_regs
+ ENABLE_BASE
+ ctxid
* ENABLE_PER_HART
;
76 * Protect mask operations on the registers given that we can't assume that
77 * atomic memory operations work on them.
79 static DEFINE_RAW_SPINLOCK(plic_toggle_lock
);
81 static inline void plic_toggle(int ctxid
, int hwirq
, int enable
)
83 u32 __iomem
*reg
= plic_enable_base(ctxid
) + (hwirq
/ 32);
84 u32 hwirq_mask
= 1 << (hwirq
% 32);
86 raw_spin_lock(&plic_toggle_lock
);
88 writel(readl(reg
) | hwirq_mask
, reg
);
90 writel(readl(reg
) & ~hwirq_mask
, reg
);
91 raw_spin_unlock(&plic_toggle_lock
);
94 static inline void plic_irq_toggle(struct irq_data
*d
, int enable
)
98 writel(enable
, plic_regs
+ PRIORITY_BASE
+ d
->hwirq
* PRIORITY_PER_ID
);
99 for_each_cpu(cpu
, irq_data_get_affinity_mask(d
)) {
100 struct plic_handler
*handler
= per_cpu_ptr(&plic_handlers
, cpu
);
102 if (handler
->present
)
103 plic_toggle(handler
->ctxid
, d
->hwirq
, enable
);
107 static void plic_irq_enable(struct irq_data
*d
)
109 plic_irq_toggle(d
, 1);
112 static void plic_irq_disable(struct irq_data
*d
)
114 plic_irq_toggle(d
, 0);
117 static struct irq_chip plic_chip
= {
118 .name
= "SiFive PLIC",
120 * There is no need to mask/unmask PLIC interrupts. They are "masked"
121 * by reading claim and "unmasked" when writing it back.
123 .irq_enable
= plic_irq_enable
,
124 .irq_disable
= plic_irq_disable
,
127 static int plic_irqdomain_map(struct irq_domain
*d
, unsigned int irq
,
128 irq_hw_number_t hwirq
)
130 irq_set_chip_and_handler(irq
, &plic_chip
, handle_simple_irq
);
131 irq_set_chip_data(irq
, NULL
);
132 irq_set_noprobe(irq
);
136 static const struct irq_domain_ops plic_irqdomain_ops
= {
137 .map
= plic_irqdomain_map
,
138 .xlate
= irq_domain_xlate_onecell
,
141 static struct irq_domain
*plic_irqdomain
;
144 * Handling an interrupt is a two-step process: first you claim the interrupt
145 * by reading the claim register, then you complete the interrupt by writing
146 * that source ID back to the same claim register. This automatically enables
147 * and disables the interrupt, so there's nothing else to do.
149 static void plic_handle_irq(struct pt_regs
*regs
)
151 struct plic_handler
*handler
= this_cpu_ptr(&plic_handlers
);
152 void __iomem
*claim
= plic_hart_offset(handler
->ctxid
) + CONTEXT_CLAIM
;
153 irq_hw_number_t hwirq
;
155 WARN_ON_ONCE(!handler
->present
);
157 csr_clear(sie
, SIE_SEIE
);
158 while ((hwirq
= readl(claim
))) {
159 int irq
= irq_find_mapping(plic_irqdomain
, hwirq
);
161 if (unlikely(irq
<= 0))
162 pr_warn_ratelimited("can't find mapping for hwirq %lu\n",
165 generic_handle_irq(irq
);
166 writel(hwirq
, claim
);
168 csr_set(sie
, SIE_SEIE
);
172 * Walk up the DT tree until we find an active RISC-V core (HART) node and
173 * extract the cpuid from it.
175 static int plic_find_hart_id(struct device_node
*node
)
177 for (; node
; node
= node
->parent
) {
178 if (of_device_is_compatible(node
, "riscv"))
179 return riscv_of_processor_hart(node
);
185 static int __init
plic_init(struct device_node
*node
,
186 struct device_node
*parent
)
188 int error
= 0, nr_handlers
, nr_mapped
= 0, i
;
192 pr_warn("PLIC already present.\n");
196 plic_regs
= of_iomap(node
, 0);
197 if (WARN_ON(!plic_regs
))
201 of_property_read_u32(node
, "riscv,ndev", &nr_irqs
);
202 if (WARN_ON(!nr_irqs
))
205 nr_handlers
= of_irq_count(node
);
206 if (WARN_ON(!nr_handlers
))
208 if (WARN_ON(nr_handlers
< num_possible_cpus()))
212 plic_irqdomain
= irq_domain_add_linear(node
, nr_irqs
+ 1,
213 &plic_irqdomain_ops
, NULL
);
214 if (WARN_ON(!plic_irqdomain
))
217 for (i
= 0; i
< nr_handlers
; i
++) {
218 struct of_phandle_args parent
;
219 struct plic_handler
*handler
;
220 irq_hw_number_t hwirq
;
223 if (of_irq_parse_one(node
, i
, &parent
)) {
224 pr_err("failed to parse parent for context %d.\n", i
);
228 /* skip context holes */
229 if (parent
.args
[0] == -1)
232 cpu
= plic_find_hart_id(parent
.np
);
234 pr_warn("failed to parse hart ID for context %d.\n", i
);
238 handler
= per_cpu_ptr(&plic_handlers
, cpu
);
239 handler
->present
= true;
242 /* priority must be > threshold to trigger an interrupt */
243 writel(0, plic_hart_offset(i
) + CONTEXT_THRESHOLD
);
244 for (hwirq
= 1; hwirq
<= nr_irqs
; hwirq
++)
245 plic_toggle(i
, hwirq
, 0);
249 pr_info("mapped %d interrupts to %d (out of %d) handlers.\n",
250 nr_irqs
, nr_mapped
, nr_handlers
);
251 set_handle_irq(plic_handle_irq
);
259 IRQCHIP_DECLARE(sifive_plic
, "sifive,plic-1.0.0", plic_init
);
260 IRQCHIP_DECLARE(riscv_plic0
, "riscv,plic0", plic_init
); /* for legacy systems */