source: rtems/c/src/lib/libbsp/powerpc/motorola_powerpc/openpic/openpic.c @ fcee56c0

4.104.114.84.95
Last change on this file since fcee56c0 was fcee56c0, checked in by Joel Sherrill <joel.sherrill@…>, on 07/01/99 at 23:39:13

Patch from Eric Valette <valette@…> to clean up the
previous submission.

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