mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 03:11:11 -04:00
irqchip/renesas-rzg2l: Add NMI support
The RZ/G2L SoC has an NMI interrupt. Add support for the NMI interrupt. Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260401114504.332825-1-biju.das.jz@bp.renesas.com
This commit is contained in:
committed by
Thomas Gleixner
parent
d3689cd02c
commit
0e5988549d
@@ -20,11 +20,14 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#define IRQC_NMI 0
|
||||
#define IRQC_IRQ_START 1
|
||||
#define IRQC_TINT_COUNT 32
|
||||
#define IRQC_SHARED_IRQ_COUNT 8
|
||||
#define IRQC_IRQ_SHARED_START (IRQC_IRQ_START + IRQC_SHARED_IRQ_COUNT)
|
||||
|
||||
#define NSCR 0x0
|
||||
#define NITSR 0x4
|
||||
#define ISCR 0x10
|
||||
#define IITSR 0x14
|
||||
#define TSCR 0x20
|
||||
@@ -43,6 +46,10 @@
|
||||
#define TSSR_OFFSET(n) ((n) % 4)
|
||||
#define TSSR_INDEX(n) ((n) / 4)
|
||||
|
||||
#define NSCR_NSTAT 0
|
||||
#define NITSR_NTSEL_EDGE_FALLING 0
|
||||
#define NITSR_NTSEL_EDGE_RISING 1
|
||||
|
||||
#define TITSR_TITSEL_EDGE_RISING 0
|
||||
#define TITSR_TITSEL_EDGE_FALLING 1
|
||||
#define TITSR_TITSEL_LEVEL_HIGH 2
|
||||
@@ -63,11 +70,13 @@
|
||||
|
||||
/**
|
||||
* struct rzg2l_irqc_reg_cache - registers cache (necessary for suspend/resume)
|
||||
* @iitsr: IITSR register
|
||||
* @inttsel: INTTSEL register
|
||||
* @titsr: TITSR registers
|
||||
* @nitsr: NITSR register
|
||||
* @iitsr: IITSR register
|
||||
* @inttsel: INTTSEL register
|
||||
* @titsr: TITSR registers
|
||||
*/
|
||||
struct rzg2l_irqc_reg_cache {
|
||||
u32 nitsr;
|
||||
u32 iitsr;
|
||||
u32 inttsel;
|
||||
u32 titsr[2];
|
||||
@@ -116,6 +125,28 @@ static struct rzg2l_irqc_priv *irq_data_to_priv(struct irq_data *data)
|
||||
return data->domain->host_data;
|
||||
}
|
||||
|
||||
static void rzg2l_clear_nmi_int(struct rzg2l_irqc_priv *priv)
|
||||
{
|
||||
u32 bit = BIT(NSCR_NSTAT);
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* No locking required as the register is not shared
|
||||
* with other interrupts.
|
||||
*
|
||||
* Writing is allowed only when NSTAT is 1
|
||||
*/
|
||||
reg = readl_relaxed(priv->base + NSCR);
|
||||
if (reg & bit) {
|
||||
writel_relaxed(reg & ~bit, priv->base + NSCR);
|
||||
/*
|
||||
* Enforce that the posted write is flushed to prevent that the
|
||||
* just handled interrupt is raised again.
|
||||
*/
|
||||
readl_relaxed(priv->base + NSCR);
|
||||
}
|
||||
}
|
||||
|
||||
static void rzg2l_clear_irq_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq)
|
||||
{
|
||||
unsigned int hw_irq = hwirq - IRQC_IRQ_START;
|
||||
@@ -155,6 +186,14 @@ static void rzg2l_clear_tint_int(struct rzg2l_irqc_priv *priv, unsigned int hwir
|
||||
}
|
||||
}
|
||||
|
||||
static void rzg2l_irqc_nmi_eoi(struct irq_data *d)
|
||||
{
|
||||
struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
|
||||
|
||||
rzg2l_clear_nmi_int(priv);
|
||||
irq_chip_eoi_parent(d);
|
||||
}
|
||||
|
||||
static void rzg2l_irqc_irq_eoi(struct irq_data *d)
|
||||
{
|
||||
struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
|
||||
@@ -341,6 +380,26 @@ static void rzg2l_irqc_tint_enable(struct irq_data *d)
|
||||
irq_chip_enable_parent(d);
|
||||
}
|
||||
|
||||
static int rzg2l_nmi_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
|
||||
u32 sense;
|
||||
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
sense = NITSR_NTSEL_EDGE_FALLING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
sense = NITSR_NTSEL_EDGE_RISING;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel_relaxed(sense, priv->base + NITSR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
|
||||
@@ -467,11 +526,23 @@ static int rzg2l_irqc_tint_set_type(struct irq_data *d, unsigned int type)
|
||||
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
|
||||
}
|
||||
|
||||
static int rzg2l_irqc_nmi_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rzg2l_nmi_set_type(d, type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
|
||||
}
|
||||
|
||||
static int rzg2l_irqc_irq_suspend(void *data)
|
||||
{
|
||||
struct rzg2l_irqc_reg_cache *cache = &rzg2l_irqc_data->cache;
|
||||
void __iomem *base = rzg2l_irqc_data->base;
|
||||
|
||||
cache->nitsr = readl_relaxed(base + NITSR);
|
||||
cache->iitsr = readl_relaxed(base + IITSR);
|
||||
if (rzg2l_irqc_data->info.shared_irq_cnt)
|
||||
cache->inttsel = readl_relaxed(base + INTTSEL);
|
||||
@@ -496,6 +567,7 @@ static void rzg2l_irqc_irq_resume(void *data)
|
||||
if (rzg2l_irqc_data->info.shared_irq_cnt)
|
||||
writel_relaxed(cache->inttsel, base + INTTSEL);
|
||||
writel_relaxed(cache->iitsr, base + IITSR);
|
||||
writel_relaxed(cache->nitsr, base + NITSR);
|
||||
}
|
||||
|
||||
static const struct syscore_ops rzg2l_irqc_syscore_ops = {
|
||||
@@ -507,6 +579,23 @@ static struct syscore rzg2l_irqc_syscore = {
|
||||
.ops = &rzg2l_irqc_syscore_ops,
|
||||
};
|
||||
|
||||
static const struct irq_chip rzg2l_irqc_nmi_chip = {
|
||||
.name = "rzg2l-irqc",
|
||||
.irq_eoi = rzg2l_irqc_nmi_eoi,
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
.irq_unmask = irq_chip_unmask_parent,
|
||||
.irq_disable = irq_chip_disable_parent,
|
||||
.irq_enable = irq_chip_enable_parent,
|
||||
.irq_get_irqchip_state = irq_chip_get_parent_state,
|
||||
.irq_set_irqchip_state = irq_chip_set_parent_state,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_set_type = rzg2l_irqc_nmi_set_type,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND |
|
||||
IRQCHIP_SET_TYPE_MASKED |
|
||||
IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static const struct irq_chip rzg2l_irqc_irq_chip = {
|
||||
.name = "rzg2l-irqc",
|
||||
.irq_eoi = rzg2l_irqc_irq_eoi,
|
||||
@@ -662,7 +751,9 @@ static int rzg2l_irqc_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
* from 16-31 bits. TINT from the pinctrl driver needs to be programmed
|
||||
* in IRQC registers to enable a given gpio pin as interrupt.
|
||||
*/
|
||||
if (hwirq > priv->info.irq_count) {
|
||||
if (hwirq == IRQC_NMI) {
|
||||
chip = &rzg2l_irqc_nmi_chip;
|
||||
} else if (hwirq > priv->info.irq_count) {
|
||||
tint = TINT_EXTRACT_GPIOINT(hwirq);
|
||||
hwirq = TINT_EXTRACT_HWIRQ(hwirq);
|
||||
chip = priv->tint_chip;
|
||||
|
||||
Reference in New Issue
Block a user