16550_console.S 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <arch.h>
  7. #include <asm_macros.S>
  8. #include <assert_macros.S>
  9. #include <console_macros.S>
  10. /* UART16550 Registers */
  11. #define UARTTX 0x0
  12. #define UARTRX 0x0
  13. #define UARTDLL 0x0
  14. #define UARTIER 0x1
  15. #define UARTDLLM 0x1
  16. #define UARTFCR 0x2
  17. #define UARTLCR 0x3
  18. #define UARTLSR 0x5
  19. #define UARTMCR 0x4
  20. /* FIFO Control Register bits */
  21. #define UARTFCR_FIFOMD_16450 (0 << 6)
  22. #define UARTFCR_FIFOMD_16550 (1 << 6)
  23. #define UARTFCR_RXTRIG_1 (0 << 6)
  24. #define UARTFCR_RXTRIG_4 (1 << 6)
  25. #define UARTFCR_RXTRIG_8 (2 << 6)
  26. #define UARTFCR_RXTRIG_16 (3 << 6)
  27. #define UARTFCR_TXTRIG_1 (0 << 4)
  28. #define UARTFCR_TXTRIG_4 (1 << 4)
  29. #define UARTFCR_TXTRIG_8 (2 << 4)
  30. #define UARTFCR_TXTRIG_16 (3 << 4)
  31. #define UARTFCR_DMAEN (1 << 3) /* Enable DMA mode */
  32. #define UARTFCR_TXCLR (1 << 2) /* Clear contents of Tx FIFO */
  33. #define UARTFCR_RXCLR (1 << 1) /* Clear contents of Rx FIFO */
  34. #define UARTFCR_FIFOEN (1 << 0) /* Enable the Tx/Rx FIFO */
  35. #define UARTFCR_64FIFO (1 << 5)
  36. /* Line Control Register bits */
  37. #define UARTLCR_DLAB (1 << 7) /* Divisor Latch Access */
  38. #define UARTLCR_SETB (1 << 6) /* Set BREAK Condition */
  39. #define UARTLCR_SETP (1 << 5) /* Set Parity to LCR[4] */
  40. #define UARTLCR_EVEN (1 << 4) /* Even Parity Format */
  41. #define UARTLCR_PAR (1 << 3) /* Parity */
  42. #define UARTLCR_STOP (1 << 2) /* Stop Bit */
  43. #define UARTLCR_WORDSZ_5 0 /* Word Length of 5 */
  44. #define UARTLCR_WORDSZ_6 1 /* Word Length of 6 */
  45. #define UARTLCR_WORDSZ_7 2 /* Word Length of 7 */
  46. #define UARTLCR_WORDSZ_8 3 /* Word Length of 8 */
  47. /* Line Status Register bits */
  48. #define UARTLSR_RXFIFOEMT (1 << 9) /* Rx Fifo Empty */
  49. #define UARTLSR_TXFIFOFULL (1 << 8) /* Tx Fifo Full */
  50. #define UARTLSR_RXFIFOERR (1 << 7) /* Rx Fifo Error */
  51. #define UARTLSR_TEMT (1 << 6) /* Tx Shift Register Empty */
  52. #define UARTLSR_THRE (1 << 5) /* Tx Holding Register Empty */
  53. #define UARTLSR_BRK (1 << 4) /* Break Condition Detected */
  54. #define UARTLSR_FERR (1 << 3) /* Framing Error */
  55. #define UARTLSR_PERR (1 << 3) /* Parity Error */
  56. #define UARTLSR_OVRF (1 << 2) /* Rx Overrun Error */
  57. #define UARTLSR_RDR (1 << 2) /* Rx Data Ready */
  58. #define CONSOLE_T_16550_BASE CONSOLE_T_BASE
  59. /*
  60. * "core" functions are low-level implementations that don't require
  61. * writable memory and are thus safe to call in BL1 crash context.
  62. */
  63. .globl nxp_console_16550_core_init
  64. .globl nxp_console_16550_core_putc
  65. .globl nxp_console_16550_core_getc
  66. .globl nxp_console_16550_core_flush
  67. .globl console_16550_putc
  68. .globl console_16550_getc
  69. .globl console_16550_flush
  70. /* -----------------------------------------------
  71. * int nxp_console_16550_core_init(uintptr_t base_addr,
  72. * unsigned int uart_clk, unsigned int baud_rate)
  73. * Function to initialize the console without a
  74. * C Runtime to print debug information. This
  75. * function will be accessed by console_init and
  76. * crash reporting.
  77. * In: x0 - console base address
  78. * w1 - Uart clock in Hz
  79. * w2 - Baud rate
  80. * Out: return 1 on success, 0 on error
  81. * Clobber list : x1, x2, x3
  82. * -----------------------------------------------
  83. */
  84. func nxp_console_16550_core_init
  85. /* Check the input base address */
  86. cbz x0, init_fail
  87. /* Check baud rate and uart clock for sanity */
  88. cbz w1, init_fail
  89. cbz w2, init_fail
  90. /* Program the baudrate */
  91. /* Divisor = Uart clock / (16 * baudrate) */
  92. lsl w2, w2, #4
  93. udiv w2, w1, w2
  94. and w1, w2, #0xff /* w1 = DLL */
  95. lsr w2, w2, #8
  96. and w2, w2, #0xff /* w2 = DLLM */
  97. ldrb w3, [x0, #UARTLCR]
  98. orr w3, w3, #UARTLCR_DLAB
  99. strb w3, [x0, #UARTLCR] /* enable DLL, DLLM programming */
  100. strb w1, [x0, #UARTDLL] /* program DLL */
  101. strb w2, [x0, #UARTDLLM] /* program DLLM */
  102. mov w2, #~UARTLCR_DLAB
  103. and w3, w3, w2
  104. strb w3, [x0, #UARTLCR] /* disable DLL, DLLM programming */
  105. /* 8n1 */
  106. mov w3, #3
  107. strb w3, [x0, #UARTLCR]
  108. /* no interrupt */
  109. mov w3, #0
  110. strb w3, [x0, #UARTIER]
  111. /* enable fifo, DMA */
  112. mov w3, #(UARTFCR_FIFOEN |UARTFCR_TXCLR | UARTFCR_RXCLR)
  113. strb w3, [x0, #UARTFCR]
  114. /* DTR + RTS */
  115. mov w3, #3
  116. str w3, [x0, #UARTMCR]
  117. mov w0, #1
  118. ret
  119. init_fail:
  120. mov w0, #0
  121. ret
  122. endfunc nxp_console_16550_core_init
  123. .globl nxp_console_16550_register
  124. /* -----------------------------------------------
  125. * int nxp_console_16550_register(uintptr_t baseaddr,
  126. * uint32_t clock, uint32_t baud,
  127. * console_t *console);
  128. * Function to initialize and register a new 16550
  129. * console. Storage passed in for the console struct
  130. * *must* be persistent (i.e. not from the stack).
  131. * If w1 (UART clock) is 0, initialisation will be
  132. * skipped, relying on previous code to have done
  133. * this already. w2 is ignored then as well.
  134. * In: x0 - UART register base address
  135. * w1 - UART clock in Hz
  136. * w2 - Baud rate (ignored if w1 is 0)
  137. * x3 - pointer to empty console_t struct
  138. * Out: return 1 on success, 0 on error
  139. * Clobber list : x0, x1, x2, x6, x7, x14
  140. * -----------------------------------------------
  141. */
  142. func nxp_console_16550_register
  143. mov x7, x30
  144. mov x6, x3
  145. cbz x6, register_fail
  146. str x0, [x6, #CONSOLE_T_16550_BASE]
  147. /* A clock rate of zero means to skip the initialisation. */
  148. cbz w1, register_16550
  149. bl nxp_console_16550_core_init
  150. cbz x0, register_fail
  151. register_16550:
  152. mov x0, x6
  153. mov x30, x7
  154. finish_console_register 16550 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
  155. register_fail:
  156. ret x7
  157. endfunc nxp_console_16550_register
  158. /* --------------------------------------------------------
  159. * int console_16550_core_putc(int c, uintptr_t base_addr)
  160. * Function to output a character over the console. It
  161. * returns the character printed on success or -1 on error.
  162. * In : w0 - character to be printed
  163. * x1 - console base address
  164. * Out : return -1 on error else return character.
  165. * Clobber list : x2
  166. * --------------------------------------------------------
  167. */
  168. func nxp_console_16550_core_putc
  169. #if ENABLE_ASSERTIONS
  170. cmp x1, #0
  171. ASM_ASSERT(ne)
  172. #endif /* ENABLE_ASSERTIONS */
  173. /* Prepend '\r' to '\n' */
  174. cmp w0, #'\n'
  175. b.ne 2f
  176. /* Check if the transmit FIFO is full */
  177. 1: ldrb w2, [x1, #UARTLSR]
  178. and w2, w2, #UARTLSR_THRE /* #(UARTLSR_TEMT | UARTLSR_THRE)*/
  179. cmp w2, #(UARTLSR_THRE)
  180. b.ne 1b
  181. mov w2, #'\r'
  182. strb w2, [x1, #UARTTX]
  183. ldrb w2, [x1, #UARTFCR]
  184. orr w2, w2, #UARTFCR_TXCLR
  185. /* Check if the transmit FIFO is full */
  186. 2: ldrb w2, [x1, #UARTLSR]
  187. and w2, w2, #(UARTLSR_THRE)
  188. cmp w2, #(UARTLSR_THRE)
  189. b.ne 2b
  190. strb w0, [x1, #UARTTX]
  191. ret
  192. endfunc nxp_console_16550_core_putc
  193. /* --------------------------------------------------------
  194. * int console_16550_putc(int c, console_t *console)
  195. * Function to output a character over the console. It
  196. * returns the character printed on success or -1 on error.
  197. * In : w0 - character to be printed
  198. * x1 - pointer to console_t structure
  199. * Out : return -1 on error else return character.
  200. * Clobber list : x2
  201. * --------------------------------------------------------
  202. */
  203. func console_16550_putc
  204. #if ENABLE_ASSERTIONS
  205. cmp x1, #0
  206. ASM_ASSERT(ne)
  207. #endif /* ENABLE_ASSERTIONS */
  208. ldr x1, [x1, #CONSOLE_T_16550_BASE]
  209. b nxp_console_16550_core_putc
  210. endfunc console_16550_putc
  211. /* ---------------------------------------------
  212. * int console_16550_core_getc(uintptr_t base_addr)
  213. * Function to get a character from the console.
  214. * It returns the character grabbed on success
  215. * or -1 on if no character is available.
  216. * In : x0 - console base address
  217. * Out : w0 - character if available, else -1
  218. * Clobber list : x0, x1
  219. * ---------------------------------------------
  220. */
  221. func nxp_console_16550_core_getc
  222. #if ENABLE_ASSERTIONS
  223. cmp x0, #0
  224. ASM_ASSERT(ne)
  225. #endif /* ENABLE_ASSERTIONS */
  226. /* Check if the receive FIFO is empty */
  227. 1: ldrb w1, [x0, #UARTLSR]
  228. tbz w1, #UARTLSR_RDR, 1b
  229. ldrb w0, [x0, #UARTRX]
  230. ret
  231. no_char:
  232. mov w0, #ERROR_NO_PENDING_CHAR
  233. ret
  234. endfunc nxp_console_16550_core_getc
  235. /* ---------------------------------------------
  236. * int console_16550_getc(console_t *console)
  237. * Function to get a character from the console.
  238. * It returns the character grabbed on success
  239. * or -1 on if no character is available.
  240. * In : x0 - pointer to console_t structure
  241. * Out : w0 - character if available, else -1
  242. * Clobber list : x0, x1
  243. * ---------------------------------------------
  244. */
  245. func console_16550_getc
  246. #if ENABLE_ASSERTIONS
  247. cmp x1, #0
  248. ASM_ASSERT(ne)
  249. #endif /* ENABLE_ASSERTIONS */
  250. ldr x0, [x0, #CONSOLE_T_16550_BASE]
  251. b nxp_console_16550_core_getc
  252. endfunc console_16550_getc
  253. /* ---------------------------------------------
  254. * int console_16550_core_flush(uintptr_t base_addr)
  255. * Function to force a write of all buffered
  256. * data that hasn't been output.
  257. * In : x0 - console base address
  258. * Out : return -1 on error else return 0.
  259. * Clobber list : x0, x1
  260. * ---------------------------------------------
  261. */
  262. func nxp_console_16550_core_flush
  263. #if ENABLE_ASSERTIONS
  264. cmp x0, #0
  265. ASM_ASSERT(ne)
  266. #endif /* ENABLE_ASSERTIONS */
  267. /* Loop until the transmit FIFO is empty */
  268. 1: ldrb w1, [x0, #UARTLSR]
  269. and w1, w1, #(UARTLSR_THRE)
  270. cmp w1, #(UARTLSR_THRE)
  271. b.ne 1b
  272. mov w0, #0
  273. ret
  274. endfunc nxp_console_16550_core_flush
  275. /* ---------------------------------------------
  276. * int console_16550_flush(console_t *console)
  277. * Function to force a write of all buffered
  278. * data that hasn't been output.
  279. * In : x0 - pointer to console_t structure
  280. * Out : return -1 on error else return 0.
  281. * Clobber list : x0, x1
  282. * ---------------------------------------------
  283. */
  284. func console_16550_flush
  285. #if ENABLE_ASSERTIONS
  286. cmp x0, #0
  287. ASM_ASSERT(ne)
  288. #endif /* ENABLE_ASSERTIONS */
  289. ldr x0, [x0, #CONSOLE_T_16550_BASE]
  290. b nxp_console_16550_core_flush
  291. endfunc console_16550_flush