1/* 2 * Copyright (c) 2016-2018, 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#define USE_FINISH_CONSOLE_REG_2 10#include <console_macros.S> 11#include <drivers/arm/pl011.h> 12 13#if !MULTI_CONSOLE_API 14/* 15 * Pull in generic functions to provide backwards compatibility for 16 * platform makefiles 17 */ 18#include "../../../console/aarch32/console.S" 19#endif 20 21 /* 22 * "core" functions are low-level implementations that don't require 23 * writeable memory and are thus safe to call in BL1 crash context. 24 */ 25 .globl console_pl011_core_init 26 .globl console_pl011_core_putc 27 .globl console_pl011_core_getc 28 .globl console_pl011_core_flush 29 30 .globl console_pl011_putc 31 .globl console_pl011_getc 32 .globl console_pl011_flush 33 34 35 /* ----------------------------------------------- 36 * int console_core_init(uintptr_t base_addr, 37 * unsigned int uart_clk, unsigned int baud_rate) 38 * Function to initialize the console without a 39 * C Runtime to print debug information. This 40 * function will be accessed by console_init and 41 * crash reporting. 42 * In: r0 - console base address 43 * r1 - Uart clock in Hz 44 * r2 - Baud rate 45 * Out: return 1 on success else 0 on error 46 * Clobber list : r1, r2, r3 47 * ----------------------------------------------- 48 */ 49func console_pl011_core_init 50 /* Check the input base address */ 51 cmp r0, #0 52 beq core_init_fail 53#if !PL011_GENERIC_UART 54 /* Check baud rate and uart clock for sanity */ 55 cmp r1, #0 56 beq core_init_fail 57 cmp r2, #0 58 beq core_init_fail 59 /* Disable the UART before initialization */ 60 ldr r3, [r0, #UARTCR] 61 bic r3, r3, #PL011_UARTCR_UARTEN 62 str r3, [r0, #UARTCR] 63 /* Program the baudrate */ 64 /* Divisor = (Uart clock * 4) / baudrate */ 65 lsl r1, r1, #2 66#if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) 67 push {r0,r3} 68 softudiv r0,r1,r2,r3 69 mov r1, r0 70 pop {r0,r3} 71#else 72 udiv r2, r1, r2 73#endif 74 /* IBRD = Divisor >> 6 */ 75 lsr r1, r2, #6 76 /* Write the IBRD */ 77 str r1, [r0, #UARTIBRD] 78 /* FBRD = Divisor & 0x3F */ 79 and r1, r2, #0x3f 80 /* Write the FBRD */ 81 str r1, [r0, #UARTFBRD] 82 mov r1, #PL011_LINE_CONTROL 83 str r1, [r0, #UARTLCR_H] 84 /* Clear any pending errors */ 85 mov r1, #0 86 str r1, [r0, #UARTECR] 87 /* Enable tx, rx, and uart overall */ 88 ldr r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN) 89 str r1, [r0, #UARTCR] 90#endif 91 mov r0, #1 92 bx lr 93core_init_fail: 94 mov r0, #0 95 bx lr 96endfunc console_pl011_core_init 97 98#if MULTI_CONSOLE_API 99 .globl console_pl011_register 100 101 /* ------------------------------------------------------- 102 * int console_pl011_register(uintptr_t baseaddr, 103 * uint32_t clock, uint32_t baud, 104 * console_pl011_t *console); 105 * Function to initialize and register a new PL011 106 * console. Storage passed in for the console struct 107 * *must* be persistent (i.e. not from the stack). 108 * In: r0 - UART register base address 109 * r1 - UART clock in Hz 110 * r2 - Baud rate 111 * r3 - pointer to empty console_pl011_t struct 112 * Out: return 1 on success, 0 on error 113 * Clobber list : r0, r1, r2 114 * ------------------------------------------------------- 115 */ 116func console_pl011_register 117 push {r4, lr} 118 mov r4, r3 119 cmp r4, #0 120 beq register_fail 121 str r0, [r4, #CONSOLE_T_PL011_BASE] 122 123 bl console_pl011_core_init 124 cmp r0, #0 125 beq register_fail 126 127 mov r0, r4 128 pop {r4, lr} 129 finish_console_register pl011 putc=1, getc=1, flush=1 130 131register_fail: 132 pop {r4, pc} 133endfunc console_pl011_register 134#else 135 .globl console_core_init 136 .globl console_core_putc 137 .globl console_core_getc 138 .globl console_core_flush 139 .equ console_core_init, console_pl011_core_init 140 .equ console_core_putc, console_pl011_core_putc 141 .equ console_core_getc, console_pl011_core_getc 142 .equ console_core_flush, console_pl011_core_flush 143#endif 144 145 /* -------------------------------------------------------- 146 * int console_core_putc(int c, uintptr_t base_addr) 147 * Function to output a character over the console. It 148 * returns the character printed on success or -1 on error. 149 * In : r0 - character to be printed 150 * r1 - console base address 151 * Out : return -1 on error else return character. 152 * Clobber list : r2 153 * -------------------------------------------------------- 154 */ 155func console_pl011_core_putc 156 /* Check the input parameter */ 157 cmp r1, #0 158 beq putc_error 159 /* Prepend '\r' to '\n' */ 160 cmp r0, #0xA 161 bne 2f 1621: 163 /* Check if the transmit FIFO is full */ 164 ldr r2, [r1, #UARTFR] 165 tst r2, #PL011_UARTFR_TXFF 166 bne 1b 167 mov r2, #0xD 168 str r2, [r1, #UARTDR] 1692: 170 /* Check if the transmit FIFO is full */ 171 ldr r2, [r1, #UARTFR] 172 tst r2, #PL011_UARTFR_TXFF 173 bne 2b 174 str r0, [r1, #UARTDR] 175 bx lr 176putc_error: 177 mov r0, #-1 178 bx lr 179endfunc console_pl011_core_putc 180 181 /* -------------------------------------------------------- 182 * int console_pl011_putc(int c, console_pl011_t *console) 183 * Function to output a character over the console. It 184 * returns the character printed on success or -1 on error. 185 * In: r0 - character to be printed 186 * r1 - pointer to console_t structure 187 * Out : return -1 on error else return character. 188 * Clobber list: r2 189 * ------------------------------------------------------- 190 */ 191func console_pl011_putc 192#if ENABLE_ASSERTIONS 193 cmp r1, #0 194 ASM_ASSERT(ne) 195#endif /* ENABLE_ASSERTIONS */ 196 ldr r1, [r1, #CONSOLE_T_PL011_BASE] 197 b console_pl011_core_putc 198endfunc console_pl011_putc 199 200 /* --------------------------------------------- 201 * int console_core_getc(uintptr_t base_addr) 202 * Function to get a character from the console. 203 * It returns the character grabbed on success 204 * or -1 on error. 205 * In : r0 - console base address 206 * Clobber list : r0, r1 207 * --------------------------------------------- 208 */ 209func console_pl011_core_getc 210 cmp r0, #0 211 beq getc_error 2121: 213 /* Check if the receive FIFO is empty */ 214 ldr r1, [r0, #UARTFR] 215 tst r1, #PL011_UARTFR_RXFE 216 bne 1b 217 ldr r1, [r0, #UARTDR] 218 mov r0, r1 219 bx lr 220getc_error: 221 mov r0, #-1 222 bx lr 223endfunc console_pl011_core_getc 224 225 /* ------------------------------------------------ 226 * int console_pl011_getc(console_pl011_t *console) 227 * Function to get a character from the console. 228 * It returns the character grabbed on success 229 * or -1 if no character is available. 230 * In : r0 - pointer to console_t structure 231 * Out: r0 - character if available, else -1 232 * Clobber list: r0, r1 233 * ------------------------------------------------ 234 */ 235func console_pl011_getc 236#if ENABLE_ASSERTIONS 237 cmp r0, #0 238 ASM_ASSERT(ne) 239#endif /* ENABLE_ASSERTIONS */ 240 ldr r0, [r0, #CONSOLE_T_PL011_BASE] 241 b console_pl011_core_getc 242endfunc console_pl011_getc 243 244 /* --------------------------------------------- 245 * int console_core_flush(uintptr_t base_addr) 246 * Function to force a write of all buffered 247 * data that hasn't been output. 248 * In : r0 - console base address 249 * Out : return -1 on error else return 0. 250 * Clobber list : r0, r1 251 * --------------------------------------------- 252 */ 253func console_pl011_core_flush 254 cmp r0, #0 255 beq flush_error 256 2571: 258 /* Loop while the transmit FIFO is busy */ 259 ldr r1, [r0, #UARTFR] 260 tst r1, #PL011_UARTFR_BUSY 261 bne 1b 262 263 mov r0, #0 264 bx lr 265flush_error: 266 mov r0, #-1 267 bx lr 268endfunc console_pl011_core_flush 269 270 /* --------------------------------------------- 271 * int console_pl011_flush(console_pl011_t *console) 272 * Function to force a write of all buffered 273 * data that hasn't been output. 274 * In : r0 - pointer to console_t structure 275 * Out : return -1 on error else return 0. 276 * Clobber list: r0, r1 277 * --------------------------------------------- 278 */ 279func console_pl011_flush 280#if ENABLE_ASSERTIONS 281 cmp r0, #0 282 ASM_ASSERT(ne) 283#endif /* ENABLE_ASSERTIONS */ 284 ldr r0, [r0, #CONSOLE_T_PL011_BASE] 285 b console_pl011_core_flush 286endfunc console_pl011_flush 287