From patchwork Tue Oct 30 10:44:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Edworthy X-Patchwork-Id: 10660661 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 00FFD14E2 for ; Tue, 30 Oct 2018 10:45:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DA13629CD6 for ; Tue, 30 Oct 2018 10:45:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CDEE329CFA; Tue, 30 Oct 2018 10:45:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5B9C029CD6 for ; Tue, 30 Oct 2018 10:45:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727565AbeJ3TiA (ORCPT ); Tue, 30 Oct 2018 15:38:00 -0400 Received: from relmlor3.renesas.com ([210.160.252.173]:38508 "EHLO relmlie2.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726692AbeJ3TiA (ORCPT ); Tue, 30 Oct 2018 15:38:00 -0400 Received: from unknown (HELO relmlir3.idc.renesas.com) ([10.200.68.153]) by relmlie2.idc.renesas.com with ESMTP; 30 Oct 2018 19:45:01 +0900 Received: from relmlii2.idc.renesas.com (relmlii2.idc.renesas.com [10.200.68.66]) by relmlir3.idc.renesas.com (Postfix) with ESMTP id 95F1F95E51; Tue, 30 Oct 2018 19:45:01 +0900 (JST) X-IronPort-AV: E=Sophos;i="5.54,444,1534777200"; d="scan'208";a="296394853" Received: from unknown (HELO vbox.ree.adwin.renesas.com) ([10.226.37.67]) by relmlii2.idc.renesas.com with ESMTP; 30 Oct 2018 19:44:58 +0900 From: Phil Edworthy To: Marc Zyngier , Thomas Gleixner , Jason Cooper , Rob Herring , Mark Rutland Cc: Geert Uytterhoeven , linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Phil Edworthy , devicetree@vger.kernel.org Subject: [PATCH v2 1/2] dt-bindings/interrupt-controller: rzn1: Add RZ/N1 gpio irq mux binding Date: Tue, 30 Oct 2018 10:44:37 +0000 Message-Id: <20181030104438.27827-2-phil.edworthy@renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181030104438.27827-1-phil.edworthy@renesas.com> References: <20181030104438.27827-1-phil.edworthy@renesas.com> Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add device binding documentation for the Renesas RZ/N1 GPIO interrupt multiplexer. Signed-off-by: Phil Edworthy --- v2: - Use interrupt-map to allow the GPIO controller info to be specified as part of the irq. - Don't show status in binding examples. - Don't show the soc/board split in binding doc. --- .../interrupt-controller/renesas,rzn1-mux.txt | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/renesas,rzn1-mux.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzn1-mux.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzn1-mux.txt new file mode 100644 index 000000000000..0b4ba27c00ef --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzn1-mux.txt @@ -0,0 +1,92 @@ +* Renesas RZ/N1 GPIO Interrupt Multiplexer + +On Renesas RZ/N1 devices, there are several GPIO Controllers each with a number +of interrupt outputs. All of the interrupts from the GPIO Controllers are passed +to the GPIO Interrupt Multiplexer, which selects a sub-set of the interrupts to +pass onto the system interrupt controller. + +A single node in the device tree is used to describe the GPIO IRQ Muxer. + +Required properties: +- compatible: SoC-specific compatible string "renesas,-gpioirqmux" + followed by "renesas,rzn1-gpioirqmux" as fallback. The SoC-specific compatible + strings must be one of: + "renesas,r9a06g032-gpioirqmux" for RZ/N1D + "renesas,r9a06g033-gpioirqmux" for RZ/N1S +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: should be <1>. The meaning of the cells is the input + interrupt index, 0 to 95. +- reg: Base address and size of GPIO IRQ Muxer registers. +- interrupts: This is a list of interrupt specifiers. Each interrupt consists of + three numbers that represent: + - (a) the index of the GPIO Interrupt Multiplexer output interrupt (0..7) + - (b) the index of the GPIO Controller input interrupt (0..2) + - (c) the interrupt index of the GPIO Controller input interrupt (0..31). +- interrupt-parent: A phandle for a local node that specifies an interrupt-map. + The interrupt-map node must specify #interrupt-cells = <3>, and an + interrupt-map property. The interrupt-map is used to translate the interrupt + specifier to the output interrupts. It is used in conjunction with an + interrupt-map-mask property to mask (b) and (c) from the interrupt specifier + so that essentially there is a direct map from (a) to the output interrupt. + Therefore (b) and (c) can be used to determine the interrupt source and + configure the hardware accordingly. For information on interrupts, + see Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example: + + The following is an example for the RZ/N1D SoC. + + gpioirqmux: gpioirqmux@51000480 { + compatible = "renesas,r9a06g032-gpioirqmux", + "renesas,rzn1-gpioirqmux"; + reg = <0x51000480 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gpioirqmux_map>; + interrupts = + <0 1 17>, /* gpio1a 17 */ + <1 1 24>, /* gpio1a 24 */ + <2 1 26>; /* gpio1a 26 */ + + gpioirqmux_map: gpioirqmux-map { + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-map-mask = <7 0 0>; + interrupt-map = + <0 0 0 &gic GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, + <1 0 0 &gic GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, + <2 0 0 &gic GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, + <3 0 0 &gic GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>, + <4 0 0 &gic GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, + <5 0 0 &gic GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, + <6 0 0 &gic GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>, + <7 0 0 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio1: gpio@5000c000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x5000c000 0x80>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "bus"; + clocks = <&sysctrl R9A06G032_HCLK_GPIO1>; + + gpio1a: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + bank-name = "gpio1a"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <32>; + reg = <0>; + + interrupt-controller; + interrupt-parent = <&gpioirqmux>; + interrupts = < 0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31 >; + #interrupt-cells = <2>; + }; + }; From patchwork Tue Oct 30 10:44:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Edworthy X-Patchwork-Id: 10660663 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E9D4213B5 for ; Tue, 30 Oct 2018 10:45:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D08C229CCA for ; Tue, 30 Oct 2018 10:45:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C416A29CD6; Tue, 30 Oct 2018 10:45:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0A33929CCA for ; Tue, 30 Oct 2018 10:45:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727566AbeJ3TiM (ORCPT ); Tue, 30 Oct 2018 15:38:12 -0400 Received: from relmlor4.renesas.com ([210.160.252.174]:12424 "EHLO relmlie3.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727558AbeJ3TiM (ORCPT ); Tue, 30 Oct 2018 15:38:12 -0400 Received: from unknown (HELO relmlir3.idc.renesas.com) ([10.200.68.153]) by relmlie3.idc.renesas.com with ESMTP; 30 Oct 2018 19:45:12 +0900 Received: from relmlii2.idc.renesas.com (relmlii2.idc.renesas.com [10.200.68.66]) by relmlir3.idc.renesas.com (Postfix) with ESMTP id B20E895EDF; Tue, 30 Oct 2018 19:45:12 +0900 (JST) X-IronPort-AV: E=Sophos;i="5.54,444,1534777200"; d="scan'208";a="296394891" Received: from unknown (HELO vbox.ree.adwin.renesas.com) ([10.226.37.67]) by relmlii2.idc.renesas.com with ESMTP; 30 Oct 2018 19:45:10 +0900 From: Phil Edworthy To: Marc Zyngier , Thomas Gleixner , Jason Cooper Cc: Geert Uytterhoeven , linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Phil Edworthy Subject: [PATCH v2 2/2] irqchip: Add support for Renesas RZ/N1 GPIO interrupt multiplexer Date: Tue, 30 Oct 2018 10:44:38 +0000 Message-Id: <20181030104438.27827-3-phil.edworthy@renesas.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181030104438.27827-1-phil.edworthy@renesas.com> References: <20181030104438.27827-1-phil.edworthy@renesas.com> Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On RZ/N1 devices, there are 3 Synopsys DesignWare GPIO blocks each configured to have 32 interrupt outputs, so we have a total of 96 GPIO interrupts. All of these are passed to the GPIO IRQ Muxer, which selects 8 of the GPIO interrupts to pass onto the GIC. The interrupt signals aren't latched, so there is nothing to do in this driver when an interrupt is received, other than tell the corresponding GPIO block. Signed-off-by: Phil Edworthy --- v2: - Use interrupt-map to allow the GPIO controller info to be specified as part of the irq. - Renamed struct and funcs from 'girq' to a more comprehenisble 'irqmux'. --- drivers/irqchip/Kconfig | 10 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/rzn1-irq-mux.c | 235 +++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/irqchip/rzn1-irq-mux.c diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 96451b581452..3a60a8af60dd 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -204,6 +204,16 @@ config RENESAS_IRQC select GENERIC_IRQ_CHIP select IRQ_DOMAIN +config RENESAS_RZN1_IRQ_MUX + bool "Renesas RZ/N1 GPIO IRQ multiplexer support" + depends on ARCH_RZN1 + select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY + help + Say yes here to add support for the GPIO IRQ multiplexer embedded + in Renesas RZ/N1 SoC devices. The GPIO IRQ Muxer selects which of + the interrupts coming from the GPIO controllers are used. + config ST_IRQCHIP bool select REGMAP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index b822199445ff..b090f84dd42e 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o +obj-$(CONFIG_RENESAS_RZN1_IRQ_MUX) += rzn1-irq-mux.o obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o diff --git a/drivers/irqchip/rzn1-irq-mux.c b/drivers/irqchip/rzn1-irq-mux.c new file mode 100644 index 000000000000..767ce67e34d2 --- /dev/null +++ b/drivers/irqchip/rzn1-irq-mux.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RZ/N1 GPIO Interrupt Multiplexer + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * On RZ/N1 devices, there are 3 Synopsys DesignWare GPIO blocks each configured + * to have 32 interrupt outputs, so we have a total of 96 GPIO interrupts. + * All of these are passed to the GPIO IRQ Muxer, which selects 8 of the GPIO + * interrupts to pass onto the GIC. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_IRQ_SPEC_SIZE 3 +#define MAX_NR_GPIO_CONTROLLERS 3 +#define MAX_NR_GPIO_IRQ 32 +#define MAX_NR_INPUT_IRQS (MAX_NR_GPIO_CONTROLLERS * MAX_NR_GPIO_IRQ) +#define MAX_NR_OUTPUT_IRQS 8 + +struct irqmux_priv; +struct irqmux_one { + unsigned int mapped_irq; + unsigned int input_irq_nr; + struct irqmux_priv *priv; +}; + +struct irqmux_priv { + struct device *dev; + struct irq_chip irq_chip; + struct irq_domain *irq_domain; + unsigned int nr_irqs; + struct irqmux_one irq[MAX_NR_OUTPUT_IRQS]; +}; + +static void irqmux_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irqmux_one *girq = irq_desc_get_handler_data(desc); + struct irqmux_priv *priv = girq->priv; + unsigned int irq; + + chained_irq_enter(chip, desc); + + irq = irq_find_mapping(priv->irq_domain, girq->input_irq_nr); + generic_handle_irq(irq); + + chained_irq_exit(chip, desc); +} + +static int irqmux_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct irqmux_priv *priv = h->host_data; + + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &priv->irq_chip, handle_simple_irq); + + return 0; +} + +static const struct irq_domain_ops irqmux_domain_ops = { + .map = irqmux_domain_map, +}; + +static int irqmux_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + u32 __iomem *regs; + struct irqmux_priv *priv; + u32 int_specs[MAX_NR_OUTPUT_IRQS][GPIO_IRQ_SPEC_SIZE]; + DECLARE_BITMAP(irqs_in_used, MAX_NR_INPUT_IRQS); + unsigned int irqs_out_used = 0; + unsigned int i; + int nr_irqs; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + platform_set_drvdata(pdev, priv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + nr_irqs = of_irq_count(np); + if (nr_irqs < 0) + return nr_irqs; + + if (nr_irqs > MAX_NR_OUTPUT_IRQS) { + dev_err(dev, "too many output interrupts\n"); + return -ENOENT; + } + + priv->nr_irqs = nr_irqs; + + /* Get the interrupt specifers */ + if (of_property_read_u32_array(dev->of_node, "interrupts", + (u32 *)int_specs, + priv->nr_irqs * GPIO_IRQ_SPEC_SIZE)) { + dev_err(dev, "cannot get interrupt specifiers\n"); + return -ENOENT; + } + + bitmap_zero(irqs_in_used, MAX_NR_INPUT_IRQS); + + /* Check the interrupt specifiers */ + for (i = 0; i < priv->nr_irqs; i++) { + u32 *int_spec = int_specs[i]; + u32 input_irq = int_spec[1] * MAX_NR_GPIO_IRQ + int_spec[2]; + + dev_info(dev, "irq %u=gpio%ua:%u\n", int_spec[0], int_spec[1], + int_spec[2]); + + if (int_spec[0] >= MAX_NR_OUTPUT_IRQS || + int_spec[1] >= MAX_NR_GPIO_CONTROLLERS || + int_spec[2] >= MAX_NR_GPIO_IRQ) { + dev_err(dev, "invalid interrupt args\n"); + return -ENOENT; + } + + if (irqs_out_used & BIT(int_spec[0]) || + test_bit(input_irq, irqs_in_used)) { + dev_err(dev, "irq %d already used\n", i); + return -ENOENT; + } + + irqs_out_used |= BIT(int_spec[0]); + set_bit(input_irq, irqs_in_used); + } + + /* Create IRQ domain for the interrupts coming from the GPIO blocks */ + priv->irq_chip.name = dev_name(dev); + priv->irq_domain = irq_domain_add_linear(np, MAX_NR_INPUT_IRQS, + &irqmux_domain_ops, priv); + if (!priv->irq_domain) + return -ENOMEM; + + /* Setup the interrupts */ + for (i = 0; i < priv->nr_irqs; i++) { + struct of_phandle_args ofirq; + u32 *int_spec = int_specs[i]; + u32 input_irq = int_spec[1] * MAX_NR_GPIO_IRQ + int_spec[2]; + struct irqmux_one *irq = &priv->irq[i]; + + if (of_irq_parse_one(dev->of_node, i, &ofirq)) { + ret = -ENOENT; + goto err; + } + + priv->irq[i].mapped_irq = irq_create_of_mapping(&ofirq); + if (!priv->irq[i].mapped_irq) { + dev_err(dev, "cannot get interrupt\n"); + ret = -ENOENT; + goto err; + } + + irq->priv = priv; + irq->input_irq_nr = input_irq; + + irq_set_chained_handler_and_data(irq->mapped_irq, + irqmux_handler, irq); + + /* Set up the hardware to pass the interrupt through */ + writel(irq->input_irq_nr, ®s[int_spec[0]]); + } + + dev_info(dev, "probed, %d gpio interrupts\n", priv->nr_irqs); + + return 0; + +err: + while (i--) { + struct irqmux_one *irq = &priv->irq[i]; + + irq_set_chained_handler_and_data(irq->mapped_irq, NULL, NULL); + irq_dispose_mapping(irq->mapped_irq); + } + irq_domain_remove(priv->irq_domain); + + return 0; +} + +static int irqmux_remove(struct platform_device *pdev) +{ + struct irqmux_priv *priv = platform_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < priv->nr_irqs; i++) { + struct irqmux_one *irq = &priv->irq[i]; + + irq_set_chained_handler_and_data(irq->mapped_irq, NULL, NULL); + irq_dispose_mapping(irq->mapped_irq); + } + irq_domain_remove(priv->irq_domain); + + return 0; +} + +static const struct of_device_id irqmux_match[] = { + { .compatible = "renesas,rzn1-gpioirqmux", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, irqmux_match); + +static struct platform_driver irqmux_driver = { + .driver = { + .name = "gpio_irq_mux", + .owner = THIS_MODULE, + .of_match_table = irqmux_match, + }, + .probe = irqmux_probe, + .remove = irqmux_remove, +}; + +module_platform_driver(irqmux_driver); + +MODULE_DESCRIPTION("Renesas RZ/N1 GPIO IRQ Multiplexer Driver"); +MODULE_AUTHOR("Phil Edworthy "); +MODULE_LICENSE("GPL v2");