1/* 2 * Copyright 2002 Momentum Computer 3 * Author: mdharm@momenco.com 4 * 5 * arch/mips/momentum/ocelot_c/cpci-irq.c 6 * Interrupt routines for cpci. Interrupt numbers are assigned from 7 * CPCI_IRQ_BASE to CPCI_IRQ_BASE+8 (8 interrupt sources). 8 * 9 * Note that the high-level software will need to be careful about using 10 * these interrupts. If this board is asserting a cPCI interrupt, it will 11 * also see the asserted interrupt. Care must be taken to avoid an 12 * interrupt flood. 13 * 14 * This program is free software; you can redistribute it and/or modify it 15 * under the terms of the GNU General Public License as published by the 16 * Free Software Foundation; either version 2 of the License, or (at your 17 * option) any later version. 18 */ 19 20#include <linux/module.h> 21#include <linux/interrupt.h> 22#include <linux/irq.h> 23#include <linux/kernel.h> 24#include <linux/sched.h> 25#include <linux/kernel_stat.h> 26#include <asm/io.h> 27#include "ocelot_c_fpga.h" 28 29#define CPCI_IRQ_BASE 8 30 31static inline int ls1bit8(unsigned int x) 32{ 33 int b = 7, s; 34 35 s = 4; if (((unsigned char)(x << 4)) == 0) s = 0; b -= s; x <<= s; 36 s = 2; if (((unsigned char)(x << 2)) == 0) s = 0; b -= s; x <<= s; 37 s = 1; if (((unsigned char)(x << 1)) == 0) s = 0; b -= s; 38 39 return b; 40} 41 42/* mask off an interrupt -- 0 is enable, 1 is disable */ 43static inline void mask_cpci_irq(unsigned int irq) 44{ 45 uint32_t value; 46 47 value = OCELOT_FPGA_READ(INTMASK); 48 value |= 1 << (irq - CPCI_IRQ_BASE); 49 OCELOT_FPGA_WRITE(value, INTMASK); 50 51 /* read the value back to assure that it's really been written */ 52 value = OCELOT_FPGA_READ(INTMASK); 53} 54 55/* unmask an interrupt -- 0 is enable, 1 is disable */ 56static inline void unmask_cpci_irq(unsigned int irq) 57{ 58 uint32_t value; 59 60 value = OCELOT_FPGA_READ(INTMASK); 61 value &= ~(1 << (irq - CPCI_IRQ_BASE)); 62 OCELOT_FPGA_WRITE(value, INTMASK); 63 64 /* read the value back to assure that it's really been written */ 65 value = OCELOT_FPGA_READ(INTMASK); 66} 67 68/* 69 * Interrupt handler for interrupts coming from the FPGA chip. 70 * It could be built in ethernet ports etc... 71 */ 72void ll_cpci_irq(void) 73{ 74 unsigned int irq_src, irq_mask; 75 76 /* read the interrupt status registers */ 77 irq_src = OCELOT_FPGA_READ(INTSTAT); 78 irq_mask = OCELOT_FPGA_READ(INTMASK); 79 80 /* mask for just the interrupts we want */ 81 irq_src &= ~irq_mask; 82 83 do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE); 84} 85 86struct irq_chip cpci_irq_type = { 87 .name = "CPCI/FPGA", 88 .ack = mask_cpci_irq, 89 .mask = mask_cpci_irq, 90 .mask_ack = mask_cpci_irq, 91 .unmask = unmask_cpci_irq, 92}; 93 94void cpci_irq_init(void) 95{ 96 int i; 97 98 for (i = CPCI_IRQ_BASE; i < (CPCI_IRQ_BASE + 8); i++) 99 set_irq_chip_and_handler(i, &cpci_irq_type, handle_level_irq); 100} 101