~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/powerpc/sysdev/qe_lib/qe_ic.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * arch/powerpc/sysdev/qe_lib/qe_ic.c
 
3
 *
 
4
 * Copyright (C) 2006 Freescale Semicondutor, Inc.  All rights reserved.
 
5
 *
 
6
 * Author: Li Yang <leoli@freescale.com>
 
7
 * Based on code from Shlomi Gridish <gridish@freescale.com>
 
8
 *
 
9
 * QUICC ENGINE Interrupt Controller
 
10
 *
 
11
 * This program is free software; you can redistribute  it and/or modify it
 
12
 * under  the terms of  the GNU General  Public License as published by the
 
13
 * Free Software Foundation;  either version 2 of the  License, or (at your
 
14
 * option) any later version.
 
15
 */
 
16
 
 
17
#include <linux/kernel.h>
 
18
#include <linux/init.h>
 
19
#include <linux/errno.h>
 
20
#include <linux/reboot.h>
 
21
#include <linux/slab.h>
 
22
#include <linux/stddef.h>
 
23
#include <linux/sched.h>
 
24
#include <linux/signal.h>
 
25
#include <linux/sysdev.h>
 
26
#include <linux/device.h>
 
27
#include <linux/bootmem.h>
 
28
#include <linux/spinlock.h>
 
29
#include <asm/irq.h>
 
30
#include <asm/io.h>
 
31
#include <asm/prom.h>
 
32
#include <asm/qe_ic.h>
 
33
 
 
34
#include "qe_ic.h"
 
35
 
 
36
static DEFINE_RAW_SPINLOCK(qe_ic_lock);
 
37
 
 
38
static struct qe_ic_info qe_ic_info[] = {
 
39
        [1] = {
 
40
               .mask = 0x00008000,
 
41
               .mask_reg = QEIC_CIMR,
 
42
               .pri_code = 0,
 
43
               .pri_reg = QEIC_CIPWCC,
 
44
               },
 
45
        [2] = {
 
46
               .mask = 0x00004000,
 
47
               .mask_reg = QEIC_CIMR,
 
48
               .pri_code = 1,
 
49
               .pri_reg = QEIC_CIPWCC,
 
50
               },
 
51
        [3] = {
 
52
               .mask = 0x00002000,
 
53
               .mask_reg = QEIC_CIMR,
 
54
               .pri_code = 2,
 
55
               .pri_reg = QEIC_CIPWCC,
 
56
               },
 
57
        [10] = {
 
58
                .mask = 0x00000040,
 
59
                .mask_reg = QEIC_CIMR,
 
60
                .pri_code = 1,
 
61
                .pri_reg = QEIC_CIPZCC,
 
62
                },
 
63
        [11] = {
 
64
                .mask = 0x00000020,
 
65
                .mask_reg = QEIC_CIMR,
 
66
                .pri_code = 2,
 
67
                .pri_reg = QEIC_CIPZCC,
 
68
                },
 
69
        [12] = {
 
70
                .mask = 0x00000010,
 
71
                .mask_reg = QEIC_CIMR,
 
72
                .pri_code = 3,
 
73
                .pri_reg = QEIC_CIPZCC,
 
74
                },
 
75
        [13] = {
 
76
                .mask = 0x00000008,
 
77
                .mask_reg = QEIC_CIMR,
 
78
                .pri_code = 4,
 
79
                .pri_reg = QEIC_CIPZCC,
 
80
                },
 
81
        [14] = {
 
82
                .mask = 0x00000004,
 
83
                .mask_reg = QEIC_CIMR,
 
84
                .pri_code = 5,
 
85
                .pri_reg = QEIC_CIPZCC,
 
86
                },
 
87
        [15] = {
 
88
                .mask = 0x00000002,
 
89
                .mask_reg = QEIC_CIMR,
 
90
                .pri_code = 6,
 
91
                .pri_reg = QEIC_CIPZCC,
 
92
                },
 
93
        [20] = {
 
94
                .mask = 0x10000000,
 
95
                .mask_reg = QEIC_CRIMR,
 
96
                .pri_code = 3,
 
97
                .pri_reg = QEIC_CIPRTA,
 
98
                },
 
99
        [25] = {
 
100
                .mask = 0x00800000,
 
101
                .mask_reg = QEIC_CRIMR,
 
102
                .pri_code = 0,
 
103
                .pri_reg = QEIC_CIPRTB,
 
104
                },
 
105
        [26] = {
 
106
                .mask = 0x00400000,
 
107
                .mask_reg = QEIC_CRIMR,
 
108
                .pri_code = 1,
 
109
                .pri_reg = QEIC_CIPRTB,
 
110
                },
 
111
        [27] = {
 
112
                .mask = 0x00200000,
 
113
                .mask_reg = QEIC_CRIMR,
 
114
                .pri_code = 2,
 
115
                .pri_reg = QEIC_CIPRTB,
 
116
                },
 
117
        [28] = {
 
118
                .mask = 0x00100000,
 
119
                .mask_reg = QEIC_CRIMR,
 
120
                .pri_code = 3,
 
121
                .pri_reg = QEIC_CIPRTB,
 
122
                },
 
123
        [32] = {
 
124
                .mask = 0x80000000,
 
125
                .mask_reg = QEIC_CIMR,
 
126
                .pri_code = 0,
 
127
                .pri_reg = QEIC_CIPXCC,
 
128
                },
 
129
        [33] = {
 
130
                .mask = 0x40000000,
 
131
                .mask_reg = QEIC_CIMR,
 
132
                .pri_code = 1,
 
133
                .pri_reg = QEIC_CIPXCC,
 
134
                },
 
135
        [34] = {
 
136
                .mask = 0x20000000,
 
137
                .mask_reg = QEIC_CIMR,
 
138
                .pri_code = 2,
 
139
                .pri_reg = QEIC_CIPXCC,
 
140
                },
 
141
        [35] = {
 
142
                .mask = 0x10000000,
 
143
                .mask_reg = QEIC_CIMR,
 
144
                .pri_code = 3,
 
145
                .pri_reg = QEIC_CIPXCC,
 
146
                },
 
147
        [36] = {
 
148
                .mask = 0x08000000,
 
149
                .mask_reg = QEIC_CIMR,
 
150
                .pri_code = 4,
 
151
                .pri_reg = QEIC_CIPXCC,
 
152
                },
 
153
        [40] = {
 
154
                .mask = 0x00800000,
 
155
                .mask_reg = QEIC_CIMR,
 
156
                .pri_code = 0,
 
157
                .pri_reg = QEIC_CIPYCC,
 
158
                },
 
159
        [41] = {
 
160
                .mask = 0x00400000,
 
161
                .mask_reg = QEIC_CIMR,
 
162
                .pri_code = 1,
 
163
                .pri_reg = QEIC_CIPYCC,
 
164
                },
 
165
        [42] = {
 
166
                .mask = 0x00200000,
 
167
                .mask_reg = QEIC_CIMR,
 
168
                .pri_code = 2,
 
169
                .pri_reg = QEIC_CIPYCC,
 
170
                },
 
171
        [43] = {
 
172
                .mask = 0x00100000,
 
173
                .mask_reg = QEIC_CIMR,
 
174
                .pri_code = 3,
 
175
                .pri_reg = QEIC_CIPYCC,
 
176
                },
 
177
};
 
178
 
 
179
static inline u32 qe_ic_read(volatile __be32  __iomem * base, unsigned int reg)
 
180
{
 
181
        return in_be32(base + (reg >> 2));
 
182
}
 
183
 
 
184
static inline void qe_ic_write(volatile __be32  __iomem * base, unsigned int reg,
 
185
                               u32 value)
 
186
{
 
187
        out_be32(base + (reg >> 2), value);
 
188
}
 
189
 
 
190
static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
 
191
{
 
192
        return irq_get_chip_data(virq);
 
193
}
 
194
 
 
195
static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
 
196
{
 
197
        return irq_data_get_irq_chip_data(d);
 
198
}
 
199
 
 
200
static void qe_ic_unmask_irq(struct irq_data *d)
 
201
{
 
202
        struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
 
203
        unsigned int src = irqd_to_hwirq(d);
 
204
        unsigned long flags;
 
205
        u32 temp;
 
206
 
 
207
        raw_spin_lock_irqsave(&qe_ic_lock, flags);
 
208
 
 
209
        temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
 
210
        qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
 
211
                    temp | qe_ic_info[src].mask);
 
212
 
 
213
        raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
 
214
}
 
215
 
 
216
static void qe_ic_mask_irq(struct irq_data *d)
 
217
{
 
218
        struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
 
219
        unsigned int src = irqd_to_hwirq(d);
 
220
        unsigned long flags;
 
221
        u32 temp;
 
222
 
 
223
        raw_spin_lock_irqsave(&qe_ic_lock, flags);
 
224
 
 
225
        temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
 
226
        qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
 
227
                    temp & ~qe_ic_info[src].mask);
 
228
 
 
229
        /* Flush the above write before enabling interrupts; otherwise,
 
230
         * spurious interrupts will sometimes happen.  To be 100% sure
 
231
         * that the write has reached the device before interrupts are
 
232
         * enabled, the mask register would have to be read back; however,
 
233
         * this is not required for correctness, only to avoid wasting
 
234
         * time on a large number of spurious interrupts.  In testing,
 
235
         * a sync reduced the observed spurious interrupts to zero.
 
236
         */
 
237
        mb();
 
238
 
 
239
        raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
 
240
}
 
241
 
 
242
static struct irq_chip qe_ic_irq_chip = {
 
243
        .name = "QEIC",
 
244
        .irq_unmask = qe_ic_unmask_irq,
 
245
        .irq_mask = qe_ic_mask_irq,
 
246
        .irq_mask_ack = qe_ic_mask_irq,
 
247
};
 
248
 
 
249
static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
 
250
{
 
251
        /* Exact match, unless qe_ic node is NULL */
 
252
        return h->of_node == NULL || h->of_node == node;
 
253
}
 
254
 
 
255
static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
 
256
                          irq_hw_number_t hw)
 
257
{
 
258
        struct qe_ic *qe_ic = h->host_data;
 
259
        struct irq_chip *chip;
 
260
 
 
261
        if (qe_ic_info[hw].mask == 0) {
 
262
                printk(KERN_ERR "Can't map reserved IRQ\n");
 
263
                return -EINVAL;
 
264
        }
 
265
        /* Default chip */
 
266
        chip = &qe_ic->hc_irq;
 
267
 
 
268
        irq_set_chip_data(virq, qe_ic);
 
269
        irq_set_status_flags(virq, IRQ_LEVEL);
 
270
 
 
271
        irq_set_chip_and_handler(virq, chip, handle_level_irq);
 
272
 
 
273
        return 0;
 
274
}
 
275
 
 
276
static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct,
 
277
                            const u32 * intspec, unsigned int intsize,
 
278
                            irq_hw_number_t * out_hwirq,
 
279
                            unsigned int *out_flags)
 
280
{
 
281
        *out_hwirq = intspec[0];
 
282
        if (intsize > 1)
 
283
                *out_flags = intspec[1];
 
284
        else
 
285
                *out_flags = IRQ_TYPE_NONE;
 
286
        return 0;
 
287
}
 
288
 
 
289
static struct irq_host_ops qe_ic_host_ops = {
 
290
        .match = qe_ic_host_match,
 
291
        .map = qe_ic_host_map,
 
292
        .xlate = qe_ic_host_xlate,
 
293
};
 
294
 
 
295
/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
 
296
unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
 
297
{
 
298
        int irq;
 
299
 
 
300
        BUG_ON(qe_ic == NULL);
 
301
 
 
302
        /* get the interrupt source vector. */
 
303
        irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
 
304
 
 
305
        if (irq == 0)
 
306
                return NO_IRQ;
 
307
 
 
308
        return irq_linear_revmap(qe_ic->irqhost, irq);
 
309
}
 
310
 
 
311
/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
 
312
unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
 
313
{
 
314
        int irq;
 
315
 
 
316
        BUG_ON(qe_ic == NULL);
 
317
 
 
318
        /* get the interrupt source vector. */
 
319
        irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
 
320
 
 
321
        if (irq == 0)
 
322
                return NO_IRQ;
 
323
 
 
324
        return irq_linear_revmap(qe_ic->irqhost, irq);
 
325
}
 
326
 
 
327
void __init qe_ic_init(struct device_node *node, unsigned int flags,
 
328
                void (*low_handler)(unsigned int irq, struct irq_desc *desc),
 
329
                void (*high_handler)(unsigned int irq, struct irq_desc *desc))
 
330
{
 
331
        struct qe_ic *qe_ic;
 
332
        struct resource res;
 
333
        u32 temp = 0, ret, high_active = 0;
 
334
 
 
335
        ret = of_address_to_resource(node, 0, &res);
 
336
        if (ret)
 
337
                return;
 
338
 
 
339
        qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL);
 
340
        if (qe_ic == NULL)
 
341
                return;
 
342
 
 
343
        qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
 
344
                                        NR_QE_IC_INTS, &qe_ic_host_ops, 0);
 
345
        if (qe_ic->irqhost == NULL) {
 
346
                kfree(qe_ic);
 
347
                return;
 
348
        }
 
349
 
 
350
        qe_ic->regs = ioremap(res.start, resource_size(&res));
 
351
 
 
352
        qe_ic->irqhost->host_data = qe_ic;
 
353
        qe_ic->hc_irq = qe_ic_irq_chip;
 
354
 
 
355
        qe_ic->virq_high = irq_of_parse_and_map(node, 0);
 
356
        qe_ic->virq_low = irq_of_parse_and_map(node, 1);
 
357
 
 
358
        if (qe_ic->virq_low == NO_IRQ) {
 
359
                printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
 
360
                kfree(qe_ic);
 
361
                return;
 
362
        }
 
363
 
 
364
        /* default priority scheme is grouped. If spread mode is    */
 
365
        /* required, configure cicr accordingly.                    */
 
366
        if (flags & QE_IC_SPREADMODE_GRP_W)
 
367
                temp |= CICR_GWCC;
 
368
        if (flags & QE_IC_SPREADMODE_GRP_X)
 
369
                temp |= CICR_GXCC;
 
370
        if (flags & QE_IC_SPREADMODE_GRP_Y)
 
371
                temp |= CICR_GYCC;
 
372
        if (flags & QE_IC_SPREADMODE_GRP_Z)
 
373
                temp |= CICR_GZCC;
 
374
        if (flags & QE_IC_SPREADMODE_GRP_RISCA)
 
375
                temp |= CICR_GRTA;
 
376
        if (flags & QE_IC_SPREADMODE_GRP_RISCB)
 
377
                temp |= CICR_GRTB;
 
378
 
 
379
        /* choose destination signal for highest priority interrupt */
 
380
        if (flags & QE_IC_HIGH_SIGNAL) {
 
381
                temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT);
 
382
                high_active = 1;
 
383
        }
 
384
 
 
385
        qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
 
386
 
 
387
        irq_set_handler_data(qe_ic->virq_low, qe_ic);
 
388
        irq_set_chained_handler(qe_ic->virq_low, low_handler);
 
389
 
 
390
        if (qe_ic->virq_high != NO_IRQ &&
 
391
                        qe_ic->virq_high != qe_ic->virq_low) {
 
392
                irq_set_handler_data(qe_ic->virq_high, qe_ic);
 
393
                irq_set_chained_handler(qe_ic->virq_high, high_handler);
 
394
        }
 
395
}
 
396
 
 
397
void qe_ic_set_highest_priority(unsigned int virq, int high)
 
398
{
 
399
        struct qe_ic *qe_ic = qe_ic_from_irq(virq);
 
400
        unsigned int src = virq_to_hw(virq);
 
401
        u32 temp = 0;
 
402
 
 
403
        temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
 
404
 
 
405
        temp &= ~CICR_HP_MASK;
 
406
        temp |= src << CICR_HP_SHIFT;
 
407
 
 
408
        temp &= ~CICR_HPIT_MASK;
 
409
        temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
 
410
 
 
411
        qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
 
412
}
 
413
 
 
414
/* Set Priority level within its group, from 1 to 8 */
 
415
int qe_ic_set_priority(unsigned int virq, unsigned int priority)
 
416
{
 
417
        struct qe_ic *qe_ic = qe_ic_from_irq(virq);
 
418
        unsigned int src = virq_to_hw(virq);
 
419
        u32 temp;
 
420
 
 
421
        if (priority > 8 || priority == 0)
 
422
                return -EINVAL;
 
423
        if (src > 127)
 
424
                return -EINVAL;
 
425
        if (qe_ic_info[src].pri_reg == 0)
 
426
                return -EINVAL;
 
427
 
 
428
        temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
 
429
 
 
430
        if (priority < 4) {
 
431
                temp &= ~(0x7 << (32 - priority * 3));
 
432
                temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
 
433
        } else {
 
434
                temp &= ~(0x7 << (24 - priority * 3));
 
435
                temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
 
436
        }
 
437
 
 
438
        qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
 
439
 
 
440
        return 0;
 
441
}
 
442
 
 
443
/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
 
444
int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
 
445
{
 
446
        struct qe_ic *qe_ic = qe_ic_from_irq(virq);
 
447
        unsigned int src = virq_to_hw(virq);
 
448
        u32 temp, control_reg = QEIC_CICNR, shift = 0;
 
449
 
 
450
        if (priority > 2 || priority == 0)
 
451
                return -EINVAL;
 
452
 
 
453
        switch (qe_ic_info[src].pri_reg) {
 
454
        case QEIC_CIPZCC:
 
455
                shift = CICNR_ZCC1T_SHIFT;
 
456
                break;
 
457
        case QEIC_CIPWCC:
 
458
                shift = CICNR_WCC1T_SHIFT;
 
459
                break;
 
460
        case QEIC_CIPYCC:
 
461
                shift = CICNR_YCC1T_SHIFT;
 
462
                break;
 
463
        case QEIC_CIPXCC:
 
464
                shift = CICNR_XCC1T_SHIFT;
 
465
                break;
 
466
        case QEIC_CIPRTA:
 
467
                shift = CRICR_RTA1T_SHIFT;
 
468
                control_reg = QEIC_CRICR;
 
469
                break;
 
470
        case QEIC_CIPRTB:
 
471
                shift = CRICR_RTB1T_SHIFT;
 
472
                control_reg = QEIC_CRICR;
 
473
                break;
 
474
        default:
 
475
                return -EINVAL;
 
476
        }
 
477
 
 
478
        shift += (2 - priority) * 2;
 
479
        temp = qe_ic_read(qe_ic->regs, control_reg);
 
480
        temp &= ~(SIGNAL_MASK << shift);
 
481
        temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
 
482
        qe_ic_write(qe_ic->regs, control_reg, temp);
 
483
 
 
484
        return 0;
 
485
}
 
486
 
 
487
static struct sysdev_class qe_ic_sysclass = {
 
488
        .name = "qe_ic",
 
489
};
 
490
 
 
491
static struct sys_device device_qe_ic = {
 
492
        .id = 0,
 
493
        .cls = &qe_ic_sysclass,
 
494
};
 
495
 
 
496
static int __init init_qe_ic_sysfs(void)
 
497
{
 
498
        int rc;
 
499
 
 
500
        printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
 
501
 
 
502
        rc = sysdev_class_register(&qe_ic_sysclass);
 
503
        if (rc) {
 
504
                printk(KERN_ERR "Failed registering qe_ic sys class\n");
 
505
                return -ENODEV;
 
506
        }
 
507
        rc = sysdev_register(&device_qe_ic);
 
508
        if (rc) {
 
509
                printk(KERN_ERR "Failed registering qe_ic sys device\n");
 
510
                return -ENODEV;
 
511
        }
 
512
        return 0;
 
513
}
 
514
 
 
515
subsys_initcall(init_qe_ic_sysfs);