irq.c (4126B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org> 4 * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org> 5 */ 6 7#include <linux/interrupt.h> 8#include <linux/io.h> 9#include <linux/irq.h> 10 11#include <asm/irq_cpu.h> 12#include <asm/mipsregs.h> 13#include <asm/mach-ar7/ar7.h> 14 15#define EXCEPT_OFFSET 0x80 16#define PACE_OFFSET 0xA0 17#define CHNLS_OFFSET 0x200 18 19#define REG_OFFSET(irq, reg) ((irq) / 32 * 0x4 + reg * 0x10) 20#define SEC_REG_OFFSET(reg) (EXCEPT_OFFSET + reg * 0x8) 21#define SEC_SR_OFFSET (SEC_REG_OFFSET(0)) /* 0x80 */ 22#define CR_OFFSET(irq) (REG_OFFSET(irq, 1)) /* 0x10 */ 23#define SEC_CR_OFFSET (SEC_REG_OFFSET(1)) /* 0x88 */ 24#define ESR_OFFSET(irq) (REG_OFFSET(irq, 2)) /* 0x20 */ 25#define SEC_ESR_OFFSET (SEC_REG_OFFSET(2)) /* 0x90 */ 26#define ECR_OFFSET(irq) (REG_OFFSET(irq, 3)) /* 0x30 */ 27#define SEC_ECR_OFFSET (SEC_REG_OFFSET(3)) /* 0x98 */ 28#define PIR_OFFSET (0x40) 29#define MSR_OFFSET (0x44) 30#define PM_OFFSET(irq) (REG_OFFSET(irq, 5)) /* 0x50 */ 31#define TM_OFFSET(irq) (REG_OFFSET(irq, 6)) /* 0x60 */ 32 33#define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr)) 34 35#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4)) 36 37static int ar7_irq_base; 38 39static void ar7_unmask_irq(struct irq_data *d) 40{ 41 writel(1 << ((d->irq - ar7_irq_base) % 32), 42 REG(ESR_OFFSET(d->irq - ar7_irq_base))); 43} 44 45static void ar7_mask_irq(struct irq_data *d) 46{ 47 writel(1 << ((d->irq - ar7_irq_base) % 32), 48 REG(ECR_OFFSET(d->irq - ar7_irq_base))); 49} 50 51static void ar7_ack_irq(struct irq_data *d) 52{ 53 writel(1 << ((d->irq - ar7_irq_base) % 32), 54 REG(CR_OFFSET(d->irq - ar7_irq_base))); 55} 56 57static void ar7_unmask_sec_irq(struct irq_data *d) 58{ 59 writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); 60} 61 62static void ar7_mask_sec_irq(struct irq_data *d) 63{ 64 writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); 65} 66 67static void ar7_ack_sec_irq(struct irq_data *d) 68{ 69 writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET)); 70} 71 72static struct irq_chip ar7_irq_type = { 73 .name = "AR7", 74 .irq_unmask = ar7_unmask_irq, 75 .irq_mask = ar7_mask_irq, 76 .irq_ack = ar7_ack_irq 77}; 78 79static struct irq_chip ar7_sec_irq_type = { 80 .name = "AR7", 81 .irq_unmask = ar7_unmask_sec_irq, 82 .irq_mask = ar7_mask_sec_irq, 83 .irq_ack = ar7_ack_sec_irq, 84}; 85 86static void __init ar7_irq_init(int base) 87{ 88 int i; 89 /* 90 * Disable interrupts and clear pending 91 */ 92 writel(0xffffffff, REG(ECR_OFFSET(0))); 93 writel(0xff, REG(ECR_OFFSET(32))); 94 writel(0xffffffff, REG(SEC_ECR_OFFSET)); 95 writel(0xffffffff, REG(CR_OFFSET(0))); 96 writel(0xff, REG(CR_OFFSET(32))); 97 writel(0xffffffff, REG(SEC_CR_OFFSET)); 98 99 ar7_irq_base = base; 100 101 for (i = 0; i < 40; i++) { 102 writel(i, REG(CHNL_OFFSET(i))); 103 /* Primary IRQ's */ 104 irq_set_chip_and_handler(base + i, &ar7_irq_type, 105 handle_level_irq); 106 /* Secondary IRQ's */ 107 if (i < 32) 108 irq_set_chip_and_handler(base + i + 40, 109 &ar7_sec_irq_type, 110 handle_level_irq); 111 } 112 113 if (request_irq(2, no_action, IRQF_NO_THREAD, "AR7 cascade interrupt", 114 NULL)) 115 pr_err("Failed to request irq 2 (AR7 cascade interrupt)\n"); 116 if (request_irq(ar7_irq_base, no_action, IRQF_NO_THREAD, 117 "AR7 cascade interrupt", NULL)) { 118 pr_err("Failed to request irq %d (AR7 cascade interrupt)\n", 119 ar7_irq_base); 120 } 121 set_c0_status(IE_IRQ0); 122} 123 124void __init arch_init_irq(void) 125{ 126 mips_cpu_irq_init(); 127 ar7_irq_init(8); 128} 129 130static void ar7_cascade(void) 131{ 132 u32 status; 133 int i, irq; 134 135 /* Primary IRQ's */ 136 irq = readl(REG(PIR_OFFSET)) & 0x3f; 137 if (irq) { 138 do_IRQ(ar7_irq_base + irq); 139 return; 140 } 141 142 /* Secondary IRQ's are cascaded through primary '0' */ 143 writel(1, REG(CR_OFFSET(irq))); 144 status = readl(REG(SEC_SR_OFFSET)); 145 for (i = 0; i < 32; i++) { 146 if (status & 1) { 147 do_IRQ(ar7_irq_base + i + 40); 148 return; 149 } 150 status >>= 1; 151 } 152 153 spurious_interrupt(); 154} 155 156asmlinkage void plat_irq_dispatch(void) 157{ 158 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; 159 if (pending & STATUSF_IP7) /* cpu timer */ 160 do_IRQ(7); 161 else if (pending & STATUSF_IP2) /* int0 hardware line */ 162 ar7_cascade(); 163 else 164 spurious_interrupt(); 165}