source: rtems/c/src/lib/libbsp/powerpc/shared/openpic/openpic.c @ 2742cc3

Last change on this file since 2742cc3 was 2742cc3, checked in by Joel Sherrill <joel.sherrill@…>, on 03/25/03 at 16:55:29

2003-03-25 Till Straumann <strauman@…>

PR 360/bsps

  • irq/irq.c, irq/irq_init.c, openpic/openpic.c, openpic/openpic.h: BSP code had set the task priority register multiple times of the OpenPIC instead of setting the individual source priorities. This patch adds openpic_get_source_priority() and openpic_set_source_priority() calls and lets IRQ management code use them.
  • Property mode set to 100644
File size: 13.6 KB
RevLine 
[acc25ee]1/*
2 *  openpic.c -- OpenPIC Interrupt Handling
3 *
4 *  Copyright (C) 1997 Geert Uytterhoeven
5 *
6 *  Modified to compile in RTEMS development environment
7 *  by Eric Valette
8 *
9 *  Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
10 *
11 *  The license and distribution terms for this file may be
12 *  found in found in the file LICENSE in this distribution or at
13 *  http://www.OARcorp.com/rtems/license.html.
14 *
15 * $Id$
16 */
17
18/*
19 *  Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
20 */
21
[2742cc3]22#include <rtems.h>
[20603d1]23#include <rtems/bspIo.h>
[acc25ee]24#include <bsp/openpic.h>
25#include <bsp/pci.h>
26#include <bsp/consoleIo.h>
27#include <libcpu/io.h>
28#include <libcpu/byteorder.h>
29#include <bsp.h>
[69ed59f]30#include <rtems/bspIo.h>
[acc25ee]31
[69ed59f]32#ifndef NULL
[acc25ee]33#define NULL 0
[69ed59f]34#endif
[acc25ee]35#define REGISTER_DEBUG
36#undef REGISTER_DEBUG
37
38
39volatile struct OpenPIC *OpenPIC = NULL;
40
41static unsigned int NumProcessors;
42static unsigned int NumSources;
43
44
45    /*
46     *  Accesses to the current processor's registers
47     */
48
49#define THIS_CPU                Processor[cpu]
50#define CHECK_THIS_CPU          check_arg_cpu(cpu)
51
52
53    /*
54     *  Sanity checks
55     */
56
57#if 1
58#define check_arg_ipi(ipi) \
59    if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
60        printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi);
61#define check_arg_timer(timer) \
62    if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
63        printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer);
64#define check_arg_vec(vec) \
65    if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
66        printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec);
67#define check_arg_pri(pri) \
68    if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
69        printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
70#define check_arg_irq(irq) \
71    if (irq < 0 || irq >= NumSources) \
72        printk("openpic.c:%d: illegal irq %d from %p,[%p],[[%p]]\n", \
73               __LINE__, irq, __builtin_return_address(0), \
74               __builtin_return_address(1), __builtin_return_address(2) \
75               );
76#define check_arg_cpu(cpu) \
77    if (cpu < 0 || cpu >= NumProcessors) \
78        printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
79#else
80#define check_arg_ipi(ipi)      do {} while (0)
81#define check_arg_timer(timer)  do {} while (0)
82#define check_arg_vec(vec)      do {} while (0)
83#define check_arg_pri(pri)      do {} while (0)
84#define check_arg_irq(irq)      do {} while (0)
85#define check_arg_cpu(cpu)      do {} while (0)
86#endif
87
88
89
90    /*
91     *  I/O functions
92     */
93
94static inline unsigned int openpic_read(volatile unsigned int *addr)
95{
96    unsigned int val;
97
[2742cc3]98    val = in_le32(addr);
[acc25ee]99#ifdef REGISTER_DEBUG
100    printk("openpic_read(0x%08x) = 0x%08x\n", (unsigned int)addr, val);
101#endif
102    return val;
103}
104
105static inline void openpic_write(volatile unsigned int *addr, unsigned int val)
106{
107#ifdef REGISTER_DEBUG
108    printk("openpic_write(0x%08x, 0x%08x)\n", (unsigned int)addr, val);
109#endif
110    out_le32(addr, val);
111}
112
113
114static inline unsigned int openpic_readfield(volatile unsigned int *addr, unsigned int mask)
115{
116    unsigned int val = openpic_read(addr);
117    return val & mask;
118}
119
120inline void openpic_writefield(volatile unsigned int *addr, unsigned int mask,
121                                      unsigned int field)
122{
123    unsigned int val = openpic_read(addr);
124    openpic_write(addr, (val & ~mask) | (field & mask));
125}
126
127static inline void openpic_clearfield(volatile unsigned int *addr, unsigned int mask)
128{
129    openpic_writefield(addr, mask, 0);
130}
131
132static inline void openpic_setfield(volatile unsigned int *addr, unsigned int mask)
133{
134    openpic_writefield(addr, mask, mask);
135}
136
137
138    /*
139     *  Update a Vector/Priority register in a safe manner. The interrupt will
140     *  be disabled.
141     */
142
143static void openpic_safe_writefield(volatile unsigned int *addr, unsigned int mask,
144                                    unsigned int field)
145{
146    openpic_setfield(addr, OPENPIC_MASK);
147    /* wait until it's not in use */
148    while (openpic_read(addr) & OPENPIC_ACTIVITY);
149    openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
150}
151
152
153/* -------- Global Operations ---------------------------------------------- */
154
155
156    /*
157     *  Initialize the OpenPIC
158     *
159     * Add some kludge to use the Motorola Raven OpenPIC which does not
160     * report vendor and device id, and gets the wrong number of interrupts.
161     * (Motorola did a great job on that one!)
[69ed59f]162     *
163     * T. Straumann, 12/20/2001: polarities and senses are now passed as
164     *                           parameters, eliminated global vars.
165     *                           IRQ0 is no longer treated specially.
[acc25ee]166     */
167
[69ed59f]168void openpic_init(int main_pic, unsigned char *polarities, unsigned char *senses)
[acc25ee]169{
170    unsigned int t, i;
171    unsigned int vendorid, devid, stepping, timerfreq;
172    const char *version, *vendor, *device;
173
174    if (!OpenPIC)
175        BSP_panic("No OpenPIC found");
176
177    t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
178    switch (t & OPENPIC_FEATURE_VERSION_MASK) {
179        case 1:
180            version = "1.0";
181            break;
182        case 2:
183            version = "1.2";
184            break;
185        default:
186            version = "?";
187            break;
188    }
189    NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
190                     OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
191    NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
192                  OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
193    t = openpic_read(&OpenPIC->Global.Vendor_Identification);
194
195    vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
196    devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
197            OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
198    stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
199               OPENPIC_VENDOR_ID_STEPPING_SHIFT;
200
201    /* Kludge for the Raven */
202    pci_read_config_dword(0, 0, 0, 0, &t);
203    if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
204        vendor = "Motorola";
205        device = "Raven";
206        NumSources += 1;
207    } else {
208        switch (vendorid) {
209            case OPENPIC_VENDOR_ID_APPLE:
210                vendor = "Apple";
211                break;
212            default:
213                vendor = "Unknown";
214            break;
215        }
216        switch (devid) {
217            case OPENPIC_DEVICE_ID_APPLE_HYDRA:
218                device = "Hydra";
219                break;
220            default:
221                device = "Unknown";
222                break;
223        }
224    }
225    printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
226           NumProcessors, NumSources, OpenPIC);
227
228    printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
229           vendor, devid, device, stepping);
230
231    timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
232    printk("OpenPIC timer frequency is ");
233    if (timerfreq)
234        printk("%d Hz\n", timerfreq);
235    else
236        printk("not set\n");
237
238    if ( main_pic )
239    {
240            /* Initialize timer interrupts */
241            for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
242                    /* Disabled, Priority 0 */
243                    openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
244                    /* No processor */
245                    openpic_maptimer(i, 0);
246            }
247           
248            /* Initialize IPI interrupts */
249            for (i = 0; i < OPENPIC_NUM_IPI; i++) {
250                    /* Disabled, Priority 0 */
251                    openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
252            }
253           
254            /* Initialize external interrupts */
[69ed59f]255            for (i = 0; i < NumSources; i++) {
[acc25ee]256                    /* Enabled, Priority 8 */
[69ed59f]257                    openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i,
258                                        polarities ? polarities[i] : 0,
259                                        senses     ? senses[i]     : 1);
[acc25ee]260                    /* Processor 0 */
261                    openpic_mapirq(i, 1<<0);
262            }
263           
264            /* Initialize the spurious interrupt */
265            openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
266#if 0       
267            if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
268                            "82c59 cascade", NULL))
269              printk("Unable to get OpenPIC IRQ 0 for cascade\n");
270#endif     
271            openpic_set_priority(0, 0);
272            openpic_disable_8259_pass_through();
273    }
274}
275
276
277    /*
278     *  Reset the OpenPIC
279     */
280
281void openpic_reset(void)
282{
283    openpic_setfield(&OpenPIC->Global.Global_Configuration0,
284                       OPENPIC_CONFIG_RESET);
285}
286
287
288    /*
289     *  Enable/disable 8259 Pass Through Mode
290     */
291
292void openpic_enable_8259_pass_through(void)
293{
294    openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
295                       OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
296}
297
298void openpic_disable_8259_pass_through(void)
299{
300    openpic_setfield(&OpenPIC->Global.Global_Configuration0,
301                     OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
302}
303
304
305    /*
306     *  Find out the current interrupt
307     */
308
309unsigned int openpic_irq(unsigned int cpu)
310{
311    unsigned int vec;
312
313    check_arg_cpu(cpu);
314    vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
315                            OPENPIC_VECTOR_MASK);
316    return vec;
317}
318
319
320    /*
321     *  Signal end of interrupt (EOI) processing
322     */
323
324void openpic_eoi(unsigned int cpu)
325{
326    check_arg_cpu(cpu);
327    openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
328}
329
330
331    /*
332     *  Get/set the current task priority
333     */
334
335unsigned int openpic_get_priority(unsigned int cpu)
336{
337    CHECK_THIS_CPU;
338    return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
339                             OPENPIC_CURRENT_TASK_PRIORITY_MASK);
340}
341
342void openpic_set_priority(unsigned int cpu, unsigned int pri)
343{
344    CHECK_THIS_CPU;
345    check_arg_pri(pri);
346    openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
347                       OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
348}
349
350    /*
351     *  Get/set the spurious vector
352     */
353
354unsigned int openpic_get_spurious(void)
355{
356    return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
357                             OPENPIC_VECTOR_MASK);
358}
359
360void openpic_set_spurious(unsigned int vec)
361{
362    check_arg_vec(vec);
363    openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
364                       vec);
365}
366
367
368    /*
369     *  Initialize one or more CPUs
370     */
371
372void openpic_init_processor(unsigned int cpumask)
373{
374    openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
375}
376
377
378/* -------- Interprocessor Interrupts -------------------------------------- */
379
380
381    /*
382     *  Initialize an interprocessor interrupt (and disable it)
383     *
384     *  ipi: OpenPIC interprocessor interrupt number
385     *  pri: interrupt source priority
386     *  vec: the vector it will produce
387     */
388
389void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vec)
390{
391    check_arg_timer(ipi);
392    check_arg_pri(pri);
393    check_arg_vec(vec);
394    openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
395                            OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
396                            (pri << OPENPIC_PRIORITY_SHIFT) | vec);
397}
398
399
400    /*
401     *  Send an IPI to one or more CPUs
402     */
403
404void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask)
405{
406    CHECK_THIS_CPU;
407    check_arg_ipi(ipi);
408    openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
409}
410
411
412/* -------- Timer Interrupts ----------------------------------------------- */
413
414
415    /*
416     *  Initialize a timer interrupt (and disable it)
417     *
418     *  timer: OpenPIC timer number
419     *  pri: interrupt source priority
420     *  vec: the vector it will produce
421     */
422
423void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vec)
424{
425    check_arg_timer(timer);
426    check_arg_pri(pri);
427    check_arg_vec(vec);
428    openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
429                            OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
430                            (pri << OPENPIC_PRIORITY_SHIFT) | vec);
431}
432
433
434    /*
435     *  Map a timer interrupt to one or more CPUs
436     */
437
438void openpic_maptimer(unsigned int timer, unsigned int cpumask)
439{
440    check_arg_timer(timer);
441    openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
442}
443
444
445/* -------- Interrupt Sources ---------------------------------------------- */
446
447
448    /*
449     *  Enable/disable an interrupt source
450     */
451
452void openpic_enable_irq(unsigned int irq)
453{
[2742cc3]454unsigned long flags;
[acc25ee]455    check_arg_irq(irq);
[2742cc3]456        rtems_interrupt_disable(flags);
[acc25ee]457    openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
[2742cc3]458        rtems_interrupt_enable(flags);
[acc25ee]459}
460
461void openpic_disable_irq(unsigned int irq)
462{
[2742cc3]463unsigned long flags;
[acc25ee]464    check_arg_irq(irq);
[2742cc3]465        rtems_interrupt_disable(flags);
[acc25ee]466    openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
[2742cc3]467        rtems_interrupt_enable(flags);
[acc25ee]468}
469
470
471    /*
472     *  Initialize an interrupt source (and disable it!)
473     *
474     *  irq: OpenPIC interrupt number
475     *  pri: interrupt source priority
476     *  vec: the vector it will produce
477     *  pol: polarity (1 for positive, 0 for negative)
478     *  sense: 1 for level, 0 for edge
479     */
480
481void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vec, int pol, int sense)
482{
483    check_arg_irq(irq);
484    check_arg_pri(pri);
485    check_arg_vec(vec);
486    openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
487                            OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
488                            OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
489                            (pri << OPENPIC_PRIORITY_SHIFT) | vec |
490                            (pol ? OPENPIC_SENSE_POLARITY : 0) |
491                            (sense ? OPENPIC_SENSE_LEVEL : 0));
492}
493
494
495    /*
496     *  Map an interrupt source to one or more CPUs
497     */
498
499void openpic_mapirq(unsigned int irq, unsigned int cpumask)
500{
501    check_arg_irq(irq);
502    openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
503}
504
[2742cc3]505        /*
506         * Get the current priority of an external interrupt
507         */
508unsigned int openpic_get_source_priority(unsigned int irq)
509{
510    check_arg_irq(irq);
511        return openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
512                                                         OPENPIC_PRIORITY_MASK) >> OPENPIC_PRIORITY_SHIFT;
513}
[acc25ee]514
[2742cc3]515void openpic_set_source_priority(unsigned int irq, unsigned int pri)
516{
517unsigned long flags;
518    check_arg_irq(irq);
519    check_arg_pri(pri);
520        rtems_interrupt_disable(flags);
521        openpic_writefield(
522                                        &OpenPIC->Source[irq].Vector_Priority,
523                                        OPENPIC_PRIORITY_MASK,
524                                        pri << OPENPIC_PRIORITY_SHIFT);
525        rtems_interrupt_enable(flags);
526}
[acc25ee]527    /*
528     *  Set the sense for an interrupt source (and disable it!)
529     *
530     *  sense: 1 for level, 0 for edge
531     */
532
533void openpic_set_sense(unsigned int irq, int sense)
534{
535    check_arg_irq(irq);
536    openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
537                            OPENPIC_SENSE_LEVEL,
538                            (sense ? OPENPIC_SENSE_LEVEL : 0));
539}
Note: See TracBrowser for help on using the repository browser.