serial_mpc8xx.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2000
  4. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  5. */
  6. #include <common.h>
  7. #include <command.h>
  8. #include <dm.h>
  9. #include <serial.h>
  10. #include <watchdog.h>
  11. #include <asm/cpm_8xx.h>
  12. #include <asm/global_data.h>
  13. #include <linux/compiler.h>
  14. DECLARE_GLOBAL_DATA_PTR;
  15. #if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */
  16. #define SMC_INDEX 0
  17. #define PROFF_SMC PROFF_SMC1
  18. #define CPM_CR_CH_SMC CPM_CR_CH_SMC1
  19. #define IOPINS 0xc0
  20. #elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */
  21. #define SMC_INDEX 1
  22. #define PROFF_SMC PROFF_SMC2
  23. #define CPM_CR_CH_SMC CPM_CR_CH_SMC2
  24. #define IOPINS 0xc00
  25. #endif /* CONFIG_8xx_CONS_SMCx */
  26. struct serialbuffer {
  27. cbd_t rxbd; /* Rx BD */
  28. cbd_t txbd; /* Tx BD */
  29. uint rxindex; /* index for next character to read */
  30. uchar rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
  31. uchar txbuf; /* tx buffers */
  32. };
  33. static void serial_setdivisor(cpm8xx_t __iomem *cp, int baudrate)
  34. {
  35. int divisor = (gd->cpu_clk + 8 * baudrate) / 16 / baudrate;
  36. if (divisor / 16 > 0x1000) {
  37. /* bad divisor, assume 50MHz clock and 9600 baud */
  38. divisor = (50 * 1000 * 1000 + 8 * 9600) / 16 / 9600;
  39. }
  40. divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
  41. if (divisor <= 0x1000)
  42. out_be32(&cp->cp_brgc1, ((divisor - 1) << 1) | CPM_BRG_EN);
  43. else
  44. out_be32(&cp->cp_brgc1, ((divisor / 16 - 1) << 1) | CPM_BRG_EN |
  45. CPM_BRG_DIV16);
  46. }
  47. /*
  48. * Minimal serial functions needed to use one of the SMC ports
  49. * as serial console interface.
  50. */
  51. static int serial_mpc8xx_setbrg(struct udevice *dev, int baudrate)
  52. {
  53. immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
  54. cpm8xx_t __iomem *cp = &(im->im_cpm);
  55. /* Set up the baud rate generator.
  56. * See 8xx_io/commproc.c for details.
  57. *
  58. * Wire BRG1 to SMCx
  59. */
  60. out_be32(&cp->cp_simode, 0);
  61. serial_setdivisor(cp, baudrate);
  62. return 0;
  63. }
  64. static int serial_mpc8xx_probe(struct udevice *dev)
  65. {
  66. immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
  67. smc_t __iomem *sp;
  68. smc_uart_t __iomem *up;
  69. u16 smc_rpbase;
  70. cpm8xx_t __iomem *cp = &(im->im_cpm);
  71. struct serialbuffer __iomem *rtx;
  72. /* initialize pointers to SMC */
  73. sp = cp->cp_smc + SMC_INDEX;
  74. up = (smc_uart_t __iomem *)&cp->cp_dpmem[PROFF_SMC];
  75. smc_rpbase = in_be16(&up->smc_rpbase);
  76. if (smc_rpbase)
  77. up = (smc_uart_t __iomem *)&cp->cp_dpmem[smc_rpbase];
  78. /* Disable transmitter/receiver. */
  79. clrbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
  80. /* Enable SDMA. */
  81. out_be32(&im->im_siu_conf.sc_sdcr, 1);
  82. /* clear error conditions */
  83. out_8(&im->im_sdma.sdma_sdsr, CONFIG_SYS_SDSR);
  84. /* clear SDMA interrupt mask */
  85. out_8(&im->im_sdma.sdma_sdmr, CONFIG_SYS_SDMR);
  86. /* Use Port B for SMCx instead of other functions. */
  87. setbits_be32(&cp->cp_pbpar, IOPINS);
  88. clrbits_be32(&cp->cp_pbdir, IOPINS);
  89. clrbits_be16(&cp->cp_pbodr, IOPINS);
  90. /* Set the physical address of the host memory buffers in
  91. * the buffer descriptors.
  92. */
  93. rtx = (struct serialbuffer __iomem *)&cp->cp_dpmem[CPM_SERIAL_BASE];
  94. /* Allocate space for two buffer descriptors in the DP ram.
  95. * For now, this address seems OK, but it may have to
  96. * change with newer versions of the firmware.
  97. * damm: allocating space after the two buffers for rx/tx data
  98. */
  99. out_be32(&rtx->rxbd.cbd_bufaddr, (__force uint)&rtx->rxbuf);
  100. out_be16(&rtx->rxbd.cbd_sc, 0);
  101. out_be32(&rtx->txbd.cbd_bufaddr, (__force uint)&rtx->txbuf);
  102. out_be16(&rtx->txbd.cbd_sc, 0);
  103. /* Set up the uart parameters in the parameter ram. */
  104. out_be16(&up->smc_rbase, CPM_SERIAL_BASE);
  105. out_be16(&up->smc_tbase, CPM_SERIAL_BASE + sizeof(cbd_t));
  106. out_8(&up->smc_rfcr, SMC_EB);
  107. out_8(&up->smc_tfcr, SMC_EB);
  108. /* Set UART mode, 8 bit, no parity, one stop.
  109. * Enable receive and transmit.
  110. */
  111. out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
  112. /* Mask all interrupts and remove anything pending.
  113. */
  114. out_8(&sp->smc_smcm, 0);
  115. out_8(&sp->smc_smce, 0xff);
  116. /* Set up the baud rate generator */
  117. serial_mpc8xx_setbrg(dev, gd->baudrate);
  118. /* Make the first buffer the only buffer. */
  119. setbits_be16(&rtx->txbd.cbd_sc, BD_SC_WRAP);
  120. setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
  121. /* single/multi character receive. */
  122. out_be16(&up->smc_mrblr, CONFIG_SYS_SMC_RXBUFLEN);
  123. out_be16(&up->smc_maxidl, CONFIG_SYS_MAXIDLE);
  124. out_be32(&rtx->rxindex, 0);
  125. out_be32(&up->smc_rstate, 0);
  126. out_be32(&up->smc_tstate, 0);
  127. out_be16(&up->smc_rbptr, CPM_SERIAL_BASE);
  128. out_be16(&up->smc_tbptr, CPM_SERIAL_BASE + sizeof(cbd_t));
  129. out_be16(&up->smc_brkcr, 1);
  130. out_be16(&up->smc_brkec, 0);
  131. /* Enable transmitter/receiver. */
  132. setbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
  133. return 0;
  134. }
  135. static int serial_mpc8xx_putc(struct udevice *dev, const char c)
  136. {
  137. immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
  138. cpm8xx_t __iomem *cpmp = &(im->im_cpm);
  139. struct serialbuffer __iomem *rtx;
  140. rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
  141. if (in_be16(&rtx->txbd.cbd_sc) & BD_SC_READY)
  142. return -EAGAIN;
  143. out_8(&rtx->txbuf, c);
  144. out_be16(&rtx->txbd.cbd_datlen, 1);
  145. setbits_be16(&rtx->txbd.cbd_sc, BD_SC_READY);
  146. return 0;
  147. }
  148. static int serial_mpc8xx_getc(struct udevice *dev)
  149. {
  150. immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
  151. cpm8xx_t __iomem *cpmp = &(im->im_cpm);
  152. struct serialbuffer __iomem *rtx;
  153. unsigned char c;
  154. uint rxindex;
  155. rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
  156. if (in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY)
  157. return -EAGAIN;
  158. /* the characters are read one by one,
  159. * use the rxindex to know the next char to deliver
  160. */
  161. rxindex = in_be32(&rtx->rxindex);
  162. c = in_8(rtx->rxbuf + rxindex);
  163. rxindex++;
  164. /* check if all char are readout, then make prepare for next receive */
  165. if (rxindex >= in_be16(&rtx->rxbd.cbd_datlen)) {
  166. rxindex = 0;
  167. setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY);
  168. }
  169. out_be32(&rtx->rxindex, rxindex);
  170. return c;
  171. }
  172. static int serial_mpc8xx_pending(struct udevice *dev, bool input)
  173. {
  174. immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
  175. cpm8xx_t __iomem *cpmp = &(im->im_cpm);
  176. struct serialbuffer __iomem *rtx;
  177. if (!input)
  178. return 0;
  179. rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
  180. return !(in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY);
  181. }
  182. static const struct dm_serial_ops serial_mpc8xx_ops = {
  183. .putc = serial_mpc8xx_putc,
  184. .pending = serial_mpc8xx_pending,
  185. .getc = serial_mpc8xx_getc,
  186. .setbrg = serial_mpc8xx_setbrg,
  187. };
  188. static const struct udevice_id serial_mpc8xx_ids[] = {
  189. { .compatible = "fsl,pq1-smc" },
  190. { }
  191. };
  192. U_BOOT_DRIVER(serial_mpc8xx) = {
  193. .name = "serial_mpc8xx",
  194. .id = UCLASS_SERIAL,
  195. .of_match = serial_mpc8xx_ids,
  196. .probe = serial_mpc8xx_probe,
  197. .ops = &serial_mpc8xx_ops,
  198. .flags = DM_FLAG_PRE_RELOC,
  199. };