rte_cb_multi.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * include/asm-v850/rte_multi.c -- Support for Multi debugger monitor ROM
  3. * on Midas lab RTE-CB series of evaluation boards
  4. *
  5. * Copyright (C) 2001,02,03 NEC Electronics Corporation
  6. * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
  7. *
  8. * This file is subject to the terms and conditions of the GNU General
  9. * Public License. See the file COPYING in the main directory of this
  10. * archive for more details.
  11. *
  12. * Written by Miles Bader <miles@gnu.org>
  13. */
  14. #include <linux/init.h>
  15. #include <asm/machdep.h>
  16. #define IRQ_ADDR(irq) (0x80 + (irq) * 0x10)
  17. /* A table of which interrupt vectors to install, since blindly
  18. installing all of them makes the debugger stop working. This is a
  19. list of offsets in the interrupt vector area; each entry means to
  20. copy that particular 16-byte vector. An entry less than zero ends
  21. the table. */
  22. static long multi_intv_install_table[] = {
  23. /* Trap vectors */
  24. 0x40, 0x50,
  25. #ifdef CONFIG_RTE_CB_MULTI_DBTRAP
  26. /* Illegal insn / dbtrap. These are used by multi, so only handle
  27. them if configured to do so. */
  28. 0x60,
  29. #endif
  30. /* GINT1 - GINT3 (note, not GINT0!) */
  31. IRQ_ADDR (IRQ_GINT(1)),
  32. IRQ_ADDR (IRQ_GINT(2)),
  33. IRQ_ADDR (IRQ_GINT(3)),
  34. /* Timer D interrupts (up to 4 timers) */
  35. IRQ_ADDR (IRQ_INTCMD(0)),
  36. #if IRQ_INTCMD_NUM > 1
  37. IRQ_ADDR (IRQ_INTCMD(1)),
  38. #if IRQ_INTCMD_NUM > 2
  39. IRQ_ADDR (IRQ_INTCMD(2)),
  40. #if IRQ_INTCMD_NUM > 3
  41. IRQ_ADDR (IRQ_INTCMD(3)),
  42. #endif
  43. #endif
  44. #endif
  45. /* UART interrupts (up to 3 channels) */
  46. IRQ_ADDR (IRQ_INTSER (0)), /* err */
  47. IRQ_ADDR (IRQ_INTSR (0)), /* rx */
  48. IRQ_ADDR (IRQ_INTST (0)), /* tx */
  49. #if IRQ_INTSR_NUM > 1
  50. IRQ_ADDR (IRQ_INTSER (1)), /* err */
  51. IRQ_ADDR (IRQ_INTSR (1)), /* rx */
  52. IRQ_ADDR (IRQ_INTST (1)), /* tx */
  53. #if IRQ_INTSR_NUM > 2
  54. IRQ_ADDR (IRQ_INTSER (2)), /* err */
  55. IRQ_ADDR (IRQ_INTSR (2)), /* rx */
  56. IRQ_ADDR (IRQ_INTST (2)), /* tx */
  57. #endif
  58. #endif
  59. -1
  60. };
  61. /* Early initialization for kernel using Multi debugger ROM monitor. */
  62. void __init multi_init (void)
  63. {
  64. /* We're using the Multi debugger monitor, so we have to install
  65. the interrupt vectors. The monitor doesn't allow them to be
  66. initially downloaded into their final destination because
  67. it's in the monitor's scratch-RAM area. Unfortunately, Multi
  68. also doesn't deal correctly with ELF sections where the LMA
  69. and VMA differ -- it just ignores the LMA -- so we can't use
  70. that feature to work around the problem. What we do instead
  71. is just put the interrupt vectors into a normal section, and
  72. do the necessary copying and relocation here. Since the
  73. interrupt vector basically only contains `jr' instructions
  74. and no-ops, it's not that hard. */
  75. extern unsigned long _intv_load_start, _intv_start;
  76. register unsigned long *src = &_intv_load_start;
  77. register unsigned long *dst = (unsigned long *)INTV_BASE;
  78. register unsigned long jr_fixup = (char *)&_intv_start - (char *)dst;
  79. register long *ii;
  80. /* Copy interrupt vectors as instructed by multi_intv_install_table. */
  81. for (ii = multi_intv_install_table; *ii >= 0; ii++) {
  82. /* Copy 16-byte interrupt vector at offset *ii. */
  83. int boffs;
  84. for (boffs = 0; boffs < 0x10; boffs += sizeof *src) {
  85. /* Copy a single word, fixing up the jump offs
  86. if it's a `jr' instruction. */
  87. int woffs = (*ii + boffs) / sizeof *src;
  88. unsigned long word = src[woffs];
  89. if ((word & 0xFC0) == 0x780) {
  90. /* A `jr' insn, fix up its offset (and yes, the
  91. weird half-word swapping is intentional). */
  92. unsigned short hi = word & 0xFFFF;
  93. unsigned short lo = word >> 16;
  94. unsigned long udisp22
  95. = lo + ((hi & 0x3F) << 16);
  96. long disp22 = (long)(udisp22 << 10) >> 10;
  97. disp22 += jr_fixup;
  98. hi = ((disp22 >> 16) & 0x3F) | 0x780;
  99. lo = disp22 & 0xFFFF;
  100. word = hi + (lo << 16);
  101. }
  102. dst[woffs] = word;
  103. }
  104. }
  105. }