Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | /*
* Copyright 2002 Momentum Computer
* Author: mdharm@momenco.com
* Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/mv643xx.h>
#include <linux/sched.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/marvell.h>
static unsigned int irq_base;
static inline int ls1bit32(unsigned int x)
{
int b = 31, s;
s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s;
s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s;
s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s;
s = 1; if (x << 1 == 0) s = 0; b -= s;
return b;
}
/* mask off an interrupt -- 1 is enable, 0 is disable */
static inline void mask_mv64340_irq(unsigned int irq)
{
uint32_t value;
if (irq < (irq_base + 32)) {
value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW);
value &= ~(1 << (irq - irq_base));
MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value);
} else {
value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH);
value &= ~(1 << (irq - irq_base - 32));
MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value);
}
}
/* unmask an interrupt -- 1 is enable, 0 is disable */
static inline void unmask_mv64340_irq(unsigned int irq)
{
uint32_t value;
if (irq < (irq_base + 32)) {
value = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW);
value |= 1 << (irq - irq_base);
MV_WRITE(MV64340_INTERRUPT0_MASK_0_LOW, value);
} else {
value = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH);
value |= 1 << (irq - irq_base - 32);
MV_WRITE(MV64340_INTERRUPT0_MASK_0_HIGH, value);
}
}
/*
* Enables the IRQ on Marvell Chip
*/
static void enable_mv64340_irq(unsigned int irq)
{
unmask_mv64340_irq(irq);
}
/*
* Initialize the IRQ on Marvell Chip
*/
static unsigned int startup_mv64340_irq(unsigned int irq)
{
unmask_mv64340_irq(irq);
return 0;
}
/*
* Disables the IRQ on Marvell Chip
*/
static void disable_mv64340_irq(unsigned int irq)
{
mask_mv64340_irq(irq);
}
/*
* Masks and ACKs an IRQ
*/
static void mask_and_ack_mv64340_irq(unsigned int irq)
{
mask_mv64340_irq(irq);
}
/*
* End IRQ processing
*/
static void end_mv64340_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
unmask_mv64340_irq(irq);
}
/*
* Interrupt handler for interrupts coming from the Marvell chip.
* It could be built in ethernet ports etc...
*/
void ll_mv64340_irq(struct pt_regs *regs)
{
unsigned int irq_src_low, irq_src_high;
unsigned int irq_mask_low, irq_mask_high;
/* read the interrupt status registers */
irq_mask_low = MV_READ(MV64340_INTERRUPT0_MASK_0_LOW);
irq_mask_high = MV_READ(MV64340_INTERRUPT0_MASK_0_HIGH);
irq_src_low = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_LOW);
irq_src_high = MV_READ(MV64340_MAIN_INTERRUPT_CAUSE_HIGH);
/* mask for just the interrupts we want */
irq_src_low &= irq_mask_low;
irq_src_high &= irq_mask_high;
if (irq_src_low)
do_IRQ(ls1bit32(irq_src_low) + irq_base, regs);
else
do_IRQ(ls1bit32(irq_src_high) + irq_base + 32, regs);
}
#define shutdown_mv64340_irq disable_mv64340_irq
struct hw_interrupt_type mv64340_irq_type = {
.typename = "MV-64340",
.startup = startup_mv64340_irq,
.shutdown = shutdown_mv64340_irq,
.enable = enable_mv64340_irq,
.disable = disable_mv64340_irq,
.ack = mask_and_ack_mv64340_irq,
.end = end_mv64340_irq,
};
void __init mv64340_irq_init(unsigned int base)
{
int i;
/* Reset irq handlers pointers to NULL */
for (i = base; i < base + 64; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 2;
irq_desc[i].handler = &mv64340_irq_type;
}
irq_base = base;
}
|