Re: [PATCH v2 2/5] irqchip/renesas-rzg2l: Add support for RZ/Five SoC

From: Geert Uytterhoeven
Date: Thu Apr 18 2024 - 11:11:36 EST


Hi Prabhakar,

On Wed, Apr 3, 2024 at 10:36 PM Prabhakar <prabhakar.csengg@xxxxxxxxx> wrote:
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
>
> The IX45 block has additional mask registers (NMSK/IMSK/TMSK) as compared
> to the RZ/G2L (family) SoC.
>
> Introduce masking/unmasking support for IRQ and TINT interrupts in IRQC
> controller driver. Two new registers, IMSK and TMSK, are defined to
> handle masking on RZ/Five SoC. The implementation utilizes a new data
> structure, `struct rzg2l_irqc_data`, to determine mask support for a
> specific controller instance.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx>
> ---
> v1->v2
> - Added IRQCHIP_MATCH() for RZ/Five
> - Retaining a copy of OF data in priv
> - Rebased the changes

Thanks for the update!

> --- a/drivers/irqchip/irq-renesas-rzg2l.c
> +++ b/drivers/irqchip/irq-renesas-rzg2l.c
> @@ -37,6 +37,8 @@
> #define TSSEL_SHIFT(n) (8 * (n))
> #define TSSEL_MASK GENMASK(7, 0)
> #define IRQ_MASK 0x3
> +#define IMSK 0x10010
> +#define TMSK 0x10020
>
> #define TSSR_OFFSET(n) ((n) % 4)
> #define TSSR_INDEX(n) ((n) / 4)
> @@ -66,15 +68,25 @@ struct rzg2l_irqc_reg_cache {
> u32 titsr[2];
> };
>
> +/**
> + * struct rzg2l_irqc_of_data - OF data structure
> + * @mask_supported: Indicates if mask registers are available
> + */
> +struct rzg2l_irqc_of_data {
> + bool mask_supported;
> +};
> +
> /**
> * struct rzg2l_irqc_priv - IRQ controller private data structure
> * @base: Controller's base address
> + * @data: OF data pointer
> * @fwspec: IRQ firmware specific data
> * @lock: Lock to serialize access to hardware registers
> * @cache: Registers cache for suspend/resume
> */
> static struct rzg2l_irqc_priv {
> void __iomem *base;
> + const struct rzg2l_irqc_of_data *data;

That's not a copy, but a pointer.

> struct irq_fwspec fwspec[IRQC_NUM_IRQ];
> raw_spinlock_t lock;
> struct rzg2l_irqc_reg_cache cache;
> @@ -138,18 +150,102 @@ static void rzg2l_irqc_eoi(struct irq_data *d)
> irq_chip_eoi_parent(d);
> }
>
> +static void rzg2l_irqc_mask_irq_interrupt(struct rzg2l_irqc_priv *priv,
> + unsigned int hwirq)
> +{
> + u32 imsk = readl_relaxed(priv->base + IMSK);
> + u32 bit = BIT(hwirq - IRQC_IRQ_START);
> +
> + writel_relaxed(imsk | bit, priv->base + IMSK);
> +}
> +
> +static void rzg2l_irqc_unmask_irq_interrupt(struct rzg2l_irqc_priv *priv,
> + unsigned int hwirq)
> +{
> + u32 imsk = readl_relaxed(priv->base + IMSK);
> + u32 bit = BIT(hwirq - IRQC_IRQ_START);
> +
> + writel_relaxed(imsk & ~bit, priv->base + IMSK);
> +}
> +
> +static void rzg2l_irqc_mask_tint_interrupt(struct rzg2l_irqc_priv *priv,
> + unsigned int hwirq)
> +{
> + u32 tmsk = readl_relaxed(priv->base + TMSK);
> + u32 bit = BIT(hwirq - IRQC_TINT_START);
> +
> + writel_relaxed(tmsk | bit, priv->base + TMSK);
> +}
> +
> +static void rzg2l_irqc_unmask_tint_interrupt(struct rzg2l_irqc_priv *priv,
> + unsigned int hwirq)
> +{
> + u32 tmsk = readl_relaxed(priv->base + TMSK);
> + u32 bit = BIT(hwirq - IRQC_TINT_START);
> +
> + writel_relaxed(tmsk & ~bit, priv->base + TMSK);
> +}
> +
> +/* Must be called while priv->lock is held */
> +static void rzg2l_irqc_mask_once(struct rzg2l_irqc_priv *priv, unsigned int hwirq)
> +{
> + if (!priv->data->mask_supported)
> + return;
> +
> + if (hwirq >= IRQC_IRQ_START && hwirq <= IRQC_IRQ_COUNT)
> + rzg2l_irqc_mask_irq_interrupt(priv, hwirq);
> + else if (hwirq >= IRQC_TINT_START && hwirq < IRQC_NUM_IRQ)
> + rzg2l_irqc_mask_tint_interrupt(priv, hwirq);
> +}
> +
> +static void rzg2l_irqc_mask(struct irq_data *d)
> +{
> + struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
> +
> + raw_spin_lock(&priv->lock);
> + rzg2l_irqc_mask_once(priv, irqd_to_hwirq(d));
> + raw_spin_unlock(&priv->lock);
> + irq_chip_mask_parent(d);
> +}
> +
> +/* Must be called while priv->lock is held */
> +static void rzg2l_irqc_unmask_once(struct rzg2l_irqc_priv *priv, unsigned int hwirq)
> +{
> + if (!priv->data->mask_supported)
> + return;
> +
> + if (hwirq >= IRQC_IRQ_START && hwirq <= IRQC_IRQ_COUNT)
> + rzg2l_irqc_unmask_irq_interrupt(priv, hwirq);
> + else if (hwirq >= IRQC_TINT_START && hwirq < IRQC_NUM_IRQ)
> + rzg2l_irqc_unmask_tint_interrupt(priv, hwirq);
> +}
> +
> +static void rzg2l_irqc_unmask(struct irq_data *d)
> +{
> + struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
> +
> + raw_spin_lock(&priv->lock);
> + rzg2l_irqc_unmask_once(priv, irqd_to_hwirq(d));
> + raw_spin_unlock(&priv->lock);
> + irq_chip_unmask_parent(d);
> +}
> +
> static void rzg2l_tint_irq_endisable(struct irq_data *d, bool enable)
> {
> + struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
> unsigned int hw_irq = irqd_to_hwirq(d);
>
> if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
> - struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
> u32 offset = hw_irq - IRQC_TINT_START;
> u32 tssr_offset = TSSR_OFFSET(offset);
> u8 tssr_index = TSSR_INDEX(offset);
> u32 reg;
>
> raw_spin_lock(&priv->lock);
> + if (enable)
> + rzg2l_irqc_unmask_once(priv, hw_irq);
> + else
> + rzg2l_irqc_mask_once(priv, hw_irq);

You already know this is a TINT interrupt, so you could call
rzg2l_irqc_(un)mask_irq_interrupt() directly.

> reg = readl_relaxed(priv->base + TSSR(tssr_index));
> if (enable)
> reg |= TIEN << TSSEL_SHIFT(tssr_offset);
> @@ -157,6 +253,13 @@ static void rzg2l_tint_irq_endisable(struct irq_data *d, bool enable)
> reg &= ~(TIEN << TSSEL_SHIFT(tssr_offset));
> writel_relaxed(reg, priv->base + TSSR(tssr_index));
> raw_spin_unlock(&priv->lock);
> + } else {
> + raw_spin_lock(&priv->lock);
> + if (enable)
> + rzg2l_irqc_unmask_once(priv, hw_irq);
> + else
> + rzg2l_irqc_mask_once(priv, hw_irq);

Likewise.

> + raw_spin_unlock(&priv->lock);
> }
> }

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68korg

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds