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

4.104.115
Last change on this file since 4c5212e was 4c5212e, checked in by Joel Sherrill <joel.sherrill@…>, on 09/16/08 at 22:16:26

2008-09-16 Joel Sherrill <joel.sherrill@…>

  • Makefile.am, startup/bspstart.c, startup/linkcmds: Use top level shared bsp_get_work_area() implementation.
  • Property mode set to 100644
File size: 20.2 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 
25/*
26 * Location of 'VME' access
27 */
28#define VME_ONE_BASE    0x30000000
29#define VME_TWO_BASE    0x31000000
30
31/*
32 * Linker Script Defined Variables
33 */
34extern char RamSize[];
35extern char RamBase[];
36
37/*
38 * CPU-space access
39 * The NOP after writing the CACR is there to address the following issue as
40 * described in "Device Errata MCF5282DE", Rev. 1.7, 09/2004:
41 *
42 * 6 Possible Cache Corruption after Setting  CACR[CINV]
43 * 6.1 Description
44 * The cache on the MCF5282 was enhanced to function as a unified data and
45 * instruction cache, an instruction cache, or an operand cache.  The cache
46 * function and organization is controlled by the cache control register (CACR).
47 * The CINV (Bit 24 = cache invalidate) bit in the CACR causes a cache clear.
48 * If the cache is configured as a unified cache and the CINV bit is set, the
49 * scope of the cache clear is controlled by two other bits in the CACR,
50 * INVI (BIT 21 = CINV instruction cache only) and INVD (BIT 20 = CINV data
51 * cache only).  These bits allow the entire cache, just the instruction
52 * portion of the cache, or just the data portion of the cache to be cleared.
53 * If a write to the CACR is performed to clear the cache (CINV = BIT 24 set)
54 * and only a partial clear will be done (INVI = BIT 21 or INVD = BIT 20 set),
55 * then cache corruption may  occur.
56 *
57 * 6.2 Workaround
58 * All loads of the CACR that perform a cache clear operation (CINV = BIT 24)
59 * should be followed immediately by a NOP instruction.  This avoids the cache
60 * corruption problem.
61 * DATECODES AFFECTED: All
62 */
63#define m68k_set_cacr_nop(_cacr) asm volatile ("movec %0,%%cacr\n\tnop" : : "d" (_cacr))
64#define m68k_set_cacr(_cacr) asm volatile ("movec %0,%%cacr" : : "d" (_cacr))
65#define m68k_set_acr0(_acr0) asm volatile ("movec %0,%%acr0" : : "d" (_acr0))
66#define m68k_set_acr1(_acr1) asm volatile ("movec %0,%%acr1" : : "d" (_acr1))
67
68/*
69 * Read/write copy of cache registers
70 *   Split instruction/data or instruction-only
71 *   Allow CPUSHL to invalidate a cache line
72 *   Enable buffered writes
73 *   No burst transfers on non-cacheable accesses
74 *   Default cache mode is *disabled* (cache only ACRx areas)
75 */
76uint32_t mcf5282_cacr_mode = MCF5XXX_CACR_CENB |
77#ifndef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
78                             MCF5XXX_CACR_DISD |
79#endif
80                             MCF5XXX_CACR_DBWE |
81                             MCF5XXX_CACR_DCM;
82uint32_t mcf5282_acr0_mode = 0;
83uint32_t mcf5282_acr1_mode = 0;
84/*
85 * Cannot be frozen
86 */
87void _CPU_cache_freeze_data(void) {}
88void _CPU_cache_unfreeze_data(void) {}
89void _CPU_cache_freeze_instruction(void) {}
90void _CPU_cache_unfreeze_instruction(void) {}
91
92/*
93 * Write-through data cache -- flushes are unnecessary
94 */
95void _CPU_cache_flush_1_data_line(const void *d_addr) {}
96void _CPU_cache_flush_entire_data(void) {}
97
98void _CPU_cache_enable_instruction(void)
99{
100    rtems_interrupt_level level;
101
102    rtems_interrupt_disable(level);
103    mcf5282_cacr_mode &= ~MCF5XXX_CACR_DIDI;
104    m68k_set_cacr(mcf5282_cacr_mode);
105    rtems_interrupt_enable(level);
106}
107
108void _CPU_cache_disable_instruction(void)
109{
110    rtems_interrupt_level level;
111
112    rtems_interrupt_disable(level);
113    mcf5282_cacr_mode |= MCF5XXX_CACR_DIDI;
114    m68k_set_cacr(mcf5282_cacr_mode);
115    rtems_interrupt_enable(level);
116}
117
118void _CPU_cache_invalidate_entire_instruction(void)
119{
120    m68k_set_cacr_nop(mcf5282_cacr_mode | MCF5XXX_CACR_CINV | MCF5XXX_CACR_INVI);
121}
122
123void _CPU_cache_invalidate_1_instruction_line(const void *addr)
124{
125    /*
126     * Top half of cache is I-space
127     */
128    addr = (void *)((int)addr | 0x400);
129    asm volatile ("cpushl %%bc,(%0)" :: "a" (addr));
130}
131
132void _CPU_cache_enable_data(void)
133{
134#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
135    rtems_interrupt_level level;
136
137    rtems_interrupt_disable(level);
138    mcf5282_cacr_mode &= ~MCF5XXX_CACR_CENB;
139    m68k_set_cacr(mcf5282_cacr_mode);
140    rtems_interrupt_enable(level);
141#endif
142}
143
144void _CPU_cache_disable_data(void)
145{
146#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
147    rtems_interrupt_level level;
148
149    rtems_interrupt_disable(level);
150    rtems_interrupt_disable(level);
151    mcf5282_cacr_mode |= MCF5XXX_CACR_CENB;
152    m68k_set_cacr(mcf5282_cacr_mode);
153    rtems_interrupt_enable(level);
154#endif
155}
156
157void _CPU_cache_invalidate_entire_data(void)
158{
159#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
160    m68k_set_cacr_nop(mcf5282_cacr_mode | MCF5XXX_CACR_CINV | MCF5XXX_CACR_INVD);
161#endif
162}
163
164void _CPU_cache_invalidate_1_data_line(const void *addr)
165{
166#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
167    /*
168     * Bottom half of cache is D-space
169     */
170    addr = (void *)((int)addr & ~0x400);
171    asm volatile ("cpushl %%bc,(%0)" :: "a" (addr));
172#endif
173}
174
175/*
176 * The Arcturus boot ROM prints exception information improperly
177 * so use this default exception handler instead.  This one also
178 * prints a call backtrace
179 */
180static void handler(int pc)
181{
182    int level;
183    static volatile int reent;
184
185    rtems_interrupt_disable(level);
186    if (reent++) bsp_reset(0);
187    {
188    int *p = &pc;
189    int info = p[-1];
190    int pc = p[0];
191    int format = (info >> 28) & 0xF;
192    int faultStatus = ((info >> 24) & 0xC) | ((info >> 16) & 0x3);
193    int vector = (info >> 18) & 0xFF;
194    int statusRegister = info & 0xFFFF;
195    int *fp;
196
197    printk("\n\nPC:%x  SR:%x  VEC:%x  FORMAT:%x  STATUS:%x\n", pc,
198                                                               statusRegister,
199                                                               vector,
200                                                               format,
201                                                               faultStatus);
202    fp = &p[-2];
203    for(;;) {
204        int *nfp = (int *)*fp;
205        if ((nfp <= fp)
206         || ((char *)nfp >= RamSize)
207         || ((char *)(nfp[1]) >= RamSize))
208            break;
209        printk("FP:%x -> %x    PC:%x\n", fp, nfp, nfp[1]);
210        fp = nfp;
211    }
212    }
213    rtems_task_suspend(0);
214    rtems_panic("done");
215}
216
217/*
218 *  bsp_start
219 *
220 *  This routine does the bulk of the system initialisation.
221 */
222void bsp_start( void )
223{
224  int i;
225
226  /*
227   * Set up default exception handler
228   */
229  for (i = 2 ; i < 256 ; i++)
230      if (i != (32+2)) /* Catch all but bootrom system calls */
231          *((void (**)(int))(i * 4)) = handler;
232
233  /*
234   * Invalidate the cache and disable it
235   */
236  m68k_set_acr0(mcf5282_acr0_mode);
237  m68k_set_acr1(mcf5282_acr1_mode);
238  m68k_set_cacr_nop(MCF5XXX_CACR_CINV);
239
240  /*
241   * Cache SDRAM
242   */
243  mcf5282_acr0_mode = MCF5XXX_ACR_AB((uint32_t)RamBase)     |
244                      MCF5XXX_ACR_AM((uint32_t)RamSize-1)   |
245                      MCF5XXX_ACR_EN                         |
246                      MCF5XXX_ACR_BWE                        |
247                      MCF5XXX_ACR_SM_IGNORE;
248  m68k_set_acr0(mcf5282_acr0_mode);
249
250  /*
251   * Enable the cache
252   */
253  m68k_set_cacr(mcf5282_cacr_mode);
254
255  /*
256   * Set up CS* space (fake 'VME')
257   *   Two A24/D16 spaces, supervisor data acces
258   */
259  MCF5282_CS1_CSAR = MCF5282_CS_CSAR_BA(VME_ONE_BASE);
260  MCF5282_CS1_CSMR = MCF5282_CS_CSMR_BAM_16M |
261                     MCF5282_CS_CSMR_CI |
262                     MCF5282_CS_CSMR_SC |
263                     MCF5282_CS_CSMR_UC |
264                     MCF5282_CS_CSMR_UD |
265                     MCF5282_CS_CSMR_V;
266  MCF5282_CS1_CSCR = MCF5282_CS_CSCR_PS_16;
267  MCF5282_CS2_CSAR = MCF5282_CS_CSAR_BA(VME_TWO_BASE);
268  MCF5282_CS2_CSMR = MCF5282_CS_CSMR_BAM_16M |
269                     MCF5282_CS_CSMR_CI |
270                     MCF5282_CS_CSMR_SC |
271                     MCF5282_CS_CSMR_UC |
272                     MCF5282_CS_CSMR_UD |
273                     MCF5282_CS_CSMR_V;
274  MCF5282_CS2_CSCR = MCF5282_CS_CSCR_PS_16;
275  MCF5282_GPIO_PJPAR |= 0x06;
276}
277
278extern char _CPUClockSpeed[];
279
280uint32_t bsp_get_CPU_clock_speed(void)
281{
282  return( (uint32_t)_CPUClockSpeed);
283}
284
285/*
286 * Interrupt controller allocation
287 */
288rtems_status_code
289bsp_allocate_interrupt(int level, int priority)
290{
291  static char used[7];
292  rtems_interrupt_level l;
293  rtems_status_code ret = RTEMS_RESOURCE_IN_USE;
294
295  if ((level < 1) || (level > 7) || (priority < 0) || (priority > 7))
296    return RTEMS_INVALID_NUMBER;
297  rtems_interrupt_disable(l);
298  if ((used[level-1] & (1 << priority)) == 0) {
299    used[level-1] |= (1 << priority);
300    ret = RTEMS_SUCCESSFUL;
301  }
302  rtems_interrupt_enable(l);
303  return ret;
304}
305
306/*
307 * Arcturus bootloader system calls
308 */
309#define syscall_return(type, ret)                      \
310do {                                                   \
311   if ((unsigned long)(ret) >= (unsigned long)(-64)) { \
312      errno = -(ret);                                  \
313      ret = -1;                                        \
314   }                                                   \
315   return (type)(ret);                                 \
316} while (0)
317
318#define syscall_1(type,name,d1type,d1)                      \
319type bsp_##name(d1type d1)                                  \
320{                                                           \
321   long ret;                                                \
322   register long __d1 __asm__ ("%d1") = (long)d1;           \
323   __asm__ __volatile__ ("move.l %1,%%d0\n\t"               \
324                         "trap #2\n\t"                      \
325                         "move.l %%d0,%0"                   \
326                         : "=g" (ret)                       \
327                         : "i" (SysCode_##name), "d" (__d1) \
328                         : "d0" );                          \
329   syscall_return(type,ret);                                \
330}
331
332#define syscall_2(type,name,d1type,d1,d2type,d2)            \
333type bsp_##name(d1type d1, d2type d2)                       \
334{                                                           \
335   long ret;                                                \
336   register long __d1 __asm__ ("%d1") = (long)d1;           \
337   register long __d2 __asm__ ("%d2") = (long)d2;           \
338   __asm__ __volatile__ ("move.l %1,%%d0\n\t"               \
339                         "trap #2\n\t"                      \
340                         "move.l %%d0,%0"                   \
341                         : "=g" (ret)                       \
342                         : "i" (SysCode_##name), "d" (__d1),\
343                                                 "d" (__d2) \
344                         : "d0" );                          \
345   syscall_return(type,ret);                                \
346}
347
348#define syscall_3(type,name,d1type,d1,d2type,d2,d3type,d3)  \
349type bsp_##name(d1type d1, d2type d2, d3type d3)            \
350{                                                           \
351   long ret;                                                \
352   register long __d1 __asm__ ("%d1") = (long)d1;           \
353   register long __d2 __asm__ ("%d2") = (long)d2;           \
354   register long __d3 __asm__ ("%d3") = (long)d3;           \
355   __asm__ __volatile__ ("move.l %1,%%d0\n\t"               \
356                         "trap #2\n\t"                      \
357                         "move.l %%d0,%0"                   \
358                         : "=g" (ret)                       \
359                         : "i" (SysCode_##name), "d" (__d1),\
360                                                 "d" (__d2),\
361                                                 "d" (__d3) \
362                         : "d0" );                          \
363   syscall_return(type,ret);                                \
364}
365
366#define SysCode_reset              0 /* reset */
367#define SysCode_program            5 /* program flash memory */
368#define SysCode_gethwaddr         12 /* get hardware address */
369#define SysCode_getbenv           14 /* get bootloader environment variable */
370#define SysCode_setbenv           15 /* set bootloader environment variable */
371#define SysCode_flash_erase_range 19 /* erase a section of flash */
372#define SysCode_flash_write_range 20 /* write a section of flash */
373syscall_1(int, reset, int, flags)
374syscall_1(unsigned const char *, gethwaddr, int, a)
375syscall_1(const char *, getbenv, const char *, a)
376syscall_1(int, setbenv, const char *, a)
377syscall_2(int, program, bsp_mnode_t *, chain, int, flags)
378syscall_3(int, flash_erase_range, volatile unsigned short *, flashptr, int, start, int, end);
379syscall_3(int, flash_write_range, volatile unsigned short *, flashptr, bsp_mnode_t *, chain, int, offset);
380
381/*
382 * 'Extended BSP' routines
383 * Should move to cpukit/score/cpu/m68k/cpu.c someday.
384 */
385
386rtems_status_code bspExtInit(void) { return RTEMS_SUCCESSFUL; }
387int BSP_enableVME_int_lvl(unsigned int level) { return 0; }
388int BSP_disableVME_int_lvl(unsigned int level) { return 0; }
389
390/*
391 * 'VME' interrupt support
392 * Interrupt vectors 192-255 are set aside for use by external logic which
393 * drives IRQ1*.  The actual interrupt source is read from the external
394 * logic at FPGA_IRQ_INFO.  The most-significant bit of the least-significant
395 * byte read from this location is set as long as the external logic has
396 * interrupts to be serviced.  The least-significant six bits indicate the
397 * interrupt source within the external logic and are used to select the
398 * specified interupt handler.
399 */
400#define NVECTOR 256
401#define FPGA_VECTOR (64+1)  /* IRQ1* pin connected to external FPGA */
402#define FPGA_IRQ_INFO    *((vuint16 *)(0x31000000 + 0xfffffe))
403
404static struct handlerTab {
405  BSP_VME_ISR_t func;
406  void         *arg;
407} handlerTab[NVECTOR];
408
409BSP_VME_ISR_t
410BSP_getVME_isr(unsigned long vector, void **pusrArg)
411{
412  if (vector >= NVECTOR)
413    return (BSP_VME_ISR_t)NULL;
414  if (pusrArg)
415    *pusrArg = handlerTab[vector].arg;
416  return handlerTab[vector].func;
417}
418
419static rtems_isr
420fpga_trampoline (rtems_vector_number v)
421{
422  /*
423   * Handle FPGA interrupts until all have been consumed
424   */
425  int loopcount = 0;
426  while (((v = FPGA_IRQ_INFO) & 0x80) != 0) {
427    v = 192 + (v & 0x3f);
428    if (++loopcount >= 50) {
429      rtems_interrupt_level level;
430      rtems_interrupt_disable(level);
431      printk("\nTOO MANY FPGA INTERRUPTS (LAST WAS 0x%x) -- DISABLING ALL FPGA INTERRUPTS.\n", v & 0x3f);
432      MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1;
433      rtems_interrupt_enable(level);
434      return;
435    }
436    if (handlerTab[v].func)  {
437      (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v);
438    }
439    else {
440      rtems_interrupt_level level;
441      rtems_vector_number nv;
442      rtems_interrupt_disable(level);
443      printk("\nSPURIOUS FPGA INTERRUPT (0x%x).\n", v & 0x3f);
444      if ((((nv = FPGA_IRQ_INFO) & 0x80) != 0)
445          && ((nv & 0x3f) == (v & 0x3f))) {
446        printk("DISABLING ALL FPGA INTERRUPTS.\n");
447        MCF5282_INTC0_IMRL |= MCF5282_INTC_IMRL_INT1;
448      }
449      rtems_interrupt_enable(level);
450      return;
451    }
452  }
453}
454
455static rtems_isr
456trampoline (rtems_vector_number v)
457{
458    if (handlerTab[v].func)
459        (*handlerTab[v].func)(handlerTab[v].arg, (unsigned long)v);
460}
461
462static void
463enable_irq(unsigned source)
464{
465rtems_interrupt_level level;
466  rtems_interrupt_disable(level);
467  if (source >= 32)
468    MCF5282_INTC0_IMRH &= ~(1 << (source - 32));
469  else
470    MCF5282_INTC0_IMRL &= ~((1 << source) |
471        MCF5282_INTC_IMRL_MASKALL);
472  rtems_interrupt_enable(level);
473}
474
475static void
476disable_irq(unsigned source)
477{
478rtems_interrupt_level level;
479
480  rtems_interrupt_disable(level);
481  if (source >= 32)
482    MCF5282_INTC0_IMRH |= (1 << (source - 32));
483  else
484    MCF5282_INTC0_IMRL |= (1 << source);
485  rtems_interrupt_enable(level);
486}
487
488void
489BSP_enable_irq_at_pic(rtems_vector_number v)
490{
491int                   source = v - 64;
492
493  if ( source > 0 && source < 64 ) {
494    enable_irq(source);
495  }
496}
497
498void
499BSP_disable_irq_at_pic(rtems_vector_number v)
500{
501int                   source = v - 64;
502
503  if ( source > 0 && source < 64 ) {
504    disable_irq(source);
505  }
506}
507
508int
509BSP_irq_is_enabled_at_pic(rtems_vector_number v)
510{
511int                   source = v - 64;
512
513  if ( source > 0 && source < 64 ) {
514    return ! ((source >= 32) ?
515      MCF5282_INTC0_IMRH & (1 << (source - 32)) :
516      MCF5282_INTC0_IMRL & (1 << source));
517  }
518  return -1;
519}
520
521
522static int
523init_intc0_bit(unsigned long vector)
524{
525rtems_interrupt_level level;
526
527    /*
528     * Find an unused level/priority if this is an on-chip (INTC0)
529     * source and this is the first time the source is being used.
530     * Interrupt sources 1 through 7 are fixed level/priority
531     */
532
533    if ((vector >= 65) && (vector <= 127)) {
534        int l, p;
535        int source = vector - 64;
536        static unsigned char installed[8];
537
538        rtems_interrupt_disable(level);
539        if (installed[source/8] & (1 << (source % 8))) {
540            rtems_interrupt_enable(level);
541            return 0;
542        }
543        installed[source/8] |= (1 << (source % 8));
544        rtems_interrupt_enable(level);
545        for (l = 1 ; l < 7 ; l++) {
546            for (p = 0 ; p < 8 ; p++) {
547                if ((source < 8)
548                 || (bsp_allocate_interrupt(l,p) == RTEMS_SUCCESSFUL)) {
549                    if (source < 8)
550                        MCF5282_EPORT_EPIER |= 1 << source;
551                    else
552                        *(&MCF5282_INTC0_ICR1 + (source - 1)) =
553                                                       MCF5282_INTC_ICR_IL(l) |
554                                                       MCF5282_INTC_ICR_IP(p);
555          enable_irq(source);
556                    return 0;
557                }
558            }
559        }
560        return -1;
561    }
562  return 0;
563}
564
565int
566BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg)
567{
568  rtems_isr_entry old_handler;
569  rtems_interrupt_level level;
570
571  /*
572   * Register the handler information
573   */
574  if (vector >= NVECTOR)
575    return -1;
576  handlerTab[vector].func = handler;
577  handlerTab[vector].arg = usrArg;
578
579  /*
580   * If this is an external FPGA ('VME') vector set up the real IRQ.
581   */
582  if ((vector >= 192) && (vector <= 255)) {
583    int i;
584    static volatile int setupDone;
585    rtems_interrupt_disable(level);
586    if (setupDone) {
587      rtems_interrupt_enable(level);
588      return 0;
589    }
590    setupDone = 1;
591    rtems_interrupt_catch(fpga_trampoline, FPGA_VECTOR, &old_handler);
592    i = init_intc0_bit(FPGA_VECTOR);
593    rtems_interrupt_enable(level);
594    return i;
595  }
596
597  /*
598   * Make the connection between the interrupt and the local handler
599   */
600  rtems_interrupt_catch(trampoline, vector, &old_handler);
601
602  return init_intc0_bit(vector);
603}
604
605int
606BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *usrArg)
607{
608  if (vector >= NVECTOR)
609    return -1;
610  if ((handlerTab[vector].func != handler)
611     || (handlerTab[vector].arg != usrArg))
612    return -1;
613  handlerTab[vector].func = (BSP_VME_ISR_t)NULL;
614  return 0;
615}
616
617int
618BSP_vme2local_adrs(unsigned am, unsigned long vmeaddr, unsigned long *plocaladdr)
619{
620  unsigned long offset;
621
622  switch (am) {
623    default:    return -1;
624    case VME_AM_SUP_SHORT_IO: offset = 0x31FF0000; break; /* A16/D16 */
625    case VME_AM_STD_SUP_DATA: offset = 0x30000000; break; /* A24/D16 */
626    case VME_AM_EXT_SUP_DATA: offset = 0x31000000; break; /* A32/D32 */
627  }
628  *plocaladdr = vmeaddr + offset;
629  return 0;
630}
631
632void
633rtems_bsp_reset_cause(char *buf, size_t capacity)
634{
635  int bit, rsr;
636  size_t i;
637  const char *cp;
638   
639  if (buf == NULL)
640    return;
641  if (capacity)
642    buf[0] = '\0';
643  rsr = MCF5282_RESET_RSR;
644  for (i = 0, bit = 0x80 ; bit != 0 ; bit >>= 1) {
645    if (rsr & bit) {
646      switch (bit) {
647        case MCF5282_RESET_RSR_LVD:  cp = "Low voltage";        break;
648        case MCF5282_RESET_RSR_SOFT: cp = "Software reset";     break;
649        case MCF5282_RESET_RSR_WDR:  cp = "Watchdog reset";     break;
650        case MCF5282_RESET_RSR_POR:  cp = "Power-on reset";     break;
651        case MCF5282_RESET_RSR_EXT:  cp = "External reset";     break;
652        case MCF5282_RESET_RSR_LOC:  cp = "Loss of clock";      break;
653        case MCF5282_RESET_RSR_LOL:  cp = "Loss of lock";       break;
654        default:                     cp = "??";                 break;
655      }
656      i += snprintf(buf+i, capacity-i, cp);
657      if (i >= capacity)
658        break;
659      rsr &= ~bit;
660      if (rsr == 0)
661        break;
662      i += snprintf(buf+i, capacity-i, ", ");
663      if (i >= capacity)
664        break;
665    }
666  }
667}
Note: See TracBrowser for help on using the repository browser.