166be868eSSoby Mathew/* 2*7e2bbef9SDaniel Boulby * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. 366be868eSSoby Mathew * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 566be868eSSoby Mathew */ 666be868eSSoby Mathew#include <arch.h> 766be868eSSoby Mathew#include <asm_macros.S> 8*7e2bbef9SDaniel Boulby#include <assert_macros.S> 9*7e2bbef9SDaniel Boulby#include <console_macros.S> 1066be868eSSoby Mathew#include <pl011.h> 1166be868eSSoby Mathew 1266be868eSSoby Mathew/* 1366be868eSSoby Mathew * Pull in generic functions to provide backwards compatibility for 1466be868eSSoby Mathew * platform makefiles 1566be868eSSoby Mathew */ 1666be868eSSoby Mathew#include "../../../console/aarch32/console.S" 1766be868eSSoby Mathew 18*7e2bbef9SDaniel Boulby /* 19*7e2bbef9SDaniel Boulby * "core" functions are low-level implementations that don't require 20*7e2bbef9SDaniel Boulby * writeable memory and are thus safe to call in BL1 crash context. 21*7e2bbef9SDaniel Boulby */ 22*7e2bbef9SDaniel Boulby .globl console_pl011_core_init 23*7e2bbef9SDaniel Boulby .globl console_pl011_core_putc 24*7e2bbef9SDaniel Boulby .globl console_pl011_core_getc 25*7e2bbef9SDaniel Boulby .globl console_pl011_core_flush 26*7e2bbef9SDaniel Boulby 27*7e2bbef9SDaniel Boulby .globl console_pl011_putc 28*7e2bbef9SDaniel Boulby .globl console_pl011_getc 29*7e2bbef9SDaniel Boulby .globl console_pl011_flush 3066be868eSSoby Mathew 3166be868eSSoby Mathew 3266be868eSSoby Mathew /* ----------------------------------------------- 3366be868eSSoby Mathew * int console_core_init(uintptr_t base_addr, 3466be868eSSoby Mathew * unsigned int uart_clk, unsigned int baud_rate) 3566be868eSSoby Mathew * Function to initialize the console without a 3666be868eSSoby Mathew * C Runtime to print debug information. This 3766be868eSSoby Mathew * function will be accessed by console_init and 3866be868eSSoby Mathew * crash reporting. 3966be868eSSoby Mathew * In: r0 - console base address 4066be868eSSoby Mathew * r1 - Uart clock in Hz 4166be868eSSoby Mathew * r2 - Baud rate 4266be868eSSoby Mathew * Out: return 1 on success else 0 on error 4366be868eSSoby Mathew * Clobber list : r1, r2, r3 4466be868eSSoby Mathew * ----------------------------------------------- 4566be868eSSoby Mathew */ 46*7e2bbef9SDaniel Boulbyfunc console_pl011_core_init 4766be868eSSoby Mathew /* Check the input base address */ 4866be868eSSoby Mathew cmp r0, #0 4966be868eSSoby Mathew beq core_init_fail 5066be868eSSoby Mathew#if !PL011_GENERIC_UART 5166be868eSSoby Mathew /* Check baud rate and uart clock for sanity */ 5266be868eSSoby Mathew cmp r1, #0 5366be868eSSoby Mathew beq core_init_fail 5466be868eSSoby Mathew cmp r2, #0 5566be868eSSoby Mathew beq core_init_fail 5666be868eSSoby Mathew /* Disable the UART before initialization */ 5766be868eSSoby Mathew ldr r3, [r0, #UARTCR] 5866be868eSSoby Mathew bic r3, r3, #PL011_UARTCR_UARTEN 5966be868eSSoby Mathew str r3, [r0, #UARTCR] 6066be868eSSoby Mathew /* Program the baudrate */ 6166be868eSSoby Mathew /* Divisor = (Uart clock * 4) / baudrate */ 6266be868eSSoby Mathew lsl r1, r1, #2 6366be868eSSoby Mathew udiv r2, r1, r2 6466be868eSSoby Mathew /* IBRD = Divisor >> 6 */ 6566be868eSSoby Mathew lsr r1, r2, #6 6666be868eSSoby Mathew /* Write the IBRD */ 6766be868eSSoby Mathew str r1, [r0, #UARTIBRD] 6866be868eSSoby Mathew /* FBRD = Divisor & 0x3F */ 6966be868eSSoby Mathew and r1, r2, #0x3f 7066be868eSSoby Mathew /* Write the FBRD */ 7166be868eSSoby Mathew str r1, [r0, #UARTFBRD] 7266be868eSSoby Mathew mov r1, #PL011_LINE_CONTROL 7366be868eSSoby Mathew str r1, [r0, #UARTLCR_H] 7466be868eSSoby Mathew /* Clear any pending errors */ 7566be868eSSoby Mathew mov r1, #0 7666be868eSSoby Mathew str r1, [r0, #UARTECR] 7766be868eSSoby Mathew /* Enable tx, rx, and uart overall */ 7866be868eSSoby Mathew ldr r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN) 7966be868eSSoby Mathew str r1, [r0, #UARTCR] 8066be868eSSoby Mathew#endif 8166be868eSSoby Mathew mov r0, #1 8266be868eSSoby Mathew bx lr 8366be868eSSoby Mathewcore_init_fail: 8466be868eSSoby Mathew mov r0, #0 8566be868eSSoby Mathew bx lr 86*7e2bbef9SDaniel Boulbyendfunc console_pl011_core_init 87*7e2bbef9SDaniel Boulby 88*7e2bbef9SDaniel Boulby#if MULTI_CONSOLE_API 89*7e2bbef9SDaniel Boulby .globl console_pl011_register 90*7e2bbef9SDaniel Boulby 91*7e2bbef9SDaniel Boulby /* ------------------------------------------------------- 92*7e2bbef9SDaniel Boulby * init console_pl011_register(console_pl011_t *console, 93*7e2bbef9SDaniel Boulby * uintptr_t base, uint32_t clk, uint32_t baud) 94*7e2bbef9SDaniel Boulby * Function to initialize and register a new PL011 95*7e2bbef9SDaniel Boulby * console. Storage passed in for the console struct 96*7e2bbef9SDaniel Boulby * *must* be persistent (i.e. not from the stack). 97*7e2bbef9SDaniel Boulby * In: r0 - UART register base address 98*7e2bbef9SDaniel Boulby * r1 - UART clock in Hz 99*7e2bbef9SDaniel Boulby * r2 - Baud rate 100*7e2bbef9SDaniel Boulby * r3 - pointer to empty console_pl011_t struct 101*7e2bbef9SDaniel Boulby * Out: return 1 on success, 0 on error 102*7e2bbef9SDaniel Boulby * Clobber list : r0, r1, r2 103*7e2bbef9SDaniel Boulby * ------------------------------------------------------- 104*7e2bbef9SDaniel Boulby */ 105*7e2bbef9SDaniel Boulbyfunc console_pl011_register 106*7e2bbef9SDaniel Boulby push {r4, lr} 107*7e2bbef9SDaniel Boulby mov r4, r3 108*7e2bbef9SDaniel Boulby cmp r4, #0 109*7e2bbef9SDaniel Boulby beq register_fail 110*7e2bbef9SDaniel Boulby str r0, [r4, #CONSOLE_T_PL011_BASE] 111*7e2bbef9SDaniel Boulby 112*7e2bbef9SDaniel Boulby bl console_pl011_core_init 113*7e2bbef9SDaniel Boulby cmp r0, #0 114*7e2bbef9SDaniel Boulby beq register_fail 115*7e2bbef9SDaniel Boulby 116*7e2bbef9SDaniel Boulby mov r0, r4 117*7e2bbef9SDaniel Boulby pop {r4, lr} 118*7e2bbef9SDaniel Boulby finish_console_register pl011 119*7e2bbef9SDaniel Boulby 120*7e2bbef9SDaniel Boulbyregister_fail: 121*7e2bbef9SDaniel Boulby pop {r4, pc} 122*7e2bbef9SDaniel Boulbyendfunc console_pl011_register 123*7e2bbef9SDaniel Boulby#else 124*7e2bbef9SDaniel Boulby .globl console_core_init 125*7e2bbef9SDaniel Boulby .globl console_core_putc 126*7e2bbef9SDaniel Boulby .globl console_core_getc 127*7e2bbef9SDaniel Boulby .globl console_core_flush 128*7e2bbef9SDaniel Boulby .equ console_core_init, console_pl011_core_init 129*7e2bbef9SDaniel Boulby .equ console_core_putc, console_pl011_core_putc 130*7e2bbef9SDaniel Boulby .equ console_core_getc, console_pl011_core_getc 131*7e2bbef9SDaniel Boulby .equ console_core_flush, console_pl011_core_flush 132*7e2bbef9SDaniel Boulby#endif 13366be868eSSoby Mathew 13466be868eSSoby Mathew /* -------------------------------------------------------- 13566be868eSSoby Mathew * int console_core_putc(int c, uintptr_t base_addr) 13666be868eSSoby Mathew * Function to output a character over the console. It 13766be868eSSoby Mathew * returns the character printed on success or -1 on error. 13866be868eSSoby Mathew * In : r0 - character to be printed 13966be868eSSoby Mathew * r1 - console base address 14066be868eSSoby Mathew * Out : return -1 on error else return character. 14166be868eSSoby Mathew * Clobber list : r2 14266be868eSSoby Mathew * -------------------------------------------------------- 14366be868eSSoby Mathew */ 144*7e2bbef9SDaniel Boulbyfunc console_pl011_core_putc 14566be868eSSoby Mathew /* Check the input parameter */ 14666be868eSSoby Mathew cmp r1, #0 14766be868eSSoby Mathew beq putc_error 14866be868eSSoby Mathew /* Prepend '\r' to '\n' */ 14966be868eSSoby Mathew cmp r0, #0xA 15066be868eSSoby Mathew bne 2f 15166be868eSSoby Mathew1: 15266be868eSSoby Mathew /* Check if the transmit FIFO is full */ 15366be868eSSoby Mathew ldr r2, [r1, #UARTFR] 15469d59e0cSYatharth Kochar tst r2, #PL011_UARTFR_TXFF 15569d59e0cSYatharth Kochar bne 1b 15666be868eSSoby Mathew mov r2, #0xD 15766be868eSSoby Mathew str r2, [r1, #UARTDR] 15866be868eSSoby Mathew2: 15966be868eSSoby Mathew /* Check if the transmit FIFO is full */ 16066be868eSSoby Mathew ldr r2, [r1, #UARTFR] 16169d59e0cSYatharth Kochar tst r2, #PL011_UARTFR_TXFF 16269d59e0cSYatharth Kochar bne 2b 16366be868eSSoby Mathew str r0, [r1, #UARTDR] 16466be868eSSoby Mathew bx lr 16566be868eSSoby Mathewputc_error: 16666be868eSSoby Mathew mov r0, #-1 16766be868eSSoby Mathew bx lr 168*7e2bbef9SDaniel Boulbyendfunc console_pl011_core_putc 169*7e2bbef9SDaniel Boulby 170*7e2bbef9SDaniel Boulby /* -------------------------------------------------------- 171*7e2bbef9SDaniel Boulby * int console_pl011_putc(int c, console_pl011_t *console) 172*7e2bbef9SDaniel Boulby * Function to output a character over the console. It 173*7e2bbef9SDaniel Boulby * returns the character printed on success or -1 on error. 174*7e2bbef9SDaniel Boulby * In: r0 - character to be printed 175*7e2bbef9SDaniel Boulby * r1 - pointer to console_t structure 176*7e2bbef9SDaniel Boulby * Out : return -1 on error else return character. 177*7e2bbef9SDaniel Boulby * Clobber list: r2 178*7e2bbef9SDaniel Boulby * ------------------------------------------------------- 179*7e2bbef9SDaniel Boulby */ 180*7e2bbef9SDaniel Boulbyfunc console_pl011_putc 181*7e2bbef9SDaniel Boulby#if ENABLE_ASSERTIONS 182*7e2bbef9SDaniel Boulby cmp r1, #0 183*7e2bbef9SDaniel Boulby ASM_ASSERT(ne) 184*7e2bbef9SDaniel Boulby#endif /* ENABLE_ASSERTIONS */ 185*7e2bbef9SDaniel Boulby ldr r1, [r1, #CONSOLE_T_PL011_BASE] 186*7e2bbef9SDaniel Boulby b console_pl011_core_putc 187*7e2bbef9SDaniel Boulbyendfunc console_pl011_putc 18866be868eSSoby Mathew 18966be868eSSoby Mathew /* --------------------------------------------- 19066be868eSSoby Mathew * int console_core_getc(uintptr_t base_addr) 19166be868eSSoby Mathew * Function to get a character from the console. 19266be868eSSoby Mathew * It returns the character grabbed on success 19366be868eSSoby Mathew * or -1 on error. 19466be868eSSoby Mathew * In : r0 - console base address 19566be868eSSoby Mathew * Clobber list : r0, r1 19666be868eSSoby Mathew * --------------------------------------------- 19766be868eSSoby Mathew */ 198*7e2bbef9SDaniel Boulbyfunc console_pl011_core_getc 19966be868eSSoby Mathew cmp r0, #0 20066be868eSSoby Mathew beq getc_error 20166be868eSSoby Mathew1: 20266be868eSSoby Mathew /* Check if the receive FIFO is empty */ 20366be868eSSoby Mathew ldr r1, [r0, #UARTFR] 20469d59e0cSYatharth Kochar tst r1, #PL011_UARTFR_RXFE 20569d59e0cSYatharth Kochar bne 1b 20666be868eSSoby Mathew ldr r1, [r0, #UARTDR] 20766be868eSSoby Mathew mov r0, r1 20866be868eSSoby Mathew bx lr 20966be868eSSoby Mathewgetc_error: 21066be868eSSoby Mathew mov r0, #-1 21166be868eSSoby Mathew bx lr 212*7e2bbef9SDaniel Boulbyendfunc console_pl011_core_getc 213*7e2bbef9SDaniel Boulby 214*7e2bbef9SDaniel Boulby /* ------------------------------------------------ 215*7e2bbef9SDaniel Boulby * int console_pl011_getc(console_pl011_t *console) 216*7e2bbef9SDaniel Boulby * Function to get a character from the console. 217*7e2bbef9SDaniel Boulby * It returns the character grabbed on success 218*7e2bbef9SDaniel Boulby * or -1 if no character is available. 219*7e2bbef9SDaniel Boulby * In : r0 - pointer to console_t structure 220*7e2bbef9SDaniel Boulby * Out: r0 - character if available, else -1 221*7e2bbef9SDaniel Boulby * Clobber list: r0, r1 222*7e2bbef9SDaniel Boulby * ------------------------------------------------ 223*7e2bbef9SDaniel Boulby */ 224*7e2bbef9SDaniel Boulbyfunc console_pl011_getc 225*7e2bbef9SDaniel Boulby#if ENABLE_ASSERTIONS 226*7e2bbef9SDaniel Boulby cmp r0, #0 227*7e2bbef9SDaniel Boulby ASM_ASSERT(ne) 228*7e2bbef9SDaniel Boulby#endif /* ENABLE_ASSERTIONS */ 229*7e2bbef9SDaniel Boulby ldr r0, [r0, #CONSOLE_T_PL011_BASE] 230*7e2bbef9SDaniel Boulby b console_pl011_core_getc 231*7e2bbef9SDaniel Boulbyendfunc console_pl011_getc 23273e05284SAntonio Nino Diaz 23373e05284SAntonio Nino Diaz /* --------------------------------------------- 23473e05284SAntonio Nino Diaz * int console_core_flush(uintptr_t base_addr) 23573e05284SAntonio Nino Diaz * Function to force a write of all buffered 23673e05284SAntonio Nino Diaz * data that hasn't been output. 23773e05284SAntonio Nino Diaz * In : r0 - console base address 23873e05284SAntonio Nino Diaz * Out : return -1 on error else return 0. 23973e05284SAntonio Nino Diaz * Clobber list : r0, r1 24073e05284SAntonio Nino Diaz * --------------------------------------------- 24173e05284SAntonio Nino Diaz */ 242*7e2bbef9SDaniel Boulbyfunc console_pl011_core_flush 24373e05284SAntonio Nino Diaz cmp r0, #0 24473e05284SAntonio Nino Diaz beq flush_error 24573e05284SAntonio Nino Diaz 24673e05284SAntonio Nino Diaz1: 24773e05284SAntonio Nino Diaz /* Loop while the transmit FIFO is busy */ 24873e05284SAntonio Nino Diaz ldr r1, [r0, #UARTFR] 24973e05284SAntonio Nino Diaz tst r1, #PL011_UARTFR_BUSY 25073e05284SAntonio Nino Diaz bne 1b 25173e05284SAntonio Nino Diaz 25273e05284SAntonio Nino Diaz mov r0, #0 25373e05284SAntonio Nino Diaz bx lr 25473e05284SAntonio Nino Diazflush_error: 25573e05284SAntonio Nino Diaz mov r0, #-1 25673e05284SAntonio Nino Diaz bx lr 257*7e2bbef9SDaniel Boulbyendfunc console_pl011_core_flush 258*7e2bbef9SDaniel Boulby 259*7e2bbef9SDaniel Boulby /* --------------------------------------------- 260*7e2bbef9SDaniel Boulby * int console_pl011_flush(console_pl011_t *console) 261*7e2bbef9SDaniel Boulby * Function to force a write of all buffered 262*7e2bbef9SDaniel Boulby * data that hasn't been output. 263*7e2bbef9SDaniel Boulby * In : r0 - pointer to console_t structure 264*7e2bbef9SDaniel Boulby * Out : return -1 on error else return 0. 265*7e2bbef9SDaniel Boulby * Clobber list: r0, r1 266*7e2bbef9SDaniel Boulby * --------------------------------------------- 267*7e2bbef9SDaniel Boulby */ 268*7e2bbef9SDaniel Boulbyfunc console_pl011_flush 269*7e2bbef9SDaniel Boulby#if ENABLE_ASSERTIONS 270*7e2bbef9SDaniel Boulby cmp r0, #0 271*7e2bbef9SDaniel Boulby ASM_ASSERT(ne) 272*7e2bbef9SDaniel Boulby#endif /* ENABLE_ASSERTIONS */ 273*7e2bbef9SDaniel Boulby ldr r0, [r0, #CONSOLE_T_PL011_BASE] 274*7e2bbef9SDaniel Boulby b console_pl011_core_flush 275*7e2bbef9SDaniel Boulbyendfunc console_pl011_flush 276