1
0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-10-19 14:08:17 +02:00

rtl838x: Add irq settings for RTL839x SoCs

This adds correct interrupt routing settings for IRQs on the RTL839x SoCs.
It also speeds up irq handling based on work by biot for all SoCs.

Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
This commit is contained in:
Birger Koblitz 2020-09-25 06:49:51 +02:00 committed by John Crispin
parent e788e9bd87
commit 3c4063f715
2 changed files with 90 additions and 142 deletions

@ -16,11 +16,13 @@
#define rtl838x_w32(val, reg) __raw_writel(val, reg) #define rtl838x_w32(val, reg) __raw_writel(val, reg)
#define rtl838x_w32_mask(clear, set, reg) rtl838x_w32((rtl838x_r32(reg) & ~(clear)) | (set), reg) #define rtl838x_w32_mask(clear, set, reg) rtl838x_w32((rtl838x_r32(reg) & ~(clear)) | (set), reg)
#define rtl838x_r8(reg) __raw_readb(reg)
#define rtl838x_w8(val, reg) __raw_writeb(val, reg)
#define sw_r32(reg) __raw_readl(RTL838X_SW_BASE + reg) #define sw_r32(reg) __raw_readl(RTL838X_SW_BASE + reg)
#define sw_w32(val, reg) __raw_writel(val, RTL838X_SW_BASE + reg) #define sw_w32(val, reg) __raw_writel(val, RTL838X_SW_BASE + reg)
#define sw_w32_mask(clear, set, reg) \ #define sw_w32_mask(clear, set, reg) \
sw_w32((sw_r32(reg) & ~(clear)) | (set), reg) sw_w32((sw_r32(reg) & ~(clear)) | (set), reg)
#define sw_r64(reg) ((((u64)__raw_readl(RTL838X_SW_BASE + reg)) << 32) | \ #define sw_r64(reg) ((((u64)__raw_readl(RTL838X_SW_BASE + reg)) << 32) | \
__raw_readl(RTL838X_SW_BASE + reg + 4)) __raw_readl(RTL838X_SW_BASE + reg + 4))
@ -102,11 +104,15 @@
#define IRR1 (0x0c) #define IRR1 (0x0c)
#define IRR1_SETTING ((GPIO_ABCD_RS << 28) | \ #define IRR1_SETTING_RTL838X ((GPIO_ABCD_RS << 28) | \
(GPIO_EFGH_RS << 24) | \ (GPIO_EFGH_RS << 24) | \
(RTC_RS << 20) | \ (RTC_RS << 20) | \
(SWCORE_RS << 16) \ (SWCORE_RS << 16) \
) )
#define IRR1_SETTING_RTL839X ((GPIO_ABCD_RS << 28) | \
(SWCORE_RS << 16) \
)
#define IRR2 (0x10) #define IRR2 (0x10)
#define IRR2_SETTING 0 #define IRR2_SETTING 0

@ -29,36 +29,7 @@ extern struct rtl838x_soc_info soc_info;
static DEFINE_RAW_SPINLOCK(irq_lock); static DEFINE_RAW_SPINLOCK(irq_lock);
extern irqreturn_t c0_compare_interrupt(int irq, void *dev_id); extern irqreturn_t c0_compare_interrupt(int irq, void *dev_id);
unsigned int rtl838x_ictl_irq_dispatch1(void);
unsigned int rtl838x_ictl_irq_dispatch2(void);
unsigned int rtl838x_ictl_irq_dispatch3(void);
unsigned int rtl838x_ictl_irq_dispatch4(void);
unsigned int rtl838x_ictl_irq_dispatch5(void);
static struct irqaction irq_cascade1 = {
.handler = no_action,
.name = "RTL838X IRQ cascade1",
};
static struct irqaction irq_cascade2 = {
.handler = no_action,
.name = "RTL838X IRQ cascade2",
};
static struct irqaction irq_cascade3 = {
.handler = no_action,
.name = "RTL838X IRQ cascade3",
};
static struct irqaction irq_cascade4 = {
.handler = no_action,
.name = "RTL838X IRQ cascade4",
};
static struct irqaction irq_cascade5 = {
.handler = no_action,
.name = "RTL838X IRQ cascade5",
};
static void rtl838x_ictl_enable_irq(struct irq_data *i) static void rtl838x_ictl_enable_irq(struct irq_data *i)
{ {
@ -69,12 +40,6 @@ static void rtl838x_ictl_enable_irq(struct irq_data *i)
raw_spin_unlock_irqrestore(&irq_lock, flags); raw_spin_unlock_irqrestore(&irq_lock, flags);
} }
static unsigned int rtl838x_ictl_startup_irq(struct irq_data *i)
{
rtl838x_ictl_enable_irq(i);
return 0;
}
static void rtl838x_ictl_disable_irq(struct irq_data *i) static void rtl838x_ictl_disable_irq(struct irq_data *i)
{ {
unsigned long flags; unsigned long flags;
@ -94,9 +59,7 @@ static void rtl838x_ictl_eoi_irq(struct irq_data *i)
} }
static struct irq_chip rtl838x_ictl_irq = { static struct irq_chip rtl838x_ictl_irq = {
.name = "RTL838X", .name = "RTL83xx",
.irq_startup = rtl838x_ictl_startup_irq,
.irq_shutdown = rtl838x_ictl_disable_irq,
.irq_enable = rtl838x_ictl_enable_irq, .irq_enable = rtl838x_ictl_enable_irq,
.irq_disable = rtl838x_ictl_disable_irq, .irq_disable = rtl838x_ictl_disable_irq,
.irq_ack = rtl838x_ictl_disable_irq, .irq_ack = rtl838x_ictl_disable_irq,
@ -106,113 +69,57 @@ static struct irq_chip rtl838x_ictl_irq = {
}; };
/* /*
* RTL8390/80/28 Interrupt Scheme * RTL8390/80/28 Interrupt Scheme
* *
* Source IRQ CPU INT * Source IRQ CPU INT
* -------- ------- ------- * -------- ------- -------
* UART0 31 IP3 * UART0 31 IP3
* UART1 30 IP2 * UART1 30 IP2
* TIMER0 29 IP6 * TIMER0 29 IP6
* TIMER1 28 IP2 * TIMER1 28 IP2
* OCPTO 27 IP2 * OCPTO 27 IP2
* HLXTO 26 IP2 * HLXTO 26 IP2
* SLXTO 25 IP2 * SLXTO 25 IP2
* NIC 24 IP5 * NIC 24 IP5
* GPIO_ABCD 23 IP5 * GPIO_ABCD 23 IP5
* SWCORE 20 IP4 * SWCORE 20 IP4
*/ */
unsigned int rtl838x_ictl_irq_dispatch1(void)
{
/* Identify shared IRQ */
unsigned int extint_ip = icu_r32(GIMR) & icu_r32(GISR);
if (extint_ip & TC1_IP)
do_IRQ(TC1_IRQ);
else if (extint_ip & UART1_IP)
do_IRQ(UART1_IRQ);
else
spurious_interrupt();
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch2(void)
{
do_IRQ(UART0_IRQ);
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch3(void)
{
do_IRQ(SWCORE_IRQ);
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch4(void)
{
/* Identify shared IRQ */
unsigned int extint_ip = icu_r32(GIMR) & icu_r32(GISR);
if (extint_ip & NIC_IP)
do_IRQ(NIC_IRQ);
else if (extint_ip & GPIO_ABCD_IP)
do_IRQ(GPIO_ABCD_IRQ);
else if ((extint_ip & GPIO_EFGH_IP) && (soc_info.family == RTL8328_FAMILY_ID))
do_IRQ(GPIO_EFGH_IRQ);
else
spurious_interrupt();
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch5(void)
{
do_IRQ(TC0_IRQ);
return IRQ_HANDLED;
}
asmlinkage void plat_irq_dispatch(void) asmlinkage void plat_irq_dispatch(void)
{ {
unsigned int pending; unsigned int pending, ext_int;
pending = read_c0_cause() & read_c0_status() & ST0_IM; pending = read_c0_cause();
if (pending & CAUSEF_IP7) if (pending & CAUSEF_IP7) {
c0_compare_interrupt(7, NULL); c0_compare_interrupt(7, NULL);
else if (pending & CAUSEF_IP6) } else if (pending & CAUSEF_IP6) {
rtl838x_ictl_irq_dispatch5(); do_IRQ(TC0_IRQ);
else if (pending & CAUSEF_IP5) } else if (pending & CAUSEF_IP5) {
rtl838x_ictl_irq_dispatch4(); ext_int = icu_r32(GIMR) & icu_r32(GISR);
else if (pending & CAUSEF_IP4) if (ext_int & NIC_IP)
rtl838x_ictl_irq_dispatch3(); do_IRQ(NIC_IRQ);
else if (pending & CAUSEF_IP3) else if (ext_int & GPIO_ABCD_IP)
rtl838x_ictl_irq_dispatch2(); do_IRQ(GPIO_ABCD_IRQ);
else if (pending & CAUSEF_IP2) else if ((ext_int & GPIO_EFGH_IP) && (soc_info.family == RTL8328_FAMILY_ID))
rtl838x_ictl_irq_dispatch1(); do_IRQ(GPIO_EFGH_IRQ);
else else
spurious_interrupt();
} else if (pending & CAUSEF_IP4) {
do_IRQ(SWCORE_IRQ);
} else if (pending & CAUSEF_IP3) {
do_IRQ(UART0_IRQ);
} 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);
else
spurious_interrupt();
} else {
spurious_interrupt(); spurious_interrupt();
} }
static void __init rtl838x_ictl_irq_init(unsigned int irq_base)
{
int i;
for (i = 0; i < RTL838X_IRQ_ICTL_NUM; i++)
irq_set_chip_and_handler(irq_base + i, &rtl838x_ictl_irq, handle_level_irq);
setup_irq(RTL838X_ICTL1_IRQ, &irq_cascade1);
setup_irq(RTL838X_ICTL2_IRQ, &irq_cascade2);
setup_irq(RTL838X_ICTL3_IRQ, &irq_cascade3);
setup_irq(RTL838X_ICTL4_IRQ, &irq_cascade4);
setup_irq(RTL838X_ICTL5_IRQ, &irq_cascade5);
/* Set GIMR, IRR */
icu_w32(TC0_IE | UART0_IE, GIMR);
icu_w32(IRR0_SETTING, IRR0);
icu_w32(IRR1_SETTING, IRR1);
icu_w32(IRR2_SETTING, IRR2);
icu_w32(IRR3_SETTING, IRR3);
} }
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
@ -234,11 +141,12 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
struct resource res; struct resource res;
pr_info("Found Interrupt controller: %s (%s)\n", node->name, node->full_name); pr_info("Found Interrupt controller: %s (%s)\n", node->name, node->full_name);
if (of_address_to_resource(node, 0, &res)) { if (of_address_to_resource(node, 0, &res))
panic("Failed to get icu memory range"); panic("Failed to get icu memory range");
}
if (!request_mem_region(res.start, resource_size(&res), res.name)) if (!request_mem_region(res.start, resource_size(&res), res.name))
pr_err("Failed to request icu memory\n"); pr_err("Failed to request icu memory\n");
soc_info.icu_base = ioremap(res.start, resource_size(&res)); soc_info.icu_base = ioremap(res.start, resource_size(&res));
pr_info("ICU Memory: %08x\n", (u32)soc_info.icu_base); pr_info("ICU Memory: %08x\n", (u32)soc_info.icu_base);
@ -247,10 +155,44 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL); domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL);
/* Setup all external HW irqs */ /* Setup all external HW irqs */
for (i = 8; i < 32; i++) for (i = 8; i < RTL838X_IRQ_ICTL_NUM; i++) {
irq_domain_associate(domain, i, i); irq_domain_associate(domain, i, i);
irq_set_chip_and_handler(RTL838X_IRQ_ICTL_BASE + i,
&rtl838x_ictl_irq, handle_level_irq);
}
rtl838x_ictl_irq_init(RTL838X_IRQ_ICTL_BASE); if (request_irq(RTL838X_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);
}
if (request_irq(RTL838X_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);
}
if (request_irq(RTL838X_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);
}
if (request_irq(RTL838X_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);
}
if (request_irq(RTL838X_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);
}
/* 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);
/* Enable timer0 and uart0 interrupts */
icu_w32(TC0_IE | UART0_IE, GIMR);
return 0; return 0;
} }