cpm-serial.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * CPM serial console support.
  3. *
  4. * Copyright 2007 Freescale Semiconductor, Inc.
  5. * Author: Scott Wood <scottwood@freescale.com>
  6. *
  7. * It is assumed that the firmware (or the platform file) has already set
  8. * up the port.
  9. */
  10. #include "types.h"
  11. #include "io.h"
  12. #include "ops.h"
  13. struct cpm_scc {
  14. u32 gsmrl;
  15. u32 gsmrh;
  16. u16 psmr;
  17. u8 res1[2];
  18. u16 todr;
  19. u16 dsr;
  20. u16 scce;
  21. u8 res2[2];
  22. u16 sccm;
  23. u8 res3;
  24. u8 sccs;
  25. u8 res4[8];
  26. };
  27. struct cpm_smc {
  28. u8 res1[2];
  29. u16 smcmr;
  30. u8 res2[2];
  31. u8 smce;
  32. u8 res3[3];
  33. u8 smcm;
  34. u8 res4[5];
  35. };
  36. struct cpm_param {
  37. u16 rbase;
  38. u16 tbase;
  39. u8 rfcr;
  40. u8 tfcr;
  41. };
  42. struct cpm_bd {
  43. u16 sc; /* Status and Control */
  44. u16 len; /* Data length in buffer */
  45. u8 *addr; /* Buffer address in host memory */
  46. };
  47. static void *cpcr;
  48. static struct cpm_param *param;
  49. static struct cpm_smc *smc;
  50. static struct cpm_scc *scc;
  51. struct cpm_bd *tbdf, *rbdf;
  52. static u32 cpm_cmd;
  53. static u8 *muram_start;
  54. static u32 muram_offset;
  55. static void (*do_cmd)(int op);
  56. static void (*enable_port)(void);
  57. static void (*disable_port)(void);
  58. #define CPM_CMD_STOP_TX 4
  59. #define CPM_CMD_RESTART_TX 6
  60. #define CPM_CMD_INIT_RX_TX 0
  61. static void cpm1_cmd(int op)
  62. {
  63. while (in_be16(cpcr) & 1)
  64. ;
  65. out_be16(cpcr, (op << 8) | cpm_cmd | 1);
  66. while (in_be16(cpcr) & 1)
  67. ;
  68. }
  69. static void cpm2_cmd(int op)
  70. {
  71. while (in_be32(cpcr) & 0x10000)
  72. ;
  73. out_be32(cpcr, op | cpm_cmd | 0x10000);
  74. while (in_be32(cpcr) & 0x10000)
  75. ;
  76. }
  77. static void smc_disable_port(void)
  78. {
  79. do_cmd(CPM_CMD_STOP_TX);
  80. out_be16(&smc->smcmr, in_be16(&smc->smcmr) & ~3);
  81. }
  82. static void scc_disable_port(void)
  83. {
  84. do_cmd(CPM_CMD_STOP_TX);
  85. out_be32(&scc->gsmrl, in_be32(&scc->gsmrl) & ~0x30);
  86. }
  87. static void smc_enable_port(void)
  88. {
  89. out_be16(&smc->smcmr, in_be16(&smc->smcmr) | 3);
  90. do_cmd(CPM_CMD_RESTART_TX);
  91. }
  92. static void scc_enable_port(void)
  93. {
  94. out_be32(&scc->gsmrl, in_be32(&scc->gsmrl) | 0x30);
  95. do_cmd(CPM_CMD_RESTART_TX);
  96. }
  97. static int cpm_serial_open(void)
  98. {
  99. disable_port();
  100. out_8(&param->rfcr, 0x10);
  101. out_8(&param->tfcr, 0x10);
  102. rbdf = (struct cpm_bd *)muram_start;
  103. rbdf->addr = (u8 *)(rbdf + 2);
  104. rbdf->sc = 0xa000;
  105. rbdf->len = 1;
  106. tbdf = rbdf + 1;
  107. tbdf->addr = (u8 *)(rbdf + 2) + 1;
  108. tbdf->sc = 0x2000;
  109. tbdf->len = 1;
  110. sync();
  111. out_be16(&param->rbase, muram_offset);
  112. out_be16(&param->tbase, muram_offset + sizeof(struct cpm_bd));
  113. do_cmd(CPM_CMD_INIT_RX_TX);
  114. enable_port();
  115. return 0;
  116. }
  117. static void cpm_serial_putc(unsigned char c)
  118. {
  119. while (tbdf->sc & 0x8000)
  120. barrier();
  121. sync();
  122. tbdf->addr[0] = c;
  123. eieio();
  124. tbdf->sc |= 0x8000;
  125. }
  126. static unsigned char cpm_serial_tstc(void)
  127. {
  128. barrier();
  129. return !(rbdf->sc & 0x8000);
  130. }
  131. static unsigned char cpm_serial_getc(void)
  132. {
  133. unsigned char c;
  134. while (!cpm_serial_tstc())
  135. ;
  136. sync();
  137. c = rbdf->addr[0];
  138. eieio();
  139. rbdf->sc |= 0x8000;
  140. return c;
  141. }
  142. int cpm_console_init(void *devp, struct serial_console_data *scdp)
  143. {
  144. void *reg_virt[2];
  145. int is_smc = 0, is_cpm2 = 0, n;
  146. unsigned long reg_phys;
  147. void *parent, *muram;
  148. if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) {
  149. is_smc = 1;
  150. } else if (dt_is_compatible(devp, "fsl,cpm2-scc-uart")) {
  151. is_cpm2 = 1;
  152. } else if (dt_is_compatible(devp, "fsl,cpm2-smc-uart")) {
  153. is_cpm2 = 1;
  154. is_smc = 1;
  155. }
  156. if (is_smc) {
  157. enable_port = smc_enable_port;
  158. disable_port = smc_disable_port;
  159. } else {
  160. enable_port = scc_enable_port;
  161. disable_port = scc_disable_port;
  162. }
  163. if (is_cpm2)
  164. do_cmd = cpm2_cmd;
  165. else
  166. do_cmd = cpm1_cmd;
  167. n = getprop(devp, "fsl,cpm-command", &cpm_cmd, 4);
  168. if (n < 4)
  169. return -1;
  170. n = getprop(devp, "virtual-reg", reg_virt, sizeof(reg_virt));
  171. if (n < (int)sizeof(reg_virt)) {
  172. for (n = 0; n < 2; n++) {
  173. if (!dt_xlate_reg(devp, n, &reg_phys, NULL))
  174. return -1;
  175. reg_virt[n] = (void *)reg_phys;
  176. }
  177. }
  178. if (is_smc)
  179. smc = reg_virt[0];
  180. else
  181. scc = reg_virt[0];
  182. param = reg_virt[1];
  183. parent = get_parent(devp);
  184. if (!parent)
  185. return -1;
  186. n = getprop(parent, "virtual-reg", reg_virt, sizeof(reg_virt));
  187. if (n < (int)sizeof(reg_virt)) {
  188. if (!dt_xlate_reg(parent, 0, &reg_phys, NULL))
  189. return -1;
  190. reg_virt[0] = (void *)reg_phys;
  191. }
  192. cpcr = reg_virt[0];
  193. muram = finddevice("/soc/cpm/muram/data");
  194. if (!muram)
  195. return -1;
  196. /* For bootwrapper-compatible device trees, we assume that the first
  197. * entry has at least 18 bytes, and that #address-cells/#data-cells
  198. * is one for both parent and child.
  199. */
  200. n = getprop(muram, "virtual-reg", reg_virt, sizeof(reg_virt));
  201. if (n < (int)sizeof(reg_virt)) {
  202. if (!dt_xlate_reg(muram, 0, &reg_phys, NULL))
  203. return -1;
  204. reg_virt[0] = (void *)reg_phys;
  205. }
  206. muram_start = reg_virt[0];
  207. n = getprop(muram, "reg", &muram_offset, 4);
  208. if (n < 4)
  209. return -1;
  210. scdp->open = cpm_serial_open;
  211. scdp->putc = cpm_serial_putc;
  212. scdp->getc = cpm_serial_getc;
  213. scdp->tstc = cpm_serial_tstc;
  214. return 0;
  215. }