-/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef __ASM_MACH_RTL838X_IRQ_H
-#define __ASM_MACH_RTL838X_IRQ_H
+// SPDX-License-Identifier: GPL-2.0-only
-#define MIPS_CPU_IRQ_BASE 0
-#define NR_IRQS 64
+#ifndef _RTL83XX_IRQ_H_
+#define _RTL83XX_IRQ_H_
+#define NR_IRQS 32
#include_next <irq.h>
-#endif /* __ASM_MACH_ATH79_IRQ_H */
+/* Global Interrupt Mask Register */
+#define RTL83XX_ICTL_GIMR 0x00
+/* Global Interrupt Status Register */
+#define RTL83XX_ICTL_GISR 0x04
+
+#define RTL83XX_IRQ_CPU_BASE 0
+#define RTL83XX_IRQ_CPU_NUM 8
+#define RTL83XX_IRQ_ICTL_BASE (RTL83XX_IRQ_CPU_BASE + RTL83XX_IRQ_CPU_NUM)
+#define RTL83XX_IRQ_ICTL_NUM 32
+
+/* Cascaded interrupts */
+#define RTL83XX_ICTL1_IRQ (RTL83XX_IRQ_CPU_BASE + 2)
+#define RTL83XX_ICTL2_IRQ (RTL83XX_IRQ_CPU_BASE + 3)
+#define RTL83XX_ICTL3_IRQ (RTL83XX_IRQ_CPU_BASE + 4)
+#define RTL83XX_ICTL4_IRQ (RTL83XX_IRQ_CPU_BASE + 5)
+#define RTL83XX_ICTL5_IRQ (RTL83XX_IRQ_CPU_BASE + 6)
+
+/* Interrupt routing register */
+#define RTL83XX_IRR0 0x08
+#define RTL83XX_IRR1 0x0c
+#define RTL83XX_IRR2 0x10
+#define RTL83XX_IRR3 0x14
+
+/* Cascade map */
+#define UART0_CASCADE 2
+#define UART1_CASCADE 1
+#define TC0_CASCADE 5
+#define TC1_CASCADE 1
+#define OCPTO_CASCADE 1
+#define HLXTO_CASCADE 1
+#define SLXTO_CASCADE 1
+#define NIC_CASCADE 4
+#define GPIO_ABCD_CASCADE 4
+#define GPIO_EFGH_CASCADE 4
+#define RTC_CASCADE 4
+#define SWCORE_CASCADE 3
+#define WDT_IP1_CASCADE 4
+#define WDT_IP2_CASCADE 5
+
+/* Pack cascade map into interrupt routing registers */
+#define RTL83XX_IRR0_SETTING (\
+ (UART0_CASCADE << 28) | \
+ (UART1_CASCADE << 24) | \
+ (TC0_CASCADE << 20) | \
+ (TC1_CASCADE << 16) | \
+ (OCPTO_CASCADE << 12) | \
+ (HLXTO_CASCADE << 8) | \
+ (SLXTO_CASCADE << 4) | \
+ (NIC_CASCADE << 0))
+#define RTL83XX_IRR1_SETTING (\
+ (GPIO_ABCD_CASCADE << 28) | \
+ (GPIO_EFGH_CASCADE << 24) | \
+ (RTC_CASCADE << 20) | \
+ (SWCORE_CASCADE << 16))
+#define RTL83XX_IRR2_SETTING 0
+#define RTL83XX_IRR3_SETTING 0
+
+#endif /* _RTL83XX_IRQ_H_ */
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Realtek RTL838X architecture specific IRQ handling
+ * Realtek RTL83XX architecture specific IRQ handling
*
* Copyright (C) 2020 B. Koblitz
* based on the original BSP
*
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/irqchip.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
#include <linux/spinlock.h>
-
+#include <linux/of_address.h>
#include <asm/irq_cpu.h>
-#include <asm/mipsregs.h>
+#include <asm/cevt-r4k.h>
+
#include <mach-rtl83xx.h>
+#include "irq.h"
-extern struct rtl83xx_soc_info soc_info;
-#define icu_r32(reg) rtl83xx_r32(soc_info.icu_base + reg)
-#define icu_w32(val, reg) rtl83xx_w32(val, soc_info.icu_base + reg)
-#define icu_w32_mask(clear, set, reg) rtl83xx_w32_mask(clear, set, soc_info.icu_base + reg)
+#define REG(x) (rtl83xx_ictl_base + x)
-static DEFINE_RAW_SPINLOCK(irq_lock);
+extern struct rtl83xx_soc_info soc_info;
-extern irqreturn_t c0_compare_interrupt(int irq, void *dev_id);
+static DEFINE_RAW_SPINLOCK(irq_lock);
+static void __iomem *rtl83xx_ictl_base;
-static void rtl838x_ictl_enable_irq(struct irq_data *i)
+static void rtl83xx_ictl_enable_irq(struct irq_data *i)
{
unsigned long flags;
+ u32 value;
raw_spin_lock_irqsave(&irq_lock, flags);
- icu_w32_mask(0, 1 << i->irq, GIMR);
- raw_spin_unlock_irqrestore(&irq_lock, flags);
-}
-static void rtl838x_ictl_disable_irq(struct irq_data *i)
-{
- unsigned long flags;
+ value = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR));
+ value |= BIT(i->irq);
+ rtl83xx_w32(value, REG(RTL83XX_ICTL_GIMR));
- raw_spin_lock_irqsave(&irq_lock, flags);
- icu_w32_mask(1 << i->irq, 0, GIMR);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
-static void rtl838x_ictl_eoi_irq(struct irq_data *i)
+static void rtl83xx_ictl_disable_irq(struct irq_data *i)
{
unsigned long flags;
+ u32 value;
raw_spin_lock_irqsave(&irq_lock, flags);
- icu_w32_mask(0, 1 << i->irq, GIMR);
+
+ value = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR));
+ value &= ~BIT(i->irq);
+ rtl83xx_w32(value, REG(RTL83XX_ICTL_GIMR));
+
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
-static struct irq_chip rtl838x_ictl_irq = {
+static struct irq_chip rtl83xx_ictl_irq = {
.name = "RTL83xx",
- .irq_enable = rtl838x_ictl_enable_irq,
- .irq_disable = rtl838x_ictl_disable_irq,
- .irq_ack = rtl838x_ictl_disable_irq,
- .irq_mask = rtl838x_ictl_disable_irq,
- .irq_unmask = rtl838x_ictl_enable_irq,
- .irq_eoi = rtl838x_ictl_eoi_irq,
+ .irq_enable = rtl83xx_ictl_enable_irq,
+ .irq_disable = rtl83xx_ictl_disable_irq,
+ .irq_ack = rtl83xx_ictl_disable_irq,
+ .irq_mask = rtl83xx_ictl_disable_irq,
+ .irq_unmask = rtl83xx_ictl_enable_irq,
+ .irq_eoi = rtl83xx_ictl_enable_irq,
};
-/*
- * RTL8390/80/28 Interrupt Scheme
- *
- * Source IRQ CPU INT
- * -------- ------- -------
- * UART0 31 IP3
- * UART1 30 IP2
- * TIMER0 29 IP6
- * TIMER1 28 IP2
- * OCPTO 27 IP2
- * HLXTO 26 IP2
- * SLXTO 25 IP2
- * NIC 24 IP5
- * GPIO_ABCD 23 IP5
- * SWCORE 20 IP4
- */
-
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending, ext_int;
- pending = read_c0_cause();
+ pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & CAUSEF_IP7) {
c0_compare_interrupt(7, NULL);
+
} else if (pending & CAUSEF_IP6) {
- do_IRQ(TC0_IRQ);
+ do_IRQ(RTL83XX_IRQ_TC0);
+
} else if (pending & CAUSEF_IP5) {
- ext_int = icu_r32(GIMR) & icu_r32(GISR);
- if (ext_int & NIC_IP)
- do_IRQ(NIC_IRQ);
- else if (ext_int & GPIO_ABCD_IP)
- do_IRQ(GPIO_ABCD_IRQ);
- else if ((ext_int & GPIO_EFGH_IP) && (soc_info.family == RTL8328_FAMILY_ID))
- do_IRQ(GPIO_EFGH_IRQ);
+ 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(SWCORE_IRQ);
+ do_IRQ(RTL83XX_IRQ_SWCORE);
+
} else if (pending & CAUSEF_IP3) {
- do_IRQ(UART0_IRQ);
+ do_IRQ(RTL83XX_IRQ_UART0);
+
} else if (pending & CAUSEF_IP2) {
- ext_int = icu_r32(GIMR) & icu_r32(GISR);
- if (ext_int & TC1_IP)
- do_IRQ(TC1_IRQ);
- else if (ext_int & UART1_IP)
- do_IRQ(UART1_IRQ);
+ 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();
+
} else {
spurious_interrupt();
}
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
- irq_set_chip_and_handler(hw, &rtl838x_ictl_irq, handle_level_irq);
+ irq_set_chip_and_handler(hw, &rtl83xx_ictl_irq, handle_level_irq);
return 0;
}
static const struct irq_domain_ops irq_domain_ops = {
- .xlate = irq_domain_xlate_onecell,
.map = intc_map,
+ .xlate = irq_domain_xlate_onecell,
};
int __init icu_of_init(struct device_node *node, struct device_node *parent)
{
- int i;
struct irq_domain *domain;
- struct resource res;
-
- pr_info("Found Interrupt controller: %s (%s)\n", node->name, node->full_name);
- if (of_address_to_resource(node, 0, &res))
- panic("Failed to get icu memory range");
-
- if (!request_mem_region(res.start, resource_size(&res), res.name))
- pr_err("Failed to request icu memory\n");
-
- soc_info.icu_base = ioremap(res.start, resource_size(&res));
- pr_info("ICU Memory: %08x\n", (u32)soc_info.icu_base);
+ int i;
mips_cpu_irq_init();
domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL);
- /* Setup all external HW irqs */
- for (i = 8; i < RTL838X_IRQ_ICTL_NUM; i++) {
+ 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(RTL838X_IRQ_ICTL_BASE + i,
- &rtl838x_ictl_irq, handle_level_irq);
+ irq_set_chip_and_handler(RTL83XX_IRQ_ICTL_BASE + i,
+ &rtl83xx_ictl_irq, handle_level_irq);
}
- if (request_irq(RTL838X_ICTL1_IRQ, no_action, IRQF_NO_THREAD,
+ 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", RTL838X_ICTL1_IRQ);
+ pr_err("request_irq() cascade 1 for irq %d failed\n", RTL83XX_ICTL1_IRQ);
}
- if (request_irq(RTL838X_ICTL2_IRQ, no_action, IRQF_NO_THREAD,
+ 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", RTL838X_ICTL2_IRQ);
+ pr_err("request_irq() cascade 2 for irq %d failed\n", RTL83XX_ICTL2_IRQ);
}
- if (request_irq(RTL838X_ICTL3_IRQ, no_action, IRQF_NO_THREAD,
+ 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", RTL838X_ICTL3_IRQ);
+ pr_err("request_irq() cascade 3 for irq %d failed\n", RTL83XX_ICTL3_IRQ);
}
- if (request_irq(RTL838X_ICTL4_IRQ, no_action, IRQF_NO_THREAD,
+ 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", RTL838X_ICTL4_IRQ);
+ pr_err("request_irq() cascade 4 for irq %d failed\n", RTL83XX_ICTL4_IRQ);
}
- if (request_irq(RTL838X_ICTL5_IRQ, no_action, IRQF_NO_THREAD,
+ 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", RTL838X_ICTL5_IRQ);
+ pr_err("request_irq() cascade 5 for irq %d failed\n", RTL83XX_ICTL5_IRQ);
}
- /* Set up interrupt routing scheme */
- icu_w32(IRR0_SETTING, IRR0);
- if (soc_info.family == RTL8380_FAMILY_ID)
- icu_w32(IRR1_SETTING_RTL838X, IRR1);
- else
- icu_w32(IRR1_SETTING_RTL839X, IRR1);
- icu_w32(IRR2_SETTING, IRR2);
- icu_w32(IRR3_SETTING, IRR3);
+ /* Disable all cascaded interrupts */
+ rtl83xx_w32(0, REG(RTL83XX_ICTL_GIMR));
+
+ /* Set up interrupt routing */
+ rtl83xx_w32(RTL83XX_IRR0_SETTING, REG(RTL83XX_IRR0));
+ rtl83xx_w32(RTL83XX_IRR1_SETTING, REG(RTL83XX_IRR1));
+ rtl83xx_w32(RTL83XX_IRR2_SETTING, REG(RTL83XX_IRR2));
+ rtl83xx_w32(RTL83XX_IRR3_SETTING, REG(RTL83XX_IRR3));
+
+ /* Clear timer interrupt */
+ write_c0_compare(0);
+
+ /* Enable all CPU interrupts */
+ write_c0_status(read_c0_status() | ST0_IM);
/* Enable timer0 and uart0 interrupts */
- icu_w32(TC0_IE | UART0_IE, GIMR);
+ rtl83xx_w32(BIT(RTL83XX_IRQ_TC0) | BIT(RTL83XX_IRQ_UART0), REG(RTL83XX_ICTL_GIMR));
+
return 0;
}
void __init arch_init_irq(void)
{
- /* do board-specific irq initialization */
irqchip_init();
}
-IRQCHIP_DECLARE(mips_cpu_intc, "rtl838x,icu", icu_of_init);
+IRQCHIP_DECLARE(mips_cpu_intc, "rtl83xx,icu", icu_of_init);