lkml.org 
[lkml]   [2018]   [Oct]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC v2 3/7] irqchip/rtl8186: Add RTL8186 interrupt controller driver
    Date
    The Realtek RTL8186 SoC is a MIPS based SoC
    used in some home routers [1][2].

    This adds a driver to handle the interrupt controller
    on this SoC.

    [1] https://www.linux-mips.org/wiki/Realtek_SOC#Realtek_RTL8186
    [2] https://wikidevi.com/wiki/Realtek_RTL8186

    Signed-off-by: Yasha Cherikovsky <yasha.che3@gmail.com>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Cc: Paul Burton <paul.burton@mips.com>
    Cc: James Hogan <jhogan@kernel.org>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Jason Cooper <jason@lakedaemon.net>
    Cc: Marc Zyngier <marc.zyngier@arm.com>
    Cc: Rob Herring <robh+dt@kernel.org>
    Cc: Mark Rutland <mark.rutland@arm.com>
    Cc: linux-mips@linux-mips.org
    Cc: devicetree@vger.kernel.org
    Cc: linux-kernel@vger.kernel.org
    ---
    drivers/irqchip/Kconfig | 5 ++
    drivers/irqchip/Makefile | 1 +
    drivers/irqchip/irq-rtl8186.c | 107 ++++++++++++++++++++++++++++++++++
    3 files changed, 113 insertions(+)
    create mode 100644 drivers/irqchip/irq-rtl8186.c

    diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
    index e9233db16e03..83099905a871 100644
    --- a/drivers/irqchip/Kconfig
    +++ b/drivers/irqchip/Kconfig
    @@ -371,4 +371,9 @@ config QCOM_PDC
    Power Domain Controller driver to manage and configure wakeup
    IRQs for Qualcomm Technologies Inc (QTI) mobile chips.

    +config RTL8186_IRQ
    + bool
    + depends on MACH_RTL8186
    + select IRQ_DOMAIN
    +
    endmenu
    diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
    index 15f268f646bf..2e0bb859a8f4 100644
    --- a/drivers/irqchip/Makefile
    +++ b/drivers/irqchip/Makefile
    @@ -87,3 +87,4 @@ obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
    obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
    obj-$(CONFIG_NDS32) += irq-ativic32.o
    obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
    +obj-$(CONFIG_RTL8186_IRQ) += irq-rtl8186.o
    diff --git a/drivers/irqchip/irq-rtl8186.c b/drivers/irqchip/irq-rtl8186.c
    new file mode 100644
    index 000000000000..3eb6b947d5a0
    --- /dev/null
    +++ b/drivers/irqchip/irq-rtl8186.c
    @@ -0,0 +1,107 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Realtek RTL8186 SoC interrupt controller driver.
    + *
    + * Copyright (C) 2018 Yasha Cherikovsky
    + */
    +
    +#include <linux/init.h>
    +#include <linux/interrupt.h>
    +#include <linux/irq.h>
    +#include <linux/irqchip.h>
    +#include <linux/irqdomain.h>
    +#include <linux/of.h>
    +#include <linux/of_address.h>
    +
    +#define RTL8186_NR_IRQS 11
    +
    +#define GIMR 0x00
    +#define GISR 0x04
    +
    +static struct {
    + void __iomem *base;
    + struct irq_domain *domain;
    +} intc;
    +
    +
    +asmlinkage void plat_irq_dispatch(void)
    +{
    + u32 hwirq, virq;
    + u32 gimr = readl(intc.base + GIMR);
    + u32 gisr = readl(intc.base + GISR);
    + u32 pending = gimr & gisr & ((1 << RTL8186_NR_IRQS) - 1);
    +
    + if (!pending) {
    + spurious_interrupt();
    + return;
    + }
    +
    + while (pending) {
    + hwirq = fls(pending) - 1;
    + virq = irq_linear_revmap(intc.domain, hwirq);
    + do_IRQ(virq);
    + pending &= ~BIT(hwirq);
    + }
    +}
    +
    +static void rtl8186_irq_mask(struct irq_data *data)
    +{
    + unsigned long irq = data->hwirq;
    +
    + writel(readl(intc.base + GIMR) & (~(BIT(irq))), intc.base + GIMR);
    +}
    +
    +static void rtl8186_irq_unmask(struct irq_data *data)
    +{
    + unsigned long irq = data->hwirq;
    +
    + writel((readl(intc.base + GIMR) | (BIT(irq))), intc.base + GIMR);
    +}
    +
    +static struct irq_chip rtl8186_irq_chip = {
    + .name = "RTL8186",
    + .irq_mask = rtl8186_irq_mask,
    + .irq_unmask = rtl8186_irq_unmask,
    +};
    +
    +static int rtl8186_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
    + irq_hw_number_t hw)
    +{
    + irq_set_chip_and_handler(virq, &rtl8186_irq_chip, handle_level_irq);
    + return 0;
    +}
    +
    +static const struct irq_domain_ops rtl8186_irq_ops = {
    + .map = rtl8186_intc_irq_domain_map,
    + .xlate = irq_domain_xlate_onecell,
    +};
    +
    +static int __init rtl8186_intc_of_init(struct device_node *node,
    + struct device_node *parent)
    +{
    + intc.base = of_io_request_and_map(node, 0, of_node_full_name(node));
    +
    + if (IS_ERR(intc.base))
    + panic("%pOF: unable to map resource", node);
    +
    + intc.domain = irq_domain_add_linear(node, RTL8186_NR_IRQS,
    + &rtl8186_irq_ops, NULL);
    +
    + if (!intc.domain)
    + panic("%pOF: unable to create IRQ domain\n", node);
    +
    + /* Start with all interrupts disabled */
    + writel(0, intc.base + GIMR);
    +
    + /*
    + * Enable all hardware interrupts in CP0 status register.
    + * Software interrupts are disabled.
    + */
    + set_c0_status(ST0_IM);
    + clear_c0_status(STATUSF_IP0 | STATUSF_IP1);
    + clear_c0_cause(CAUSEF_IP);
    +
    + return 0;
    +}
    +
    +IRQCHIP_DECLARE(rtl8186_intc, "realtek,rtl8186-intc", rtl8186_intc_of_init);
    --
    2.19.0
    \
     
     \ /
      Last update: 2018-10-01 12:31    [W:4.609 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site