source: rtems/c/src/lib/libbsp/powerpc/shared/openpic/openpic.c @ 2d5c486

4.115
Last change on this file since 2d5c486 was 2d5c486, checked in by Nick Withers <nick.withers@…>, on 11/27/14 at 06:39:36

Use fixed-width C99 types for PowerPC in_be16() and co.

Also use the const qualifier on the address pointer's target in in_*()

Closes #2128

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