source: rtems/c/src/lib/libbsp/powerpc/shared/openpic/openpic.c @ 6ad36947

Last change on this file since 6ad36947 was 6ad36947, checked in by Joel Sherrill <joel.sherrill@…>, on 04/10/03 at 16:35:13

2003-04-10 Till Straumann <strauman@…>

PR 379/bsps

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