diff options
Diffstat (limited to 'plat/socionext/uniphier/uniphier_console.S')
-rw-r--r-- | plat/socionext/uniphier/uniphier_console.S | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/plat/socionext/uniphier/uniphier_console.S b/plat/socionext/uniphier/uniphier_console.S new file mode 100644 index 00000000..03aff483 --- /dev/null +++ b/plat/socionext/uniphier/uniphier_console.S @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> + +#define UNIPHIER_UART_BASE 0x54006800 +#define UNIPHIER_UART_END 0x54006c00 +#define UNIPHIER_UART_OFFSET 0x100 + +#define UNIPHIER_UART_RX 0x00 /* In: Receive buffer */ +#define UNIPHIER_UART_TX 0x00 /* Out: Transmit buffer */ + +#define UNIPHIER_UART_FCR 0x0c /* Char/FIFO Control Register */ +#define UNIPHIER_UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ + +#define UNIPHIER_UART_LCR_MCR 0x10 /* Line/Modem Control Register */ +#define UNIPHIER_UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ +#define UNIPHIER_UART_LSR 0x14 /* Line Status Register */ +#define UNIPHIER_UART_LSR_TEMT_BIT 6 /* Transmitter empty */ +#define UNIPHIER_UART_LSR_THRE_BIT 5 /* Transmit-hold-register empty */ +#define UNIPHIER_UART_LSR_DR_BIT 0 /* Receiver data ready */ +#define UNIPHIER_UART_DLR 0x24 /* Divisor Latch Register */ + +/* + * Uncomment for debug + */ +/* #define UNIPHIER_UART_INIT_DIVISOR */ +#define UNIPHIER_UART_DEFAULT_BASE (UNIPHIER_UART_BASE) +#define UNIPHIER_UART_CLK_RATE 58820000 +#define UNIPHIER_UART_DEFAULT_BAUDRATE 115200 + +/* + * In: x0 - console base address + * w1 - uart clock in Hz + * w2 - baud rate + * Out: return 1 on success, or 0 on error + */ + .globl console_core_init +func console_core_init + cbz x0, 1f +#ifdef UNIPHIER_UART_INIT_DIVISOR + cbz w1, 1f + cbz w2, 1f + /* divisor = uart_clock / (16 * baud_rate) */ + udiv w2, w1, w2 + lsr w2, w2, #4 +#endif + /* Make sure the transmitter is empty before the divisor set/change */ +0: ldr w1, [x0, #UNIPHIER_UART_LSR] + tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b +#ifdef UNIPHIER_UART_INIT_DIVISOR + str w2, [x0, #UNIPHIER_UART_DLR] +#endif + mov w2, #UNIPHIER_UART_FCR_ENABLE_FIFO + str w2, [x0, #UNIPHIER_UART_FCR] + + mov w2, #(UNIPHIER_UART_LCR_WLEN8 << 8) + str w2, [x0, #UNIPHIER_UART_LCR_MCR] + + mov w0, #1 + ret +1: mov w0, #0 + ret +endfunc console_core_init + +/* + * In: w0 - character to be printed + * x1 - console base address + * Out: return the character written, or -1 on error + * Clobber: x2 + */ + .globl console_core_putc +func console_core_putc + /* Error out if the console is not initialized */ + cbz x1, 2f + + /* Wait until the transmitter FIFO gets empty */ +0: ldr w2, [x1, #UNIPHIER_UART_LSR] + tbz w2, #UNIPHIER_UART_LSR_THRE_BIT, 0b + + mov w2, w0 + +1: str w2, [x1, #UNIPHIER_UART_TX] + + cmp w2, #'\n' + b.ne 3f + mov w2, #'\r' /* Append '\r' to '\n' */ + b 1b +2: mov w0, #-1 +3: ret +endfunc console_core_putc + +/* + * In: x0 - console base address + * Out: return the character read + * Clobber: x1 + */ + .globl console_core_getc +func console_core_getc + /* Error out if the console is not initialized */ + cbz x0, 1f + + /* Wait while the receiver FIFO is empty */ +0: ldr w1, [x0, #UNIPHIER_UART_LSR] + tbz w1, #UNIPHIER_UART_LSR_DR_BIT, 0b + + ldr w0, [x0, #UNIPHIER_UART_RX] + + ret +1: mov w0, #-1 + ret +endfunc console_core_getc + +/* + * In: x0 - console base address + * Out: return 0, or -1 on error + * Clobber: x1 + */ + .global console_core_flush +func console_core_flush + /* Error out if the console is not initialized */ + cbz x0, 1f + + /* wait until the transmitter gets empty */ +0: ldr w1, [x0, #UNIPHIER_UART_LSR] + tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b + + mov w0, #0 + ret +1: mov w0, #-1 + ret +endfunc console_core_flush + +/* find initialized UART port */ +.macro uniphier_console_get_base base, tmpx, tmpw + ldr \base, =UNIPHIER_UART_BASE +0000: ldr \tmpw, [\base, #UNIPHIER_UART_DLR] + mvn \tmpw, \tmpw + uxth \tmpw, \tmpw + cbnz \tmpw, 0001f + add \base, \base, #UNIPHIER_UART_OFFSET + ldr \tmpx, =UNIPHIER_UART_END + cmp \base, \tmpx + b.lo 0000b + mov \base, #0 +0001: +.endm + +/* + * int plat_crash_console_init(void) + * Clobber: x0-x2 + */ + .globl plat_crash_console_init +func plat_crash_console_init +#ifdef UNIPHIER_UART_INIT_DIVISOR + ldr x0, =UNIPHIER_UART_DEFAULT_BASE + ldr x1, =UNIPHIER_UART_CLK_RATE + ldr x2, =UNIPHIER_UART_DEFAULT_BAUDRATE + b console_core_init +#else + ret +#endif +endfunc plat_crash_console_init + +/* + * int plat_crash_console_putc(int c) + * Clobber: x1, x2 + */ + .globl plat_crash_console_putc +func plat_crash_console_putc +#ifdef UNIPHIER_UART_INIT_DIVISOR + ldr x1, =UNIPHIER_UART_DEFAULT_BASE +#else + uniphier_console_get_base x1, x2, w2 +#endif + b console_core_putc +endfunc plat_crash_console_putc + +/* + * int plat_crash_console_flush(void) + * Clobber: x0, x1 + */ + .global plat_crash_console_flush +func plat_crash_console_flush +#ifdef UNIPHIER_UART_INIT_DIVISOR + ldr x0, =UNIPHIER_UART_DEFAULT_BASE +#else + uniphier_console_get_base x0, x1, w1 +#endif + b console_core_flush +endfunc plat_crash_console_flush + +/* + * void uniphier_console_setup(void) + * Clobber: x0-x2 + */ + .globl uniphier_console_setup +func uniphier_console_setup +#ifdef UNIPHIER_UART_INIT_DIVISOR + ldr x0, =UNIPHIER_UART_DEFAULT_BASE + ldr w1, =UNIPHIER_UART_CLK_RATE + ldr w2, =UNIPHIER_UART_DEFAULT_BAUDRATE +#else + uniphier_console_get_base x0, x1, w1 + mov w1, #0 + mov w2, #0 +#endif + b console_init +endfunc uniphier_console_setup |