1/* 2 * Copyright 2002 Momentum Computer 3 * Author: mdharm@momenco.com 4 * Copyright (C) 2004, 06 Ralf Baechle <ralf@linux-mips.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 */ 11#include <linux/module.h> 12#include <linux/interrupt.h> 13#include <linux/kernel.h> 14#include <linux/kernel_stat.h> 15#include <linux/mv643xx.h> 16#include <linux/sched.h> 17 18#include <asm/io.h> 19#include <asm/irq.h> 20#include <asm/marvell.h> 21 22static unsigned int irq_base; 23 24static inline int ls1bit32(unsigned int x) 25{ 26 int b = 31, s; 27 28 s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; 29 s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; 30 s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; 31 s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; 32 s = 1; if (x << 1 == 0) s = 0; b -= s; 33 34 return b; 35} 36 37/* mask off an interrupt -- 1 is enable, 0 is disable */ 38static inline void mask_mv64340_irq(unsigned int irq) 39{ 40 uint32_t value; 41 42 if (irq < (irq_base + 32)) { 43 value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW); 44 value &= ~(1 << (irq - irq_base)); 45 MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value); 46 } else { 47 value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH); 48 value &= ~(1 << (irq - irq_base - 32)); 49 MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value); 50 } 51} 52 53/* unmask an interrupt -- 1 is enable, 0 is disable */ 54static inline void unmask_mv64340_irq(unsigned int irq) 55{ 56 uint32_t value; 57 58 if (irq < (irq_base + 32)) { 59 value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW); 60 value |= 1 << (irq - irq_base); 61 MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value); 62 } else { 63 value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH); 64 value |= 1 << (irq - irq_base - 32); 65 MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value); 66 } 67} 68 69/* 70 * Interrupt handler for interrupts coming from the Marvell chip. 71 * It could be built in ethernet ports etc... 72 */ 73void ll_mv64340_irq(void) 74{ 75 unsigned int irq_src_low, irq_src_high; 76 unsigned int irq_mask_low, irq_mask_high; 77 78 /* read the interrupt status registers */ 79 irq_mask_low = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW); 80 irq_mask_high = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH); 81 irq_src_low = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_LOW); 82 irq_src_high = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_HIGH); 83 84 /* mask for just the interrupts we want */ 85 irq_src_low &= irq_mask_low; 86 irq_src_high &= irq_mask_high; 87 88 if (irq_src_low) 89 do_IRQ(ls1bit32(irq_src_low) + irq_base); 90 else 91 do_IRQ(ls1bit32(irq_src_high) + irq_base + 32); 92} 93 94struct irq_chip mv64340_irq_type = { 95 .name = "MV-64340", 96 .ack = mask_mv64340_irq, 97 .mask = mask_mv64340_irq, 98 .mask_ack = mask_mv64340_irq, 99 .unmask = unmask_mv64340_irq, 100}; 101 102void __init mv64340_irq_init(unsigned int base) 103{ 104 int i; 105 106 for (i = base; i < base + 64; i++) 107 set_irq_chip_and_handler(i, &mv64340_irq_type, 108 handle_level_irq); 109 110 irq_base = base; 111} 112