~ubuntu-branches/ubuntu/maverick/u-boot-omap3/maverick

« back to all changes in this revision

Viewing changes to cpu/mpc5xxx/interrupts.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2010-03-22 15:06:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100322150623-i21g8rgiyl5dohag
Tags: upstream-2010.3git20100315
ImportĀ upstreamĀ versionĀ 2010.3git20100315

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (C) Copyright 2006
 
3
 * Detlev Zundel, DENX Software Engineering, dzu@denx.de
 
4
 *
 
5
 * (C) Copyright -2003
 
6
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
7
 *
 
8
 * (C) Copyright 2001
 
9
 * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
 
10
 *
 
11
 * See file CREDITS for list of people who contributed to this
 
12
 * project.
 
13
 *
 
14
 * This program is free software; you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation; either version 2 of
 
17
 * the License, or (at your option) any later version.
 
18
 *
 
19
 * This program is distributed in the hope that it will be useful,
 
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 * GNU General Public License for more details.
 
23
 *
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program; if not, write to the Free Software
 
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 
27
 * MA 02111-1307 USA
 
28
 */
 
29
 
 
30
/* this section was ripped out of arch/ppc/syslib/mpc52xx_pic.c in the
 
31
 * Linux 2.6 source with the following copyright.
 
32
 *
 
33
 * Based on (well, mostly copied from) the code from the 2.4 kernel by
 
34
 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
 
35
 *
 
36
 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
 
37
 * Copyright (C) 2003 Montavista Software, Inc
 
38
 */
 
39
 
 
40
#include <common.h>
 
41
#include <asm/processor.h>
 
42
#include <asm/io.h>
 
43
#include <command.h>
 
44
 
 
45
struct irq_action {
 
46
        interrupt_handler_t *handler;
 
47
        void *arg;
 
48
        ulong count;
 
49
};
 
50
 
 
51
static struct irq_action irq_handlers[NR_IRQS];
 
52
 
 
53
static struct mpc5xxx_intr *intr;
 
54
static struct mpc5xxx_sdma *sdma;
 
55
 
 
56
static void mpc5xxx_ic_disable(unsigned int irq)
 
57
{
 
58
        u32 val;
 
59
 
 
60
        if (irq == MPC5XXX_IRQ0) {
 
61
                val = in_be32(&intr->ctrl);
 
62
                val &= ~(1 << 11);
 
63
                out_be32(&intr->ctrl, val);
 
64
        } else if (irq < MPC5XXX_IRQ1) {
 
65
                BUG();
 
66
        } else if (irq <= MPC5XXX_IRQ3) {
 
67
                val = in_be32(&intr->ctrl);
 
68
                val &= ~(1 << (10 - (irq - MPC5XXX_IRQ1)));
 
69
                out_be32(&intr->ctrl, val);
 
70
        } else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
 
71
                val = in_be32(&intr->main_mask);
 
72
                val |= 1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE));
 
73
                out_be32(&intr->main_mask, val);
 
74
        } else if (irq < MPC5XXX_PERP_IRQ_BASE) {
 
75
                val = in_be32(&sdma->IntMask);
 
76
                val |= 1 << (irq - MPC5XXX_SDMA_IRQ_BASE);
 
77
                out_be32(&sdma->IntMask, val);
 
78
        } else {
 
79
                val = in_be32(&intr->per_mask);
 
80
                val |= 1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE));
 
81
                out_be32(&intr->per_mask, val);
 
82
        }
 
83
}
 
84
 
 
85
static void mpc5xxx_ic_enable(unsigned int irq)
 
86
{
 
87
        u32 val;
 
88
 
 
89
        if (irq == MPC5XXX_IRQ0) {
 
90
                val = in_be32(&intr->ctrl);
 
91
                val |= 1 << 11;
 
92
                out_be32(&intr->ctrl, val);
 
93
        } else if (irq < MPC5XXX_IRQ1) {
 
94
                BUG();
 
95
        } else if (irq <= MPC5XXX_IRQ3) {
 
96
                val = in_be32(&intr->ctrl);
 
97
                val |= 1 << (10 - (irq - MPC5XXX_IRQ1));
 
98
                out_be32(&intr->ctrl, val);
 
99
        } else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
 
100
                val = in_be32(&intr->main_mask);
 
101
                val &= ~(1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE)));
 
102
                out_be32(&intr->main_mask, val);
 
103
        } else if (irq < MPC5XXX_PERP_IRQ_BASE) {
 
104
                val = in_be32(&sdma->IntMask);
 
105
                val &= ~(1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
 
106
                out_be32(&sdma->IntMask, val);
 
107
        } else {
 
108
                val = in_be32(&intr->per_mask);
 
109
                val &= ~(1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE)));
 
110
                out_be32(&intr->per_mask, val);
 
111
        }
 
112
}
 
113
 
 
114
static void mpc5xxx_ic_ack(unsigned int irq)
 
115
{
 
116
        u32 val;
 
117
 
 
118
        /*
 
119
         * Only some irqs are reset here, others in interrupting hardware.
 
120
         */
 
121
 
 
122
        switch (irq) {
 
123
        case MPC5XXX_IRQ0:
 
124
                val = in_be32(&intr->ctrl);
 
125
                val |= 0x08000000;
 
126
                out_be32(&intr->ctrl, val);
 
127
                break;
 
128
        case MPC5XXX_CCS_IRQ:
 
129
                val = in_be32(&intr->enc_status);
 
130
                val |= 0x00000400;
 
131
                out_be32(&intr->enc_status, val);
 
132
                break;
 
133
        case MPC5XXX_IRQ1:
 
134
                val = in_be32(&intr->ctrl);
 
135
                val |= 0x04000000;
 
136
                out_be32(&intr->ctrl, val);
 
137
                break;
 
138
        case MPC5XXX_IRQ2:
 
139
                val = in_be32(&intr->ctrl);
 
140
                val |= 0x02000000;
 
141
                out_be32(&intr->ctrl, val);
 
142
                break;
 
143
        case MPC5XXX_IRQ3:
 
144
                val = in_be32(&intr->ctrl);
 
145
                val |= 0x01000000;
 
146
                out_be32(&intr->ctrl, val);
 
147
                break;
 
148
        default:
 
149
                if (irq >= MPC5XXX_SDMA_IRQ_BASE
 
150
                    && irq < (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM)) {
 
151
                        out_be32(&sdma->IntPend,
 
152
                                 1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
 
153
                }
 
154
                break;
 
155
        }
 
156
}
 
157
 
 
158
static void mpc5xxx_ic_disable_and_ack(unsigned int irq)
 
159
{
 
160
        mpc5xxx_ic_disable(irq);
 
161
        mpc5xxx_ic_ack(irq);
 
162
}
 
163
 
 
164
static void mpc5xxx_ic_end(unsigned int irq)
 
165
{
 
166
        mpc5xxx_ic_enable(irq);
 
167
}
 
168
 
 
169
void mpc5xxx_init_irq(void)
 
170
{
 
171
        u32 intr_ctrl;
 
172
 
 
173
        /* Remap the necessary zones */
 
174
        intr = (struct mpc5xxx_intr *)(MPC5XXX_ICTL);
 
175
        sdma = (struct mpc5xxx_sdma *)(MPC5XXX_SDMA);
 
176
 
 
177
        /* Disable all interrupt sources. */
 
178
        out_be32(&sdma->IntPend, 0xffffffff);   /* 1 means clear pending */
 
179
        out_be32(&sdma->IntMask, 0xffffffff);   /* 1 means disabled */
 
180
        out_be32(&intr->per_mask, 0x7ffffc00);  /* 1 means disabled */
 
181
        out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
 
182
        intr_ctrl = in_be32(&intr->ctrl);
 
183
        intr_ctrl |= 0x0f000000 |       /* clear IRQ 0-3 */
 
184
            0x00ff0000 |        /* IRQ 0-3 level sensitive low active */
 
185
            0x00001000 |        /* MEE master external enable */
 
186
            0x00000000 |        /* 0 means disable IRQ 0-3 */
 
187
            0x00000001;         /* CEb route critical normally */
 
188
        out_be32(&intr->ctrl, intr_ctrl);
 
189
 
 
190
        /* Zero a bunch of the priority settings.  */
 
191
        out_be32(&intr->per_pri1, 0);
 
192
        out_be32(&intr->per_pri2, 0);
 
193
        out_be32(&intr->per_pri3, 0);
 
194
        out_be32(&intr->main_pri1, 0);
 
195
        out_be32(&intr->main_pri2, 0);
 
196
}
 
197
 
 
198
int mpc5xxx_get_irq(struct pt_regs *regs)
 
199
{
 
200
        u32 status;
 
201
        int irq = -1;
 
202
 
 
203
        status = in_be32(&intr->enc_status);
 
204
 
 
205
        if (status & 0x00000400) {      /* critical */
 
206
                irq = (status >> 8) & 0x3;
 
207
                if (irq == 2)   /* high priority peripheral */
 
208
                        goto peripheral;
 
209
                irq += MPC5XXX_CRIT_IRQ_BASE;
 
210
        } else if (status & 0x00200000) {       /* main */
 
211
                irq = (status >> 16) & 0x1f;
 
212
                if (irq == 4)   /* low priority peripheral */
 
213
                        goto peripheral;
 
214
                irq += MPC5XXX_MAIN_IRQ_BASE;
 
215
        } else if (status & 0x20000000) {       /* peripheral */
 
216
              peripheral:
 
217
                irq = (status >> 24) & 0x1f;
 
218
                if (irq == 0) { /* bestcomm */
 
219
                        status = in_be32(&sdma->IntPend);
 
220
                        irq = ffs(status) + MPC5XXX_SDMA_IRQ_BASE - 1;
 
221
                } else
 
222
                        irq += MPC5XXX_PERP_IRQ_BASE;
 
223
        }
 
224
 
 
225
        return irq;
 
226
}
 
227
 
 
228
/****************************************************************************/
 
229
 
 
230
int interrupt_init_cpu(ulong * decrementer_count)
 
231
{
 
232
        *decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
 
233
 
 
234
        mpc5xxx_init_irq();
 
235
 
 
236
        return (0);
 
237
}
 
238
 
 
239
/****************************************************************************/
 
240
 
 
241
/*
 
242
 * Handle external interrupts
 
243
 */
 
244
void external_interrupt(struct pt_regs *regs)
 
245
{
 
246
        int irq, unmask = 1;
 
247
 
 
248
        irq = mpc5xxx_get_irq(regs);
 
249
 
 
250
        mpc5xxx_ic_disable_and_ack(irq);
 
251
 
 
252
        enable_interrupts();
 
253
 
 
254
        if (irq_handlers[irq].handler != NULL)
 
255
                (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
 
256
        else {
 
257
                printf("\nBogus External Interrupt IRQ %d\n", irq);
 
258
                /*
 
259
                 * turn off the bogus interrupt, otherwise it
 
260
                 * might repeat forever
 
261
                 */
 
262
                unmask = 0;
 
263
        }
 
264
 
 
265
        if (unmask)
 
266
                mpc5xxx_ic_end(irq);
 
267
}
 
268
 
 
269
void timer_interrupt_cpu(struct pt_regs *regs)
 
270
{
 
271
        /* nothing to do here */
 
272
        return;
 
273
}
 
274
 
 
275
/****************************************************************************/
 
276
 
 
277
/*
 
278
 * Install and free a interrupt handler.
 
279
 */
 
280
 
 
281
void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg)
 
282
{
 
283
        if (irq < 0 || irq >= NR_IRQS) {
 
284
                printf("irq_install_handler: bad irq number %d\n", irq);
 
285
                return;
 
286
        }
 
287
 
 
288
        if (irq_handlers[irq].handler != NULL)
 
289
                printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
 
290
                       (ulong) handler, (ulong) irq_handlers[irq].handler);
 
291
 
 
292
        irq_handlers[irq].handler = handler;
 
293
        irq_handlers[irq].arg = arg;
 
294
 
 
295
        mpc5xxx_ic_enable(irq);
 
296
}
 
297
 
 
298
void irq_free_handler(int irq)
 
299
{
 
300
        if (irq < 0 || irq >= NR_IRQS) {
 
301
                printf("irq_free_handler: bad irq number %d\n", irq);
 
302
                return;
 
303
        }
 
304
 
 
305
        mpc5xxx_ic_disable(irq);
 
306
 
 
307
        irq_handlers[irq].handler = NULL;
 
308
        irq_handlers[irq].arg = NULL;
 
309
}
 
310
 
 
311
/****************************************************************************/
 
312
 
 
313
#if defined(CONFIG_CMD_IRQ)
 
314
void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
 
315
{
 
316
        int irq, re_enable;
 
317
        u32 intr_ctrl;
 
318
        char *irq_config[] = { "level sensitive, active high",
 
319
                "edge sensitive, rising active edge",
 
320
                "edge sensitive, falling active edge",
 
321
                "level sensitive, active low"
 
322
        };
 
323
 
 
324
        re_enable = disable_interrupts();
 
325
 
 
326
        intr_ctrl = in_be32(&intr->ctrl);
 
327
        printf("Interrupt configuration:\n");
 
328
 
 
329
        for (irq = 0; irq <= 3; irq++) {
 
330
                printf("IRQ%d: %s\n", irq,
 
331
                       irq_config[(intr_ctrl >> (22 - 2 * irq)) & 0x3]);
 
332
        }
 
333
 
 
334
        puts("\nInterrupt-Information:\n" "Nr  Routine   Arg       Count\n");
 
335
 
 
336
        for (irq = 0; irq < NR_IRQS; irq++)
 
337
                if (irq_handlers[irq].handler != NULL)
 
338
                        printf("%02d  %08lx  %08lx  %ld\n", irq,
 
339
                               (ulong) irq_handlers[irq].handler,
 
340
                               (ulong) irq_handlers[irq].arg,
 
341
                               irq_handlers[irq].count);
 
342
 
 
343
        if (re_enable)
 
344
                enable_interrupts();
 
345
}
 
346
#endif