commproc.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. * General Purpose functions for the global management of the
  3. * Communication Processor Module.
  4. *
  5. * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
  6. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  7. *
  8. * In addition to the individual control of the communication
  9. * channels, there are a few functions that globally affect the
  10. * communication processor.
  11. *
  12. * Buffer descriptors must be allocated from the dual ported memory
  13. * space. The allocator for that is here. When the communication
  14. * process is reset, we reclaim the memory available. There is
  15. * currently no deallocator for this memory.
  16. * The amount of space available is platform dependent. On the
  17. * MBX, the EPPC software loads additional microcode into the
  18. * communication processor, and uses some of the DP ram for this
  19. * purpose. Current, the first 512 bytes and the last 256 bytes of
  20. * memory are used. Right now I am conservative and only use the
  21. * memory that can never be used for microcode. If there are
  22. * applications that require more DP ram, we can expand the boundaries
  23. * but then we have to be careful of any downloaded microcode.
  24. *
  25. */
  26. /*
  27. * Michael Leslie <mleslie@lineo.com>
  28. * adapted Dan Malek's ppc8xx drivers to M68360
  29. *
  30. */
  31. #include <linux/errno.h>
  32. #include <linux/sched.h>
  33. #include <linux/kernel.h>
  34. #include <linux/param.h>
  35. #include <linux/string.h>
  36. #include <linux/mm.h>
  37. #include <linux/interrupt.h>
  38. #include <asm/irq.h>
  39. #include <asm/m68360.h>
  40. #include <asm/commproc.h>
  41. /* #include <asm/page.h> */
  42. /* #include <asm/pgtable.h> */
  43. extern void *_quicc_base;
  44. extern unsigned int system_clock;
  45. static uint dp_alloc_base; /* Starting offset in DP ram */
  46. static uint dp_alloc_top; /* Max offset + 1 */
  47. #if 0
  48. static void *host_buffer; /* One page of host buffer */
  49. static void *host_end; /* end + 1 */
  50. #endif
  51. /* struct cpm360_t *cpmp; */ /* Pointer to comm processor space */
  52. QUICC *pquicc;
  53. /* QUICC *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */
  54. /* CPM interrupt vector functions. */
  55. struct cpm_action {
  56. void (*handler)(void *);
  57. void *dev_id;
  58. };
  59. static struct cpm_action cpm_vecs[CPMVEC_NR];
  60. static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
  61. static void cpm_error_interrupt(void *);
  62. /* prototypes: */
  63. void cpm_install_handler(int vec, void (*handler)(), void *dev_id);
  64. void m360_cpm_reset(void);
  65. void m360_cpm_reset()
  66. {
  67. /* pte_t *pte; */
  68. pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */
  69. /* Perform a CPM reset. */
  70. pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG);
  71. /* Wait for CPM to become ready (should be 2 clocks). */
  72. while (pquicc->cp_cr & CMD_FLAG);
  73. /* On the recommendation of the 68360 manual, p. 7-60
  74. * - Set sdma interrupt service mask to 7
  75. * - Set sdma arbitration ID to 4
  76. */
  77. pquicc->sdma_sdcr = 0x0740;
  78. /* Claim the DP memory for our use.
  79. */
  80. dp_alloc_base = CPM_DATAONLY_BASE;
  81. dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
  82. /* Set the host page for allocation.
  83. */
  84. /* host_buffer = host_page_addr; */
  85. /* host_end = host_page_addr + PAGE_SIZE; */
  86. /* pte = find_pte(&init_mm, host_page_addr); */
  87. /* pte_val(*pte) |= _PAGE_NO_CACHE; */
  88. /* flush_tlb_page(current->mm->mmap, host_buffer); */
  89. /* Tell everyone where the comm processor resides.
  90. */
  91. /* cpmp = (cpm360_t *)commproc; */
  92. }
  93. /* This is called during init_IRQ. We used to do it above, but this
  94. * was too early since init_IRQ was not yet called.
  95. */
  96. void
  97. cpm_interrupt_init(void)
  98. {
  99. /* Initialize the CPM interrupt controller.
  100. * NOTE THAT pquicc had better have been initialized!
  101. * reference: MC68360UM p. 7-377
  102. */
  103. pquicc->intr_cicr =
  104. (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
  105. (CPM_INTERRUPT << 13) |
  106. CICR_HP_MASK |
  107. (CPM_VECTOR_BASE << 5) |
  108. CICR_SPS;
  109. /* mask all CPM interrupts from reaching the cpu32 core: */
  110. pquicc->intr_cimr = 0;
  111. /* mles - If I understand correctly, the 360 just pops over to the CPM
  112. * specific vector, obviating the necessity to vector through the IRQ
  113. * whose priority the CPM is set to. This needs a closer look, though.
  114. */
  115. /* Set our interrupt handler with the core CPU. */
  116. /* if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */
  117. /* panic("Could not allocate CPM IRQ!"); */
  118. /* Install our own error handler.
  119. */
  120. /* I think we want to hold off on this one for the moment - mles */
  121. /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */
  122. /* master CPM interrupt enable */
  123. /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */
  124. }
  125. /* CPM interrupt controller interrupt.
  126. */
  127. static void
  128. cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
  129. {
  130. /* uint vec; */
  131. /* mles: Note that this stuff is currently being performed by
  132. * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c */
  133. /* figure out the vector */
  134. /* call that vector's handler */
  135. /* clear the irq's bit in the service register */
  136. #if 0 /* old 860 stuff: */
  137. /* Get the vector by setting the ACK bit and then reading
  138. * the register.
  139. */
  140. ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
  141. vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
  142. vec >>= 11;
  143. if (cpm_vecs[vec].handler != 0)
  144. (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
  145. else
  146. ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
  147. /* After servicing the interrupt, we have to remove the status
  148. * indicator.
  149. */
  150. ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
  151. #endif
  152. }
  153. /* The CPM can generate the error interrupt when there is a race condition
  154. * between generating and masking interrupts. All we have to do is ACK it
  155. * and return. This is a no-op function so we don't need any special
  156. * tests in the interrupt handler.
  157. */
  158. static void
  159. cpm_error_interrupt(void *dev)
  160. {
  161. }
  162. /* Install a CPM interrupt handler.
  163. */
  164. void
  165. cpm_install_handler(int vec, void (*handler)(), void *dev_id)
  166. {
  167. request_irq(vec, handler, IRQ_FLG_LOCK, "timer", dev_id);
  168. /* if (cpm_vecs[vec].handler != 0) */
  169. /* printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
  170. /* (uint)handler, (uint)cpm_vecs[vec].handler); */
  171. /* cpm_vecs[vec].handler = handler; */
  172. /* cpm_vecs[vec].dev_id = dev_id; */
  173. /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */
  174. /* pquicc->intr_cimr |= (1 << vec); */
  175. }
  176. /* Free a CPM interrupt handler.
  177. */
  178. void
  179. cpm_free_handler(int vec)
  180. {
  181. cpm_vecs[vec].handler = NULL;
  182. cpm_vecs[vec].dev_id = NULL;
  183. /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */
  184. pquicc->intr_cimr &= ~(1 << vec);
  185. }
  186. /* Allocate some memory from the dual ported ram. We may want to
  187. * enforce alignment restrictions, but right now everyone is a good
  188. * citizen.
  189. */
  190. uint
  191. m360_cpm_dpalloc(uint size)
  192. {
  193. uint retloc;
  194. if ((dp_alloc_base + size) >= dp_alloc_top)
  195. return(CPM_DP_NOSPACE);
  196. retloc = dp_alloc_base;
  197. dp_alloc_base += size;
  198. return(retloc);
  199. }
  200. #if 0 /* mleslie - for now these are simply kmalloc'd */
  201. /* We also own one page of host buffer space for the allocation of
  202. * UART "fifos" and the like.
  203. */
  204. uint
  205. m360_cpm_hostalloc(uint size)
  206. {
  207. uint retloc;
  208. if ((host_buffer + size) >= host_end)
  209. return(0);
  210. retloc = host_buffer;
  211. host_buffer += size;
  212. return(retloc);
  213. }
  214. #endif
  215. /* Set a baud rate generator. This needs lots of work. There are
  216. * four BRGs, any of which can be wired to any channel.
  217. * The internal baud rate clock is the system clock divided by 16.
  218. * This assumes the baudrate is 16x oversampled by the uart.
  219. */
  220. /* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */
  221. #define BRG_INT_CLK system_clock
  222. #define BRG_UART_CLK (BRG_INT_CLK/16)
  223. void
  224. m360_cpm_setbrg(uint brg, uint rate)
  225. {
  226. volatile uint *bp;
  227. /* This is good enough to get SMCs running.....
  228. */
  229. /* bp = (uint *)&cpmp->cp_brgc1; */
  230. bp = (volatile uint *)(&pquicc->brgc[0].l);
  231. bp += brg;
  232. *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN;
  233. }
  234. /*
  235. * Local variables:
  236. * c-indent-level: 4
  237. * c-basic-offset: 4
  238. * tab-width: 4
  239. * End:
  240. */