1/* 2 * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7#include <arch.h> 8#include <asm_macros.S> 9#include <console_macros.S> 10#include <assert_macros.S> 11#include "ls_16550.h" 12 13 /* 14 * "core" functions are low-level implementations that don't require 15 * writable memory and are thus safe to call in BL1 crash context. 16 */ 17 .globl console_ls_16550_core_init 18 .globl console_ls_16550_core_putc 19 .globl console_ls_16550_core_getc 20 21 .globl console_ls_16550_putc 22 .globl console_ls_16550_getc 23 .globl console_ls_16550_flush 24 25 /* ----------------------------------------------- 26 * int console_ls_16550_core_init(uintptr_t base_addr, 27 * unsigned int uart_clk, unsigned int baud_rate) 28 * Function to initialize the console without a 29 * C Runtime to print debug information. This 30 * function will be accessed by console_init and 31 * crash reporting. 32 * In: x0 - console base address 33 * w1 - Uart clock in Hz 34 * w2 - Baud rate 35 * Out: return 1 on success, 0 on error 36 * Clobber list : x1, x2, x3 37 * ----------------------------------------------- 38 */ 39func console_ls_16550_core_init 40 /* Check the input base address */ 41 cbz x0, init_fail 42 /* Check baud rate and uart clock for sanity */ 43 cbz w1, init_fail 44 cbz w2, init_fail 45 46 /* Program the baudrate */ 47 /* Divisor = Uart clock / (16 * baudrate) */ 48 lsl w2, w2, #4 49 udiv w2, w1, w2 50 and w1, w2, #0xff /* w1 = DLL */ 51 lsr w2, w2, #8 52 and w2, w2, #0xff /* w2 = DLLM */ 53 ldrb w3, [x0, #UARTLCR] 54 orr w3, w3, #UARTLCR_DLAB 55 strb w3, [x0, #UARTLCR] /* enable DLL, DLLM programming */ 56 strb w1, [x0, #UARTDLL] /* program DLL */ 57 strb w2, [x0, #UARTDLLM] /* program DLLM */ 58 mov w2, #~UARTLCR_DLAB 59 and w3, w3, w2 60 strb w3, [x0, #UARTLCR] /* disable DLL, DLLM programming */ 61 62 /* 8n1 */ 63 mov w3, #3 64 strb w3, [x0, #UARTLCR] 65 /* no interrupt */ 66 mov w3, #0 67 strb w3, [x0, #UARTIER] 68 /* enable fifo, DMA */ 69 mov w3, #(UARTFCR_FIFOEN |UARTFCR_TXCLR | UARTFCR_RXCLR) 70 strb w3, [x0, #UARTFCR] 71 /* DTR + RTS */ 72 mov w3, #3 73 str w3, [x0, #UARTMCR] 74 mov w0, #1 75 ret 76init_fail: 77 mov w0, #0 78 ret 79endfunc console_ls_16550_core_init 80 81 .globl console_ls_16550_register 82 83 /* ----------------------------------------------- 84 * int console_ls_16550_register(console_t *console, 85 * uintptr_t base, uint32_t clk, uint32_t baud) 86 * Function to initialize and register a new 16550 87 * console. Storage passed in for the console struct 88 * *must* be persistent (i.e. not from the stack). 89 * In: x0 - UART register base address 90 * w1 - UART clock in Hz 91 * w2 - Baud rate 92 * x3 - pointer to empty console_t struct 93 * Out: return 1 on success, 0 on error 94 * Clobber list : x0, x1, x2, x6, x7, x14 95 * ----------------------------------------------- 96 */ 97func console_ls_16550_register 98 mov x7, x30 99 mov x6, x3 100 cbz x6, register_fail 101 str x0, [x6, #CONSOLE_T_BASE] 102 103 bl console_ls_16550_core_init 104 cbz x0, register_fail 105 106 mov x0, x6 107 mov x30, x7 108 finish_console_register ls_16550 putc=1, getc=1, flush=1 109 110register_fail: 111 ret x7 112endfunc console_ls_16550_register 113 114 /* -------------------------------------------------------- 115 * int console_ls_16550_core_putc(int c, uintptr_t base_addr) 116 * Function to output a character over the console. It 117 * returns the character printed on success or -1 on error. 118 * In : w0 - character to be printed 119 * x1 - console base address 120 * Out : return -1 on error else return character. 121 * Clobber list : x2 122 * -------------------------------------------------------- 123 */ 124func console_ls_16550_core_putc 125#if ENABLE_ASSERTIONS 126 cmp x1, #0 127 ASM_ASSERT(ne) 128#endif /* ENABLE_ASSERTIONS */ 129 130 /* Prepend '\r' to '\n' */ 131 cmp w0, #0xA //'\n' 132 b.ne 2f 133 /* Check if the transmit FIFO is full */ 1341: ldrb w2, [x1, #UARTLSR] 135 and w2, w2, #UARTLSR_THRE /* #(UARTLSR_TEMT | UARTLSR_THRE)*/ 136 cmp w2, #(UARTLSR_THRE) 137 b.ne 1b 138 mov w2, #0xD /* '\r' */ 139 strb w2, [x1, #UARTTX] 140 ldrb w2, [x1, #UARTFCR] 141 orr w2, w2, #UARTFCR_TXCLR 142 143 /* Check if the transmit FIFO is full */ 1442: ldrb w2, [x1, #UARTLSR] 145 and w2, w2, #(UARTLSR_THRE) 146 cmp w2, #(UARTLSR_THRE) 147 b.ne 2b 148 strb w0, [x1, #UARTTX] 149 ret 150endfunc console_ls_16550_core_putc 151 152 /* -------------------------------------------------------- 153 * int console_16550_putc(int c, console_t *console) 154 * Function to output a character over the console. It 155 * returns the character printed on success or -1 on error. 156 * In : w0 - character to be printed 157 * x1 - pointer to console_t structure 158 * Out : return -1 on error else return character. 159 * Clobber list : x2 160 * -------------------------------------------------------- 161 */ 162func console_ls_16550_putc 163#if ENABLE_ASSERTIONS 164 cmp x1, #0 165 ASM_ASSERT(ne) 166#endif /* ENABLE_ASSERTIONS */ 167 ldr x1, [x1, #CONSOLE_T_BASE] 168 b console_ls_16550_core_putc 169endfunc console_ls_16550_putc 170 171 /* --------------------------------------------- 172 * int console_ls_16550_core_getc(uintptr_t base_addr) 173 * Function to get a character from the console. 174 * It returns the character grabbed on success 175 * or -1 on if no character is available. 176 * In : x0 - console base address 177 * Out : w0 - character if available, else -1 178 * Clobber list : x0, x1 179 * --------------------------------------------- 180 */ 181func console_ls_16550_core_getc 182#if ENABLE_ASSERTIONS 183 cmp x0, #0 184 ASM_ASSERT(ne) 185#endif /* ENABLE_ASSERTIONS */ 186 187 /* Check if the receive FIFO is empty */ 1881: ldrb w1, [x0, #UARTLSR] 189 tbz w1, #UARTLSR_RDR, 1b 190 ldrb w0, [x0, #UARTRX] 191 ret 192no_char: 193 mov w0, #ERROR_NO_PENDING_CHAR 194 ret 195endfunc console_ls_16550_core_getc 196 197 /* --------------------------------------------- 198 * int console_ls_16550_getc(console_t *console) 199 * Function to get a character from the console. 200 * It returns the character grabbed on success 201 * or -1 on if no character is available. 202 * In : x0 - pointer to console_t structure 203 * Out : w0 - character if available, else -1 204 * Clobber list : x0, x1 205 * --------------------------------------------- 206 */ 207func console_ls_16550_getc 208#if ENABLE_ASSERTIONS 209 cmp x1, #0 210 ASM_ASSERT(ne) 211#endif /* ENABLE_ASSERTIONS */ 212 ldr x0, [x0, #CONSOLE_T_BASE] 213 b console_ls_16550_core_getc 214endfunc console_ls_16550_getc 215 216 /* --------------------------------------------- 217 * void console_ls_16550_core_flush(uintptr_t base_addr) 218 * Function to force a write of all buffered 219 * data that hasn't been output. 220 * In : x0 - console base address 221 * Out : void 222 * Clobber list : x0, x1 223 * --------------------------------------------- 224 */ 225func console_ls_16550_core_flush 226#if ENABLE_ASSERTIONS 227 cmp x0, #0 228 ASM_ASSERT(ne) 229#endif /* ENABLE_ASSERTIONS */ 230 231 /* Loop until the transmit FIFO is empty */ 2321: ldrb w1, [x0, #UARTLSR] 233 and w1, w1, #(UARTLSR_TEMT | UARTLSR_THRE) 234 cmp w1, #(UARTLSR_TEMT | UARTLSR_THRE) 235 b.ne 1b 236 237 ret 238endfunc console_ls_16550_core_flush 239 240 /* --------------------------------------------- 241 * void console_ls_16550_flush(console_t *console) 242 * Function to force a write of all buffered 243 * data that hasn't been output. 244 * In : x0 - pointer to console_t structure 245 * Out : void 246 * Clobber list : x0, x1 247 * --------------------------------------------- 248 */ 249func console_ls_16550_flush 250#if ENABLE_ASSERTIONS 251 cmp x0, #0 252 ASM_ASSERT(ne) 253#endif /* ENABLE_ASSERTIONS */ 254 ldr x0, [x0, #CONSOLE_T_BASE] 255 b console_ls_16550_core_flush 256endfunc console_ls_16550_flush 257