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/] [uic.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * arch/powerpc/sysdev/uic.c
3
 *
4
 * IBM PowerPC 4xx Universal Interrupt Controller
5
 *
6
 * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
7
 *
8
 * This program is free software; you can redistribute  it and/or modify it
9
 * under  the terms of  the GNU General  Public License as published by the
10
 * Free Software Foundation;  either version 2 of the  License, or (at your
11
 * option) any later version.
12
 */
13
#include <linux/kernel.h>
14
#include <linux/init.h>
15
#include <linux/errno.h>
16
#include <linux/reboot.h>
17
#include <linux/slab.h>
18
#include <linux/stddef.h>
19
#include <linux/sched.h>
20
#include <linux/signal.h>
21
#include <linux/sysdev.h>
22
#include <linux/device.h>
23
#include <linux/bootmem.h>
24
#include <linux/spinlock.h>
25
#include <linux/irq.h>
26
#include <linux/interrupt.h>
27
#include <linux/kernel_stat.h>
28
#include <asm/irq.h>
29
#include <asm/io.h>
30
#include <asm/prom.h>
31
#include <asm/dcr.h>
32
 
33
#define NR_UIC_INTS     32
34
 
35
#define UIC_SR          0x0
36
#define UIC_ER          0x2
37
#define UIC_CR          0x3
38
#define UIC_PR          0x4
39
#define UIC_TR          0x5
40
#define UIC_MSR         0x6
41
#define UIC_VR          0x7
42
#define UIC_VCR         0x8
43
 
44
#define uic_irq_to_hw(virq)     (irq_map[virq].hwirq)
45
 
46
struct uic *primary_uic;
47
 
48
struct uic {
49
        int index;
50
        int dcrbase;
51
 
52
        spinlock_t lock;
53
 
54
        /* The remapper for this UIC */
55
        struct irq_host *irqhost;
56
 
57
        /* For secondary UICs, the cascade interrupt's irqaction */
58
        struct irqaction cascade;
59
};
60
 
61
static void uic_unmask_irq(unsigned int virq)
62
{
63
        struct uic *uic = get_irq_chip_data(virq);
64
        unsigned int src = uic_irq_to_hw(virq);
65
        unsigned long flags;
66
        u32 er;
67
 
68
        spin_lock_irqsave(&uic->lock, flags);
69
        er = mfdcr(uic->dcrbase + UIC_ER);
70
        er |= 1 << (31 - src);
71
        mtdcr(uic->dcrbase + UIC_ER, er);
72
        spin_unlock_irqrestore(&uic->lock, flags);
73
}
74
 
75
static void uic_mask_irq(unsigned int virq)
76
{
77
        struct uic *uic = get_irq_chip_data(virq);
78
        unsigned int src = uic_irq_to_hw(virq);
79
        unsigned long flags;
80
        u32 er;
81
 
82
        spin_lock_irqsave(&uic->lock, flags);
83
        er = mfdcr(uic->dcrbase + UIC_ER);
84
        er &= ~(1 << (31 - src));
85
        mtdcr(uic->dcrbase + UIC_ER, er);
86
        spin_unlock_irqrestore(&uic->lock, flags);
87
}
88
 
89
static void uic_ack_irq(unsigned int virq)
90
{
91
        struct uic *uic = get_irq_chip_data(virq);
92
        unsigned int src = uic_irq_to_hw(virq);
93
        unsigned long flags;
94
 
95
        spin_lock_irqsave(&uic->lock, flags);
96
        mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
97
        spin_unlock_irqrestore(&uic->lock, flags);
98
}
99
 
100
static void uic_mask_ack_irq(unsigned int virq)
101
{
102
        struct uic *uic = get_irq_chip_data(virq);
103
        unsigned int src = uic_irq_to_hw(virq);
104
        unsigned long flags;
105
        u32 er, sr;
106
 
107
        sr = 1 << (31-src);
108
        spin_lock_irqsave(&uic->lock, flags);
109
        er = mfdcr(uic->dcrbase + UIC_ER);
110
        er &= ~sr;
111
        mtdcr(uic->dcrbase + UIC_ER, er);
112
        mtdcr(uic->dcrbase + UIC_SR, sr);
113
        spin_unlock_irqrestore(&uic->lock, flags);
114
}
115
 
116
static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
117
{
118
        struct uic *uic = get_irq_chip_data(virq);
119
        unsigned int src = uic_irq_to_hw(virq);
120
        struct irq_desc *desc = get_irq_desc(virq);
121
        unsigned long flags;
122
        int trigger, polarity;
123
        u32 tr, pr, mask;
124
 
125
        switch (flow_type & IRQ_TYPE_SENSE_MASK) {
126
        case IRQ_TYPE_NONE:
127
                uic_mask_irq(virq);
128
                return 0;
129
 
130
        case IRQ_TYPE_EDGE_RISING:
131
                trigger = 1; polarity = 1;
132
                break;
133
        case IRQ_TYPE_EDGE_FALLING:
134
                trigger = 1; polarity = 0;
135
                break;
136
        case IRQ_TYPE_LEVEL_HIGH:
137
                trigger = 0; polarity = 1;
138
                break;
139
        case IRQ_TYPE_LEVEL_LOW:
140
                trigger = 0; polarity = 0;
141
                break;
142
        default:
143
                return -EINVAL;
144
        }
145
 
146
        mask = ~(1 << (31 - src));
147
 
148
        spin_lock_irqsave(&uic->lock, flags);
149
        tr = mfdcr(uic->dcrbase + UIC_TR);
150
        pr = mfdcr(uic->dcrbase + UIC_PR);
151
        tr = (tr & mask) | (trigger << (31-src));
152
        pr = (pr & mask) | (polarity << (31-src));
153
 
154
        mtdcr(uic->dcrbase + UIC_PR, pr);
155
        mtdcr(uic->dcrbase + UIC_TR, tr);
156
 
157
        desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
158
        desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
159
        if (!trigger)
160
                desc->status |= IRQ_LEVEL;
161
 
162
        spin_unlock_irqrestore(&uic->lock, flags);
163
 
164
        return 0;
165
}
166
 
167
static struct irq_chip uic_irq_chip = {
168
        .typename       = " UIC  ",
169
        .unmask         = uic_unmask_irq,
170
        .mask           = uic_mask_irq,
171
        .mask_ack       = uic_mask_ack_irq,
172
        .ack            = uic_ack_irq,
173
        .set_type       = uic_set_irq_type,
174
};
175
 
176
/**
177
 *      handle_uic_irq - irq flow handler for UIC
178
 *      @irq:   the interrupt number
179
 *      @desc:  the interrupt description structure for this irq
180
 *
181
 * This is modified version of the generic handle_level_irq() suitable
182
 * for the UIC.  On the UIC, acking (i.e. clearing the SR bit) a level
183
 * irq will have no effect if the interrupt is still asserted by the
184
 * device, even if the interrupt is already masked.  Therefore, unlike
185
 * the standard handle_level_irq(), we must ack the interrupt *after*
186
 * invoking the ISR (which should have de-asserted the interrupt in
187
 * the external source).  For edge interrupts we ack at the beginning
188
 * instead of the end, to keep the window in which we can miss an
189
 * interrupt as small as possible.
190
 */
191
void fastcall handle_uic_irq(unsigned int irq, struct irq_desc *desc)
192
{
193
        unsigned int cpu = smp_processor_id();
194
        struct irqaction *action;
195
        irqreturn_t action_ret;
196
 
197
        spin_lock(&desc->lock);
198
        if (desc->status & IRQ_LEVEL)
199
                desc->chip->mask(irq);
200
        else
201
                desc->chip->mask_ack(irq);
202
 
203
        if (unlikely(desc->status & IRQ_INPROGRESS))
204
                goto out_unlock;
205
        desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
206
        kstat_cpu(cpu).irqs[irq]++;
207
 
208
        /*
209
         * If its disabled or no action available
210
         * keep it masked and get out of here
211
         */
212
        action = desc->action;
213
        if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
214
                desc->status |= IRQ_PENDING;
215
                goto out_unlock;
216
        }
217
 
218
        desc->status |= IRQ_INPROGRESS;
219
        desc->status &= ~IRQ_PENDING;
220
        spin_unlock(&desc->lock);
221
 
222
        action_ret = handle_IRQ_event(irq, action);
223
 
224
        spin_lock(&desc->lock);
225
        desc->status &= ~IRQ_INPROGRESS;
226
        if (desc->status & IRQ_LEVEL)
227
                desc->chip->ack(irq);
228
        if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
229
                desc->chip->unmask(irq);
230
out_unlock:
231
        spin_unlock(&desc->lock);
232
}
233
 
234
static int uic_host_map(struct irq_host *h, unsigned int virq,
235
                        irq_hw_number_t hw)
236
{
237
        struct uic *uic = h->host_data;
238
 
239
        set_irq_chip_data(virq, uic);
240
        /* Despite the name, handle_level_irq() works for both level
241
         * and edge irqs on UIC.  FIXME: check this is correct */
242
        set_irq_chip_and_handler(virq, &uic_irq_chip, handle_uic_irq);
243
 
244
        /* Set default irq type */
245
        set_irq_type(virq, IRQ_TYPE_NONE);
246
 
247
        return 0;
248
}
249
 
250
static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
251
                          u32 *intspec, unsigned int intsize,
252
                          irq_hw_number_t *out_hwirq, unsigned int *out_type)
253
 
254
{
255
        /* UIC intspecs must have 2 cells */
256
        BUG_ON(intsize != 2);
257
        *out_hwirq = intspec[0];
258
        *out_type = intspec[1];
259
        return 0;
260
}
261
 
262
static struct irq_host_ops uic_host_ops = {
263
        .map    = uic_host_map,
264
        .xlate  = uic_host_xlate,
265
};
266
 
267
irqreturn_t uic_cascade(int virq, void *data)
268
{
269
        struct uic *uic = data;
270
        u32 msr;
271
        int src;
272
        int subvirq;
273
 
274
        msr = mfdcr(uic->dcrbase + UIC_MSR);
275
        if (!msr) /* spurious interrupt */
276
                return IRQ_HANDLED;
277
 
278
        src = 32 - ffs(msr);
279
 
280
        subvirq = irq_linear_revmap(uic->irqhost, src);
281
        generic_handle_irq(subvirq);
282
 
283
        return IRQ_HANDLED;
284
}
285
 
286
static struct uic * __init uic_init_one(struct device_node *node)
287
{
288
        struct uic *uic;
289
        const u32 *indexp, *dcrreg;
290
        int len;
291
 
292
        BUG_ON(! of_device_is_compatible(node, "ibm,uic"));
293
 
294
        uic = alloc_bootmem(sizeof(*uic));
295
        if (! uic)
296
                return NULL; /* FIXME: panic? */
297
 
298
        memset(uic, 0, sizeof(*uic));
299
        spin_lock_init(&uic->lock);
300
        indexp = of_get_property(node, "cell-index", &len);
301
        if (!indexp || (len != sizeof(u32))) {
302
                printk(KERN_ERR "uic: Device node %s has missing or invalid "
303
                       "cell-index property\n", node->full_name);
304
                return NULL;
305
        }
306
        uic->index = *indexp;
307
 
308
        dcrreg = of_get_property(node, "dcr-reg", &len);
309
        if (!dcrreg || (len != 2*sizeof(u32))) {
310
                printk(KERN_ERR "uic: Device node %s has missing or invalid "
311
                       "dcr-reg property\n", node->full_name);
312
                return NULL;
313
        }
314
        uic->dcrbase = *dcrreg;
315
 
316
        uic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR,
317
                                      NR_UIC_INTS, &uic_host_ops, -1);
318
        if (! uic->irqhost) {
319
                of_node_put(node);
320
                return NULL; /* FIXME: panic? */
321
        }
322
 
323
        uic->irqhost->host_data = uic;
324
 
325
        /* Start with all interrupts disabled, level and non-critical */
326
        mtdcr(uic->dcrbase + UIC_ER, 0);
327
        mtdcr(uic->dcrbase + UIC_CR, 0);
328
        mtdcr(uic->dcrbase + UIC_TR, 0);
329
        /* Clear any pending interrupts, in case the firmware left some */
330
        mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);
331
 
332
        printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
333
                NR_UIC_INTS, uic->dcrbase);
334
 
335
        return uic;
336
}
337
 
338
void __init uic_init_tree(void)
339
{
340
        struct device_node *np;
341
        struct uic *uic;
342
        const u32 *interrupts;
343
 
344
        /* First locate and initialize the top-level UIC */
345
 
346
        np = of_find_compatible_node(NULL, NULL, "ibm,uic");
347
        while (np) {
348
                interrupts = of_get_property(np, "interrupts", NULL);
349
                if (! interrupts)
350
                        break;
351
 
352
                np = of_find_compatible_node(np, NULL, "ibm,uic");
353
        }
354
 
355
        BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
356
                      * top-level interrupt controller */
357
        primary_uic = uic_init_one(np);
358
        if (! primary_uic)
359
                panic("Unable to initialize primary UIC %s\n", np->full_name);
360
 
361
        irq_set_default_host(primary_uic->irqhost);
362
        of_node_put(np);
363
 
364
        /* The scan again for cascaded UICs */
365
        np = of_find_compatible_node(NULL, NULL, "ibm,uic");
366
        while (np) {
367
                interrupts = of_get_property(np, "interrupts", NULL);
368
                if (interrupts) {
369
                        /* Secondary UIC */
370
                        int cascade_virq;
371
                        int ret;
372
 
373
                        uic = uic_init_one(np);
374
                        if (! uic)
375
                                panic("Unable to initialize a secondary UIC %s\n",
376
                                      np->full_name);
377
 
378
                        cascade_virq = irq_of_parse_and_map(np, 0);
379
 
380
                        uic->cascade.handler = uic_cascade;
381
                        uic->cascade.name = "UIC cascade";
382
                        uic->cascade.dev_id = uic;
383
 
384
                        ret = setup_irq(cascade_virq, &uic->cascade);
385
                        if (ret)
386
                                printk(KERN_ERR "Failed to setup_irq(%d) for "
387
                                       "UIC%d cascade\n", cascade_virq,
388
                                       uic->index);
389
 
390
                        /* FIXME: setup critical cascade?? */
391
                }
392
 
393
                np = of_find_compatible_node(np, NULL, "ibm,uic");
394
        }
395
}
396
 
397
/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
398
unsigned int uic_get_irq(void)
399
{
400
        u32 msr;
401
        int src;
402
 
403
        BUG_ON(! primary_uic);
404
 
405
        msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
406
        src = 32 - ffs(msr);
407
 
408
        return irq_linear_revmap(primary_uic->irqhost, src);
409
}

powered by: WebSVN 2.1.0

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