All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
Cc: openbmc@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	Avi Fishman <avifishman70@gmail.com>,
	Tomer Maimon <tmaimon77@gmail.com>,
	Tali Perry <tali.perry1@gmail.com>,
	Patrick Venture <venture@google.com>,
	Nancy Yuen <yuenn@google.com>,
	Benjamin Fair <benjaminfair@google.com>,
	Russell King <linux@armlinux.org.uk>,
	Thomas Gleixner <tglx@linutronix.de>
Subject: Re: [PATCH 08/14] irqchip: Add driver for WPCM450 interrupt controller
Date: Wed, 24 Mar 2021 17:16:35 +0000	[thread overview]
Message-ID: <87sg4kiia4.wl-maz@kernel.org> (raw)
In-Reply-To: <20210320181610.680870-9-j.neuschaefer@gmx.net>

On Sat, 20 Mar 2021 18:16:04 +0000,
Jonathan Neuschäfer <j.neuschaefer@gmx.net> wrote:
> 
> The WPCM450 AIC ("Advanced Interrupt Controller") is the interrupt
> controller found in the Nuvoton WPCM450 SoC and other Winbond/Nuvoton
> SoCs.
> 
> The list of registers if based on the AMI vendor kernel and the
> Nuvoton W90N745 datasheet.
> 
> Although the hardware supports other interrupt modes, the driver only
> supports high-level interrupts at the moment, because other modes could
> not be tested so far.
> 
> Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> ---
>  arch/arm/mach-npcm/Kconfig        |   1 +
>  drivers/irqchip/Kconfig           |   6 ++
>  drivers/irqchip/Makefile          |   1 +
>  drivers/irqchip/irq-wpcm450-aic.c | 162 ++++++++++++++++++++++++++++++
>  4 files changed, 170 insertions(+)
>  create mode 100644 drivers/irqchip/irq-wpcm450-aic.c
> 
> diff --git a/arch/arm/mach-npcm/Kconfig b/arch/arm/mach-npcm/Kconfig
> index 658c8efb4ca14..a71cf1d189ae5 100644
> --- a/arch/arm/mach-npcm/Kconfig
> +++ b/arch/arm/mach-npcm/Kconfig
> @@ -10,6 +10,7 @@ config ARCH_WPCM450
>  	bool "Support for WPCM450 BMC (Hermon)"
>  	depends on ARCH_MULTI_V5
>  	select CPU_ARM926T
> +	select WPCM450_AIC
>  	select NPCM7XX_TIMER
>  	help
>  	  General support for WPCM450 BMC (Hermon).
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index e74fa206240a1..baf4efec31c67 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -586,4 +586,10 @@ config MST_IRQ
>  	help
>  	  Support MStar Interrupt Controller.
> 
> +config WPCM450_AIC
> +	bool "Nuvoton WPCM450 Advanced Interrupt Controller"
> +	depends on ARCH_WPCM450 || COMPILE_TEST
> +	help
> +	  Support for the interrupt controller in the Nuvoton WPCM450 BMC SoC.
> +
>  endmenu
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index c59b95a0532c9..bef57937e7296 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
>  obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o
>  obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o
>  obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o
> +obj-$(CONFIG_WPCM450_AIC)		+= irq-wpcm450-aic.o
> diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c
> new file mode 100644
> index 0000000000000..0d6dd8b1fc824
> --- /dev/null
> +++ b/drivers/irqchip/irq-wpcm450-aic.c
> @@ -0,0 +1,162 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright 2021 Jonathan Neuschäfer
> +
> +#include <linux/console.h>

That's unexpected. Why do you need this?

> +#include <linux/irqchip.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <asm/exception.h>
> +
> +#define AIC_SCR(x)	((x)*4)	/* Source control registers */
> +#define AIC_GEN		0x84
> +#define AIC_GRSR	0x88
> +#define AIC_IRSR	0x100	/* Interrupt raw status register */
> +#define AIC_IASR	0x104	/* Interrupt active status register */
> +#define AIC_ISR		0x108	/* Interrupt status register */
> +#define AIC_IPER	0x10c	/* Interrupt priority encoding register */
> +#define AIC_ISNR	0x110	/* Interrupt source number register */
> +#define AIC_IMR		0x114	/* Interrupt mask register */
> +#define AIC_OISR	0x118	/* Output interrupt status register */
> +#define AIC_MECR	0x120	/* Mask enable command register */
> +#define AIC_MDCR	0x124	/* Mask disable command register */
> +#define AIC_SSCR	0x128	/* Source set command register */
> +#define AIC_SCCR	0x12c	/* Source clear command register */
> +#define AIC_EOSCR	0x130	/* End of service command register */
> +
> +#define AIC_SCR_SRCTYPE_LOW_LEVEL	(0 << 6)
> +#define AIC_SCR_SRCTYPE_HIGH_LEVEL	(1 << 6)
> +#define AIC_SCR_SRCTYPE_NEG_EDGE	(2 << 6)
> +#define AIC_SCR_SRCTYPE_POS_EDGE	(3 << 6)
> +#define AIC_SCR_PRIORITY(x)		(x)

A mask would be welcomed for this field.

> +
> +#define IRQS		32

Please use something a bit less generic.

> +
> +struct wpcm450_aic {
> +	void __iomem *regs;
> +	struct irq_domain *domain;
> +};
> +
> +static struct wpcm450_aic *aic;
> +
> +static void wpcm450_aic_init_hw(void)
> +{
> +	int i;
> +
> +	/* Disable (mask) all interrupts */
> +	writel(0xffffffff, aic->regs + AIC_MDCR);

Consider using relaxed accessors throughout this driver.

> +
> +	/*
> +	 * Make sure the interrupt controller is ready to serve new interrupts.
> +	 * Reading from IPER indicates that the nIRQ signal may be deasserted,
> +	 * and writing to EOSCR indicates that interrupt handling has finished.
> +	 */
> +	readl(aic->regs + AIC_IPER);
> +	writel(0, aic->regs + AIC_EOSCR);
> +
> +	/* Initialize trigger mode and priority of each interrupt source */
> +	for (i = 0; i < IRQS; i++)
> +		writel(AIC_SCR_SRCTYPE_HIGH_LEVEL | AIC_SCR_PRIORITY(7),
> +		       aic->regs + AIC_SCR(i));
> +}
> +
> +static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs)
> +{
> +	int hwirq;
> +
> +	/* Determine the interrupt source */
> +	/* Read IPER to signal that nIRQ can be de-asserted */
> +	hwirq = readl(aic->regs + AIC_IPER) / 4;
> +
> +	handle_domain_irq(aic->domain, hwirq, regs);
> +}
> +
> +static void wpcm450_aic_ack(struct irq_data *d)
> +{
> +	/* Signal end-of-service */
> +	writel(0, aic->regs + AIC_EOSCR);

Is that an Ack or an EOI? My gut feeling is that the above read is the
Ack, and that this write should actually be an EOI callback.

> +}
> +
> +static void wpcm450_aic_mask(struct irq_data *d)
> +{
> +	unsigned int mask = 1U << d->hwirq;

Consider using BIT().

> +
> +	/* Disable (mask) the interrupt */
> +	writel(mask, aic->regs + AIC_MDCR);
> +}
> +
> +static void wpcm450_aic_unmask(struct irq_data *d)
> +{
> +	unsigned int mask = 1U << d->hwirq;
> +
> +	/* Enable (unmask) the interrupt */
> +	writel(mask, aic->regs + AIC_MECR);
> +}
> +
> +static int wpcm450_aic_set_type(struct irq_data *d, unsigned int flow_type)
> +{
> +	/*
> +	 * The hardware supports high/low level, as well as rising/falling edge
> +	 * modes, and the DT binding accommodates for that, but as long as
> +	 * other modes than high level mode are not used and can't be tested,
> +	 * they are rejected in this driver.
> +	 */
> +	if ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) {
> +		pr_err("IRQ mode %#x is not supported\n", flow_type);

The core kernel shouts loudly enough, no need for extra messages.

> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct irq_chip wpcm450_aic_chip = {
> +	.name = "wpcm450-aic",
> +	.irq_ack = wpcm450_aic_ack,
> +	.irq_mask = wpcm450_aic_mask,
> +	.irq_unmask = wpcm450_aic_unmask,
> +	.irq_set_type = wpcm450_aic_set_type,
> +};
> +
> +static int wpcm450_aic_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
> +{
> +	if (hwirq > IRQS)
> +		return -EPERM;
> +
> +	irq_set_chip_and_handler(irq, &wpcm450_aic_chip, handle_level_irq);
> +	irq_set_chip_data(irq, aic);
> +	irq_set_probe(irq);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops wpcm450_aic_ops = {
> +	.map = wpcm450_aic_map,
> +	.xlate = irq_domain_xlate_twocell,
> +};
> +
> +static int __init wpcm450_aic_of_init(struct device_node *node,
> +				      struct device_node *parent)
> +{
> +	if (parent)
> +		return -EINVAL;
> +
> +	aic = kzalloc(sizeof(*aic), GFP_KERNEL);
> +	if (!aic)
> +		return -ENOMEM;
> +
> +	aic->regs = of_iomap(node, 0);
> +	if (!aic->regs) {
> +		pr_err("Failed to map WPCM450 AIC registers\n");
> +		return -ENOMEM;
> +	}
> +
> +	wpcm450_aic_init_hw();
> +
> +	set_handle_irq(wpcm450_aic_handle_irq);
> +
> +	aic->domain = irq_domain_add_linear(node, IRQS, &wpcm450_aic_ops, aic);
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(wpcm450_aic, "nuvoton,wpcm450-aic", wpcm450_aic_of_init);

Otherwise, looks good.

	M.

-- 
Without deviation from the norm, progress is not possible.

WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
Cc: devicetree@vger.kernel.org, Tomer Maimon <tmaimon77@gmail.com>,
	Avi Fishman <avifishman70@gmail.com>,
	Patrick Venture <venture@google.com>,
	openbmc@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	Tali Perry <tali.perry1@gmail.com>,
	Russell King <linux@armlinux.org.uk>,
	Thomas Gleixner <tglx@linutronix.de>,
	linux-arm-kernel@lists.infradead.org,
	Benjamin Fair <benjaminfair@google.com>
Subject: Re: [PATCH 08/14] irqchip: Add driver for WPCM450 interrupt controller
Date: Wed, 24 Mar 2021 17:16:35 +0000	[thread overview]
Message-ID: <87sg4kiia4.wl-maz@kernel.org> (raw)
In-Reply-To: <20210320181610.680870-9-j.neuschaefer@gmx.net>

On Sat, 20 Mar 2021 18:16:04 +0000,
Jonathan Neuschäfer <j.neuschaefer@gmx.net> wrote:
> 
> The WPCM450 AIC ("Advanced Interrupt Controller") is the interrupt
> controller found in the Nuvoton WPCM450 SoC and other Winbond/Nuvoton
> SoCs.
> 
> The list of registers if based on the AMI vendor kernel and the
> Nuvoton W90N745 datasheet.
> 
> Although the hardware supports other interrupt modes, the driver only
> supports high-level interrupts at the moment, because other modes could
> not be tested so far.
> 
> Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> ---
>  arch/arm/mach-npcm/Kconfig        |   1 +
>  drivers/irqchip/Kconfig           |   6 ++
>  drivers/irqchip/Makefile          |   1 +
>  drivers/irqchip/irq-wpcm450-aic.c | 162 ++++++++++++++++++++++++++++++
>  4 files changed, 170 insertions(+)
>  create mode 100644 drivers/irqchip/irq-wpcm450-aic.c
> 
> diff --git a/arch/arm/mach-npcm/Kconfig b/arch/arm/mach-npcm/Kconfig
> index 658c8efb4ca14..a71cf1d189ae5 100644
> --- a/arch/arm/mach-npcm/Kconfig
> +++ b/arch/arm/mach-npcm/Kconfig
> @@ -10,6 +10,7 @@ config ARCH_WPCM450
>  	bool "Support for WPCM450 BMC (Hermon)"
>  	depends on ARCH_MULTI_V5
>  	select CPU_ARM926T
> +	select WPCM450_AIC
>  	select NPCM7XX_TIMER
>  	help
>  	  General support for WPCM450 BMC (Hermon).
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index e74fa206240a1..baf4efec31c67 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -586,4 +586,10 @@ config MST_IRQ
>  	help
>  	  Support MStar Interrupt Controller.
> 
> +config WPCM450_AIC
> +	bool "Nuvoton WPCM450 Advanced Interrupt Controller"
> +	depends on ARCH_WPCM450 || COMPILE_TEST
> +	help
> +	  Support for the interrupt controller in the Nuvoton WPCM450 BMC SoC.
> +
>  endmenu
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index c59b95a0532c9..bef57937e7296 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
>  obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o
>  obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o
>  obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o
> +obj-$(CONFIG_WPCM450_AIC)		+= irq-wpcm450-aic.o
> diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c
> new file mode 100644
> index 0000000000000..0d6dd8b1fc824
> --- /dev/null
> +++ b/drivers/irqchip/irq-wpcm450-aic.c
> @@ -0,0 +1,162 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright 2021 Jonathan Neuschäfer
> +
> +#include <linux/console.h>

That's unexpected. Why do you need this?

> +#include <linux/irqchip.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <asm/exception.h>
> +
> +#define AIC_SCR(x)	((x)*4)	/* Source control registers */
> +#define AIC_GEN		0x84
> +#define AIC_GRSR	0x88
> +#define AIC_IRSR	0x100	/* Interrupt raw status register */
> +#define AIC_IASR	0x104	/* Interrupt active status register */
> +#define AIC_ISR		0x108	/* Interrupt status register */
> +#define AIC_IPER	0x10c	/* Interrupt priority encoding register */
> +#define AIC_ISNR	0x110	/* Interrupt source number register */
> +#define AIC_IMR		0x114	/* Interrupt mask register */
> +#define AIC_OISR	0x118	/* Output interrupt status register */
> +#define AIC_MECR	0x120	/* Mask enable command register */
> +#define AIC_MDCR	0x124	/* Mask disable command register */
> +#define AIC_SSCR	0x128	/* Source set command register */
> +#define AIC_SCCR	0x12c	/* Source clear command register */
> +#define AIC_EOSCR	0x130	/* End of service command register */
> +
> +#define AIC_SCR_SRCTYPE_LOW_LEVEL	(0 << 6)
> +#define AIC_SCR_SRCTYPE_HIGH_LEVEL	(1 << 6)
> +#define AIC_SCR_SRCTYPE_NEG_EDGE	(2 << 6)
> +#define AIC_SCR_SRCTYPE_POS_EDGE	(3 << 6)
> +#define AIC_SCR_PRIORITY(x)		(x)

A mask would be welcomed for this field.

> +
> +#define IRQS		32

Please use something a bit less generic.

> +
> +struct wpcm450_aic {
> +	void __iomem *regs;
> +	struct irq_domain *domain;
> +};
> +
> +static struct wpcm450_aic *aic;
> +
> +static void wpcm450_aic_init_hw(void)
> +{
> +	int i;
> +
> +	/* Disable (mask) all interrupts */
> +	writel(0xffffffff, aic->regs + AIC_MDCR);

Consider using relaxed accessors throughout this driver.

> +
> +	/*
> +	 * Make sure the interrupt controller is ready to serve new interrupts.
> +	 * Reading from IPER indicates that the nIRQ signal may be deasserted,
> +	 * and writing to EOSCR indicates that interrupt handling has finished.
> +	 */
> +	readl(aic->regs + AIC_IPER);
> +	writel(0, aic->regs + AIC_EOSCR);
> +
> +	/* Initialize trigger mode and priority of each interrupt source */
> +	for (i = 0; i < IRQS; i++)
> +		writel(AIC_SCR_SRCTYPE_HIGH_LEVEL | AIC_SCR_PRIORITY(7),
> +		       aic->regs + AIC_SCR(i));
> +}
> +
> +static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs)
> +{
> +	int hwirq;
> +
> +	/* Determine the interrupt source */
> +	/* Read IPER to signal that nIRQ can be de-asserted */
> +	hwirq = readl(aic->regs + AIC_IPER) / 4;
> +
> +	handle_domain_irq(aic->domain, hwirq, regs);
> +}
> +
> +static void wpcm450_aic_ack(struct irq_data *d)
> +{
> +	/* Signal end-of-service */
> +	writel(0, aic->regs + AIC_EOSCR);

Is that an Ack or an EOI? My gut feeling is that the above read is the
Ack, and that this write should actually be an EOI callback.

> +}
> +
> +static void wpcm450_aic_mask(struct irq_data *d)
> +{
> +	unsigned int mask = 1U << d->hwirq;

Consider using BIT().

> +
> +	/* Disable (mask) the interrupt */
> +	writel(mask, aic->regs + AIC_MDCR);
> +}
> +
> +static void wpcm450_aic_unmask(struct irq_data *d)
> +{
> +	unsigned int mask = 1U << d->hwirq;
> +
> +	/* Enable (unmask) the interrupt */
> +	writel(mask, aic->regs + AIC_MECR);
> +}
> +
> +static int wpcm450_aic_set_type(struct irq_data *d, unsigned int flow_type)
> +{
> +	/*
> +	 * The hardware supports high/low level, as well as rising/falling edge
> +	 * modes, and the DT binding accommodates for that, but as long as
> +	 * other modes than high level mode are not used and can't be tested,
> +	 * they are rejected in this driver.
> +	 */
> +	if ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) {
> +		pr_err("IRQ mode %#x is not supported\n", flow_type);

The core kernel shouts loudly enough, no need for extra messages.

> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct irq_chip wpcm450_aic_chip = {
> +	.name = "wpcm450-aic",
> +	.irq_ack = wpcm450_aic_ack,
> +	.irq_mask = wpcm450_aic_mask,
> +	.irq_unmask = wpcm450_aic_unmask,
> +	.irq_set_type = wpcm450_aic_set_type,
> +};
> +
> +static int wpcm450_aic_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
> +{
> +	if (hwirq > IRQS)
> +		return -EPERM;
> +
> +	irq_set_chip_and_handler(irq, &wpcm450_aic_chip, handle_level_irq);
> +	irq_set_chip_data(irq, aic);
> +	irq_set_probe(irq);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops wpcm450_aic_ops = {
> +	.map = wpcm450_aic_map,
> +	.xlate = irq_domain_xlate_twocell,
> +};
> +
> +static int __init wpcm450_aic_of_init(struct device_node *node,
> +				      struct device_node *parent)
> +{
> +	if (parent)
> +		return -EINVAL;
> +
> +	aic = kzalloc(sizeof(*aic), GFP_KERNEL);
> +	if (!aic)
> +		return -ENOMEM;
> +
> +	aic->regs = of_iomap(node, 0);
> +	if (!aic->regs) {
> +		pr_err("Failed to map WPCM450 AIC registers\n");
> +		return -ENOMEM;
> +	}
> +
> +	wpcm450_aic_init_hw();
> +
> +	set_handle_irq(wpcm450_aic_handle_irq);
> +
> +	aic->domain = irq_domain_add_linear(node, IRQS, &wpcm450_aic_ops, aic);
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(wpcm450_aic, "nuvoton,wpcm450-aic", wpcm450_aic_of_init);

Otherwise, looks good.

	M.

-- 
Without deviation from the norm, progress is not possible.

WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
Cc: openbmc@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	Avi Fishman <avifishman70@gmail.com>,
	Tomer Maimon <tmaimon77@gmail.com>,
	Tali Perry <tali.perry1@gmail.com>,
	Patrick Venture <venture@google.com>,
	Nancy Yuen <yuenn@google.com>,
	Benjamin Fair <benjaminfair@google.com>,
	Russell King <linux@armlinux.org.uk>,
	Thomas Gleixner <tglx@linutronix.de>
Subject: Re: [PATCH 08/14] irqchip: Add driver for WPCM450 interrupt controller
Date: Wed, 24 Mar 2021 17:16:35 +0000	[thread overview]
Message-ID: <87sg4kiia4.wl-maz@kernel.org> (raw)
In-Reply-To: <20210320181610.680870-9-j.neuschaefer@gmx.net>

On Sat, 20 Mar 2021 18:16:04 +0000,
Jonathan Neuschäfer <j.neuschaefer@gmx.net> wrote:
> 
> The WPCM450 AIC ("Advanced Interrupt Controller") is the interrupt
> controller found in the Nuvoton WPCM450 SoC and other Winbond/Nuvoton
> SoCs.
> 
> The list of registers if based on the AMI vendor kernel and the
> Nuvoton W90N745 datasheet.
> 
> Although the hardware supports other interrupt modes, the driver only
> supports high-level interrupts at the moment, because other modes could
> not be tested so far.
> 
> Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> ---
>  arch/arm/mach-npcm/Kconfig        |   1 +
>  drivers/irqchip/Kconfig           |   6 ++
>  drivers/irqchip/Makefile          |   1 +
>  drivers/irqchip/irq-wpcm450-aic.c | 162 ++++++++++++++++++++++++++++++
>  4 files changed, 170 insertions(+)
>  create mode 100644 drivers/irqchip/irq-wpcm450-aic.c
> 
> diff --git a/arch/arm/mach-npcm/Kconfig b/arch/arm/mach-npcm/Kconfig
> index 658c8efb4ca14..a71cf1d189ae5 100644
> --- a/arch/arm/mach-npcm/Kconfig
> +++ b/arch/arm/mach-npcm/Kconfig
> @@ -10,6 +10,7 @@ config ARCH_WPCM450
>  	bool "Support for WPCM450 BMC (Hermon)"
>  	depends on ARCH_MULTI_V5
>  	select CPU_ARM926T
> +	select WPCM450_AIC
>  	select NPCM7XX_TIMER
>  	help
>  	  General support for WPCM450 BMC (Hermon).
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index e74fa206240a1..baf4efec31c67 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -586,4 +586,10 @@ config MST_IRQ
>  	help
>  	  Support MStar Interrupt Controller.
> 
> +config WPCM450_AIC
> +	bool "Nuvoton WPCM450 Advanced Interrupt Controller"
> +	depends on ARCH_WPCM450 || COMPILE_TEST
> +	help
> +	  Support for the interrupt controller in the Nuvoton WPCM450 BMC SoC.
> +
>  endmenu
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index c59b95a0532c9..bef57937e7296 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -113,3 +113,4 @@ obj-$(CONFIG_LOONGSON_PCH_MSI)		+= irq-loongson-pch-msi.o
>  obj-$(CONFIG_MST_IRQ)			+= irq-mst-intc.o
>  obj-$(CONFIG_SL28CPLD_INTC)		+= irq-sl28cpld.o
>  obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o
> +obj-$(CONFIG_WPCM450_AIC)		+= irq-wpcm450-aic.o
> diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c
> new file mode 100644
> index 0000000000000..0d6dd8b1fc824
> --- /dev/null
> +++ b/drivers/irqchip/irq-wpcm450-aic.c
> @@ -0,0 +1,162 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright 2021 Jonathan Neuschäfer
> +
> +#include <linux/console.h>

That's unexpected. Why do you need this?

> +#include <linux/irqchip.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <asm/exception.h>
> +
> +#define AIC_SCR(x)	((x)*4)	/* Source control registers */
> +#define AIC_GEN		0x84
> +#define AIC_GRSR	0x88
> +#define AIC_IRSR	0x100	/* Interrupt raw status register */
> +#define AIC_IASR	0x104	/* Interrupt active status register */
> +#define AIC_ISR		0x108	/* Interrupt status register */
> +#define AIC_IPER	0x10c	/* Interrupt priority encoding register */
> +#define AIC_ISNR	0x110	/* Interrupt source number register */
> +#define AIC_IMR		0x114	/* Interrupt mask register */
> +#define AIC_OISR	0x118	/* Output interrupt status register */
> +#define AIC_MECR	0x120	/* Mask enable command register */
> +#define AIC_MDCR	0x124	/* Mask disable command register */
> +#define AIC_SSCR	0x128	/* Source set command register */
> +#define AIC_SCCR	0x12c	/* Source clear command register */
> +#define AIC_EOSCR	0x130	/* End of service command register */
> +
> +#define AIC_SCR_SRCTYPE_LOW_LEVEL	(0 << 6)
> +#define AIC_SCR_SRCTYPE_HIGH_LEVEL	(1 << 6)
> +#define AIC_SCR_SRCTYPE_NEG_EDGE	(2 << 6)
> +#define AIC_SCR_SRCTYPE_POS_EDGE	(3 << 6)
> +#define AIC_SCR_PRIORITY(x)		(x)

A mask would be welcomed for this field.

> +
> +#define IRQS		32

Please use something a bit less generic.

> +
> +struct wpcm450_aic {
> +	void __iomem *regs;
> +	struct irq_domain *domain;
> +};
> +
> +static struct wpcm450_aic *aic;
> +
> +static void wpcm450_aic_init_hw(void)
> +{
> +	int i;
> +
> +	/* Disable (mask) all interrupts */
> +	writel(0xffffffff, aic->regs + AIC_MDCR);

Consider using relaxed accessors throughout this driver.

> +
> +	/*
> +	 * Make sure the interrupt controller is ready to serve new interrupts.
> +	 * Reading from IPER indicates that the nIRQ signal may be deasserted,
> +	 * and writing to EOSCR indicates that interrupt handling has finished.
> +	 */
> +	readl(aic->regs + AIC_IPER);
> +	writel(0, aic->regs + AIC_EOSCR);
> +
> +	/* Initialize trigger mode and priority of each interrupt source */
> +	for (i = 0; i < IRQS; i++)
> +		writel(AIC_SCR_SRCTYPE_HIGH_LEVEL | AIC_SCR_PRIORITY(7),
> +		       aic->regs + AIC_SCR(i));
> +}
> +
> +static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs)
> +{
> +	int hwirq;
> +
> +	/* Determine the interrupt source */
> +	/* Read IPER to signal that nIRQ can be de-asserted */
> +	hwirq = readl(aic->regs + AIC_IPER) / 4;
> +
> +	handle_domain_irq(aic->domain, hwirq, regs);
> +}
> +
> +static void wpcm450_aic_ack(struct irq_data *d)
> +{
> +	/* Signal end-of-service */
> +	writel(0, aic->regs + AIC_EOSCR);

Is that an Ack or an EOI? My gut feeling is that the above read is the
Ack, and that this write should actually be an EOI callback.

> +}
> +
> +static void wpcm450_aic_mask(struct irq_data *d)
> +{
> +	unsigned int mask = 1U << d->hwirq;

Consider using BIT().

> +
> +	/* Disable (mask) the interrupt */
> +	writel(mask, aic->regs + AIC_MDCR);
> +}
> +
> +static void wpcm450_aic_unmask(struct irq_data *d)
> +{
> +	unsigned int mask = 1U << d->hwirq;
> +
> +	/* Enable (unmask) the interrupt */
> +	writel(mask, aic->regs + AIC_MECR);
> +}
> +
> +static int wpcm450_aic_set_type(struct irq_data *d, unsigned int flow_type)
> +{
> +	/*
> +	 * The hardware supports high/low level, as well as rising/falling edge
> +	 * modes, and the DT binding accommodates for that, but as long as
> +	 * other modes than high level mode are not used and can't be tested,
> +	 * they are rejected in this driver.
> +	 */
> +	if ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) {
> +		pr_err("IRQ mode %#x is not supported\n", flow_type);

The core kernel shouts loudly enough, no need for extra messages.

> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct irq_chip wpcm450_aic_chip = {
> +	.name = "wpcm450-aic",
> +	.irq_ack = wpcm450_aic_ack,
> +	.irq_mask = wpcm450_aic_mask,
> +	.irq_unmask = wpcm450_aic_unmask,
> +	.irq_set_type = wpcm450_aic_set_type,
> +};
> +
> +static int wpcm450_aic_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
> +{
> +	if (hwirq > IRQS)
> +		return -EPERM;
> +
> +	irq_set_chip_and_handler(irq, &wpcm450_aic_chip, handle_level_irq);
> +	irq_set_chip_data(irq, aic);
> +	irq_set_probe(irq);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops wpcm450_aic_ops = {
> +	.map = wpcm450_aic_map,
> +	.xlate = irq_domain_xlate_twocell,
> +};
> +
> +static int __init wpcm450_aic_of_init(struct device_node *node,
> +				      struct device_node *parent)
> +{
> +	if (parent)
> +		return -EINVAL;
> +
> +	aic = kzalloc(sizeof(*aic), GFP_KERNEL);
> +	if (!aic)
> +		return -ENOMEM;
> +
> +	aic->regs = of_iomap(node, 0);
> +	if (!aic->regs) {
> +		pr_err("Failed to map WPCM450 AIC registers\n");
> +		return -ENOMEM;
> +	}
> +
> +	wpcm450_aic_init_hw();
> +
> +	set_handle_irq(wpcm450_aic_handle_irq);
> +
> +	aic->domain = irq_domain_add_linear(node, IRQS, &wpcm450_aic_ops, aic);
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(wpcm450_aic, "nuvoton,wpcm450-aic", wpcm450_aic_of_init);

Otherwise, looks good.

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2021-03-24 17:17 UTC|newest]

Thread overview: 96+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-20 18:15 [PATCH 00/14] Initial support for Nuvoton WPCM450 BMC SoC Jonathan Neuschäfer
2021-03-20 18:15 ` Jonathan Neuschäfer
2021-03-20 18:15 ` Jonathan Neuschäfer
2021-03-20 18:15 ` [PATCH 01/14] dt-bindings: vendor-prefixes: Add Supermicro Jonathan Neuschäfer
2021-03-20 18:15   ` Jonathan Neuschäfer
2021-03-20 18:15   ` Jonathan Neuschäfer
2021-03-27 16:36   ` Rob Herring
2021-03-27 16:36     ` Rob Herring
2021-03-27 16:36     ` Rob Herring
2021-03-20 18:15 ` [PATCH 02/14] dt-bindings: arm: npcm: Add nuvoton,wpcm450 compatible string Jonathan Neuschäfer
2021-03-20 18:15   ` [PATCH 02/14] dt-bindings: arm: npcm: Add nuvoton, wpcm450 " Jonathan Neuschäfer
2021-03-20 18:15   ` Jonathan Neuschäfer
2021-03-27 16:36   ` Rob Herring
2021-03-27 16:36     ` Rob Herring
2021-03-27 16:36     ` Rob Herring
2021-03-20 18:15 ` [PATCH 03/14] dt-bindings: interrupt-controller: Add nuvoton,wpcm450-aic Jonathan Neuschäfer
2021-03-20 18:15   ` [PATCH 03/14] dt-bindings: interrupt-controller: Add nuvoton, wpcm450-aic Jonathan Neuschäfer
2021-03-20 18:15   ` Jonathan Neuschäfer
2021-03-27 16:37   ` Rob Herring
2021-03-27 16:37     ` Rob Herring
2021-03-27 16:37     ` Rob Herring
2021-03-20 18:16 ` [PATCH 04/14] dt-bindings: serial: 8250: Add nuvoton,wpcm450-uart Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-27 16:37   ` Rob Herring
2021-03-27 16:37     ` [PATCH 04/14] dt-bindings: serial: 8250: Add nuvoton, wpcm450-uart Rob Herring
2021-03-27 16:37     ` Rob Herring
2021-03-20 18:16 ` [PATCH 05/14] dt-bindings: timer: nuvoton,npcm7xx: Add wpcm450-timer Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-27 16:39   ` Rob Herring
2021-03-27 16:39     ` Rob Herring
2021-03-27 16:39     ` Rob Herring
2021-04-04 20:28   ` Daniel Lezcano
2021-04-04 20:28     ` Daniel Lezcano
2021-04-04 20:28     ` Daniel Lezcano
2021-04-09 10:27   ` [tip: timers/core] " tip-bot2 for Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 06/14] dt-bindings: watchdog: npcm: Add nuvoton,wpcm450-wdt Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-27 16:39   ` Rob Herring
2021-03-27 16:39     ` Rob Herring
2021-03-27 16:39     ` Rob Herring
2021-03-20 18:16 ` [PATCH 07/14] ARM: npcm: Introduce Nuvoton WPCM450 SoC Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 08/14] irqchip: Add driver for WPCM450 interrupt controller Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-24 17:16   ` Marc Zyngier [this message]
2021-03-24 17:16     ` Marc Zyngier
2021-03-24 17:16     ` Marc Zyngier
2021-03-26 18:52     ` Jonathan Neuschäfer
2021-03-26 18:52       ` Jonathan Neuschäfer
2021-03-26 18:52       ` Jonathan Neuschäfer
2021-04-05 17:25       ` Jonathan Neuschäfer
2021-04-05 17:25         ` Jonathan Neuschäfer
2021-04-05 17:25         ` Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 09/14] serial: 8250_of: Add nuvoton,wpcm450-uart Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 10/14] clocksource/drivers/npcm: Add support for WPCM450 Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-22 10:46   ` Daniel Lezcano
2021-03-22 10:46     ` Daniel Lezcano
2021-03-22 10:46     ` Daniel Lezcano
2021-04-09 10:27   ` [tip: timers/core] " tip-bot2 for Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 11/14] watchdog: npcm: " Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 20:24   ` Guenter Roeck
2021-03-20 20:24     ` Guenter Roeck
2021-03-20 20:24     ` Guenter Roeck
2021-03-20 20:43     ` Jonathan Neuschäfer
2021-03-20 20:43       ` Jonathan Neuschäfer
2021-03-20 20:43       ` Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 12/14] ARM: dts: Add devicetree for Nuvoton WPCM450 BMC chip Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 13/14] ARM: dts: Add devicetree for Supermicro X9SCi-LN4F based on WPCM450 Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:44   ` Jonathan Neuschäfer
2021-03-20 18:44     ` Jonathan Neuschäfer
2021-03-20 18:44     ` Jonathan Neuschäfer
2021-03-20 18:16 ` [PATCH 14/14] MAINTAINERS: Nuvoton NPCM: Add wpcm patterns Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:16   ` Jonathan Neuschäfer
2021-03-20 18:47 ` [PATCH 00/14] Initial support for Nuvoton WPCM450 BMC SoC Jonathan Neuschäfer
2021-03-20 18:47   ` Jonathan Neuschäfer
2021-03-20 18:47   ` Jonathan Neuschäfer
2021-03-21 11:07 ` Tomer Maimon
2021-03-21 12:31   ` Jonathan Neuschäfer
2021-03-21 12:31     ` Jonathan Neuschäfer
2021-03-21 12:31     ` Jonathan Neuschäfer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87sg4kiia4.wl-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=avifishman70@gmail.com \
    --cc=benjaminfair@google.com \
    --cc=devicetree@vger.kernel.org \
    --cc=j.neuschaefer@gmx.net \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=openbmc@lists.ozlabs.org \
    --cc=tali.perry1@gmail.com \
    --cc=tglx@linutronix.de \
    --cc=tmaimon77@gmail.com \
    --cc=venture@google.com \
    --cc=yuenn@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.