udbg_16550.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * udbg for NS16550 compatible serial ports
  3. *
  4. * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/types.h>
  12. #include <asm/udbg.h>
  13. #include <asm/io.h>
  14. #include <asm/reg_a2.h>
  15. extern u8 real_readb(volatile u8 __iomem *addr);
  16. extern void real_writeb(u8 data, volatile u8 __iomem *addr);
  17. extern u8 real_205_readb(volatile u8 __iomem *addr);
  18. extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
  19. struct NS16550 {
  20. /* this struct must be packed */
  21. unsigned char rbr; /* 0 */
  22. unsigned char ier; /* 1 */
  23. unsigned char fcr; /* 2 */
  24. unsigned char lcr; /* 3 */
  25. unsigned char mcr; /* 4 */
  26. unsigned char lsr; /* 5 */
  27. unsigned char msr; /* 6 */
  28. unsigned char scr; /* 7 */
  29. };
  30. #define thr rbr
  31. #define iir fcr
  32. #define dll rbr
  33. #define dlm ier
  34. #define dlab lcr
  35. #define LSR_DR 0x01 /* Data ready */
  36. #define LSR_OE 0x02 /* Overrun */
  37. #define LSR_PE 0x04 /* Parity error */
  38. #define LSR_FE 0x08 /* Framing error */
  39. #define LSR_BI 0x10 /* Break */
  40. #define LSR_THRE 0x20 /* Xmit holding register empty */
  41. #define LSR_TEMT 0x40 /* Xmitter empty */
  42. #define LSR_ERR 0x80 /* Error */
  43. #define LCR_DLAB 0x80
  44. static struct NS16550 __iomem *udbg_comport;
  45. static void udbg_550_flush(void)
  46. {
  47. if (udbg_comport) {
  48. while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
  49. /* wait for idle */;
  50. }
  51. }
  52. static void udbg_550_putc(char c)
  53. {
  54. if (udbg_comport) {
  55. if (c == '\n')
  56. udbg_550_putc('\r');
  57. udbg_550_flush();
  58. out_8(&udbg_comport->thr, c);
  59. }
  60. }
  61. static int udbg_550_getc_poll(void)
  62. {
  63. if (udbg_comport) {
  64. if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
  65. return in_8(&udbg_comport->rbr);
  66. else
  67. return -1;
  68. }
  69. return -1;
  70. }
  71. static int udbg_550_getc(void)
  72. {
  73. if (udbg_comport) {
  74. while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
  75. /* wait for char */;
  76. return in_8(&udbg_comport->rbr);
  77. }
  78. return -1;
  79. }
  80. void udbg_init_uart(void __iomem *comport, unsigned int speed,
  81. unsigned int clock)
  82. {
  83. unsigned int dll, base_bauds;
  84. if (clock == 0)
  85. clock = 1843200;
  86. if (speed == 0)
  87. speed = 9600;
  88. base_bauds = clock / 16;
  89. dll = base_bauds / speed;
  90. if (comport) {
  91. udbg_comport = (struct NS16550 __iomem *)comport;
  92. out_8(&udbg_comport->lcr, 0x00);
  93. out_8(&udbg_comport->ier, 0xff);
  94. out_8(&udbg_comport->ier, 0x00);
  95. out_8(&udbg_comport->lcr, LCR_DLAB);
  96. out_8(&udbg_comport->dll, dll & 0xff);
  97. out_8(&udbg_comport->dlm, dll >> 8);
  98. /* 8 data, 1 stop, no parity */
  99. out_8(&udbg_comport->lcr, 0x03);
  100. /* RTS/DTR */
  101. out_8(&udbg_comport->mcr, 0x03);
  102. /* Clear & enable FIFOs */
  103. out_8(&udbg_comport->fcr ,0x07);
  104. udbg_putc = udbg_550_putc;
  105. udbg_flush = udbg_550_flush;
  106. udbg_getc = udbg_550_getc;
  107. udbg_getc_poll = udbg_550_getc_poll;
  108. }
  109. }
  110. unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
  111. {
  112. unsigned int dll, dlm, divisor, prescaler, speed;
  113. u8 old_lcr;
  114. struct NS16550 __iomem *port = comport;
  115. old_lcr = in_8(&port->lcr);
  116. /* select divisor latch registers. */
  117. out_8(&port->lcr, LCR_DLAB);
  118. /* now, read the divisor */
  119. dll = in_8(&port->dll);
  120. dlm = in_8(&port->dlm);
  121. divisor = dlm << 8 | dll;
  122. /* check prescaling */
  123. if (in_8(&port->mcr) & 0x80)
  124. prescaler = 4;
  125. else
  126. prescaler = 1;
  127. /* restore the LCR */
  128. out_8(&port->lcr, old_lcr);
  129. /* calculate speed */
  130. speed = (clock / prescaler) / (divisor * 16);
  131. /* sanity check */
  132. if (speed > (clock / 16))
  133. speed = 9600;
  134. return speed;
  135. }
  136. #ifdef CONFIG_PPC_MAPLE
  137. void udbg_maple_real_flush(void)
  138. {
  139. if (udbg_comport) {
  140. while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
  141. /* wait for idle */;
  142. }
  143. }
  144. void udbg_maple_real_putc(char c)
  145. {
  146. if (udbg_comport) {
  147. if (c == '\n')
  148. udbg_maple_real_putc('\r');
  149. udbg_maple_real_flush();
  150. real_writeb(c, &udbg_comport->thr); eieio();
  151. }
  152. }
  153. void __init udbg_init_maple_realmode(void)
  154. {
  155. udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
  156. udbg_putc = udbg_maple_real_putc;
  157. udbg_flush = udbg_maple_real_flush;
  158. udbg_getc = NULL;
  159. udbg_getc_poll = NULL;
  160. }
  161. #endif /* CONFIG_PPC_MAPLE */
  162. #ifdef CONFIG_PPC_PASEMI
  163. void udbg_pas_real_flush(void)
  164. {
  165. if (udbg_comport) {
  166. while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
  167. /* wait for idle */;
  168. }
  169. }
  170. void udbg_pas_real_putc(char c)
  171. {
  172. if (udbg_comport) {
  173. if (c == '\n')
  174. udbg_pas_real_putc('\r');
  175. udbg_pas_real_flush();
  176. real_205_writeb(c, &udbg_comport->thr); eieio();
  177. }
  178. }
  179. void udbg_init_pas_realmode(void)
  180. {
  181. udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
  182. udbg_putc = udbg_pas_real_putc;
  183. udbg_flush = udbg_pas_real_flush;
  184. udbg_getc = NULL;
  185. udbg_getc_poll = NULL;
  186. }
  187. #endif /* CONFIG_PPC_MAPLE */
  188. #ifdef CONFIG_PPC_EARLY_DEBUG_44x
  189. #include <platforms/44x/44x.h>
  190. static void udbg_44x_as1_flush(void)
  191. {
  192. if (udbg_comport) {
  193. while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
  194. /* wait for idle */;
  195. }
  196. }
  197. static void udbg_44x_as1_putc(char c)
  198. {
  199. if (udbg_comport) {
  200. if (c == '\n')
  201. udbg_44x_as1_putc('\r');
  202. udbg_44x_as1_flush();
  203. as1_writeb(c, &udbg_comport->thr); eieio();
  204. }
  205. }
  206. static int udbg_44x_as1_getc(void)
  207. {
  208. if (udbg_comport) {
  209. while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0)
  210. ; /* wait for char */
  211. return as1_readb(&udbg_comport->rbr);
  212. }
  213. return -1;
  214. }
  215. void __init udbg_init_44x_as1(void)
  216. {
  217. udbg_comport =
  218. (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
  219. udbg_putc = udbg_44x_as1_putc;
  220. udbg_flush = udbg_44x_as1_flush;
  221. udbg_getc = udbg_44x_as1_getc;
  222. }
  223. #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
  224. #ifdef CONFIG_PPC_EARLY_DEBUG_40x
  225. static void udbg_40x_real_flush(void)
  226. {
  227. if (udbg_comport) {
  228. while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
  229. /* wait for idle */;
  230. }
  231. }
  232. static void udbg_40x_real_putc(char c)
  233. {
  234. if (udbg_comport) {
  235. if (c == '\n')
  236. udbg_40x_real_putc('\r');
  237. udbg_40x_real_flush();
  238. real_writeb(c, &udbg_comport->thr); eieio();
  239. }
  240. }
  241. static int udbg_40x_real_getc(void)
  242. {
  243. if (udbg_comport) {
  244. while ((real_readb(&udbg_comport->lsr) & LSR_DR) == 0)
  245. ; /* wait for char */
  246. return real_readb(&udbg_comport->rbr);
  247. }
  248. return -1;
  249. }
  250. void __init udbg_init_40x_realmode(void)
  251. {
  252. udbg_comport = (struct NS16550 __iomem *)
  253. CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;
  254. udbg_putc = udbg_40x_real_putc;
  255. udbg_flush = udbg_40x_real_flush;
  256. udbg_getc = udbg_40x_real_getc;
  257. udbg_getc_poll = NULL;
  258. }
  259. #endif /* CONFIG_PPC_EARLY_DEBUG_40x */
  260. #ifdef CONFIG_PPC_EARLY_DEBUG_WSP
  261. static void udbg_wsp_flush(void)
  262. {
  263. if (udbg_comport) {
  264. while ((readb(&udbg_comport->lsr) & LSR_THRE) == 0)
  265. /* wait for idle */;
  266. }
  267. }
  268. static void udbg_wsp_putc(char c)
  269. {
  270. if (udbg_comport) {
  271. if (c == '\n')
  272. udbg_wsp_putc('\r');
  273. udbg_wsp_flush();
  274. writeb(c, &udbg_comport->thr); eieio();
  275. }
  276. }
  277. static int udbg_wsp_getc(void)
  278. {
  279. if (udbg_comport) {
  280. while ((readb(&udbg_comport->lsr) & LSR_DR) == 0)
  281. ; /* wait for char */
  282. return readb(&udbg_comport->rbr);
  283. }
  284. return -1;
  285. }
  286. static int udbg_wsp_getc_poll(void)
  287. {
  288. if (udbg_comport)
  289. if (readb(&udbg_comport->lsr) & LSR_DR)
  290. return readb(&udbg_comport->rbr);
  291. return -1;
  292. }
  293. void __init udbg_init_wsp(void)
  294. {
  295. udbg_comport = (struct NS16550 __iomem *)WSP_UART_VIRT;
  296. udbg_init_uart(udbg_comport, 57600, 50000000);
  297. udbg_putc = udbg_wsp_putc;
  298. udbg_flush = udbg_wsp_flush;
  299. udbg_getc = udbg_wsp_getc;
  300. udbg_getc_poll = udbg_wsp_getc_poll;
  301. }
  302. #endif /* CONFIG_PPC_EARLY_DEBUG_WSP */