OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libcpu/] [powerpc/] [ppc403/] [ictrl/] [ictrl.c] - Blame information for rev 778

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*  ictrl.c
2
 *
3
 *  This routine installs and handles external interrupt vectors for
4
 *  PowerPC 403 CPU built-in external interrupt controller
5
 *
6
 *  Author: Thomas Doerfler <td@imd.m.isar.de>
7
 *
8
 *  COPYRIGHT (c) 1998 by IMD, Puchheim, Germany
9
 *
10
 *  To anyone who acknowledges that this file is provided "AS IS"
11
 *  without any express or implied warranty:
12
 *      permission to use, copy, modify, and distribute this file
13
 *      for any purpose is hereby granted without fee, provided that
14
 *      the above copyright notice and this notice appears in all
15
 *      copies, and that the name of IMD not be used in
16
 *      advertising or publicity pertaining to distribution of the
17
 *      software without specific, written prior permission.
18
 *      IMD makes no representations about the suitability
19
 *      of this software for any purpose.
20
 *
21
 */
22
 
23
#include "ictrl.h"
24
#include <rtems.h>
25
#include <rtems/libio.h>
26
 
27
#include <stdlib.h>                     /* for atexit() */
28
 
29
/*
30
 *  ISR vector table to dispatch external interrupts
31
 */
32
 
33
rtems_isr_entry ictrl_vector_table[PPC_IRQ_EXT_MAX];
34
 
35
/*
36
 *
37
 *  some utilities to access the EXI* registers
38
 *
39
 */
40
 
41
/*
42
 *  clear bits in EXISR that have a bit set in mask
43
 */
44
RTEMS_INLINE_ROUTINE void
45
clr_exisr(unsigned32 mask)
46
{
47
    asm volatile ("mtdcr 0x40,%0"::"r" (mask));/*EXISR*/
48
}
49
 
50
/*
51
 *  get value of EXISR
52
 */
53
RTEMS_INLINE_ROUTINE unsigned32
54
get_exisr(void)
55
{
56
    unsigned32 val;
57
 
58
    asm volatile ("mfdcr %0,0x40":"=r" (val));/*EXISR*/
59
    return val;
60
}
61
 
62
/*
63
 *  get value of EXIER
64
 */
65
RTEMS_INLINE_ROUTINE unsigned32
66
get_exier(void)
67
{
68
    unsigned32 val;
69
    asm volatile ("mfdcr %0,0x42":"=r" (val));/*EXIER*/
70
    return val;
71
}
72
 
73
/*
74
 *  set value of EXIER
75
 */
76
RTEMS_INLINE_ROUTINE void
77
set_exier(unsigned32 val)
78
{
79
    asm volatile ("mtdcr 0x42,%0"::"r" (val));/*EXIER*/
80
}
81
 
82
/*
83
 *  enable an external interrupt, make this interrupt consistent
84
 */
85
RTEMS_INLINE_ROUTINE void
86
enable_ext_irq( unsigned32 mask)
87
{
88
    unsigned32 isrlvl;
89
    _CPU_ISR_Disable(isrlvl);
90
    set_exier(get_exier() | ((mask)&PPC_EXI_MASK));
91
    _CPU_ISR_Enable(isrlvl);
92
}
93
 
94
/*
95
 *  disable an external interrupt, make this interrupt consistent
96
 */
97
RTEMS_INLINE_ROUTINE void
98
disable_ext_irq( unsigned32 mask)
99
{
100
    unsigned32 isrlvl;
101
    _CPU_ISR_Disable(isrlvl);
102
    set_exier(get_exier() & ~(mask) & PPC_EXI_MASK);
103
    _CPU_ISR_Enable(isrlvl);
104
}
105
 
106
/*
107
 *
108
 *  this function is called, when a external interrupt is present and
109
 *  enabled but there is no handler installed. It will clear
110
 *  the corresponding enable bits and call the spurious handler
111
 *  present in the CPU Configuration Table, if any.
112
 *
113
 */
114
void
115
ictrl_spurious_handler(unsigned32 spurious_mask,
116
                       CPU_Interrupt_frame *cpu_frame)
117
{
118
  int v;
119
 
120
  for (v=0; v < PPC_IRQ_EXT_MAX; v++) {
121
    if (VEC_TO_EXMSK(v) & spurious_mask) {
122
      clr_exisr(VEC_TO_EXMSK(v));
123
      disable_ext_irq(VEC_TO_EXMSK(v));
124
#if 0
125
      printf("spurious external interrupt: %d at pc 0x%x; disabling\n",
126
             vector, cpu_frame->Interrupt.pcoqfront);
127
#endif
128
      if (rtems_cpu_configuration_get_spurious_handler()) {
129
        rtems_cpu_configuration_get_spurious_handler()(v + PPC_IRQ_EXT_BASE,cpu_frame);
130
      }
131
    }
132
  }
133
}
134
 
135
 
136
/*
137
 *  ISR Handler: this is called from the primary exception dispatcher
138
 */
139
 
140
void
141
ictrl_isr(rtems_vector_number vector,CPU_Interrupt_frame *cpu_frame)
142
{
143
  unsigned32        istat,
144
                    mask,
145
                    global_vec;
146
  int               exvec;
147
  rtems_isr_entry handler;
148
 
149
  istat = get_exisr() & get_exier() & PPC_EXI_MASK;
150
 
151
  /* FIXME: this may be speeded up using cntlzw instruction */
152
  for (exvec = 0;exvec < PPC_IRQ_EXT_MAX;exvec++) {
153
    mask = VEC_TO_EXMSK(exvec);
154
    if (0 != (istat & mask)) {
155
      clr_exisr(mask);
156
      handler = ictrl_vector_table[exvec];
157
      if (handler) {
158
        istat &= ~mask;
159
        global_vec = exvec + PPC_IRQ_EXT_BASE;
160
        (handler)(global_vec);
161
      }
162
    }
163
  }
164
  if (istat != 0) { /* anything left? then we have a spurious interrupt */
165
    ictrl_spurious_handler(istat,cpu_frame);
166
  }
167
}
168
 
169
/*
170
 *
171
 * the following functions form the user interface
172
 *
173
 */
174
 
175
/*
176
 *
177
 * install a user vector for one of the external interrupt sources
178
 *
179
 */
180
rtems_status_code
181
ictrl_set_vector(rtems_isr_entry   new_handler,
182
                 unsigned32        vector,
183
                 rtems_isr_entry   *old_handler
184
)
185
{
186
  /*
187
   *  We put the actual user ISR address in 'ictrl_vector_table'.  This will
188
   *  be used by the _ictrl_isr so the user gets control.
189
   */
190
 
191
  /* check for valid vector range */
192
  if ((vector >= PPC_IRQ_EXT_BASE) &&
193
      (vector <  PPC_IRQ_EXT_BASE + PPC_IRQ_EXT_MAX)) {
194
 
195
    /* return old handler entry */
196
    *old_handler = ictrl_vector_table[vector - PPC_IRQ_EXT_BASE];
197
 
198
    if (new_handler != NULL) {
199
      /* store handler function... */
200
      ictrl_vector_table[vector - PPC_IRQ_EXT_BASE] = new_handler;
201
      /* then enable it in EXIER register */
202
      enable_ext_irq(VEC_TO_EXMSK(vector - PPC_IRQ_EXT_BASE));
203
    }
204
    else { /* new_handler == NULL */
205
      /* then disable it in EXIER register */
206
      disable_ext_irq(VEC_TO_EXMSK(vector - PPC_IRQ_EXT_BASE));
207
      ictrl_vector_table[vector - PPC_IRQ_EXT_BASE] = NULL;
208
    }
209
    return RTEMS_SUCCESSFUL;
210
  }
211
  else {
212
    return RTEMS_INVALID_NUMBER;
213
  }
214
}
215
 
216
/*
217
 * Called via atexit()
218
 * deactivate the interrupt controller
219
 */
220
 
221
void
222
ictrl_exit(void)
223
{
224
  /* mark them all unused */
225
  disable_ext_irq(~0);
226
  clr_exisr(~0);
227
 
228
}
229
 
230
/*
231
 * activate the interrupt controller
232
 */
233
 
234
rtems_status_code
235
ictrl_init(void)
236
{
237
  proc_ptr dummy;
238
 
239
  /* mark them all unused */
240
  disable_ext_irq(~0);
241
  clr_exisr(~0);
242
 
243
  /* install the external interrupt handler */
244
  _CPU_ISR_install_vector(PPC_IRQ_EXTERNAL,
245
                          ictrl_isr,
246
                          &dummy);
247
  atexit(ictrl_exit);
248
  return RTEMS_SUCCESSFUL;
249
}
250
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.