ps2ser.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /***********************************************************************
  2. *
  3. * (C) Copyright 2004
  4. * DENX Software Engineering
  5. * Wolfgang Denk, wd@denx.de
  6. * All rights reserved.
  7. *
  8. * Simple 16550A serial driver
  9. *
  10. * Originally from linux source (drivers/char/ps2ser.c)
  11. *
  12. * Used by the PS/2 multiplexer driver (ps2mult.c)
  13. *
  14. ***********************************************************************/
  15. #include <common.h>
  16. #ifdef CONFIG_PS2SERIAL
  17. #include <asm/io.h>
  18. #include <asm/atomic.h>
  19. #include <ps2mult.h>
  20. DECLARE_GLOBAL_DATA_PTR;
  21. /* #define DEBUG */
  22. #define PS2SER_BAUD 57600
  23. #ifdef CONFIG_MPC5xxx
  24. #if CONFIG_PS2SERIAL == 1
  25. #define PSC_BASE MPC5XXX_PSC1
  26. #elif CONFIG_PS2SERIAL == 2
  27. #define PSC_BASE MPC5XXX_PSC2
  28. #elif CONFIG_PS2SERIAL == 3
  29. #define PSC_BASE MPC5XXX_PSC3
  30. #elif defined(CONFIG_MGT5100)
  31. #error CONFIG_PS2SERIAL must be in 1, 2 or 3
  32. #elif CONFIG_PS2SERIAL == 4
  33. #define PSC_BASE MPC5XXX_PSC4
  34. #elif CONFIG_PS2SERIAL == 5
  35. #define PSC_BASE MPC5XXX_PSC5
  36. #elif CONFIG_PS2SERIAL == 6
  37. #define PSC_BASE MPC5XXX_PSC6
  38. #else
  39. #error CONFIG_PS2SERIAL must be in 1 ... 6
  40. #endif
  41. #endif /* CONFIG_MPC5xxx */
  42. static int ps2ser_getc_hw(void);
  43. static void ps2ser_interrupt(void *dev_id);
  44. extern struct serial_state rs_table[]; /* in serial.c */
  45. #ifndef CONFIG_MPC5xxx
  46. static struct serial_state *state;
  47. #endif
  48. static u_char ps2buf[PS2BUF_SIZE];
  49. static atomic_t ps2buf_cnt;
  50. static int ps2buf_in_idx;
  51. static int ps2buf_out_idx;
  52. #ifdef CONFIG_MPC5xxx
  53. int ps2ser_init(void)
  54. {
  55. volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
  56. unsigned long baseclk;
  57. int div;
  58. /* reset PSC */
  59. psc->command = PSC_SEL_MODE_REG_1;
  60. /* select clock sources */
  61. #if defined(CONFIG_MGT5100)
  62. psc->psc_clock_select = 0xdd00;
  63. baseclk = (CFG_MPC5XXX_CLKIN + 16) / 32;
  64. #elif defined(CONFIG_MPC5200)
  65. psc->psc_clock_select = 0;
  66. baseclk = (gd->ipb_clk + 16) / 32;
  67. #endif
  68. /* switch to UART mode */
  69. psc->sicr = 0;
  70. /* configure parity, bit length and so on */
  71. #if defined(CONFIG_MGT5100)
  72. psc->mode = PSC_MODE_ERR | PSC_MODE_8_BITS | PSC_MODE_PARNONE;
  73. #elif defined(CONFIG_MPC5200)
  74. psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE;
  75. #endif
  76. psc->mode = PSC_MODE_ONE_STOP;
  77. /* set up UART divisor */
  78. div = (baseclk + (PS2SER_BAUD/2)) / PS2SER_BAUD;
  79. psc->ctur = (div >> 8) & 0xff;
  80. psc->ctlr = div & 0xff;
  81. /* disable all interrupts */
  82. psc->psc_imr = 0;
  83. /* reset and enable Rx/Tx */
  84. psc->command = PSC_RST_RX;
  85. psc->command = PSC_RST_TX;
  86. psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE;
  87. return (0);
  88. }
  89. #else /* !CONFIG_MPC5xxx */
  90. static inline unsigned int ps2ser_in(int offset)
  91. {
  92. return readb((unsigned long) state->iomem_base + offset);
  93. }
  94. static inline void ps2ser_out(int offset, int value)
  95. {
  96. writeb(value, (unsigned long) state->iomem_base + offset);
  97. }
  98. int ps2ser_init(void)
  99. {
  100. int quot;
  101. unsigned cval;
  102. state = rs_table + CONFIG_PS2SERIAL;
  103. quot = state->baud_base / PS2SER_BAUD;
  104. cval = 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
  105. /* Set speed, enable interrupts, enable FIFO
  106. */
  107. ps2ser_out(UART_LCR, cval | UART_LCR_DLAB);
  108. ps2ser_out(UART_DLL, quot & 0xff);
  109. ps2ser_out(UART_DLM, quot >> 8);
  110. ps2ser_out(UART_LCR, cval);
  111. ps2ser_out(UART_IER, UART_IER_RDI);
  112. ps2ser_out(UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
  113. ps2ser_out(UART_FCR,
  114. UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
  115. /* If we read 0xff from the LSR, there is no UART here
  116. */
  117. if (ps2ser_in(UART_LSR) == 0xff) {
  118. printf ("ps2ser.c: no UART found\n");
  119. return -1;
  120. }
  121. irq_install_handler(state->irq, ps2ser_interrupt, NULL);
  122. return 0;
  123. }
  124. #endif /* CONFIG_MPC5xxx */
  125. void ps2ser_putc(int chr)
  126. {
  127. #ifdef CONFIG_MPC5xxx
  128. volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
  129. #endif
  130. #ifdef DEBUG
  131. printf(">>>> 0x%02x\n", chr);
  132. #endif
  133. #ifdef CONFIG_MPC5xxx
  134. while (!(psc->psc_status & PSC_SR_TXRDY));
  135. psc->psc_buffer_8 = chr;
  136. #else
  137. while (!(ps2ser_in(UART_LSR) & UART_LSR_THRE));
  138. ps2ser_out(UART_TX, chr);
  139. #endif
  140. }
  141. static int ps2ser_getc_hw(void)
  142. {
  143. #ifdef CONFIG_MPC5xxx
  144. volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
  145. #endif
  146. int res = -1;
  147. #ifdef CONFIG_MPC5xxx
  148. if (psc->psc_status & PSC_SR_RXRDY) {
  149. res = (psc->psc_buffer_8);
  150. }
  151. #else
  152. if (ps2ser_in(UART_LSR) & UART_LSR_DR) {
  153. res = (ps2ser_in(UART_RX));
  154. }
  155. #endif
  156. return res;
  157. }
  158. int ps2ser_getc(void)
  159. {
  160. volatile int chr;
  161. int flags;
  162. #ifdef DEBUG
  163. printf("<< ");
  164. #endif
  165. flags = disable_interrupts();
  166. do {
  167. if (atomic_read(&ps2buf_cnt) != 0) {
  168. chr = ps2buf[ps2buf_out_idx++];
  169. ps2buf_out_idx &= (PS2BUF_SIZE - 1);
  170. atomic_dec(&ps2buf_cnt);
  171. } else {
  172. chr = ps2ser_getc_hw();
  173. }
  174. }
  175. while (chr < 0);
  176. if (flags) enable_interrupts();
  177. #ifdef DEBUG
  178. printf("0x%02x\n", chr);
  179. #endif
  180. return chr;
  181. }
  182. int ps2ser_check(void)
  183. {
  184. int flags;
  185. flags = disable_interrupts();
  186. ps2ser_interrupt(NULL);
  187. if (flags) enable_interrupts();
  188. return atomic_read(&ps2buf_cnt);
  189. }
  190. static void ps2ser_interrupt(void *dev_id)
  191. {
  192. #ifdef CONFIG_MPC5xxx
  193. volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
  194. #endif
  195. int chr;
  196. int status;
  197. do {
  198. chr = ps2ser_getc_hw();
  199. #ifdef CONFIG_MPC5xxx
  200. status = psc->psc_status;
  201. #else
  202. status = ps2ser_in(UART_IIR);
  203. #endif
  204. if (chr < 0) continue;
  205. if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
  206. ps2buf[ps2buf_in_idx++] = chr;
  207. ps2buf_in_idx &= (PS2BUF_SIZE - 1);
  208. atomic_inc(&ps2buf_cnt);
  209. } else {
  210. printf ("ps2ser.c: buffer overflow\n");
  211. }
  212. #ifdef CONFIG_MPC5xxx
  213. } while (status & PSC_SR_RXRDY);
  214. #else
  215. } while (status & UART_IIR_RDI);
  216. #endif
  217. if (atomic_read(&ps2buf_cnt)) {
  218. ps2mult_callback(atomic_read(&ps2buf_cnt));
  219. }
  220. }
  221. #endif /* CONFIG_PS2SERIAL */