OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [sysdev/] [mv64x60_pic.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Interrupt handling for Marvell mv64360/mv64460 host bridges (Discovery)
3
 *
4
 * Author: Dale Farnsworth <dale@farnsworth.org>
5
 *
6
 * 2007 (c) MontaVista, Software, Inc.  This file is licensed under
7
 * the terms of the GNU General Public License version 2.  This program
8
 * is licensed "as is" without any warranty of any kind, whether express
9
 * or implied.
10
 */
11
 
12
#include <linux/stddef.h>
13
#include <linux/kernel.h>
14
#include <linux/init.h>
15
#include <linux/irq.h>
16
#include <linux/interrupt.h>
17
#include <linux/spinlock.h>
18
 
19
#include <asm/byteorder.h>
20
#include <asm/io.h>
21
#include <asm/prom.h>
22
#include <asm/irq.h>
23
 
24
#include "mv64x60.h"
25
 
26
/* Interrupt Controller Interface Registers */
27
#define MV64X60_IC_MAIN_CAUSE_LO        0x0004
28
#define MV64X60_IC_MAIN_CAUSE_HI        0x000c
29
#define MV64X60_IC_CPU0_INTR_MASK_LO    0x0014
30
#define MV64X60_IC_CPU0_INTR_MASK_HI    0x001c
31
#define MV64X60_IC_CPU0_SELECT_CAUSE    0x0024
32
 
33
#define MV64X60_HIGH_GPP_GROUPS         0x0f000000
34
#define MV64X60_SELECT_CAUSE_HIGH       0x40000000
35
 
36
/* General Purpose Pins Controller Interface Registers */
37
#define MV64x60_GPP_INTR_CAUSE          0x0008
38
#define MV64x60_GPP_INTR_MASK           0x000c
39
 
40
#define MV64x60_LEVEL1_LOW              0
41
#define MV64x60_LEVEL1_HIGH             1
42
#define MV64x60_LEVEL1_GPP              2
43
 
44
#define MV64x60_LEVEL1_MASK             0x00000060
45
#define MV64x60_LEVEL1_OFFSET           5
46
 
47
#define MV64x60_LEVEL2_MASK             0x0000001f
48
 
49
#define MV64x60_NUM_IRQS                96
50
 
51
static DEFINE_SPINLOCK(mv64x60_lock);
52
 
53
static void __iomem *mv64x60_irq_reg_base;
54
static void __iomem *mv64x60_gpp_reg_base;
55
 
56
/*
57
 * Interrupt Controller Handling
58
 *
59
 * The interrupt controller handles three groups of interrupts:
60
 *   main low:  IRQ0-IRQ31
61
 *   main high: IRQ32-IRQ63
62
 *   gpp:       IRQ64-IRQ95
63
 *
64
 * This code handles interrupts in two levels.  Level 1 selects the
65
 * interrupt group, and level 2 selects an IRQ within that group.
66
 * Each group has its own irq_chip structure.
67
 */
68
 
69
static u32 mv64x60_cached_low_mask;
70
static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS;
71
static u32 mv64x60_cached_gpp_mask;
72
 
73
static struct irq_host *mv64x60_irq_host;
74
 
75
/*
76
 * mv64x60_chip_low functions
77
 */
78
 
79
static void mv64x60_mask_low(unsigned int virq)
80
{
81
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
82
        unsigned long flags;
83
 
84
        spin_lock_irqsave(&mv64x60_lock, flags);
85
        mv64x60_cached_low_mask &= ~(1 << level2);
86
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
87
                 mv64x60_cached_low_mask);
88
        spin_unlock_irqrestore(&mv64x60_lock, flags);
89
        (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
90
}
91
 
92
static void mv64x60_unmask_low(unsigned int virq)
93
{
94
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
95
        unsigned long flags;
96
 
97
        spin_lock_irqsave(&mv64x60_lock, flags);
98
        mv64x60_cached_low_mask |= 1 << level2;
99
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
100
                 mv64x60_cached_low_mask);
101
        spin_unlock_irqrestore(&mv64x60_lock, flags);
102
        (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
103
}
104
 
105
static struct irq_chip mv64x60_chip_low = {
106
        .name           = "mv64x60_low",
107
        .mask           = mv64x60_mask_low,
108
        .mask_ack       = mv64x60_mask_low,
109
        .unmask         = mv64x60_unmask_low,
110
};
111
 
112
/*
113
 * mv64x60_chip_high functions
114
 */
115
 
116
static void mv64x60_mask_high(unsigned int virq)
117
{
118
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
119
        unsigned long flags;
120
 
121
        spin_lock_irqsave(&mv64x60_lock, flags);
122
        mv64x60_cached_high_mask &= ~(1 << level2);
123
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
124
                 mv64x60_cached_high_mask);
125
        spin_unlock_irqrestore(&mv64x60_lock, flags);
126
        (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
127
}
128
 
129
static void mv64x60_unmask_high(unsigned int virq)
130
{
131
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
132
        unsigned long flags;
133
 
134
        spin_lock_irqsave(&mv64x60_lock, flags);
135
        mv64x60_cached_high_mask |= 1 << level2;
136
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
137
                 mv64x60_cached_high_mask);
138
        spin_unlock_irqrestore(&mv64x60_lock, flags);
139
        (void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
140
}
141
 
142
static struct irq_chip mv64x60_chip_high = {
143
        .name           = "mv64x60_high",
144
        .mask           = mv64x60_mask_high,
145
        .mask_ack       = mv64x60_mask_high,
146
        .unmask         = mv64x60_unmask_high,
147
};
148
 
149
/*
150
 * mv64x60_chip_gpp functions
151
 */
152
 
153
static void mv64x60_mask_gpp(unsigned int virq)
154
{
155
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
156
        unsigned long flags;
157
 
158
        spin_lock_irqsave(&mv64x60_lock, flags);
159
        mv64x60_cached_gpp_mask &= ~(1 << level2);
160
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
161
                 mv64x60_cached_gpp_mask);
162
        spin_unlock_irqrestore(&mv64x60_lock, flags);
163
        (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
164
}
165
 
166
static void mv64x60_mask_ack_gpp(unsigned int virq)
167
{
168
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
169
        unsigned long flags;
170
 
171
        spin_lock_irqsave(&mv64x60_lock, flags);
172
        mv64x60_cached_gpp_mask &= ~(1 << level2);
173
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
174
                 mv64x60_cached_gpp_mask);
175
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE,
176
                 ~(1 << level2));
177
        spin_unlock_irqrestore(&mv64x60_lock, flags);
178
        (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE);
179
}
180
 
181
static void mv64x60_unmask_gpp(unsigned int virq)
182
{
183
        int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
184
        unsigned long flags;
185
 
186
        spin_lock_irqsave(&mv64x60_lock, flags);
187
        mv64x60_cached_gpp_mask |= 1 << level2;
188
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
189
                 mv64x60_cached_gpp_mask);
190
        spin_unlock_irqrestore(&mv64x60_lock, flags);
191
        (void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
192
}
193
 
194
static struct irq_chip mv64x60_chip_gpp = {
195
        .name           = "mv64x60_gpp",
196
        .mask           = mv64x60_mask_gpp,
197
        .mask_ack       = mv64x60_mask_ack_gpp,
198
        .unmask         = mv64x60_unmask_gpp,
199
};
200
 
201
/*
202
 * mv64x60_host_ops functions
203
 */
204
 
205
static struct irq_chip *mv64x60_chips[] = {
206
        [MV64x60_LEVEL1_LOW]  = &mv64x60_chip_low,
207
        [MV64x60_LEVEL1_HIGH] = &mv64x60_chip_high,
208
        [MV64x60_LEVEL1_GPP]  = &mv64x60_chip_gpp,
209
};
210
 
211
static int mv64x60_host_map(struct irq_host *h, unsigned int virq,
212
                          irq_hw_number_t hwirq)
213
{
214
        int level1;
215
 
216
        get_irq_desc(virq)->status |= IRQ_LEVEL;
217
 
218
        level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET;
219
        BUG_ON(level1 > MV64x60_LEVEL1_GPP);
220
        set_irq_chip_and_handler(virq, mv64x60_chips[level1], handle_level_irq);
221
 
222
        return 0;
223
}
224
 
225
static struct irq_host_ops mv64x60_host_ops = {
226
        .map   = mv64x60_host_map,
227
};
228
 
229
/*
230
 * Global functions
231
 */
232
 
233
void __init mv64x60_init_irq(void)
234
{
235
        struct device_node *np;
236
        phys_addr_t paddr;
237
        unsigned int size;
238
        const unsigned int *reg;
239
        unsigned long flags;
240
 
241
        np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-gpp");
242
        reg = of_get_property(np, "reg", &size);
243
        paddr = of_translate_address(np, reg);
244
        mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
245
        of_node_put(np);
246
 
247
        np = of_find_compatible_node(NULL, NULL, "marvell,mv64x60-pic");
248
        reg = of_get_property(np, "reg", &size);
249
        paddr = of_translate_address(np, reg);
250
        mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
251
 
252
        mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
253
                                          MV64x60_NUM_IRQS,
254
                                          &mv64x60_host_ops, MV64x60_NUM_IRQS);
255
 
256
        spin_lock_irqsave(&mv64x60_lock, flags);
257
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
258
                 mv64x60_cached_gpp_mask);
259
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO,
260
                 mv64x60_cached_low_mask);
261
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI,
262
                 mv64x60_cached_high_mask);
263
 
264
        out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE, 0);
265
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_MAIN_CAUSE_LO, 0);
266
        out_le32(mv64x60_irq_reg_base + MV64X60_IC_MAIN_CAUSE_HI, 0);
267
        spin_unlock_irqrestore(&mv64x60_lock, flags);
268
}
269
 
270
unsigned int mv64x60_get_irq(void)
271
{
272
        u32 cause;
273
        int level1;
274
        irq_hw_number_t hwirq;
275
        int virq = NO_IRQ;
276
 
277
        cause = in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_SELECT_CAUSE);
278
        if (cause & MV64X60_SELECT_CAUSE_HIGH) {
279
                cause &= mv64x60_cached_high_mask;
280
                level1 = MV64x60_LEVEL1_HIGH;
281
                if (cause & MV64X60_HIGH_GPP_GROUPS) {
282
                        cause = in_le32(mv64x60_gpp_reg_base +
283
                                        MV64x60_GPP_INTR_CAUSE);
284
                        cause &= mv64x60_cached_gpp_mask;
285
                        level1 = MV64x60_LEVEL1_GPP;
286
                }
287
        } else {
288
                cause &= mv64x60_cached_low_mask;
289
                level1 = MV64x60_LEVEL1_LOW;
290
        }
291
        if (cause) {
292
                hwirq = (level1 << MV64x60_LEVEL1_OFFSET) | __ilog2(cause);
293
                virq = irq_linear_revmap(mv64x60_irq_host, hwirq);
294
        }
295
 
296
        return virq;
297
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.