~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to arch/mips/nxp/pnx8550/common/int.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *
3
 
 * Copyright (C) 2005 Embedded Alley Solutions, Inc
4
 
 * Ported to 2.6.
5
 
 *
6
 
 * Per Hallsmark, per.hallsmark@mvista.com
7
 
 * Copyright (C) 2000, 2001 MIPS Technologies, Inc.
8
 
 * Copyright (C) 2001 Ralf Baechle
9
 
 *
10
 
 * Cleaned up and bug fixing: Pete Popov, ppopov@embeddedalley.com
11
 
 *
12
 
 *  This program is free software; you can distribute it and/or modify it
13
 
 *  under the terms of the GNU General Public License (Version 2) as
14
 
 *  published by the Free Software Foundation.
15
 
 *
16
 
 *  This program is distributed in the hope it will be useful, but WITHOUT
17
 
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
 
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19
 
 *  for more details.
20
 
 *
21
 
 *  You should have received a copy of the GNU General Public License along
22
 
 *  with this program; if not, write to the Free Software Foundation, Inc.,
23
 
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
24
 
 *
25
 
 */
26
 
#include <linux/compiler.h>
27
 
#include <linux/init.h>
28
 
#include <linux/irq.h>
29
 
#include <linux/sched.h>
30
 
#include <linux/slab.h>
31
 
#include <linux/interrupt.h>
32
 
#include <linux/kernel_stat.h>
33
 
#include <linux/random.h>
34
 
#include <linux/module.h>
35
 
 
36
 
#include <asm/io.h>
37
 
#include <int.h>
38
 
#include <uart.h>
39
 
 
40
 
/* default prio for interrupts */
41
 
/* first one is a no-no so therefore always prio 0 (disabled) */
42
 
static char gic_prio[PNX8550_INT_GIC_TOTINT] = {
43
 
        0, 1, 1, 1, 1, 15, 1, 1, 1, 1,  //   0 -  9
44
 
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   //  10 - 19
45
 
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   //  20 - 29
46
 
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   //  30 - 39
47
 
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   //  40 - 49
48
 
        1, 1, 1, 1, 1, 1, 1, 1, 2, 1,   //  50 - 59
49
 
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   //  60 - 69
50
 
        1                       //  70
51
 
};
52
 
 
53
 
static void hw0_irqdispatch(int irq)
54
 
{
55
 
        /* find out which interrupt */
56
 
        irq = PNX8550_GIC_VECTOR_0 >> 3;
57
 
 
58
 
        if (irq == 0) {
59
 
                printk("hw0_irqdispatch: irq 0, spurious interrupt?\n");
60
 
                return;
61
 
        }
62
 
        do_IRQ(PNX8550_INT_GIC_MIN + irq);
63
 
}
64
 
 
65
 
 
66
 
static void timer_irqdispatch(int irq)
67
 
{
68
 
        irq = (0x01c0 & read_c0_config7()) >> 6;
69
 
 
70
 
        if (unlikely(irq == 0)) {
71
 
                printk("timer_irqdispatch: irq 0, spurious interrupt?\n");
72
 
                return;
73
 
        }
74
 
 
75
 
        if (irq & 0x1)
76
 
                do_IRQ(PNX8550_INT_TIMER1);
77
 
        if (irq & 0x2)
78
 
                do_IRQ(PNX8550_INT_TIMER2);
79
 
        if (irq & 0x4)
80
 
                do_IRQ(PNX8550_INT_TIMER3);
81
 
}
82
 
 
83
 
asmlinkage void plat_irq_dispatch(void)
84
 
{
85
 
        unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
86
 
 
87
 
        if (pending & STATUSF_IP2)
88
 
                hw0_irqdispatch(2);
89
 
        else if (pending & STATUSF_IP7) {
90
 
                if (read_c0_config7() & 0x01c0)
91
 
                        timer_irqdispatch(7);
92
 
        } else
93
 
                spurious_interrupt();
94
 
}
95
 
 
96
 
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
97
 
{
98
 
        unsigned long status = read_c0_status();
99
 
 
100
 
        status &= ~((clr_mask & 0xFF) << 8);
101
 
        status |= (set_mask & 0xFF) << 8;
102
 
 
103
 
        write_c0_status(status);
104
 
}
105
 
 
106
 
static inline void mask_gic_int(unsigned int irq_nr)
107
 
{
108
 
        /* interrupt disabled, bit 26(WE_ENABLE)=1 and bit 16(enable)=0 */
109
 
        PNX8550_GIC_REQ(irq_nr) = 1<<28; /* set priority to 0 */
110
 
}
111
 
 
112
 
static inline void unmask_gic_int(unsigned int irq_nr)
113
 
{
114
 
        /* set prio mask to lower four bits and enable interrupt */
115
 
        PNX8550_GIC_REQ(irq_nr) = (1<<26 | 1<<16) | (1<<28) | gic_prio[irq_nr];
116
 
}
117
 
 
118
 
static inline void mask_irq(unsigned int irq_nr)
119
 
{
120
 
        if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) {
121
 
                modify_cp0_intmask(1 << irq_nr, 0);
122
 
        } else if ((PNX8550_INT_GIC_MIN <= irq_nr) &&
123
 
                (irq_nr <= PNX8550_INT_GIC_MAX)) {
124
 
                mask_gic_int(irq_nr - PNX8550_INT_GIC_MIN);
125
 
        } else if ((PNX8550_INT_TIMER_MIN <= irq_nr) &&
126
 
                (irq_nr <= PNX8550_INT_TIMER_MAX)) {
127
 
                modify_cp0_intmask(1 << 7, 0);
128
 
        } else {
129
 
                printk("mask_irq: irq %d doesn't exist!\n", irq_nr);
130
 
        }
131
 
}
132
 
 
133
 
static inline void unmask_irq(unsigned int irq_nr)
134
 
{
135
 
        if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) {
136
 
                modify_cp0_intmask(0, 1 << irq_nr);
137
 
        } else if ((PNX8550_INT_GIC_MIN <= irq_nr) &&
138
 
                (irq_nr <= PNX8550_INT_GIC_MAX)) {
139
 
                unmask_gic_int(irq_nr - PNX8550_INT_GIC_MIN);
140
 
        } else if ((PNX8550_INT_TIMER_MIN <= irq_nr) &&
141
 
                (irq_nr <= PNX8550_INT_TIMER_MAX)) {
142
 
                modify_cp0_intmask(0, 1 << 7);
143
 
        } else {
144
 
                printk("mask_irq: irq %d doesn't exist!\n", irq_nr);
145
 
        }
146
 
}
147
 
 
148
 
int pnx8550_set_gic_priority(int irq, int priority)
149
 
{
150
 
        int gic_irq = irq-PNX8550_INT_GIC_MIN;
151
 
        int prev_priority = PNX8550_GIC_REQ(gic_irq) & 0xf;
152
 
 
153
 
        gic_prio[gic_irq] = priority;
154
 
        PNX8550_GIC_REQ(gic_irq) |= (0x10000000 | gic_prio[gic_irq]);
155
 
 
156
 
        return prev_priority;
157
 
}
158
 
 
159
 
static struct irq_chip level_irq_type = {
160
 
        .name =         "PNX Level IRQ",
161
 
        .ack =          mask_irq,
162
 
        .mask =         mask_irq,
163
 
        .mask_ack =     mask_irq,
164
 
        .unmask =       unmask_irq,
165
 
};
166
 
 
167
 
static struct irqaction gic_action = {
168
 
        .handler =      no_action,
169
 
        .flags =        IRQF_DISABLED,
170
 
        .name =         "GIC",
171
 
};
172
 
 
173
 
static struct irqaction timer_action = {
174
 
        .handler =      no_action,
175
 
        .flags =        IRQF_DISABLED | IRQF_TIMER,
176
 
        .name =         "Timer",
177
 
};
178
 
 
179
 
void __init arch_init_irq(void)
180
 
{
181
 
        int i;
182
 
        int configPR;
183
 
 
184
 
        for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
185
 
                set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq);
186
 
                mask_irq(i);    /* mask the irq just in case  */
187
 
        }
188
 
 
189
 
        /* init of GIC/IPC interrupts */
190
 
        /* should be done before cp0 since cp0 init enables the GIC int */
191
 
        for (i = PNX8550_INT_GIC_MIN; i <= PNX8550_INT_GIC_MAX; i++) {
192
 
                int gic_int_line = i - PNX8550_INT_GIC_MIN;
193
 
                if (gic_int_line == 0 )
194
 
                        continue;       // don't fiddle with int 0
195
 
                /*
196
 
                 * enable change of TARGET, ENABLE and ACTIVE_LOW bits
197
 
                 * set TARGET        0 to route through hw0 interrupt
198
 
                 * set ACTIVE_LOW    0 active high  (correct?)
199
 
                 *
200
 
                 * We really should setup an interrupt description table
201
 
                 * to do this nicely.
202
 
                 * Note, PCI INTA is active low on the bus, but inverted
203
 
                 * in the GIC, so to us it's active high.
204
 
                 */
205
 
                PNX8550_GIC_REQ(i - PNX8550_INT_GIC_MIN) = 0x1E000000;
206
 
 
207
 
                /* mask/priority is still 0 so we will not get any
208
 
                 * interrupts until it is unmasked */
209
 
 
210
 
                set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq);
211
 
        }
212
 
 
213
 
        /* Priority level 0 */
214
 
        PNX8550_GIC_PRIMASK_0 = PNX8550_GIC_PRIMASK_1 = 0;
215
 
 
216
 
        /* Set int vector table address */
217
 
        PNX8550_GIC_VECTOR_0 = PNX8550_GIC_VECTOR_1 = 0;
218
 
 
219
 
        set_irq_chip_and_handler(MIPS_CPU_GIC_IRQ, &level_irq_type,
220
 
                                 handle_level_irq);
221
 
        setup_irq(MIPS_CPU_GIC_IRQ, &gic_action);
222
 
 
223
 
        /* init of Timer interrupts */
224
 
        for (i = PNX8550_INT_TIMER_MIN; i <= PNX8550_INT_TIMER_MAX; i++)
225
 
                set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq);
226
 
 
227
 
        /* Stop Timer 1-3 */
228
 
        configPR = read_c0_config7();
229
 
        configPR |= 0x00000038;
230
 
        write_c0_config7(configPR);
231
 
 
232
 
        set_irq_chip_and_handler(MIPS_CPU_TIMER_IRQ, &level_irq_type,
233
 
                                 handle_level_irq);
234
 
        setup_irq(MIPS_CPU_TIMER_IRQ, &timer_action);
235
 
}
236
 
 
237
 
EXPORT_SYMBOL(pnx8550_set_gic_priority);