19c94d3b3SSoby Mathew/* 273e05284SAntonio Nino Diaz * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. 39c94d3b3SSoby Mathew * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 59c94d3b3SSoby Mathew */ 69c94d3b3SSoby Mathew#include <arch.h> 79c94d3b3SSoby Mathew#include <asm_macros.S> 8*4a0c4571SJulius Werner#include <assert_macros.S> 99c94d3b3SSoby Mathew#include <pl011.h> 109c94d3b3SSoby Mathew 119c94d3b3SSoby Mathew/* 129c94d3b3SSoby Mathew * Pull in generic functions to provide backwards compatibility for 139c94d3b3SSoby Mathew * platform makefiles 149c94d3b3SSoby Mathew */ 159c94d3b3SSoby Mathew#include "../../../console/aarch64/console.S" 169c94d3b3SSoby Mathew 17*4a0c4571SJulius Werner /* 18*4a0c4571SJulius Werner * "core" functions are low-level implementations that don't require 19*4a0c4571SJulius Werner * writable memory and are thus safe to call in BL1 crash context. 20*4a0c4571SJulius Werner */ 21*4a0c4571SJulius Werner .globl console_pl011_core_init 22*4a0c4571SJulius Werner .globl console_pl011_core_putc 23*4a0c4571SJulius Werner .globl console_pl011_core_getc 24*4a0c4571SJulius Werner .globl console_pl011_core_flush 259c94d3b3SSoby Mathew 26*4a0c4571SJulius Werner .globl console_pl011_putc 27*4a0c4571SJulius Werner .globl console_pl011_getc 28*4a0c4571SJulius Werner .globl console_pl011_flush 299c94d3b3SSoby Mathew 309c94d3b3SSoby Mathew /* ----------------------------------------------- 31*4a0c4571SJulius Werner * int console_pl011_core_init(uintptr_t base_addr, 329c94d3b3SSoby Mathew * unsigned int uart_clk, unsigned int baud_rate) 339c94d3b3SSoby Mathew * Function to initialize the console without a 349c94d3b3SSoby Mathew * C Runtime to print debug information. This 359c94d3b3SSoby Mathew * function will be accessed by console_init and 369c94d3b3SSoby Mathew * crash reporting. 379c94d3b3SSoby Mathew * In: x0 - console base address 389c94d3b3SSoby Mathew * w1 - Uart clock in Hz 399c94d3b3SSoby Mathew * w2 - Baud rate 409c94d3b3SSoby Mathew * Out: return 1 on success else 0 on error 419c94d3b3SSoby Mathew * Clobber list : x1, x2, x3, x4 429c94d3b3SSoby Mathew * ----------------------------------------------- 439c94d3b3SSoby Mathew */ 44*4a0c4571SJulius Wernerfunc console_pl011_core_init 459c94d3b3SSoby Mathew /* Check the input base address */ 469c94d3b3SSoby Mathew cbz x0, core_init_fail 479c94d3b3SSoby Mathew#if !PL011_GENERIC_UART 489c94d3b3SSoby Mathew /* Check baud rate and uart clock for sanity */ 499c94d3b3SSoby Mathew cbz w1, core_init_fail 509c94d3b3SSoby Mathew cbz w2, core_init_fail 519c94d3b3SSoby Mathew /* Disable uart before programming */ 529c94d3b3SSoby Mathew ldr w3, [x0, #UARTCR] 539c94d3b3SSoby Mathew mov w4, #PL011_UARTCR_UARTEN 549c94d3b3SSoby Mathew bic w3, w3, w4 559c94d3b3SSoby Mathew str w3, [x0, #UARTCR] 569c94d3b3SSoby Mathew /* Program the baudrate */ 579c94d3b3SSoby Mathew /* Divisor = (Uart clock * 4) / baudrate */ 589c94d3b3SSoby Mathew lsl w1, w1, #2 599c94d3b3SSoby Mathew udiv w2, w1, w2 609c94d3b3SSoby Mathew /* IBRD = Divisor >> 6 */ 619c94d3b3SSoby Mathew lsr w1, w2, #6 629c94d3b3SSoby Mathew /* Write the IBRD */ 639c94d3b3SSoby Mathew str w1, [x0, #UARTIBRD] 649c94d3b3SSoby Mathew /* FBRD = Divisor & 0x3F */ 659c94d3b3SSoby Mathew and w1, w2, #0x3f 669c94d3b3SSoby Mathew /* Write the FBRD */ 679c94d3b3SSoby Mathew str w1, [x0, #UARTFBRD] 689c94d3b3SSoby Mathew mov w1, #PL011_LINE_CONTROL 699c94d3b3SSoby Mathew str w1, [x0, #UARTLCR_H] 709c94d3b3SSoby Mathew /* Clear any pending errors */ 719c94d3b3SSoby Mathew str wzr, [x0, #UARTECR] 729c94d3b3SSoby Mathew /* Enable tx, rx, and uart overall */ 739c94d3b3SSoby Mathew mov w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN) 749c94d3b3SSoby Mathew str w1, [x0, #UARTCR] 759c94d3b3SSoby Mathew#endif 769c94d3b3SSoby Mathew mov w0, #1 779c94d3b3SSoby Mathew ret 789c94d3b3SSoby Mathewcore_init_fail: 799c94d3b3SSoby Mathew mov w0, wzr 809c94d3b3SSoby Mathew ret 81*4a0c4571SJulius Wernerendfunc console_pl011_core_init 82*4a0c4571SJulius Werner 83*4a0c4571SJulius Werner#if MULTI_CONSOLE_API 84*4a0c4571SJulius Werner .globl console_pl011_register 85*4a0c4571SJulius Werner 86*4a0c4571SJulius Werner /* ----------------------------------------------- 87*4a0c4571SJulius Werner * int console_pl011_register(console_pl011_t *console, 88*4a0c4571SJulius Werner uintptr_t base, uint32_t clk, uint32_t baud) 89*4a0c4571SJulius Werner * Function to initialize and register a new PL011 90*4a0c4571SJulius Werner * console. Storage passed in for the console struct 91*4a0c4571SJulius Werner * *must* be persistent (i.e. not from the stack). 92*4a0c4571SJulius Werner * In: x0 - UART register base address 93*4a0c4571SJulius Werner * w1 - UART clock in Hz 94*4a0c4571SJulius Werner * w2 - Baud rate 95*4a0c4571SJulius Werner * x3 - pointer to empty console_pl011_t struct 96*4a0c4571SJulius Werner * Out: return 1 on success, 0 on error 97*4a0c4571SJulius Werner * Clobber list : x0, x1, x2, x6, x7, x14 98*4a0c4571SJulius Werner * ----------------------------------------------- 99*4a0c4571SJulius Werner */ 100*4a0c4571SJulius Wernerfunc console_pl011_register 101*4a0c4571SJulius Werner mov x7, x30 102*4a0c4571SJulius Werner mov x6, x3 103*4a0c4571SJulius Werner cbz x6, register_fail 104*4a0c4571SJulius Werner str x0, [x6, #CONSOLE_T_PL011_BASE] 105*4a0c4571SJulius Werner 106*4a0c4571SJulius Werner bl console_pl011_core_init 107*4a0c4571SJulius Werner cbz x0, register_fail 108*4a0c4571SJulius Werner 109*4a0c4571SJulius Werner mov x0, x6 110*4a0c4571SJulius Werner mov x30, x7 111*4a0c4571SJulius Werner finish_console_register pl011 112*4a0c4571SJulius Werner 113*4a0c4571SJulius Wernerregister_fail: 114*4a0c4571SJulius Werner ret x7 115*4a0c4571SJulius Wernerendfunc console_pl011_register 116*4a0c4571SJulius Werner#else 117*4a0c4571SJulius Werner .globl console_core_init 118*4a0c4571SJulius Werner .globl console_core_putc 119*4a0c4571SJulius Werner .globl console_core_getc 120*4a0c4571SJulius Werner .globl console_core_flush 121*4a0c4571SJulius Werner .equ console_core_init,console_pl011_core_init 122*4a0c4571SJulius Werner .equ console_core_putc,console_pl011_core_putc 123*4a0c4571SJulius Werner .equ console_core_getc,console_pl011_core_getc 124*4a0c4571SJulius Werner .equ console_core_flush,console_pl011_core_flush 125*4a0c4571SJulius Werner#endif 1269c94d3b3SSoby Mathew 1279c94d3b3SSoby Mathew /* -------------------------------------------------------- 128*4a0c4571SJulius Werner * int console_pl011_core_putc(int c, uintptr_t base_addr) 1299c94d3b3SSoby Mathew * Function to output a character over the console. It 1309c94d3b3SSoby Mathew * returns the character printed on success or -1 on error. 1319c94d3b3SSoby Mathew * In : w0 - character to be printed 1329c94d3b3SSoby Mathew * x1 - console base address 1339c94d3b3SSoby Mathew * Out : return -1 on error else return character. 1349c94d3b3SSoby Mathew * Clobber list : x2 1359c94d3b3SSoby Mathew * -------------------------------------------------------- 1369c94d3b3SSoby Mathew */ 137*4a0c4571SJulius Wernerfunc console_pl011_core_putc 138*4a0c4571SJulius Werner#if ENABLE_ASSERTIONS 139*4a0c4571SJulius Werner cmp x1, #0 140*4a0c4571SJulius Werner ASM_ASSERT(ne) 141*4a0c4571SJulius Werner#endif /* ENABLE_ASSERTIONS */ 142*4a0c4571SJulius Werner 1439c94d3b3SSoby Mathew /* Prepend '\r' to '\n' */ 1449c94d3b3SSoby Mathew cmp w0, #0xA 1459c94d3b3SSoby Mathew b.ne 2f 1469c94d3b3SSoby Mathew1: 1479c94d3b3SSoby Mathew /* Check if the transmit FIFO is full */ 1489c94d3b3SSoby Mathew ldr w2, [x1, #UARTFR] 1499c94d3b3SSoby Mathew tbnz w2, #PL011_UARTFR_TXFF_BIT, 1b 1509c94d3b3SSoby Mathew mov w2, #0xD 1519c94d3b3SSoby Mathew str w2, [x1, #UARTDR] 1529c94d3b3SSoby Mathew2: 1539c94d3b3SSoby Mathew /* Check if the transmit FIFO is full */ 1549c94d3b3SSoby Mathew ldr w2, [x1, #UARTFR] 1559c94d3b3SSoby Mathew tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b 1569c94d3b3SSoby Mathew str w0, [x1, #UARTDR] 1579c94d3b3SSoby Mathew ret 158*4a0c4571SJulius Wernerendfunc console_pl011_core_putc 159*4a0c4571SJulius Werner 160*4a0c4571SJulius Werner /* -------------------------------------------------------- 161*4a0c4571SJulius Werner * int console_pl011_putc(int c, console_pl011_t *console) 162*4a0c4571SJulius Werner * Function to output a character over the console. It 163*4a0c4571SJulius Werner * returns the character printed on success or -1 on error. 164*4a0c4571SJulius Werner * In : w0 - character to be printed 165*4a0c4571SJulius Werner * x1 - pointer to console_t structure 166*4a0c4571SJulius Werner * Out : return -1 on error else return character. 167*4a0c4571SJulius Werner * Clobber list : x2 168*4a0c4571SJulius Werner * -------------------------------------------------------- 169*4a0c4571SJulius Werner */ 170*4a0c4571SJulius Wernerfunc console_pl011_putc 171*4a0c4571SJulius Werner#if ENABLE_ASSERTIONS 172*4a0c4571SJulius Werner cmp x1, #0 173*4a0c4571SJulius Werner ASM_ASSERT(ne) 174*4a0c4571SJulius Werner#endif /* ENABLE_ASSERTIONS */ 175*4a0c4571SJulius Werner ldr x1, [x1, #CONSOLE_T_PL011_BASE] 176*4a0c4571SJulius Werner b console_pl011_core_putc 177*4a0c4571SJulius Wernerendfunc console_pl011_putc 1789c94d3b3SSoby Mathew 1799c94d3b3SSoby Mathew /* --------------------------------------------- 180*4a0c4571SJulius Werner * int console_pl011_core_getc(uintptr_t base_addr) 1819c94d3b3SSoby Mathew * Function to get a character from the console. 1829c94d3b3SSoby Mathew * It returns the character grabbed on success 183*4a0c4571SJulius Werner * or -1 if no character is available. 1849c94d3b3SSoby Mathew * In : x0 - console base address 185*4a0c4571SJulius Werner * Out: w0 - character if available, else -1 1869c94d3b3SSoby Mathew * Clobber list : x0, x1 1879c94d3b3SSoby Mathew * --------------------------------------------- 1889c94d3b3SSoby Mathew */ 189*4a0c4571SJulius Wernerfunc console_pl011_core_getc 190*4a0c4571SJulius Werner#if ENABLE_ASSERTIONS 191*4a0c4571SJulius Werner cmp x0, #0 192*4a0c4571SJulius Werner ASM_ASSERT(ne) 193*4a0c4571SJulius Werner#endif /* ENABLE_ASSERTIONS */ 194*4a0c4571SJulius Werner 1959c94d3b3SSoby Mathew /* Check if the receive FIFO is empty */ 1969c94d3b3SSoby Mathew ldr w1, [x0, #UARTFR] 197*4a0c4571SJulius Werner tbnz w1, #PL011_UARTFR_RXFE_BIT, no_char 1989c94d3b3SSoby Mathew ldr w1, [x0, #UARTDR] 1999c94d3b3SSoby Mathew mov w0, w1 2009c94d3b3SSoby Mathew ret 201*4a0c4571SJulius Wernerno_char: 202*4a0c4571SJulius Werner mov w0, #ERROR_NO_PENDING_CHAR 2039c94d3b3SSoby Mathew ret 204*4a0c4571SJulius Wernerendfunc console_pl011_core_getc 20573e05284SAntonio Nino Diaz 20673e05284SAntonio Nino Diaz /* --------------------------------------------- 207*4a0c4571SJulius Werner * int console_pl011_getc(console_pl011_t *console) 208*4a0c4571SJulius Werner * Function to get a character from the console. 209*4a0c4571SJulius Werner * It returns the character grabbed on success 210*4a0c4571SJulius Werner * or -1 if no character is available. 211*4a0c4571SJulius Werner * In : x0 - pointer to console_t structure 212*4a0c4571SJulius Werner * Out: w0 - character if available, else -1 213*4a0c4571SJulius Werner * Clobber list : x0, x1 214*4a0c4571SJulius Werner * --------------------------------------------- 215*4a0c4571SJulius Werner */ 216*4a0c4571SJulius Wernerfunc console_pl011_getc 217*4a0c4571SJulius Werner#if ENABLE_ASSERTIONS 218*4a0c4571SJulius Werner cmp x0, #0 219*4a0c4571SJulius Werner ASM_ASSERT(ne) 220*4a0c4571SJulius Werner#endif /* ENABLE_ASSERTIONS */ 221*4a0c4571SJulius Werner ldr x0, [x0, #CONSOLE_T_PL011_BASE] 222*4a0c4571SJulius Werner b console_pl011_core_getc 223*4a0c4571SJulius Wernerendfunc console_pl011_getc 224*4a0c4571SJulius Werner 225*4a0c4571SJulius Werner /* --------------------------------------------- 226*4a0c4571SJulius Werner * int console_pl011_core_flush(uintptr_t base_addr) 22773e05284SAntonio Nino Diaz * Function to force a write of all buffered 22873e05284SAntonio Nino Diaz * data that hasn't been output. 22973e05284SAntonio Nino Diaz * In : x0 - console base address 23073e05284SAntonio Nino Diaz * Out : return -1 on error else return 0. 23173e05284SAntonio Nino Diaz * Clobber list : x0, x1 23273e05284SAntonio Nino Diaz * --------------------------------------------- 23373e05284SAntonio Nino Diaz */ 234*4a0c4571SJulius Wernerfunc console_pl011_core_flush 235*4a0c4571SJulius Werner#if ENABLE_ASSERTIONS 236*4a0c4571SJulius Werner cmp x0, #0 237*4a0c4571SJulius Werner ASM_ASSERT(ne) 238*4a0c4571SJulius Werner#endif /* ENABLE_ASSERTIONS */ 23973e05284SAntonio Nino Diaz1: 24073e05284SAntonio Nino Diaz /* Loop until the transmit FIFO is empty */ 24173e05284SAntonio Nino Diaz ldr w1, [x0, #UARTFR] 24273e05284SAntonio Nino Diaz tbnz w1, #PL011_UARTFR_BUSY_BIT, 1b 24373e05284SAntonio Nino Diaz 24473e05284SAntonio Nino Diaz mov w0, #0 24573e05284SAntonio Nino Diaz ret 246*4a0c4571SJulius Wernerendfunc console_pl011_core_flush 247*4a0c4571SJulius Werner 248*4a0c4571SJulius Werner /* --------------------------------------------- 249*4a0c4571SJulius Werner * int console_pl011_flush(console_pl011_t *console) 250*4a0c4571SJulius Werner * Function to force a write of all buffered 251*4a0c4571SJulius Werner * data that hasn't been output. 252*4a0c4571SJulius Werner * In : x0 - pointer to console_t structure 253*4a0c4571SJulius Werner * Out : return -1 on error else return 0. 254*4a0c4571SJulius Werner * Clobber list : x0, x1 255*4a0c4571SJulius Werner * --------------------------------------------- 256*4a0c4571SJulius Werner */ 257*4a0c4571SJulius Wernerfunc console_pl011_flush 258*4a0c4571SJulius Werner#if ENABLE_ASSERTIONS 259*4a0c4571SJulius Werner cmp x0, #0 260*4a0c4571SJulius Werner ASM_ASSERT(ne) 261*4a0c4571SJulius Werner#endif /* ENABLE_ASSERTIONS */ 262*4a0c4571SJulius Werner ldr x0, [x0, #CONSOLE_T_PL011_BASE] 263*4a0c4571SJulius Werner b console_pl011_core_flush 264*4a0c4571SJulius Wernerendfunc console_pl011_flush 265