Skip to content

Commit dd46337

Browse files
prabhakarladMarc Zyngier
authored andcommitted
irqchip/sifive-plic: Add support for Renesas RZ/Five SoC
The Renesas RZ/Five SoC has a RISC-V AX45MP AndesCore with NCEPLIC100. The NCEPLIC100 supports both edge-triggered and level-triggered interrupts. In case of edge-triggered interrupts NCEPLIC100 ignores the next interrupt edge until the previous completion message has been received and NCEPLIC100 doesn't support pending interrupt counter, hence losing the interrupts if not acknowledged in time. So the workaround for edge-triggered interrupts to be handled correctly and without losing is that it needs to be acknowledged first and then handler must be run so that we don't miss on the next edge-triggered interrupt. This patch adds a new compatible string for NCEPLIC100 (from Andes Technology) interrupt controller found on Renesas RZ/Five SoC and adds quirk bits to priv structure and implements PLIC_QUIRK_EDGE_INTERRUPT quirk to change the interrupt flow. Suggested-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Signed-off-by: Samuel Holland <samuel@sholland.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220630100241.35233-3-samuel@sholland.org
1 parent 1267d98 commit dd46337

File tree

1 file changed

+74
-4
lines changed

1 file changed

+74
-4
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,13 @@
6060
#define PLIC_DISABLE_THRESHOLD 0x7
6161
#define PLIC_ENABLE_THRESHOLD 0
6262

63+
#define PLIC_QUIRK_EDGE_INTERRUPT 0
64+
6365
struct plic_priv {
6466
struct cpumask lmask;
6567
struct irq_domain *irqdomain;
6668
void __iomem *regs;
69+
unsigned long plic_quirks;
6770
};
6871

6972
struct plic_handler {
@@ -81,6 +84,8 @@ static int plic_parent_irq __ro_after_init;
8184
static bool plic_cpuhp_setup_done __ro_after_init;
8285
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
8386

87+
static int plic_irq_set_type(struct irq_data *d, unsigned int type);
88+
8489
static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable)
8590
{
8691
u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32);
@@ -176,6 +181,17 @@ static void plic_irq_eoi(struct irq_data *d)
176181
}
177182
}
178183

184+
static struct irq_chip plic_edge_chip = {
185+
.name = "SiFive PLIC",
186+
.irq_ack = plic_irq_eoi,
187+
.irq_mask = plic_irq_mask,
188+
.irq_unmask = plic_irq_unmask,
189+
#ifdef CONFIG_SMP
190+
.irq_set_affinity = plic_set_affinity,
191+
#endif
192+
.irq_set_type = plic_irq_set_type,
193+
};
194+
179195
static struct irq_chip plic_chip = {
180196
.name = "SiFive PLIC",
181197
.irq_mask = plic_irq_mask,
@@ -184,8 +200,32 @@ static struct irq_chip plic_chip = {
184200
#ifdef CONFIG_SMP
185201
.irq_set_affinity = plic_set_affinity,
186202
#endif
203+
.irq_set_type = plic_irq_set_type,
187204
};
188205

206+
static int plic_irq_set_type(struct irq_data *d, unsigned int type)
207+
{
208+
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
209+
210+
if (!test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
211+
return IRQ_SET_MASK_OK_NOCOPY;
212+
213+
switch (type) {
214+
case IRQ_TYPE_EDGE_RISING:
215+
irq_set_chip_handler_name_locked(d, &plic_edge_chip,
216+
handle_edge_irq, NULL);
217+
break;
218+
case IRQ_TYPE_LEVEL_HIGH:
219+
irq_set_chip_handler_name_locked(d, &plic_chip,
220+
handle_fasteoi_irq, NULL);
221+
break;
222+
default:
223+
return -EINVAL;
224+
}
225+
226+
return IRQ_SET_MASK_OK;
227+
}
228+
189229
static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
190230
irq_hw_number_t hwirq)
191231
{
@@ -198,6 +238,19 @@ static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
198238
return 0;
199239
}
200240

241+
static int plic_irq_domain_translate(struct irq_domain *d,
242+
struct irq_fwspec *fwspec,
243+
unsigned long *hwirq,
244+
unsigned int *type)
245+
{
246+
struct plic_priv *priv = d->host_data;
247+
248+
if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
249+
return irq_domain_translate_twocell(d, fwspec, hwirq, type);
250+
251+
return irq_domain_translate_onecell(d, fwspec, hwirq, type);
252+
}
253+
201254
static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
202255
unsigned int nr_irqs, void *arg)
203256
{
@@ -206,7 +259,7 @@ static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
206259
unsigned int type;
207260
struct irq_fwspec *fwspec = arg;
208261

209-
ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
262+
ret = plic_irq_domain_translate(domain, fwspec, &hwirq, &type);
210263
if (ret)
211264
return ret;
212265

@@ -220,7 +273,7 @@ static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
220273
}
221274

222275
static const struct irq_domain_ops plic_irqdomain_ops = {
223-
.translate = irq_domain_translate_onecell,
276+
.translate = plic_irq_domain_translate,
224277
.alloc = plic_irq_domain_alloc,
225278
.free = irq_domain_free_irqs_top,
226279
};
@@ -281,8 +334,9 @@ static int plic_starting_cpu(unsigned int cpu)
281334
return 0;
282335
}
283336

284-
static int __init plic_init(struct device_node *node,
285-
struct device_node *parent)
337+
static int __init __plic_init(struct device_node *node,
338+
struct device_node *parent,
339+
unsigned long plic_quirks)
286340
{
287341
int error = 0, nr_contexts, nr_handlers = 0, i;
288342
u32 nr_irqs;
@@ -293,6 +347,8 @@ static int __init plic_init(struct device_node *node,
293347
if (!priv)
294348
return -ENOMEM;
295349

350+
priv->plic_quirks = plic_quirks;
351+
296352
priv->regs = of_iomap(node, 0);
297353
if (WARN_ON(!priv->regs)) {
298354
error = -EIO;
@@ -410,6 +466,20 @@ static int __init plic_init(struct device_node *node,
410466
return error;
411467
}
412468

469+
static int __init plic_init(struct device_node *node,
470+
struct device_node *parent)
471+
{
472+
return __plic_init(node, parent, 0);
473+
}
474+
413475
IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
414476
IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
415477
IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */
478+
479+
static int __init plic_edge_init(struct device_node *node,
480+
struct device_node *parent)
481+
{
482+
return __plic_init(node, parent, BIT(PLIC_QUIRK_EDGE_INTERRUPT));
483+
}
484+
485+
IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init);

0 commit comments

Comments
 (0)