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