source: rtems/c/src/lib/libbsp/powerpc/shared/openpic/openpic.c @ 1b290ce7

4.104.11
Last change on this file since 1b290ce7 was 1b290ce7, checked in by Till Straumann <strauman@…>, on Sep 11, 2009 at 4:58:30 PM

2009-09-11 Till Straumann <strauman@…>

  • shared/openpic/openpic.c: include the more generic <rtems/pci.h> rather than <bsp/pci.h>.
  • Property mode set to 100644
File size: 17.0 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.rtems.com/license/LICENSE.
14 *
15 * $Id$
16 */
17
18/*
19 *  Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
20 */
21
22#include <rtems.h>
23#include <bsp.h>
24#include <rtems/bspIo.h>
25#include <bsp/openpic.h>
26#include <rtems/pci.h>
27#include <libcpu/io.h>
28#include <libcpu/byteorder.h>
29#include <rtems/bspIo.h>
30
31#ifndef NULL
32#define NULL 0
33#endif
34#define REGISTER_DEBUG
35#undef REGISTER_DEBUG
36
37volatile struct OpenPIC *OpenPIC = NULL;
38
39static unsigned int NumProcessors;
40static unsigned int NumSources;
41
42static unsigned int openpic_eoi_delay = 0;
43static          int openpic_src_offst = 0;
44#define SOURCE(irq)     Source[ (irq) + openpic_src_offst ]
45
46    /*
47     *  Accesses to the current processor's registers
48     */
49
50#define THIS_CPU                Processor[cpu]
51#define CHECK_THIS_CPU          check_arg_cpu(cpu)
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 0x%08x,[0x%08x],[[0x%08x]]\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     *  I/O functions
90     */
91
92static inline unsigned int openpic_read(volatile unsigned int *addr)
93{
94    unsigned int val;
95
96#ifdef BSP_OPEN_PIC_BIG_ENDIAN
97        val = in_be32(addr);
98#else
99    val = in_le32(addr);
100#endif
101#ifdef REGISTER_DEBUG
102    printk("openpic_read(0x%08x) = 0x%08x\n", (unsigned int)addr, val);
103#endif
104    return val;
105}
106
107static inline void openpic_write(volatile unsigned int *addr, unsigned int val)
108{
109#ifdef REGISTER_DEBUG
110    printk("openpic_write(0x%08x, 0x%08x)\n", (unsigned int)addr, val);
111#endif
112#ifdef BSP_OPEN_PIC_BIG_ENDIAN
113    out_be32(addr, val);
114#else
115        out_le32(addr, val);
116#endif
117}
118
119static inline unsigned int openpic_readfield(volatile unsigned int *addr, unsigned int mask)
120{
121    unsigned int val = openpic_read(addr);
122    return val & mask;
123}
124
125inline void openpic_writefield(volatile unsigned int *addr, unsigned int mask,
126                                      unsigned int field)
127{
128    unsigned int val = openpic_read(addr);
129    openpic_write(addr, (val & ~mask) | (field & mask));
130}
131
132static inline void openpic_clearfield(volatile unsigned int *addr, unsigned int mask)
133{
134    openpic_writefield(addr, mask, 0);
135}
136
137static inline void openpic_setfield(volatile unsigned int *addr, unsigned int mask)
138{
139    openpic_writefield(addr, mask, mask);
140}
141
142    /*
143     *  Update a Vector/Priority register in a safe manner. The interrupt will
144     *  be disabled.
145     */
146
147static void openpic_safe_writefield(volatile unsigned int *addr, unsigned int mask,
148                                    unsigned int field)
149{
150    openpic_setfield(addr, OPENPIC_MASK);
151    /* wait until it's not in use */
152    while (openpic_read(addr) & OPENPIC_ACTIVITY);
153    openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
154}
155
156/* -------- Global Operations ---------------------------------------------- */
157
158    /*
159     *  Initialize the OpenPIC
160     *
161     * Add some kludge to use the Motorola Raven OpenPIC which does not
162     * report vendor and device id, and gets the wrong number of interrupts.
163     * (Motorola did a great job on that one!)
164     *
165     * T. Straumann, 12/20/2001: polarities and senses are now passed as
166     *                           parameters, eliminated global vars.
167     *                           IRQ0 is no longer treated specially.
168     */
169
170void openpic_init(int main_pic, unsigned char *polarities, unsigned char *senses, int num_sources, int source_offset, unsigned long epic_freq)
171{
172    unsigned int t, i;
173    unsigned int vendorid, devid, stepping, timerfreq;
174    const char *version, *vendor, *device;
175
176    if (!OpenPIC)
177        BSP_panic("No OpenPIC found");
178
179    t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
180    switch (t & OPENPIC_FEATURE_VERSION_MASK) {
181        case 1:
182            version = "1.0";
183            break;
184        case 2:
185            version = "1.2";
186            break;
187        default:
188            version = "?";
189            break;
190    }
191    NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
192                     OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
193    NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
194                  OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
195    t = openpic_read(&OpenPIC->Global.Vendor_Identification);
196
197    vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
198    devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
199            OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
200    stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
201               OPENPIC_VENDOR_ID_STEPPING_SHIFT;
202
203    /* Kludge for the Raven */
204/*
205    pci_read_config_dword(0, 0, 0, 0, &t);
206*/
207    if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
208        vendor = "Motorola";
209        device = "Raven";
210        NumSources += 1;
211    }
212    else if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_HAWK<<16)) {
213        vendor = "Motorola";
214        device = "Hawk";
215        NumSources += 1;
216    } else {
217        switch (vendorid) {
218            case OPENPIC_VENDOR_ID_APPLE:
219                vendor = "Apple";
220                break;
221            default:
222                vendor = "Unknown";
223            break;
224        }
225        switch (devid) {
226            case OPENPIC_DEVICE_ID_APPLE_HYDRA:
227                device = "Hydra";
228                break;
229            default:
230                device = "Unknown";
231                break;
232        }
233    }
234    printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at 0x%08x\n", version,
235           NumProcessors, NumSources, OpenPIC);
236
237    printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
238           vendor, devid, device, stepping);
239
240        /* Override if they desire */
241        if ( num_sources ) {
242                if ( NumSources != num_sources )
243                        printk("Overriding NumSources (%i) from configuration with %i\n",
244                                NumSources, num_sources);
245                NumSources = num_sources;
246        }
247
248        openpic_src_offst = source_offset;
249
250    timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
251    printk("OpenPIC timer frequency is ");
252    if (timerfreq)
253        printk("%d Hz\n", timerfreq);
254    else
255        printk("not set\n");
256
257    if ( main_pic )
258    {
259            /* Initialize timer interrupts */
260            for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
261                    /* Disabled, Priority 0 */
262                    openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
263                    /* No processor */
264                    openpic_maptimer(i, 0);
265            }
266
267            /* Initialize IPI interrupts */
268            for (i = 0; i < OPENPIC_NUM_IPI; i++) {
269                    /* Disabled, Priority 0 */
270                    openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
271            }
272
273            /* Initialize external interrupts */
274            for (i = 0; i < NumSources; i++) {
275                    /* Enabled, Priority 8 */
276                    openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i,
277                                        polarities ? polarities[i] : 0,
278                                        senses     ? senses[i]     : 1);
279                    /* Processor 0 */
280                    openpic_mapirq(i, 1<<0);
281            }
282
283            /* Initialize the spurious interrupt */
284            openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
285#if 0
286            if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
287                            "82c59 cascade", NULL))
288              printk("Unable to get OpenPIC IRQ 0 for cascade\n");
289#endif
290            openpic_set_priority(0, 0);
291            openpic_disable_8259_pass_through();
292    }
293        if ( epic_freq ) {
294                /* Speed up the serial interface; if it is too slow then we might get spurious
295                 * interrupts:
296                 * After an ISR clears the interrupt condition at the source/device, the wire
297                 * remains asserted during the propagation delay introduced by the serial interface
298                 * (something really stupid). If the ISR returns while the wire is not released
299                 * yet, then a spurious interrupt happens.
300                 * The book says we should be careful if the serial clock is > 33MHz.
301                 * Empirically, it seems that running it at 33MHz is fast enough. Otherwise,
302                 * we should introduce a delay in openpic_eoi().
303                 * The maximal delay are 16 (serial) clock cycles. If the divisor is 8
304                 * [power-up default] then the lag is 2us [66MHz SDRAM clock; I assume this
305                 * is equal to the bus frequency].
306                 * FIXME: This should probably be a EPIC-specific piece in 'openpic.c'
307                 *        Unfortunately, there is no easy way of figuring out if the
308                 *        device is an EPIC or not.
309                 */
310                uint32_t eicr_val, ratio;
311                /* On the 8240 this is the EICR register */
312                eicr_val = in_le32( &OpenPIC->Global.Global_Configuration1 ) & ~(7<<28);
313                if ( (1<<27) & eicr_val ) {
314                        /* serial interface mode enabled */
315
316                        /* round to nearest integer:
317                         *   round(Bus_freq/33000000) = floor( 2*(Bus_freq/33e6) + 1 ) / 2
318                         */ 
319                        ratio   = epic_freq / 16500000 + 1;
320                        ratio >>= 2; /* EICR value is half actual divisor */
321                        if ( 0==ratio )
322                                ratio = 1;
323                        out_le32(&OpenPIC->Global.Global_Configuration1, eicr_val | ((ratio &7) << 28));
324                        /*  Delay in TB cycles (assuming TB runs at 1/4 of the bus frequency) */
325                        openpic_set_eoi_delay( 16 * (2*ratio) / 4 );
326                }
327        }
328}
329
330    /*
331     *  Reset the OpenPIC
332     */
333
334void openpic_reset(void)
335{
336    openpic_setfield(&OpenPIC->Global.Global_Configuration0,
337                       OPENPIC_CONFIG_RESET);
338}
339
340    /*
341     *  Enable/disable 8259 Pass Through Mode
342     */
343
344void openpic_enable_8259_pass_through(void)
345{
346    openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
347                       OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
348}
349
350void openpic_disable_8259_pass_through(void)
351{
352    openpic_setfield(&OpenPIC->Global.Global_Configuration0,
353                     OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
354}
355
356    /*
357     *  Find out the current interrupt
358     */
359
360unsigned int openpic_irq(unsigned int cpu)
361{
362    unsigned int vec;
363
364    check_arg_cpu(cpu);
365    vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
366                            OPENPIC_VECTOR_MASK);
367    return vec;
368}
369
370    /*
371     *  Signal end of interrupt (EOI) processing
372     */
373
374void openpic_eoi(unsigned int cpu)
375{
376    check_arg_cpu(cpu);
377    if ( openpic_eoi_delay )
378        rtems_bsp_delay_in_bus_cycles(openpic_eoi_delay);
379    openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
380}
381
382unsigned openpic_set_eoi_delay(unsigned tb_cycles)
383{
384unsigned rval = openpic_eoi_delay;
385    openpic_eoi_delay = tb_cycles;
386        return rval;
387}
388
389    /*
390     *  Get/set the current task priority
391     */
392
393unsigned int openpic_get_priority(unsigned int cpu)
394{
395    CHECK_THIS_CPU;
396    return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
397                             OPENPIC_CURRENT_TASK_PRIORITY_MASK);
398}
399
400void openpic_set_priority(unsigned int cpu, unsigned int pri)
401{
402    CHECK_THIS_CPU;
403    check_arg_pri(pri);
404    openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
405                       OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
406}
407
408    /*
409     *  Get/set the spurious vector
410     */
411
412unsigned int openpic_get_spurious(void)
413{
414    return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
415                             OPENPIC_VECTOR_MASK);
416}
417
418void openpic_set_spurious(unsigned int vec)
419{
420    check_arg_vec(vec);
421    openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
422                       vec);
423}
424
425    /*
426     *  Initialize one or more CPUs
427     */
428
429void openpic_init_processor(unsigned int cpumask)
430{
431    openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
432}
433
434/* -------- Interprocessor Interrupts -------------------------------------- */
435
436    /*
437     *  Initialize an interprocessor interrupt (and disable it)
438     *
439     *  ipi: OpenPIC interprocessor interrupt number
440     *  pri: interrupt source priority
441     *  vec: the vector it will produce
442     */
443
444void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vec)
445{
446    check_arg_timer(ipi);
447    check_arg_pri(pri);
448    check_arg_vec(vec);
449    openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
450                            OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
451                            (pri << OPENPIC_PRIORITY_SHIFT) | vec);
452}
453
454    /*
455     *  Send an IPI to one or more CPUs
456     */
457
458void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask)
459{
460    CHECK_THIS_CPU;
461    check_arg_ipi(ipi);
462    openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
463}
464
465/* -------- Timer Interrupts ----------------------------------------------- */
466
467    /*
468     *  Initialize a timer interrupt (and disable it)
469     *
470     *  timer: OpenPIC timer number
471     *  pri: interrupt source priority
472     *  vec: the vector it will produce
473     */
474
475void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vec)
476{
477    check_arg_timer(timer);
478    check_arg_pri(pri);
479    check_arg_vec(vec);
480    openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
481                            OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
482                            (pri << OPENPIC_PRIORITY_SHIFT) | vec);
483}
484
485    /*
486     *  Map a timer interrupt to one or more CPUs
487     */
488
489void openpic_maptimer(unsigned int timer, unsigned int cpumask)
490{
491    check_arg_timer(timer);
492    openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
493}
494
495    /*
496     *  Set base count and / or enable / disable interrupt.
497     */
498
499
500void openpic_settimer(unsigned int timer, unsigned int base_count, int irq_enable)
501{
502        check_arg_timer(timer);
503        if ( base_count )
504                openpic_write(&OpenPIC->Global.Timer[timer].Base_Count, base_count);
505        if ( irq_enable )
506                openpic_clearfield(&OpenPIC->Global.Timer[timer].Vector_Priority, OPENPIC_MASK);
507        else
508                openpic_setfield(&OpenPIC->Global.Timer[timer].Vector_Priority, OPENPIC_MASK);
509}
510
511unsigned int openpic_gettimer(unsigned int timer)
512{
513        check_arg_timer(timer);
514        return (openpic_read(&OpenPIC->Global.Timer[timer].Current_Count) & ~OPENPIC_MASK);
515}
516
517/* -------- Interrupt Sources ---------------------------------------------- */
518
519    /*
520     *  Enable/disable an interrupt source
521     */
522
523void openpic_enable_irq(unsigned int irq)
524{
525unsigned long flags;
526    check_arg_irq(irq);
527        rtems_interrupt_disable(flags);
528    openpic_clearfield(&OpenPIC->SOURCE(irq).Vector_Priority, OPENPIC_MASK);
529        rtems_interrupt_enable(flags);
530}
531
532int openpic_disable_irq(unsigned int irq)
533{
534int           rval;
535unsigned long flags;
536    check_arg_irq(irq);
537        if ( irq < 0 || irq >=NumSources )
538                return -1;
539        rtems_interrupt_disable(flags);
540        rval = openpic_readfield(&OpenPIC->SOURCE(irq).Vector_Priority, OPENPIC_MASK) ? 0 : 1;
541    openpic_setfield(&OpenPIC->SOURCE(irq).Vector_Priority, OPENPIC_MASK);
542        rtems_interrupt_enable(flags);
543        return rval;
544}
545
546    /*
547     *  Initialize an interrupt source (and disable it!)
548     *
549     *  irq: OpenPIC interrupt number
550     *  pri: interrupt source priority
551     *  vec: the vector it will produce
552     *  pol: polarity (1 for positive, 0 for negative)
553     *  sense: 1 for level, 0 for edge
554     */
555
556void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vec, int pol, int sense)
557{
558#if 0
559  printk("openpic_initirq: irq=%d pri=%d vec=%d pol=%d sense=%d\n",
560    irq, pri, vec, pol, sense);
561#endif
562
563    check_arg_irq(irq);
564    check_arg_pri(pri);
565    check_arg_vec(vec);
566    openpic_safe_writefield(&OpenPIC->SOURCE(irq).Vector_Priority,
567                            OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
568                            OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
569                            (pri << OPENPIC_PRIORITY_SHIFT) | vec |
570                            (pol ? OPENPIC_SENSE_POLARITY : 0) |
571                            (sense ? OPENPIC_SENSE_LEVEL : 0));
572}
573
574    /*
575     *  Map an interrupt source to one or more CPUs
576     */
577
578void openpic_mapirq(unsigned int irq, unsigned int cpumask)
579{
580    check_arg_irq(irq);
581    openpic_write(&OpenPIC->SOURCE(irq).Destination, cpumask);
582}
583
584        /*
585         * Get the current priority of an external interrupt
586         */
587unsigned int openpic_get_source_priority(unsigned int irq)
588{
589    check_arg_irq(irq);
590        return openpic_readfield(&OpenPIC->SOURCE(irq).Vector_Priority,
591                                                         OPENPIC_PRIORITY_MASK) >> OPENPIC_PRIORITY_SHIFT;
592}
593
594void openpic_set_source_priority(unsigned int irq, unsigned int pri)
595{
596unsigned long flags;
597    check_arg_irq(irq);
598    check_arg_pri(pri);
599        rtems_interrupt_disable(flags);
600        openpic_writefield(
601                                        &OpenPIC->SOURCE(irq).Vector_Priority,
602                                        OPENPIC_PRIORITY_MASK,
603                                        pri << OPENPIC_PRIORITY_SHIFT);
604        rtems_interrupt_enable(flags);
605}
606    /*
607     *  Set the sense for an interrupt source (and disable it!)
608     *
609     *  sense: 1 for level, 0 for edge
610     */
611
612void openpic_set_sense(unsigned int irq, int sense)
613{
614    check_arg_irq(irq);
615    openpic_safe_writefield(&OpenPIC->SOURCE(irq).Vector_Priority,
616                            OPENPIC_SENSE_LEVEL,
617                            (sense ? OPENPIC_SENSE_LEVEL : 0));
618}
Note: See TracBrowser for help on using the repository browser.