source: rtems/c/src/lib/libbsp/powerpc/shared/openpic/openpic.c @ 73f8d93

Last change on this file since 73f8d93 was 73f8d93, checked in by Sebastian Huber <sebastian.huber@…>, on Feb 15, 2017 at 10:09:50 AM

bsps/powerpc: Fix warnings

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