1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 327f76819SRalf Baechle * 427f76819SRalf Baechle * Copyright (c) 2004 MIPS Inc 527f76819SRalf Baechle * Author: chris@mips.com 627f76819SRalf Baechle * 727f76819SRalf Baechle * Copyright (C) 2004, 06 Ralf Baechle <ralf@linux-mips.org> 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds #include <linux/interrupt.h> 101da177e4SLinus Torvalds #include <linux/kernel.h> 111da177e4SLinus Torvalds #include <linux/sched.h> 121da177e4SLinus Torvalds #include <linux/kernel_stat.h> 131da177e4SLinus Torvalds #include <asm/io.h> 141da177e4SLinus Torvalds #include <asm/irq.h> 151da177e4SLinus Torvalds #include <asm/msc01_ic.h> 16411ba7fcSAtsushi Nemoto #include <asm/traps.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds static unsigned long _icctrl_msc; 191da177e4SLinus Torvalds #define MSC01_IC_REG_BASE _icctrl_msc 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) 221da177e4SLinus Torvalds #define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds static unsigned int irq_base; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds /* mask off an interrupt */ 27e15883daSThomas Gleixner static inline void mask_msc_irq(struct irq_data *d) 281da177e4SLinus Torvalds { 29e15883daSThomas Gleixner unsigned int irq = d->irq; 30e15883daSThomas Gleixner 311da177e4SLinus Torvalds if (irq < (irq_base + 32)) 321da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); 331da177e4SLinus Torvalds else 341da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds /* unmask an interrupt */ 38e15883daSThomas Gleixner static inline void unmask_msc_irq(struct irq_data *d) 391da177e4SLinus Torvalds { 40e15883daSThomas Gleixner unsigned int irq = d->irq; 41e15883daSThomas Gleixner 421da177e4SLinus Torvalds if (irq < (irq_base + 32)) 431da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); 441da177e4SLinus Torvalds else 451da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds * Masks and ACKs an IRQ 501da177e4SLinus Torvalds */ 51e15883daSThomas Gleixner static void level_mask_and_ack_msc_irq(struct irq_data *d) 521da177e4SLinus Torvalds { 53e15883daSThomas Gleixner mask_msc_irq(d); 54e01402b1SRalf Baechle if (!cpu_has_veic) 551da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds /* 591da177e4SLinus Torvalds * Masks and ACKs an IRQ 601da177e4SLinus Torvalds */ 61e15883daSThomas Gleixner static void edge_mask_and_ack_msc_irq(struct irq_data *d) 621da177e4SLinus Torvalds { 63e15883daSThomas Gleixner unsigned int irq = d->irq; 64e15883daSThomas Gleixner 65e15883daSThomas Gleixner mask_msc_irq(d); 66e01402b1SRalf Baechle if (!cpu_has_veic) 671da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 681da177e4SLinus Torvalds else { 691da177e4SLinus Torvalds u32 r; 701da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 711da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 721da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* 771da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 781da177e4SLinus Torvalds */ 79937a8015SRalf Baechle void ll_msc_irq(void) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds unsigned int irq; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* read the interrupt vector register */ 841da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 851da177e4SLinus Torvalds if (irq < 64) 86937a8015SRalf Baechle do_IRQ(irq + irq_base); 871da177e4SLinus Torvalds else { 881da177e4SLinus Torvalds /* Ignore spurious interrupt */ 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 92411ba7fcSAtsushi Nemoto static void msc_bind_eic_interrupt(int irq, int set) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 951da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 98411ba7fcSAtsushi Nemoto static struct irq_chip msc_levelirq_type = { 9970d21cdeSAtsushi Nemoto .name = "SOC-it-Level", 100e15883daSThomas Gleixner .irq_ack = level_mask_and_ack_msc_irq, 101e15883daSThomas Gleixner .irq_mask = mask_msc_irq, 102e15883daSThomas Gleixner .irq_mask_ack = level_mask_and_ack_msc_irq, 103e15883daSThomas Gleixner .irq_unmask = unmask_msc_irq, 104e15883daSThomas Gleixner .irq_eoi = unmask_msc_irq, 1051da177e4SLinus Torvalds }; 1061da177e4SLinus Torvalds 107411ba7fcSAtsushi Nemoto static struct irq_chip msc_edgeirq_type = { 10870d21cdeSAtsushi Nemoto .name = "SOC-it-Edge", 109e15883daSThomas Gleixner .irq_ack = edge_mask_and_ack_msc_irq, 110e15883daSThomas Gleixner .irq_mask = mask_msc_irq, 111e15883daSThomas Gleixner .irq_mask_ack = edge_mask_and_ack_msc_irq, 112e15883daSThomas Gleixner .irq_unmask = unmask_msc_irq, 113e15883daSThomas Gleixner .irq_eoi = unmask_msc_irq, 1141da177e4SLinus Torvalds }; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds 117d725cf38SChris Dearman void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq) 1181da177e4SLinus Torvalds { 119d725cf38SChris Dearman _icctrl_msc = (unsigned long) ioremap(icubase, 0x40000); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 1221da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 1251da177e4SLinus Torvalds 126ab6c15bcSMarkos Chandras for (; nirq > 0; nirq--, imp++) { 1271da177e4SLinus Torvalds int n = imp->im_irq; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds switch (imp->im_type) { 1301da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 131e4ec7989SThomas Gleixner irq_set_chip_and_handler_name(irqbase + n, 132e4ec7989SThomas Gleixner &msc_edgeirq_type, 133e4ec7989SThomas Gleixner handle_edge_irq, 134e4ec7989SThomas Gleixner "edge"); 135e01402b1SRalf Baechle if (cpu_has_veic) 1361da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 1371da177e4SLinus Torvalds else 1381da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 1391da177e4SLinus Torvalds break; 1401da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 141e4ec7989SThomas Gleixner irq_set_chip_and_handler_name(irqbase + n, 142e4ec7989SThomas Gleixner &msc_levelirq_type, 143e4ec7989SThomas Gleixner handle_level_irq, 144e4ec7989SThomas Gleixner "level"); 145e01402b1SRalf Baechle if (cpu_has_veic) 1461da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 1471da177e4SLinus Torvalds else 1481da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 152d725cf38SChris Dearman irq_base = irqbase; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds } 157