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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Platform information definitions.
3
 *
4
 * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates
5
 * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek.
6
 *
7
 * Author:  Vitaly Bordug <vbordug@ru.mvista.com>
8
 *
9
 * 1999-2001 (c) Dan Malek <dan@embeddedalley.com>
10
 * 2006 (c) MontaVista Software, Inc.
11
 *
12
 * This file is licensed under the terms of the GNU General Public License
13
 * version 2. This program is licensed "as is" without any warranty of any
14
 * kind, whether express or implied.
15
 */
16
 
17
/* The CPM2 internal interrupt controller.  It is usually
18
 * the only interrupt controller.
19
 * There are two 32-bit registers (high/low) for up to 64
20
 * possible interrupts.
21
 *
22
 * Now, the fun starts.....Interrupt Numbers DO NOT MAP
23
 * in a simple arithmetic fashion to mask or pending registers.
24
 * That is, interrupt 4 does not map to bit position 4.
25
 * We create two tables, indexed by vector number, to indicate
26
 * which register to use and which bit in the register to use.
27
 */
28
 
29
#include <linux/stddef.h>
30
#include <linux/init.h>
31
#include <linux/sched.h>
32
#include <linux/signal.h>
33
#include <linux/irq.h>
34
 
35
#include <asm/immap_cpm2.h>
36
#include <asm/mpc8260.h>
37
#include <asm/io.h>
38
#include <asm/prom.h>
39
#include <asm/fs_pd.h>
40
 
41
#include "cpm2_pic.h"
42
 
43
/* External IRQS */
44
#define CPM2_IRQ_EXT1           19
45
#define CPM2_IRQ_EXT7           25
46
 
47
/* Port C IRQS */
48
#define CPM2_IRQ_PORTC15        48
49
#define CPM2_IRQ_PORTC0         63
50
 
51
static intctl_cpm2_t __iomem *cpm2_intctl;
52
 
53
static struct irq_host *cpm2_pic_host;
54
#define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)
55
static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
56
 
57
static const u_char irq_to_siureg[] = {
58
        1, 1, 1, 1, 1, 1, 1, 1,
59
        1, 1, 1, 1, 1, 1, 1, 1,
60
        0, 0, 0, 0, 0, 0, 0, 0,
61
        0, 0, 0, 0, 0, 0, 0, 0,
62
        1, 1, 1, 1, 1, 1, 1, 1,
63
        1, 1, 1, 1, 1, 1, 1, 1,
64
        0, 0, 0, 0, 0, 0, 0, 0,
65
        0, 0, 0, 0, 0, 0, 0, 0
66
};
67
 
68
/* bit numbers do not match the docs, these are precomputed so the bit for
69
 * a given irq is (1 << irq_to_siubit[irq]) */
70
static const u_char irq_to_siubit[] = {
71
         0, 15, 14, 13, 12, 11, 10,  9,
72
         8,  7,  6,  5,  4,  3,  2,  1,
73
         2,  1,  0, 14, 13, 12, 11, 10,
74
         9,  8,  7,  6,  5,  4,  3,  0,
75
        31, 30, 29, 28, 27, 26, 25, 24,
76
        23, 22, 21, 20, 19, 18, 17, 16,
77
        16, 17, 18, 19, 20, 21, 22, 23,
78
        24, 25, 26, 27, 28, 29, 30, 31,
79
};
80
 
81
static void cpm2_mask_irq(unsigned int virq)
82
{
83
        int     bit, word;
84
        unsigned int irq_nr = virq_to_hw(virq);
85
 
86
        bit = irq_to_siubit[irq_nr];
87
        word = irq_to_siureg[irq_nr];
88
 
89
        ppc_cached_irq_mask[word] &= ~(1 << bit);
90
        out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
91
}
92
 
93
static void cpm2_unmask_irq(unsigned int virq)
94
{
95
        int     bit, word;
96
        unsigned int irq_nr = virq_to_hw(virq);
97
 
98
        bit = irq_to_siubit[irq_nr];
99
        word = irq_to_siureg[irq_nr];
100
 
101
        ppc_cached_irq_mask[word] |= 1 << bit;
102
        out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
103
}
104
 
105
static void cpm2_ack(unsigned int virq)
106
{
107
        int     bit, word;
108
        unsigned int irq_nr = virq_to_hw(virq);
109
 
110
        bit = irq_to_siubit[irq_nr];
111
        word = irq_to_siureg[irq_nr];
112
 
113
        out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
114
}
115
 
116
static void cpm2_end_irq(unsigned int virq)
117
{
118
        int     bit, word;
119
        unsigned int irq_nr = virq_to_hw(virq);
120
 
121
        if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
122
                        && irq_desc[irq_nr].action) {
123
 
124
                bit = irq_to_siubit[irq_nr];
125
                word = irq_to_siureg[irq_nr];
126
 
127
                ppc_cached_irq_mask[word] |= 1 << bit;
128
                out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
129
 
130
                /*
131
                 * Work around large numbers of spurious IRQs on PowerPC 82xx
132
                 * systems.
133
                 */
134
                mb();
135
        }
136
}
137
 
138
static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
139
{
140
        unsigned int src = virq_to_hw(virq);
141
        struct irq_desc *desc = get_irq_desc(virq);
142
        unsigned int vold, vnew, edibit;
143
 
144
        if (flow_type == IRQ_TYPE_NONE)
145
                flow_type = IRQ_TYPE_LEVEL_LOW;
146
 
147
        if (flow_type & IRQ_TYPE_EDGE_RISING) {
148
                printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n",
149
                        flow_type);
150
                return -EINVAL;
151
        }
152
 
153
        desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
154
        desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
155
        if (flow_type & IRQ_TYPE_LEVEL_LOW)  {
156
                desc->status |= IRQ_LEVEL;
157
                desc->handle_irq = handle_level_irq;
158
        } else
159
                desc->handle_irq = handle_edge_irq;
160
 
161
        /* internal IRQ senses are LEVEL_LOW
162
         * EXT IRQ and Port C IRQ senses are programmable
163
         */
164
        if (src >= CPM2_IRQ_EXT1 && src <= CPM2_IRQ_EXT7)
165
                        edibit = (14 - (src - CPM2_IRQ_EXT1));
166
        else
167
                if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0)
168
                        edibit = (31 - (src - CPM2_IRQ_PORTC15));
169
                else
170
                        return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
171
 
172
        vold = in_be32(&cpm2_intctl->ic_siexr);
173
 
174
        if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING)
175
                vnew = vold | (1 << edibit);
176
        else
177
                vnew = vold & ~(1 << edibit);
178
 
179
        if (vold != vnew)
180
                out_be32(&cpm2_intctl->ic_siexr, vnew);
181
        return 0;
182
}
183
 
184
static struct irq_chip cpm2_pic = {
185
        .typename = " CPM2 SIU ",
186
        .mask = cpm2_mask_irq,
187
        .unmask = cpm2_unmask_irq,
188
        .ack = cpm2_ack,
189
        .eoi = cpm2_end_irq,
190
        .set_type = cpm2_set_irq_type,
191
};
192
 
193
unsigned int cpm2_get_irq(void)
194
{
195
        int irq;
196
        unsigned long bits;
197
 
198
       /* For CPM2, read the SIVEC register and shift the bits down
199
         * to get the irq number.         */
200
        bits = in_be32(&cpm2_intctl->ic_sivec);
201
        irq = bits >> 26;
202
 
203
        if (irq == 0)
204
                return(-1);
205
        return irq_linear_revmap(cpm2_pic_host, irq);
206
}
207
 
208
static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
209
                          irq_hw_number_t hw)
210
{
211
        pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
212
 
213
        get_irq_desc(virq)->status |= IRQ_LEVEL;
214
        set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq);
215
        return 0;
216
}
217
 
218
static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
219
                            u32 *intspec, unsigned int intsize,
220
                            irq_hw_number_t *out_hwirq, unsigned int *out_flags)
221
{
222
        *out_hwirq = intspec[0];
223
        if (intsize > 1)
224
                *out_flags = intspec[1];
225
        else
226
                *out_flags = IRQ_TYPE_NONE;
227
        return 0;
228
}
229
 
230
static struct irq_host_ops cpm2_pic_host_ops = {
231
        .map = cpm2_pic_host_map,
232
        .xlate = cpm2_pic_host_xlate,
233
};
234
 
235
void cpm2_pic_init(struct device_node *node)
236
{
237
        int i;
238
 
239
        cpm2_intctl = cpm2_map(im_intctl);
240
 
241
        /* Clear the CPM IRQ controller, in case it has any bits set
242
         * from the bootloader
243
         */
244
 
245
        /* Mask out everything */
246
 
247
        out_be32(&cpm2_intctl->ic_simrh, 0x00000000);
248
        out_be32(&cpm2_intctl->ic_simrl, 0x00000000);
249
 
250
        wmb();
251
 
252
        /* Ack everything */
253
        out_be32(&cpm2_intctl->ic_sipnrh, 0xffffffff);
254
        out_be32(&cpm2_intctl->ic_sipnrl, 0xffffffff);
255
        wmb();
256
 
257
        /* Dummy read of the vector */
258
        i = in_be32(&cpm2_intctl->ic_sivec);
259
        rmb();
260
 
261
        /* Initialize the default interrupt mapping priorities,
262
         * in case the boot rom changed something on us.
263
         */
264
        out_be16(&cpm2_intctl->ic_sicr, 0);
265
        out_be32(&cpm2_intctl->ic_scprrh, 0x05309770);
266
        out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
267
 
268
        /* create a legacy host */
269
        cpm2_pic_host = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR,
270
                                       64, &cpm2_pic_host_ops, 64);
271
        if (cpm2_pic_host == NULL) {
272
                printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
273
                return;
274
        }
275
}

powered by: WebSVN 2.1.0

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