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