/*
* Realtek RTL83XX architecture specific IRQ handling
*
- * Copyright (C) 2020 B. Koblitz
* based on the original BSP
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
- *
+ * Copyright (C) 2020 B. Koblitz
+ * Copyright (C) 2020 Bert Vermeulen <bert@biot.com>
+ * Copyright (C) 2020 John Crispin <john@phrozen.org>
*/
#include <linux/irqchip.h>
#include <linux/spinlock.h>
#include <linux/of_address.h>
#include <asm/irq_cpu.h>
+#include <linux/of_irq.h>
#include <asm/cevt-r4k.h>
#include <mach-rtl83xx.h>
#include "irq.h"
+#define REALTEK_CPU_IRQ_SHARED0 (MIPS_CPU_IRQ_BASE + 2)
+#define REALTEK_CPU_IRQ_UART (MIPS_CPU_IRQ_BASE + 3)
+#define REALTEK_CPU_IRQ_SWITCH (MIPS_CPU_IRQ_BASE + 4)
+#define REALTEK_CPU_IRQ_SHARED1 (MIPS_CPU_IRQ_BASE + 5)
+#define REALTEK_CPU_IRQ_EXTERNAL (MIPS_CPU_IRQ_BASE + 6)
+#define REALTEK_CPU_IRQ_COUNTER (MIPS_CPU_IRQ_BASE + 7)
-#define REG(x) (rtl83xx_ictl_base + x)
+#define REG(x) (rtl83xx_ictl_base + x)
extern struct rtl83xx_soc_info soc_info;
static DEFINE_RAW_SPINLOCK(irq_lock);
static void __iomem *rtl83xx_ictl_base;
-
static void rtl83xx_ictl_enable_irq(struct irq_data *i)
{
unsigned long flags;
raw_spin_lock_irqsave(&irq_lock, flags);
value = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR));
- value |= BIT(i->irq);
+ value |= BIT(i->hwirq);
rtl83xx_w32(value, REG(RTL83XX_ICTL_GIMR));
raw_spin_unlock_irqrestore(&irq_lock, flags);
raw_spin_lock_irqsave(&irq_lock, flags);
value = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR));
- value &= ~BIT(i->irq);
+ value &= ~BIT(i->hwirq);
rtl83xx_w32(value, REG(RTL83XX_ICTL_GIMR));
raw_spin_unlock_irqrestore(&irq_lock, flags);
.irq_eoi = rtl83xx_ictl_enable_irq,
};
-asmlinkage void plat_irq_dispatch(void)
+static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
- unsigned int pending, ext_int;
+ irq_set_chip_and_handler(hw, &rtl83xx_ictl_irq, handle_level_irq);
- pending = read_c0_cause() & read_c0_status() & ST0_IM;
+ return 0;
+}
- if (pending & CAUSEF_IP7) {
- c0_compare_interrupt(7, NULL);
-
- } else if (pending & CAUSEF_IP6) {
- do_IRQ(RTL83XX_IRQ_TC0);
-
- } else if (pending & CAUSEF_IP5) {
- ext_int = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)) & rtl83xx_r32(REG(RTL83XX_ICTL_GISR));
- if (ext_int & BIT(RTL83XX_IRQ_NIC))
- do_IRQ(RTL83XX_IRQ_NIC);
- else if (ext_int & BIT(RTL83XX_IRQ_GPIO_ABCD))
- do_IRQ(RTL83XX_IRQ_GPIO_ABCD);
- else if ((ext_int & BIT(RTL83XX_IRQ_GPIO_EFGH)) && (soc_info.family == RTL8328_FAMILY_ID))
- do_IRQ(RTL83XX_IRQ_GPIO_EFGH);
- else
- spurious_interrupt();
-
- } else if (pending & CAUSEF_IP4) {
- do_IRQ(RTL83XX_IRQ_SWCORE);
-
- } else if (pending & CAUSEF_IP3) {
- do_IRQ(RTL83XX_IRQ_UART0);
-
- } else if (pending & CAUSEF_IP2) {
- ext_int = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)) & rtl83xx_r32(REG(RTL83XX_ICTL_GISR));
- if (ext_int & BIT(RTL83XX_IRQ_TC1))
- do_IRQ(RTL83XX_IRQ_TC1);
- else if (ext_int & BIT(RTL83XX_IRQ_UART1))
- do_IRQ(RTL83XX_IRQ_UART1);
- else
- spurious_interrupt();
+static const struct irq_domain_ops irq_domain_ops = {
+ .map = intc_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+static void rtl838x_irq_dispatch(struct irq_desc *desc)
+{
+ unsigned int pending = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)) & rtl83xx_r32(REG(RTL83XX_ICTL_GISR));
+
+ if (pending) {
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+ generic_handle_irq(irq_find_mapping(domain, __ffs(pending)));
} else {
spurious_interrupt();
}
}
-static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+asmlinkage void plat_irq_dispatch(void)
{
- irq_set_chip_and_handler(hw, &rtl83xx_ictl_irq, handle_level_irq);
+ unsigned int pending;
- return 0;
-}
+ pending = read_c0_cause() & read_c0_status() & ST0_IM;
-static const struct irq_domain_ops irq_domain_ops = {
- .map = intc_map,
- .xlate = irq_domain_xlate_onecell,
-};
+ if (pending & CAUSEF_IP7)
+ do_IRQ(REALTEK_CPU_IRQ_COUNTER);
+
+ else if (pending & CAUSEF_IP6)
+ do_IRQ(REALTEK_CPU_IRQ_EXTERNAL);
+
+ else if (pending & CAUSEF_IP5)
+ do_IRQ(REALTEK_CPU_IRQ_SHARED1);
+
+ else if (pending & CAUSEF_IP4)
+ do_IRQ(REALTEK_CPU_IRQ_SWITCH);
+
+ else if (pending & CAUSEF_IP3)
+ do_IRQ(REALTEK_CPU_IRQ_UART);
+
+ else if (pending & CAUSEF_IP2)
+ do_IRQ(REALTEK_CPU_IRQ_SHARED0);
-int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ else
+ spurious_interrupt();
+}
+
+static void __init icu_of_init(struct device_node *node, struct device_node *parent)
{
struct irq_domain *domain;
- int i;
- mips_cpu_irq_init();
-
- domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL);
+ domain = irq_domain_add_simple(node, 32, 0,
+ &irq_domain_ops, NULL);
+ irq_set_chained_handler_and_data(2, rtl838x_irq_dispatch, domain);
+ irq_set_chained_handler_and_data(5, rtl838x_irq_dispatch, domain);
rtl83xx_ictl_base = of_iomap(node, 0);
if (!rtl83xx_ictl_base)
- return -EIO;
-
- for (i = 8; i < RTL83XX_IRQ_ICTL_NUM; i++) {
- irq_domain_associate(domain, i, i);
- irq_set_chip_and_handler(RTL83XX_IRQ_ICTL_BASE + i,
- &rtl83xx_ictl_irq, handle_level_irq);
- }
-
- if (request_irq(RTL83XX_ICTL1_IRQ, no_action, IRQF_NO_THREAD,
- "IRQ cascade 1", NULL)) {
- pr_err("request_irq() cascade 1 for irq %d failed\n", RTL83XX_ICTL1_IRQ);
- }
- if (request_irq(RTL83XX_ICTL2_IRQ, no_action, IRQF_NO_THREAD,
- "IRQ cascade 2", NULL)) {
- pr_err("request_irq() cascade 2 for irq %d failed\n", RTL83XX_ICTL2_IRQ);
- }
- if (request_irq(RTL83XX_ICTL3_IRQ, no_action, IRQF_NO_THREAD,
- "IRQ cascade 3", NULL)) {
- pr_err("request_irq() cascade 3 for irq %d failed\n", RTL83XX_ICTL3_IRQ);
- }
- if (request_irq(RTL83XX_ICTL4_IRQ, no_action, IRQF_NO_THREAD,
- "IRQ cascade 4", NULL)) {
- pr_err("request_irq() cascade 4 for irq %d failed\n", RTL83XX_ICTL4_IRQ);
- }
- if (request_irq(RTL83XX_ICTL5_IRQ, no_action, IRQF_NO_THREAD,
- "IRQ cascade 5", NULL)) {
- pr_err("request_irq() cascade 5 for irq %d failed\n", RTL83XX_ICTL5_IRQ);
- }
+ return;
/* Disable all cascaded interrupts */
rtl83xx_w32(0, REG(RTL83XX_ICTL_GIMR));
/* Enable timer0 and uart0 interrupts */
rtl83xx_w32(BIT(RTL83XX_IRQ_TC0) | BIT(RTL83XX_IRQ_UART0), REG(RTL83XX_ICTL_GIMR));
-
- return 0;
}
+static struct of_device_id __initdata of_irq_ids[] = {
+ { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
+ { .compatible = "realtek,rt8380-intc", .data = icu_of_init },
+ {},
+};
+
void __init arch_init_irq(void)
{
- irqchip_init();
+ of_irq_init(of_irq_ids);
}
-
-IRQCHIP_DECLARE(mips_cpu_intc, "rtl83xx,icu", icu_of_init);