From patchwork Tue Apr 6 12:09:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?J=2E_Neusch=C3=A4fer?= X-Patchwork-Id: 12185103 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60A33C433ED for ; Tue, 6 Apr 2021 12:13:48 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 94E31613C4 for ; Tue, 6 Apr 2021 12:13:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 94E31613C4 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmx.net Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=DM86fiu5ZEgui/rjnIhTHv8XLCZEKLqQQGcwZmeOoQs=; b=bqTJ+w+O3niINmD8pKfc/zM7M luIjypzCSBmM/6qFm8oyvzxMnBlF19GirFHV3NmntGS2vKvbX9GU/dRAXHhJdweN/OVcDjBfVZFMi tAKyMXeSXJq0qp2W80vVYYie3jA4wON6wXOss8TRxEQCeYdqcNyNjeTASAMNadeuvqEEglgH1YaAI zd/Ni8JpWb4FLGBF/lceuySX9gFZ8aemAIHeouP/c/dsVcaaHqz+C1pTTD5COluzmX1UGDI///PN1 qiUFPotPTJutGngIYCXxdv0hyzN36eO8n8f37r/vhU2oQiOABKgkXgp1Dna8Cp1jmsIdqdLMmGcUm 1R76iFPyA==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lTkY7-002WEg-Ao; Tue, 06 Apr 2021 12:11:15 +0000 Received: from mout.gmx.net ([212.227.17.22]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lTkXv-002WAt-N5 for linux-arm-kernel@lists.infradead.org; Tue, 06 Apr 2021 12:11:06 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1617711051; bh=FYOblBUbHRlSqo0KG/HksG7r9RNT7O0AdZ2/oD/Ognw=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=RaH/JCpVSXdwQjn+FNBZ/SQLlrLqpd+q3r505SnLpijrBPCWzMGARAvLue/FEcWm/ 83VA1gUHuDSE6bkFhOQtI7WXhk2NvRmBi1scQnx4Fj94alk4+W+nDe41M/PTOYOORn nNq7UK0Ew8wDzcdWtDmUSKYjtr55Mz2IJQIczVOQ= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from longitude ([37.201.215.134]) by mail.gmx.net (mrgmx104 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MRTRN-1lFfVW1NnZ-00NPRq; Tue, 06 Apr 2021 14:10:51 +0200 From: =?utf-8?q?Jonathan_Neusch=C3=A4fer?= To: openbmc@lists.ozlabs.org Cc: Tomer Maimon , Joel Stanley , devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, =?utf-8?q?Jonathan_Neusch=C3=A4fer?= , Avi Fishman , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Russell King , Thomas Gleixner , Marc Zyngier Subject: [PATCH v2 06/10] irqchip: Add driver for WPCM450 interrupt controller Date: Tue, 6 Apr 2021 14:09:17 +0200 Message-Id: <20210406120921.2484986-7-j.neuschaefer@gmx.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210406120921.2484986-1-j.neuschaefer@gmx.net> References: <20210406120921.2484986-1-j.neuschaefer@gmx.net> MIME-Version: 1.0 X-Provags-ID: V03:K1:hefIZlOtQ+LbUsf9BJMTwfPpAhYwakBaowyBoCpHN/A5qME7nVV rDAsFv0ZibsTdppttyGMkqh81M7g6z9CtYIgiOpTxybu7hPI8crW3LRsZMmA571f8l+IxKw vRWo/zEhH0YknrATgoKP6qA5kBVDSBegfDwrOnpaqZLujH5Jt1Llu7BcFmGpthLUrwjFB16 xKbDnu8zAvDaUV0orGhiQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:zwygWbOrTOo=:HtR7OlXL/+jYezqulrWYYL ThpapzqeSaNDM3oVxkecDOeWVEkqorKyAU9ye5hXg5pSA3j9kmIlfGwpynZWklNKua8HObrjl NvXH6K3EEzIZZStnS3anOUnZv85jH8RyU4P/9ztaBcRooUr8XXjm39JBQtHwk5y6MiCga6ToA YqSumWPu2VO1L4odTw+V4qoGx9npaQ9BjLap0DleWKV5o3Si0L9ykflZbCEfxOxkbAoZpOYlz s4SXUjRzowamINhZAqPqkYz0OTw7wqydiSIapkTaTMGCXo5RwvS45sY05bV9FRu5mXGTzeuql aYEdT6g86mH3f2hUHSfdvnWik7dN8g88p595O8945v8DBS7X7mXJA3B3YpzNK5Mi2FtHguxgl V4pz9+TDaxHO0JY/I1OkMA18MEyamVN7CwEqVSc2Zrm34rres19qLHd2V2PQx32bI4qQAElO6 osibLYsj3JUtEgDIwvMeqYaIJtCkkyTLeUGHc3smpj1kFnP3CvystnhAvfxXgo8IeB0RJb756 tmkoCwS6mCsfDsGkKuqdIki7sI2ZvvWkJdlFycUOg0a3x4qPrAx7H8pQWLUlqUVmz7WJz7J2x 9U6EgGHGfbRGChSIXlC+k/hgC9elVaFxvglxt6rRMmLWCdxiZB+gc08c424vcxvKmQoCiEvb6 O18IU44HxoJvzE2c9vqxixqQVD270d0llT2nVC6sttYEWSnRCuunYHpz3jMASi5f1Go6vBeFk FnLinZrL3+lAZxfAmeqTuZcRKDlxaOr7CNIOVfOMXEqlgVjZxeYyeK7s0E3g/BIGNCLFfIowO 9BYD8Z/GP02BL5iEgbWzQEvHxJVfgHaWIBOCqIKijKbR0qfoAKbMadlXhVMJrTBiOYaIjY0K7 EAZC2DEw+NWpaF7IruG5UtrcWY9wss/DDXQjtXdSmx5ZMPuYqaWVfI2G3NtxltfixTyF746NV Ywqr/TYgQ+mpKAx4M43yDfY5blbObRrG6Sj6/VtYUmXXtdy2Ne6tySPU2j54Idd035TCnlsab VJ4HkulU4ZETqTh1NQhE1OYJUpkUAwyRFGerJNqSZVCDCtvF+qMC43JsuznqbqH68cxK9B4nC FY693+70sX1H0icDyCRtRm2Ecdc5g5YPW9vzfE5oqYdaVeNqXVV/39T30/y665K3IY5GO1/Jw Pnkb3jGAmhFjn9B9BbPdtRBwDH1NTcuFtg6Sf4uUEWjR0AIQfFrmvdj4FY3n8Gx0j+kJ0lFk8 lk1IAzuPtP441C8CG X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210406_131103_970954_62E1DAFD X-CRM114-Status: GOOD ( 26.53 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org 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 --- v2: - Rename IRQS macro to AIC_NUM_IRQS - Fix IRQ range check - Use linux/printk.h header instead of linux/console.h - Add AIC_SCR_PRIORITY_MASK constant - Add missing register descriptions - Remove superfluous printk about IRQ flow type mismatch - Use BIT() macro - Rename _ack function to _eoi for accuracy, and use handle_fasteoi_irq --- arch/arm/mach-npcm/Kconfig | 1 + drivers/irqchip/Kconfig | 6 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-wpcm450-aic.c | 161 ++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 drivers/irqchip/irq-wpcm450-aic.c -- 2.30.2 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..f3ac392d5bc87 --- /dev/null +++ b/drivers/irqchip/irq-wpcm450-aic.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2021 Jonathan Neuschäfer + +#include +#include +#include +#include + +#include + +#define AIC_SCR(x) ((x)*4) /* Source control registers */ +#define AIC_GEN 0x84 /* Interrupt group enable control register */ +#define AIC_GRSR 0x88 /* Interrupt group raw status register */ +#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) +#define AIC_SCR_PRIORITY_MASK 0x7 + +#define AIC_NUM_IRQS 32 + +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); + + /* + * 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 < AIC_NUM_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_eoi(struct irq_data *d) +{ + /* Signal end-of-service */ + writel(0, aic->regs + AIC_EOSCR); +} + +static void wpcm450_aic_mask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + /* Disable (mask) the interrupt */ + writel(mask, aic->regs + AIC_MDCR); +} + +static void wpcm450_aic_unmask(struct irq_data *d) +{ + unsigned int mask = BIT(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) + return -EINVAL; + + return 0; +} + +static struct irq_chip wpcm450_aic_chip = { + .name = "wpcm450-aic", + .irq_eoi = wpcm450_aic_eoi, + .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 >= AIC_NUM_IRQS) + return -EPERM; + + irq_set_chip_and_handler(irq, &wpcm450_aic_chip, handle_fasteoi_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, AIC_NUM_IRQS, &wpcm450_aic_ops, aic); + + return 0; +} + +IRQCHIP_DECLARE(wpcm450_aic, "nuvoton,wpcm450-aic", wpcm450_aic_of_init);