source: rtems/c/src/lib/libbsp/m68k/uC5282/startup/bspstart.c @ d75792b

4.115
Last change on this file since d75792b was d75792b, checked in by Joel Sherrill <joel.sherrill@…>, on 03/15/11 at 21:34:44

2011-03-15 Till Straumann <strauman@…>

  • startup/bspstart.c: Fix clock code on qemu. Also ensure UART is initialized early for printk.
  • Property mode set to 100644
File size: 24.9 KB
Line 
1/*
2 *  BSP startup
3 *
4 *  This routine starts the application.  It includes application,
5 *  board, and monitor specific initialization and configuration.
6 *  The generic CPU dependent initialization has been performed
7 *  before this routine is invoked.
8 *
9 *  Author: W. Eric Norum <norume@aps.anl.gov>
10 *
11 *  COPYRIGHT (c) 2005.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.com/license/LICENSE.
17 *
18 *  $Id$
19 */
20
21#include <bsp.h>
22#include <rtems/error.h>
23#include <errno.h>
24#include <stdio.h>
25#include <mcf5282/mcf5282.h>
26
27/*
28 * Location of 'VME' access
29 */
30#define VME_ONE_BASE    0x30000000
31#define VME_TWO_BASE    0x31000000
32
33/*
34 * Linker Script Defined Variables
35 */
36extern char RamSize[];
37extern char RamBase[];
38extern char _CPUClockSpeed[];
39extern char _PLLRefClockSpeed[];
40
41uint32_t BSP_sys_clk_speed = (uint32_t)_CPUClockSpeed;
42uint32_t BSP_pll_ref_clock = (uint32_t)_PLLRefClockSpeed;
43/*
44 * CPU-space access
45 * The NOP after writing the CACR is there to address the following issue as
46 * described in "Device Errata MCF5282DE", Rev. 1.7, 09/2004:
47 *
48 * 6 Possible Cache Corruption after Setting  CACR[CINV]
49 * 6.1 Description
50 * The cache on the MCF5282 was enhanced to function as a unified data and
51 * instruction cache, an instruction cache, or an operand cache.  The cache
52 * function and organization is controlled by the cache control register (CACR).
53 * The CINV (Bit 24 = cache invalidate) bit in the CACR causes a cache clear.
54 * If the cache is configured as a unified cache and the CINV bit is set, the
55 * scope of the cache clear is controlled by two other bits in the CACR,
56 * INVI (BIT 21 = CINV instruction cache only) and INVD (BIT 20 = CINV data
57 * cache only).  These bits allow the entire cache, just the instruction
58 * portion of the cache, or just the data portion of the cache to be cleared.
59 * If a write to the CACR is performed to clear the cache (CINV = BIT 24 set)
60 * and only a partial clear will be done (INVI = BIT 21 or INVD = BIT 20 set),
61 * then cache corruption may  occur.
62 *
63 * 6.2 Workaround
64 * All loads of the CACR that perform a cache clear operation (CINV = BIT 24)
65 * should be followed immediately by a NOP instruction.  This avoids the cache
66 * corruption problem.
67 * DATECODES AFFECTED: All
68 *
69 *
70 * Buffered writes must be disabled as described in "MCF5282 Chip Errata",
71 * MCF5282DE, Rev. 6, 5/2009:
72 *   SECF124: Buffered Write May Be Executed Twice
73 *   Errata type: Silicon
74 *   Affected component: Cache
75 *   Description: If buffered writes are enabled using the CACR or ACR
76 *                registers, the imprecise write transaction generated
77 *                by a buffered write may be executed twice.
78 *   Workaround: Do not enable buffered writes in the CACR or ACR registers:
79 *               CACR[8] = DBWE (default buffered write enable) must be 0
80 *               ACRn[5] = BUFW (buffered write enable) must be 0
81 *   Fix plan: Currently, there are no plans to fix this.
82 */
83#define m68k_set_cacr_nop(_cacr) __asm__ volatile ("movec %0,%%cacr\n\tnop" : : "d" (_cacr))
84#define m68k_set_cacr(_cacr) __asm__ volatile ("movec %0,%%cacr" : : "d" (_cacr))
85#define m68k_set_acr0(_acr0) __asm__ volatile ("movec %0,%%acr0" : : "d" (_acr0))
86#define m68k_set_acr1(_acr1) __asm__ volatile ("movec %0,%%acr1" : : "d" (_acr1))
87
88/*
89 * Read/write copy of cache registers
90 *   Split instruction/data or instruction-only
91 *   Allow CPUSHL to invalidate a cache line
92 *   Disable buffered writes
93 *   No burst transfers on non-cacheable accesses
94 *   Default cache mode is *disabled* (cache only ACRx areas)
95 */
96uint32_t mcf5282_cacr_mode = MCF5XXX_CACR_CENB |
97#ifndef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
98                             MCF5XXX_CACR_DISD |
99#endif
100                             MCF5XXX_CACR_DCM;
101uint32_t mcf5282_acr0_mode = 0;
102uint32_t mcf5282_acr1_mode = 0;
103/*
104 * Cannot be frozen
105 */
106void _CPU_cache_freeze_data(void) {}
107void _CPU_cache_unfreeze_data(void) {}
108void _CPU_cache_freeze_instruction(void) {}
109void _CPU_cache_unfreeze_instruction(void) {}
110
111/*
112 * Write-through data cache -- flushes are unnecessary
113 */
114void _CPU_cache_flush_1_data_line(const void *d_addr) {}
115void _CPU_cache_flush_entire_data(void) {}
116
117void _CPU_cache_enable_instruction(void)
118{
119    rtems_interrupt_level level;
120
121    rtems_interrupt_disable(level);
122    mcf5282_cacr_mode &= ~MCF5XXX_CACR_DIDI;
123    m68k_set_cacr_nop(mcf5282_cacr_mode | MCF5XXX_CACR_CINV | MCF5XXX_CACR_INVI);
124    rtems_interrupt_enable(level);
125}
126
127void _CPU_cache_disable_instruction(void)
128{
129    rtems_interrupt_level level;
130
131    rtems_interrupt_disable(level);
132    mcf5282_cacr_mode |= MCF5XXX_CACR_DIDI;
133    m68k_set_cacr(mcf5282_cacr_mode);
134    rtems_interrupt_enable(level);
135}
136
137void _CPU_cache_invalidate_entire_instruction(void)
138{
139    m68k_set_cacr_nop(mcf5282_cacr_mode | MCF5XXX_CACR_CINV | MCF5XXX_CACR_INVI);
140}
141
142void _CPU_cache_invalidate_1_instruction_line(const void *addr)
143{
144    /*
145     * Top half of cache is I-space
146     */
147    addr = (void *)((int)addr | 0x400);
148    __asm__ volatile ("cpushl %%bc,(%0)" :: "a" (addr));
149}
150
151void _CPU_cache_enable_data(void)
152{
153#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
154    rtems_interrupt_level level;
155
156    rtems_interrupt_disable(level);
157    mcf5282_cacr_mode &= ~MCF5XXX_CACR_DISD;
158    m68k_set_cacr_nop(mcf5282_cacr_mode | MCF5XXX_CACR_CINV | MCF5XXX_CACR_INVD);
159    rtems_interrupt_enable(level);
160#endif
161}
162
163void _CPU_cache_disable_data(void)
164{
165#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
166    rtems_interrupt_level level;
167
168    rtems_interrupt_disable(level);
169    mcf5282_cacr_mode |= MCF5XXX_CACR_DISD;
170    m68k_set_cacr(mcf5282_cacr_mode);
171    rtems_interrupt_enable(level);
172#endif
173}
174
175void _CPU_cache_invalidate_entire_data(void)
176{
177#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
178    m68k_set_cacr_nop(mcf5282_cacr_mode | MCF5XXX_CACR_CINV | MCF5XXX_CACR_INVD);
179#endif
180}
181
182void _CPU_cache_invalidate_1_data_line(const void *addr)
183{
184#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
185    /*
186     * Bottom half of cache is D-space
187     */
188    addr = (void *)((int)addr & ~0x400);
189    __asm__ volatile ("cpushl %%bc,(%0)" :: "a" (addr));
190#endif
191}
192
193extern void bsp_fake_syscall(int);
194
195/*
196 * The Arcturus boot ROM prints exception information improperly
197 * so use this default exception handler instead.  This one also
198 * prints a call backtrace
199 */
200static void handler(int pc)
201{
202    int level;
203    static volatile int reent;
204
205    rtems_interrupt_disable(level);
206    if (reent++) bsp_sysReset(0);
207    {
208    int *p = &pc;
209    int info = p[-1];
210    int pc = p[0];
211    int format = (info >> 28) & 0xF;
212    int faultStatus = ((info >> 24) & 0xC) | ((info >> 16) & 0x3);
213    int vector = (info >> 18) & 0xFF;
214    int statusRegister = info & 0xFFFF;
215    int *fp;
216
217    printk("\n\nPC:%x  SR:%x  VEC:%x  FORMAT:%x  STATUS:%x\n", pc,
218                                                               statusRegister,
219                                                               vector,
220                                                               format,
221                                                               faultStatus);
222    fp = &p[-2];
223    for(;;) {
224        int *nfp = (int *)*fp;
225        if ((nfp <= fp)
226         || ((char *)nfp >= RamSize)
227         || ((char *)(nfp[1]) >= RamSize))
228            break;
229        printk("FP:%x -> %x    PC:%x\n", fp, nfp, nfp[1]);
230        fp = nfp;
231    }
232    }
233    rtems_task_suspend(0);
234    rtems_panic("done");
235}
236
237/*
238 *  bsp_start
239 *
240 *  This routine does the bulk of the system initialisation.
241 */
242void bsp_start( void )
243{
244  int   i;
245  const char *clk_speed_str;
246  uint32_t clk_speed, mfd, rfd;
247  uint8_t  byte;
248
249  /*
250   * Make sure UART TX is running - necessary for
251   * early printk to work. The firmware monitor
252   * usually enables this anyways but qemu doesn't!
253   */
254  MCF5282_UART_UCR(CONSOLE_PORT) = MCF5282_UART_UCR_TX_ENABLED;
255
256  /*
257   * Set up default exception handler
258   */
259  for (i = 2 ; i < 256 ; i++)
260      if (i != (32+2)) /* Catch all but bootrom system calls */
261          *((void (**)(int))(i * 4)) = handler;
262
263  /*
264   * Invalidate the cache and disable it
265   */
266  m68k_set_acr0(mcf5282_acr0_mode);
267  m68k_set_acr1(mcf5282_acr1_mode);
268  m68k_set_cacr_nop(MCF5XXX_CACR_CINV);
269
270  /*
271   * Cache SDRAM
272   * Enable buffered writes
273   * As Device Errata SECF124 notes this may cause double writes,
274   * but that's not really a big problem and benchmarking tests have
275   * shown that buffered writes do gain some performance.
276   */
277  mcf5282_acr0_mode = MCF5XXX_ACR_AB((uint32_t)RamBase)     |
278                      MCF5XXX_ACR_AM((uint32_t)RamSize-1)   |
279                      MCF5XXX_ACR_EN                        |
280                      MCF5XXX_ACR_SM_IGNORE                 |
281                      MCF5XXX_ACR_BWE;
282  m68k_set_acr0(mcf5282_acr0_mode);
283
284  /*
285   * Qemu has no trap handler; install our fake syscall
286   * implementation if there is no existing handler.
287   */
288  if ( 0 == *((void (**)(int))((32+2) * 4)) )
289    *((void (**)(int))((32+2) * 4)) = bsp_fake_syscall;
290
291  /*
292   * Enable the cache
293   */
294  m68k_set_cacr(mcf5282_cacr_mode);
295
296  /*
297   * Set up CS* space (fake 'VME')
298   *   Two A24/D16 spaces, supervisor data acces
299   */
300  MCF5282_CS1_CSAR = MCF5282_CS_CSAR_BA(VME_ONE_BASE);
301  MCF5282_CS1_CSMR = MCF5282_CS_CSMR_BAM_16M |
302                     MCF5282_CS_CSMR_CI |
303                     MCF5282_CS_CSMR_SC |
304                     MCF5282_CS_CSMR_UC |
305                     MCF5282_CS_CSMR_UD |
306                     MCF5282_CS_CSMR_V;
307  MCF5282_CS1_CSCR = MCF5282_CS_CSCR_PS_16;
308  MCF5282_CS2_CSAR = MCF5282_CS_CSAR_BA(VME_TWO_BASE);
309  MCF5282_CS2_CSMR = MCF5282_CS_CSMR_BAM_16M |
310                     MCF5282_CS_CSMR_CI |
311                     MCF5282_CS_CSMR_SC |
312                     MCF5282_CS_CSMR_UC |
313                     MCF5282_CS_CSMR_UD |
314                     MCF5282_CS_CSMR_V;
315  MCF5282_CS2_CSCR = MCF5282_CS_CSCR_PS_16;
316  MCF5282_GPIO_PJPAR |= 0x06;
317
318  /*
319   * Hopefully, the UART clock is still correctly set up
320   * so they can see the printk() output...
321   */
322  clk_speed = 0;
323  printk("Trying to figure out the system clock\n");
324  printk("Checking ENV variable SYS_CLOCK_SPEED:\n");
325  if ( (clk_speed_str = bsp_getbenv("SYS_CLOCK_SPEED")) ) {
326    printk("Found: %s\n", clk_speed_str);
327        for ( clk_speed = 0, i=0;
328              clk_speed_str[i] >= '0' && clk_speed_str[i] <= '9';
329              i++ ) {
330                clk_speed = 10*clk_speed + clk_speed_str[i] - '0';
331        }
332        if ( 0 != clk_speed_str[i] ) {
333                printk("Not a decimal number; I'm not using this setting\n");
334                clk_speed = 0;
335        }
336  } else {
337    printk("Not set.\n");
338  }
339
340  if ( 0 == clk_speed )
341        clk_speed = BSP_sys_clk_speed;
342
343  if ( 0 == clk_speed ) {
344        printk("Using some heuristics to determine clock speed...\n");
345        byte = MCF5282_CLOCK_SYNSR;
346        if ( 0 == byte ) {
347                printk("SYNSR == 0; assuming QEMU at 66MHz\n");
348                BSP_pll_ref_clock = 8250000;
349                mfd = ( 0 << 8 ) | ( 2 << 12 );
350        } else {
351                if ( 0xf8 != byte ) {
352                        printk("FATAL ERROR: Unexpected SYNSR contents (0x%02x), can't proceed\n", byte);
353                        bsp_sysReset(0);
354                }
355                mfd = MCF5282_CLOCK_SYNCR;
356        }
357        printk("Assuming %uHz PLL ref. clock\n", BSP_pll_ref_clock);
358        rfd = (mfd >>  8) & 7;
359        mfd = (mfd >> 12) & 7;
360        /* Check against 'known' cases */
361        if ( 0 != rfd || (2 != mfd && 3 != mfd) ) {
362          printk("WARNING: Pll divisor/multiplier has unknown value; \n");
363          printk("         either your board is not 64MHz or 80Mhz or\n");
364          printk("         it uses a PLL reference other than 8MHz.\n");
365          printk("         I'll proceed anyways but you might have to\n");
366          printk("         reset the board and set uCbootloader ENV\n");
367          printk("         variable \"SYS_CLOCK_SPEED\".\n");
368        }
369        mfd = 2 * (mfd + 2);
370        /* sysclk = pll_ref * 2 * (MFD + 2) / 2^(rfd) */
371        printk("PLL multiplier: %u, output divisor: %u\n", mfd, rfd);
372        clk_speed = (BSP_pll_ref_clock * mfd) >> rfd;
373  }
374
375  if ( 0 == clk_speed ) {
376        printk("FATAL ERROR: Unable to determine system clock speed\n");
377        bsp_sysReset(0);
378  } else {
379        BSP_sys_clk_speed = clk_speed;
380        printk("System clock speed: %uHz\n", bsp_get_CPU_clock_speed());
381  }
382}
383
384uint32_t bsp_get_CPU_clock_speed(void)
385{
386  return( BSP_sys_clk_speed );
387}
388
389/*
390 * Interrupt controller allocation
391 */
392rtems_status_code
393bsp_allocate_interrupt(int level, int priority)
394{
395  static char used[7];
396  rtems_interrupt_level l;
397  rtems_status_code ret = RTEMS_RESOURCE_IN_USE;
398
399  if ((level < 1) || (level > 7) || (priority < 0) || (priority > 7))
400    return RTEMS_INVALID_NUMBER;
401  rtems_interrupt_disable(l);
402  if ((used[level-1] & (1 << priority)) == 0) {
403    used[level-1] |= (1 << priority);
404    ret = RTEMS_SUCCESSFUL;
405  }
406  rtems_interrupt_enable(l);
407  return ret;
408}
409
410/*
411 * Arcturus bootloader system calls
412 */
413#define syscall_return(type, ret)                      \
414do {                                                   \
415   if ((unsigned long)(ret) >= (unsigned long)(-64)) { \
416      errno = -(ret);                                  \
417      ret = -1;                                        \
418   }                                                   \
419   return (type)(ret);                                 \
420} while (0)
421
422#define syscall_1(type,name,d1type,d1)                      \
423type bsp_##name(d1type d1)                                  \
424{                                                           \
425   long ret;                                                \
426   register long __d1 __asm__ ("%d1") = (long)d1;           \
427   __asm__ __volatile__ ("move.l %1,%%d0\n\t"               \
428                         "trap #2\n\t"                      \
429                         "move.l %%d0,%0"                   \
430                         : "=g" (ret)                       \
431                         : "i" (SysCode_##name), "d" (__d1) \
432                         : "d0" );                          \
433   syscall_return(type,ret);                                \
434}
435
436#define syscall_2(type,name,d1type,d1,d2type,d2)            \
437type bsp_##name(d1type d1, d2type d2)                       \
438{                                                           \
439   long ret;                                                \
440   register long __d1 __asm__ ("%d1") = (long)d1;           \
441   register long __d2 __asm__ ("%d2") = (long)d2;           \
442   __asm__ __volatile__ ("move.l %1,%%d0\n\t"               \
443                         "trap #2\n\t"                      \
444                         "move.l %%d0,%0"                   \
445                         : "=g" (ret)                       \
446                         : "i" (SysCode_##name), "d" (__d1),\
447                                                 "d" (__d2) \
448                         : "d0" );                          \
449   syscall_return(type,ret);                                \
450}
451
452#define syscall_3(type,name,d1type,d1,d2type,d2,d3type,d3)  \
453type bsp_##name(d1type d1, d2type d2, d3type d3)            \
454{                                                           \
455   long ret;                                                \
456   register long __d1 __asm__ ("%d1") = (long)d1;           \
457   register long __d2 __asm__ ("%d2") = (long)d2;           \
458   register long __d3 __asm__ ("%d3") = (long)d3;           \
459   __asm__ __volatile__ ("move.l %1,%%d0\n\t"               \
460                         "trap #2\n\t"                      \
461                         "move.l %%d0,%0"                   \
462                         : "=g" (ret)                       \
463                         : "i" (SysCode_##name), "d" (__d1),\
464                                                 "d" (__d2),\
465                                                 "d" (__d3) \
466                         : "d0" );                          \
467   syscall_return(type,ret);                                \
468}
469
470#define SysCode_sysReset           0 /* system reset */
471#define SysCode_program            5 /* program flash memory */
472#define SysCode_gethwaddr         12 /* get hardware address */
473#define SysCode_getbenv           14 /* get bootloader environment variable */
474#define SysCode_setbenv           15 /* set bootloader environment variable */
475#define SysCode_flash_erase_range 19 /* erase a section of flash */
476#define SysCode_flash_write_range 20 /* write a section of flash */
477syscall_1(int, sysReset, int, flags)
478syscall_1(unsigned const char *, gethwaddr, int, a)
479syscall_1(const char *, getbenv, const char *, a)
480syscall_1(int, setbenv, const char *, a)
481syscall_2(int, program, bsp_mnode_t *, chain, int, flags)
482syscall_3(int, flash_erase_range, volatile unsigned short *, flashptr, int, start, int, end);
483syscall_3(int, flash_write_range, volatile unsigned short *, flashptr, bsp_mnode_t *, chain, int, offset);
484
485/* Provide a dummy-implementation of these syscalls
486 * for qemu (which lacks the firmware).
487 */
488
489#define __STR(x)    #x
490#define __STRSTR(x) __STR(x)
491#define ERRVAL      __STRSTR(EACCES)
492
493/* reset-control register */
494#define RCR "__IPSBAR + 0x110000"
495
496__asm__ (
497    "bsp_fake_syscall:         \n"
498    "   cmpl  #0,  %d0         \n" /* sysreset    */
499    "   bne   1f               \n"
500    "   moveb #0x80, %d0       \n"
501    "   moveb %d0, "RCR"       \n" /* reset-controller */
502        /* should never get here - but we'd return -EACCESS if we do */
503    "1:                        \n"
504    "   cmpl  #12, %d0         \n" /* gethwaddr   */
505    "   beq   2f               \n"
506    "   cmpl  #14, %d0         \n" /* getbenv     */
507    "   beq   2f               \n"
508    "   movel #-"ERRVAL", %d0  \n" /* return -EACCESS */
509    "   rte                    \n"
510    "2:                        \n"
511    "   movel #0,  %d0         \n" /* return NULL */
512    "   rte                    \n"
513);
514
515
516/*
517 * 'Extended BSP' routines
518 * Should move to cpukit/score/cpu/m68k/cpu.c someday.
519 */
520
521rtems_status_code bspExtInit(void) { return RTEMS_SUCCESSFUL; }
522int BSP_enableVME_int_lvl(unsigned int level) { return 0; }
523int BSP_disableVME_int_lvl(unsigned int level) { return 0; }
524
525/*
526 * 'VME' interrupt support
527 * Interrupt vectors 192-255 are set aside for use by external logic which
528 * drives IRQ1*.  The actual interrupt source is read from the external
529 * logic at FPGA_IRQ_INFO.  The most-significant bit of the least-significant
530 * byte read from this location is set as long as the external logic has
531 * interrupts to be serviced.  The least-significant six bits indicate the
532 * interrupt source within the external logic and are used to select the
533 * specified interupt handler.
534 */
535#define NVECTOR 256
536#define FPGA_VECTOR (64+1)  /* IRQ1* pin connected to external FPGA */
537#define FPGA_IRQ_INFO    *((vuint16 *)(0x31000000 + 0xfffffe))
538
539static struct handlerTab {
540  BSP_VME_ISR_t func;
541  void         *arg;
542} handlerTab[NVECTOR];
543
544BSP_VME_ISR_t
545BSP_getVME_isr(unsigned long vector, void **pusrArg)
546{
547  if (vector >= NVECTOR)
548    return (BSP_VME_ISR_t)NULL;
549  if (pusrArg)
550    *pusrArg = handlerTab[vector].arg;
551  return handlerTab[vector].func;
552}
553
554static rtems_isr
555fpga_trampoline (rtems_vector_number v)
556{
557  /*
558   * Handle FPGA interrupts until all have been consumed
559   */
560  int loopcount = 0;
561  while (((v = FPGA_IRQ_INFO) & 0x80) != 0) {
562    v = 192 + (v & 0x3f);
563    if (++loopcount >= 50) {
564      rtems_interrupt_level level;
565      rtems_interrupt_disable(level);
566      printk("\nTOO MANY FPGA INTERRUPTS (LAST WAS 0x%x) -- DISABLING ALL FPGA INTERRUPTS.\n", v & 0x3f);
567      MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1;
568      rtems_interrupt_enable(level);
569      return;
570    }
571    if (handlerTab[v].func)  {
572      (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v);
573    }
574    else {
575      rtems_interrupt_level level;
576      rtems_vector_number nv;
577      rtems_interrupt_disable(level);
578      printk("\nSPURIOUS FPGA INTERRUPT (0x%x).\n", v & 0x3f);
579      if ((((nv = FPGA_IRQ_INFO) & 0x80) != 0)
580          && ((nv & 0x3f) == (v & 0x3f))) {
581        printk("DISABLING ALL FPGA INTERRUPTS.\n");
582        MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1;
583      }
584      rtems_interrupt_enable(level);
585      return;
586    }
587  }
588}
589
590static rtems_isr
591trampoline (rtems_vector_number v)
592{
593    if (handlerTab[v].func)
594        (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v);
595}
596
597static void
598enable_irq(unsigned source)
599{
600rtems_interrupt_level level;
601  rtems_interrupt_disable(level);
602  if (source >= 32)
603    MCF5282_INTC0_IMRH &= ~(1 << (source - 32));
604  else
605    MCF5282_INTC0_IMRL &= ~((1 << source) |
606        MCF5282_INTC_IMRL_MASKALL);
607  rtems_interrupt_enable(level);
608}
609
610static void
611disable_irq(unsigned source)
612{
613rtems_interrupt_level level;
614
615  rtems_interrupt_disable(level);
616  if (source >= 32)
617    MCF5282_INTC0_IMRH |= (1 << (source - 32));
618  else
619    MCF5282_INTC0_IMRL |= (1 << source);
620  rtems_interrupt_enable(level);
621}
622
623void
624BSP_enable_irq_at_pic(rtems_vector_number v)
625{
626int                   source = v - 64;
627
628  if ( source > 0 && source < 64 ) {
629    enable_irq(source);
630  }
631}
632
633void
634BSP_disable_irq_at_pic(rtems_vector_number v)
635{
636int                   source = v - 64;
637
638  if ( source > 0 && source < 64 ) {
639    disable_irq(source);
640  }
641}
642
643int
644BSP_irq_is_enabled_at_pic(rtems_vector_number v)
645{
646int                   source = v - 64;
647
648  if ( source > 0 && source < 64 ) {
649    return ! ((source >= 32) ?
650      MCF5282_INTC0_IMRH & (1 << (source - 32)) :
651      MCF5282_INTC0_IMRL & (1 << source));
652  }
653  return -1;
654}
655
656
657static int
658init_intc0_bit(unsigned long vector)
659{
660rtems_interrupt_level level;
661
662    /*
663     * Find an unused level/priority if this is an on-chip (INTC0)
664     * source and this is the first time the source is being used.
665     * Interrupt sources 1 through 7 are fixed level/priority
666     */
667
668    if ((vector >= 65) && (vector <= 127)) {
669        int l, p;
670        int source = vector - 64;
671        static unsigned char installed[8];
672
673        rtems_interrupt_disable(level);
674        if (installed[source/8] & (1 << (source % 8))) {
675            rtems_interrupt_enable(level);
676            return 0;
677        }
678        installed[source/8] |= (1 << (source % 8));
679        rtems_interrupt_enable(level);
680        for (l = 1 ; l < 7 ; l++) {
681            for (p = 0 ; p < 8 ; p++) {
682                if ((source < 8)
683                 || (bsp_allocate_interrupt(l,p) == RTEMS_SUCCESSFUL)) {
684                    if (source < 8)
685                        MCF5282_EPORT_EPIER |= 1 << source;
686                    else
687                        *(&MCF5282_INTC0_ICR1 + (source - 1)) =
688                                                       MCF5282_INTC_ICR_IL(l) |
689                                                       MCF5282_INTC_ICR_IP(p);
690          enable_irq(source);
691                    return 0;
692                }
693            }
694        }
695        return -1;
696    }
697  return 0;
698}
699
700int
701BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg)
702{
703  rtems_isr_entry old_handler;
704  rtems_interrupt_level level;
705
706  /*
707   * Register the handler information
708   */
709  if (vector >= NVECTOR)
710    return -1;
711  handlerTab[vector].func = handler;
712  handlerTab[vector].arg = usrArg;
713
714  /*
715   * If this is an external FPGA ('VME') vector set up the real IRQ.
716   */
717  if ((vector >= 192) && (vector <= 255)) {
718    int i;
719    static volatile int setupDone;
720    rtems_interrupt_disable(level);
721    if (setupDone) {
722      rtems_interrupt_enable(level);
723      return 0;
724    }
725    setupDone = 1;
726    rtems_interrupt_catch(fpga_trampoline, FPGA_VECTOR, &old_handler);
727    i = init_intc0_bit(FPGA_VECTOR);
728    rtems_interrupt_enable(level);
729    return i;
730  }
731
732  /*
733   * Make the connection between the interrupt and the local handler
734   */
735  rtems_interrupt_catch(trampoline, vector, &old_handler);
736
737  return init_intc0_bit(vector);
738}
739
740int
741BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg)
742{
743  if (vector >= NVECTOR)
744    return -1;
745  if ((handlerTab[vector].func != handler)
746     || (handlerTab[vector].arg != usrArg))
747    return -1;
748  handlerTab[vector].func = (BSP_VME_ISR_t)NULL;
749  return 0;
750}
751
752int
753BSP_vme2local_adrs(unsigned am, unsigned long vmeaddr, unsigned long *plocaladdr)
754{
755  unsigned long offset;
756
757  switch (am) {
758    default:    return -1;
759    case VME_AM_SUP_SHORT_IO: offset = 0x31FF0000; break; /* A16/D16 */
760    case VME_AM_STD_SUP_DATA: offset = 0x30000000; break; /* A24/D16 */
761    case VME_AM_EXT_SUP_DATA: offset = 0x31000000; break; /* A32/D32 */
762  }
763  *plocaladdr = vmeaddr + offset;
764  return 0;
765}
766
767void
768rtems_bsp_reset_cause(char *buf, size_t capacity)
769{
770  int bit, rsr;
771  size_t i;
772  const char *cp;
773
774  if (buf == NULL)
775    return;
776  if (capacity)
777    buf[0] = '\0';
778  rsr = MCF5282_RESET_RSR;
779  for (i = 0, bit = 0x80 ; bit != 0 ; bit >>= 1) {
780    if (rsr & bit) {
781      switch (bit) {
782        case MCF5282_RESET_RSR_LVD:  cp = "Low voltage";        break;
783        case MCF5282_RESET_RSR_SOFT: cp = "Software reset";     break;
784        case MCF5282_RESET_RSR_WDR:  cp = "Watchdog reset";     break;
785        case MCF5282_RESET_RSR_POR:  cp = "Power-on reset";     break;
786        case MCF5282_RESET_RSR_EXT:  cp = "External reset";     break;
787        case MCF5282_RESET_RSR_LOC:  cp = "Loss of clock";      break;
788        case MCF5282_RESET_RSR_LOL:  cp = "Loss of lock";       break;
789        default:                     cp = "??";                 break;
790      }
791      i += snprintf(buf+i, capacity-i, cp);
792      if (i >= capacity)
793        break;
794      rsr &= ~bit;
795      if (rsr == 0)
796        break;
797      i += snprintf(buf+i, capacity-i, ", ");
798      if (i >= capacity)
799        break;
800    }
801  }
802}
Note: See TracBrowser for help on using the repository browser.