linux/drivers/irqchip/irq-realtek-rtl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2020 Birger Koblitz <mail@birger-koblitz.de>
   4 * Copyright (C) 2020 Bert Vermeulen <bert@biot.com>
   5 * Copyright (C) 2020 John Crispin <john@phrozen.org>
   6 */
   7
   8#include <linux/of_irq.h>
   9#include <linux/irqchip.h>
  10#include <linux/spinlock.h>
  11#include <linux/of_address.h>
  12#include <linux/irqchip/chained_irq.h>
  13
  14/* Global Interrupt Mask Register */
  15#define RTL_ICTL_GIMR           0x00
  16/* Global Interrupt Status Register */
  17#define RTL_ICTL_GISR           0x04
  18/* Interrupt Routing Registers */
  19#define RTL_ICTL_IRR0           0x08
  20#define RTL_ICTL_IRR1           0x0c
  21#define RTL_ICTL_IRR2           0x10
  22#define RTL_ICTL_IRR3           0x14
  23
  24#define REG(x)          (realtek_ictl_base + x)
  25
  26static DEFINE_RAW_SPINLOCK(irq_lock);
  27static void __iomem *realtek_ictl_base;
  28
  29static void realtek_ictl_unmask_irq(struct irq_data *i)
  30{
  31        unsigned long flags;
  32        u32 value;
  33
  34        raw_spin_lock_irqsave(&irq_lock, flags);
  35
  36        value = readl(REG(RTL_ICTL_GIMR));
  37        value |= BIT(i->hwirq);
  38        writel(value, REG(RTL_ICTL_GIMR));
  39
  40        raw_spin_unlock_irqrestore(&irq_lock, flags);
  41}
  42
  43static void realtek_ictl_mask_irq(struct irq_data *i)
  44{
  45        unsigned long flags;
  46        u32 value;
  47
  48        raw_spin_lock_irqsave(&irq_lock, flags);
  49
  50        value = readl(REG(RTL_ICTL_GIMR));
  51        value &= ~BIT(i->hwirq);
  52        writel(value, REG(RTL_ICTL_GIMR));
  53
  54        raw_spin_unlock_irqrestore(&irq_lock, flags);
  55}
  56
  57static struct irq_chip realtek_ictl_irq = {
  58        .name = "realtek-rtl-intc",
  59        .irq_mask = realtek_ictl_mask_irq,
  60        .irq_unmask = realtek_ictl_unmask_irq,
  61};
  62
  63static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
  64{
  65        irq_set_chip_and_handler(hw, &realtek_ictl_irq, handle_level_irq);
  66
  67        return 0;
  68}
  69
  70static const struct irq_domain_ops irq_domain_ops = {
  71        .map = intc_map,
  72        .xlate = irq_domain_xlate_onecell,
  73};
  74
  75static void realtek_irq_dispatch(struct irq_desc *desc)
  76{
  77        struct irq_chip *chip = irq_desc_get_chip(desc);
  78        struct irq_domain *domain;
  79        unsigned int pending;
  80
  81        chained_irq_enter(chip, desc);
  82        pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR));
  83        if (unlikely(!pending)) {
  84                spurious_interrupt();
  85                goto out;
  86        }
  87        domain = irq_desc_get_handler_data(desc);
  88        generic_handle_domain_irq(domain, __ffs(pending));
  89
  90out:
  91        chained_irq_exit(chip, desc);
  92}
  93
  94/*
  95 * SoC interrupts are cascaded to MIPS CPU interrupts according to the
  96 * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
  97 * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
  98 * thus go into 4 IRRs.
  99 */
 100static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
 101{
 102        struct device_node *cpu_ictl;
 103        const __be32 *imap;
 104        u32 imaplen, soc_int, cpu_int, tmp, regs[4];
 105        int ret, i, irr_regs[] = {
 106                RTL_ICTL_IRR3,
 107                RTL_ICTL_IRR2,
 108                RTL_ICTL_IRR1,
 109                RTL_ICTL_IRR0,
 110        };
 111        u8 mips_irqs_set;
 112
 113        ret = of_property_read_u32(node, "#address-cells", &tmp);
 114        if (ret || tmp)
 115                return -EINVAL;
 116
 117        imap = of_get_property(node, "interrupt-map", &imaplen);
 118        if (!imap || imaplen % 3)
 119                return -EINVAL;
 120
 121        mips_irqs_set = 0;
 122        memset(regs, 0, sizeof(regs));
 123        for (i = 0; i < imaplen; i += 3 * sizeof(u32)) {
 124                soc_int = be32_to_cpup(imap);
 125                if (soc_int > 31)
 126                        return -EINVAL;
 127
 128                cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1));
 129                if (!cpu_ictl)
 130                        return -EINVAL;
 131                ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp);
 132                if (ret || tmp != 1)
 133                        return -EINVAL;
 134                of_node_put(cpu_ictl);
 135
 136                cpu_int = be32_to_cpup(imap + 2);
 137                if (cpu_int > 7)
 138                        return -EINVAL;
 139
 140                if (!(mips_irqs_set & BIT(cpu_int))) {
 141                        irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch,
 142                                                         domain);
 143                        mips_irqs_set |= BIT(cpu_int);
 144                }
 145
 146                regs[(soc_int * 4) / 32] |= cpu_int << (soc_int * 4) % 32;
 147                imap += 3;
 148        }
 149
 150        for (i = 0; i < 4; i++)
 151                writel(regs[i], REG(irr_regs[i]));
 152
 153        return 0;
 154}
 155
 156static int __init realtek_rtl_of_init(struct device_node *node, struct device_node *parent)
 157{
 158        struct irq_domain *domain;
 159        int ret;
 160
 161        realtek_ictl_base = of_iomap(node, 0);
 162        if (!realtek_ictl_base)
 163                return -ENXIO;
 164
 165        /* Disable all cascaded interrupts */
 166        writel(0, REG(RTL_ICTL_GIMR));
 167
 168        domain = irq_domain_add_simple(node, 32, 0,
 169                                       &irq_domain_ops, NULL);
 170
 171        ret = map_interrupts(node, domain);
 172        if (ret) {
 173                pr_err("invalid interrupt map\n");
 174                return ret;
 175        }
 176
 177        return 0;
 178}
 179
 180IRQCHIP_DECLARE(realtek_rtl_intc, "realtek,rtl-intc", realtek_rtl_of_init);
 181