1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * This file define the irq handler for MSP SLM subsystem interrupts. 4 * 5 * Copyright 2005-2006 PMC-Sierra, Inc, derived from irq_cpu.c 6 * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com 7 */ 8 9#include <linux/init.h> 10#include <linux/interrupt.h> 11#include <linux/kernel.h> 12#include <linux/bitops.h> 13 14#include <asm/mipsregs.h> 15 16#include <msp_slp_int.h> 17#include <msp_regs.h> 18 19static inline void unmask_msp_slp_irq(struct irq_data *d) 20{ 21 unsigned int irq = d->irq; 22 23 /* check for PER interrupt range */ 24 if (irq < MSP_PER_INTBASE) 25 *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE)); 26 else 27 *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE)); 28} 29 30static inline void mask_msp_slp_irq(struct irq_data *d) 31{ 32 unsigned int irq = d->irq; 33 34 /* check for PER interrupt range */ 35 if (irq < MSP_PER_INTBASE) 36 *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE)); 37 else 38 *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE)); 39} 40 41/* 42 * While we ack the interrupt interrupts are disabled and thus we don't need 43 * to deal with concurrency issues. Same for msp_slp_irq_end. 44 */ 45static inline void ack_msp_slp_irq(struct irq_data *d) 46{ 47 unsigned int irq = d->irq; 48 49 /* check for PER interrupt range */ 50 if (irq < MSP_PER_INTBASE) 51 *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE)); 52 else 53 *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE)); 54} 55 56static struct irq_chip msp_slp_irq_controller = { 57 .name = "MSP_SLP", 58 .irq_ack = ack_msp_slp_irq, 59 .irq_mask = mask_msp_slp_irq, 60 .irq_unmask = unmask_msp_slp_irq, 61}; 62 63void __init msp_slp_irq_init(void) 64{ 65 int i; 66 67 /* Mask/clear interrupts. */ 68 *SLP_INT_MSK_REG = 0x00000000; 69 *PER_INT_MSK_REG = 0x00000000; 70 *SLP_INT_STS_REG = 0xFFFFFFFF; 71 *PER_INT_STS_REG = 0xFFFFFFFF; 72 73 /* initialize all the IRQ descriptors */ 74 for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++) 75 irq_set_chip_and_handler(i, &msp_slp_irq_controller, 76 handle_level_irq); 77} 78 79void msp_slp_irq_dispatch(void) 80{ 81 u32 pending; 82 int intbase; 83 84 intbase = MSP_SLP_INTBASE; 85 pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG; 86 87 /* check for PER interrupt */ 88 if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) { 89 intbase = MSP_PER_INTBASE; 90 pending = *PER_INT_STS_REG & *PER_INT_MSK_REG; 91 } 92 93 /* check for spurious interrupt */ 94 if (pending == 0x00000000) { 95 printk(KERN_ERR "Spurious %s interrupt?\n", 96 (intbase == MSP_SLP_INTBASE) ? "SLP" : "PER"); 97 return; 98 } 99 100 /* dispatch the irq */ 101 do_IRQ(ffs(pending) + intbase - 1); 102} 103