1*4a079c75SCarlo Caione/* 2*4a079c75SCarlo Caione * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. 3*4a079c75SCarlo Caione * 4*4a079c75SCarlo Caione * SPDX-License-Identifier: BSD-3-Clause 5*4a079c75SCarlo Caione */ 6*4a079c75SCarlo Caione 7*4a079c75SCarlo Caione#include <asm_macros.S> 8*4a079c75SCarlo Caione#include <assert_macros.S> 9*4a079c75SCarlo Caione#include <console_macros.S> 10*4a079c75SCarlo Caione#include <drivers/amlogic/meson_console.h> 11*4a079c75SCarlo Caione 12*4a079c75SCarlo Caione .globl console_meson_register 13*4a079c75SCarlo Caione .globl console_meson_init 14*4a079c75SCarlo Caione .globl console_meson_putc 15*4a079c75SCarlo Caione .globl console_meson_getc 16*4a079c75SCarlo Caione .globl console_meson_flush 17*4a079c75SCarlo Caione .globl console_meson_core_putc 18*4a079c75SCarlo Caione .globl console_meson_core_getc 19*4a079c75SCarlo Caione .globl console_meson_core_flush 20*4a079c75SCarlo Caione 21*4a079c75SCarlo Caione /* ----------------------------------------------- 22*4a079c75SCarlo Caione * Hardware definitions 23*4a079c75SCarlo Caione * ----------------------------------------------- 24*4a079c75SCarlo Caione */ 25*4a079c75SCarlo Caione#define MESON_WFIFO_OFFSET 0x0 26*4a079c75SCarlo Caione#define MESON_RFIFO_OFFSET 0x4 27*4a079c75SCarlo Caione#define MESON_CONTROL_OFFSET 0x8 28*4a079c75SCarlo Caione#define MESON_STATUS_OFFSET 0xC 29*4a079c75SCarlo Caione#define MESON_MISC_OFFSET 0x10 30*4a079c75SCarlo Caione#define MESON_REG5_OFFSET 0x14 31*4a079c75SCarlo Caione 32*4a079c75SCarlo Caione#define MESON_CONTROL_CLR_ERROR_BIT 24 33*4a079c75SCarlo Caione#define MESON_CONTROL_RX_RESET_BIT 23 34*4a079c75SCarlo Caione#define MESON_CONTROL_TX_RESET_BIT 22 35*4a079c75SCarlo Caione#define MESON_CONTROL_RX_ENABLE_BIT 13 36*4a079c75SCarlo Caione#define MESON_CONTROL_TX_ENABLE_BIT 12 37*4a079c75SCarlo Caione 38*4a079c75SCarlo Caione#define MESON_STATUS_RX_EMPTY_BIT 20 39*4a079c75SCarlo Caione#define MESON_STATUS_TX_FULL_BIT 21 40*4a079c75SCarlo Caione#define MESON_STATUS_TX_EMPTY_BIT 22 41*4a079c75SCarlo Caione 42*4a079c75SCarlo Caione#define MESON_REG5_USE_XTAL_CLK_BIT 24 43*4a079c75SCarlo Caione#define MESON_REG5_USE_NEW_RATE_BIT 23 44*4a079c75SCarlo Caione#define MESON_REG5_NEW_BAUD_RATE_MASK 0x7FFFFF 45*4a079c75SCarlo Caione 46*4a079c75SCarlo Caione /* ----------------------------------------------- 47*4a079c75SCarlo Caione * int console_meson_register(uintptr_t base, 48*4a079c75SCarlo Caione * uint32_t clk, uint32_t baud, 49*4a079c75SCarlo Caione * console_meson_t *console); 50*4a079c75SCarlo Caione * Function to initialize and register a new MESON 51*4a079c75SCarlo Caione * console. Storage passed in for the console struct 52*4a079c75SCarlo Caione * *must* be persistent (i.e. not from the stack). 53*4a079c75SCarlo Caione * In: x0 - UART register base address 54*4a079c75SCarlo Caione * w1 - UART clock in Hz 55*4a079c75SCarlo Caione * w2 - Baud rate 56*4a079c75SCarlo Caione * x3 - pointer to empty console_meson_t struct 57*4a079c75SCarlo Caione * Out: return 1 on success, 0 on error 58*4a079c75SCarlo Caione * Clobber list : x0, x1, x2, x6, x7, x14 59*4a079c75SCarlo Caione * ----------------------------------------------- 60*4a079c75SCarlo Caione */ 61*4a079c75SCarlo Caionefunc console_meson_register 62*4a079c75SCarlo Caione mov x7, x30 63*4a079c75SCarlo Caione mov x6, x3 64*4a079c75SCarlo Caione cbz x6, register_fail 65*4a079c75SCarlo Caione str x0, [x6, #CONSOLE_T_MESON_BASE] 66*4a079c75SCarlo Caione 67*4a079c75SCarlo Caione bl console_meson_init 68*4a079c75SCarlo Caione cbz x0, register_fail 69*4a079c75SCarlo Caione 70*4a079c75SCarlo Caione mov x0, x6 71*4a079c75SCarlo Caione mov x30, x7 72*4a079c75SCarlo Caione finish_console_register meson putc=1, getc=1, flush=1 73*4a079c75SCarlo Caione 74*4a079c75SCarlo Caioneregister_fail: 75*4a079c75SCarlo Caione ret x7 76*4a079c75SCarlo Caioneendfunc console_meson_register 77*4a079c75SCarlo Caione 78*4a079c75SCarlo Caione /* ----------------------------------------------- 79*4a079c75SCarlo Caione * int console_meson_init(uintptr_t base_addr, 80*4a079c75SCarlo Caione * unsigned int uart_clk, unsigned int baud_rate) 81*4a079c75SCarlo Caione * Function to initialize the console without a 82*4a079c75SCarlo Caione * C Runtime to print debug information. This 83*4a079c75SCarlo Caione * function will be accessed by console_init and 84*4a079c75SCarlo Caione * crash reporting. 85*4a079c75SCarlo Caione * In: x0 - console base address 86*4a079c75SCarlo Caione * w1 - Uart clock in Hz 87*4a079c75SCarlo Caione * w2 - Baud rate 88*4a079c75SCarlo Caione * Out: return 1 on success else 0 on error 89*4a079c75SCarlo Caione * Clobber list : x0-x3 90*4a079c75SCarlo Caione * ----------------------------------------------- 91*4a079c75SCarlo Caione */ 92*4a079c75SCarlo Caionefunc console_meson_init 93*4a079c75SCarlo Caione cmp w0, #0 94*4a079c75SCarlo Caione beq init_fail 95*4a079c75SCarlo Caione mov_imm w3, 24000000 /* TODO: This only works with a 24 MHz clock. */ 96*4a079c75SCarlo Caione cmp w1, w3 97*4a079c75SCarlo Caione bne init_fail 98*4a079c75SCarlo Caione cmp w2, #0 99*4a079c75SCarlo Caione beq init_fail 100*4a079c75SCarlo Caione /* Set baud rate: value = ((clock / 3) / baudrate) - 1 */ 101*4a079c75SCarlo Caione mov w3, #3 102*4a079c75SCarlo Caione udiv w3, w1, w3 103*4a079c75SCarlo Caione udiv w3, w3, w2 104*4a079c75SCarlo Caione sub w3, w3, #1 105*4a079c75SCarlo Caione orr w3, w3, #((1 << MESON_REG5_USE_XTAL_CLK_BIT) | \ 106*4a079c75SCarlo Caione (1 << MESON_REG5_USE_NEW_RATE_BIT)) 107*4a079c75SCarlo Caione str w3, [x0, #MESON_REG5_OFFSET] 108*4a079c75SCarlo Caione /* Reset UART and clear error flag */ 109*4a079c75SCarlo Caione ldr w3, [x0, #MESON_CONTROL_OFFSET] 110*4a079c75SCarlo Caione orr w3, w3, #((1 << MESON_CONTROL_CLR_ERROR_BIT) | \ 111*4a079c75SCarlo Caione (1 << MESON_CONTROL_RX_RESET_BIT) | \ 112*4a079c75SCarlo Caione (1 << MESON_CONTROL_TX_RESET_BIT)) 113*4a079c75SCarlo Caione str w3, [x0, #MESON_CONTROL_OFFSET] 114*4a079c75SCarlo Caione bic w3, w3, #((1 << MESON_CONTROL_CLR_ERROR_BIT) | \ 115*4a079c75SCarlo Caione (1 << MESON_CONTROL_RX_RESET_BIT) | \ 116*4a079c75SCarlo Caione (1 << MESON_CONTROL_TX_RESET_BIT)) 117*4a079c75SCarlo Caione str w3, [x0, #MESON_CONTROL_OFFSET] 118*4a079c75SCarlo Caione /* Enable transfer and receive FIFO */ 119*4a079c75SCarlo Caione orr w3, w3, #((1 << MESON_CONTROL_RX_ENABLE_BIT) | \ 120*4a079c75SCarlo Caione (1 << MESON_CONTROL_TX_ENABLE_BIT)) 121*4a079c75SCarlo Caione str w3, [x0, #MESON_CONTROL_OFFSET] 122*4a079c75SCarlo Caione /* Success */ 123*4a079c75SCarlo Caione mov w0, #1 124*4a079c75SCarlo Caione ret 125*4a079c75SCarlo Caioneinit_fail: 126*4a079c75SCarlo Caione mov w0, wzr 127*4a079c75SCarlo Caione ret 128*4a079c75SCarlo Caioneendfunc console_meson_init 129*4a079c75SCarlo Caione 130*4a079c75SCarlo Caione /* -------------------------------------------------------- 131*4a079c75SCarlo Caione * int console_meson_putc(int c, console_meson_t *console) 132*4a079c75SCarlo Caione * Function to output a character over the console. It 133*4a079c75SCarlo Caione * returns the character printed on success or -1 on error. 134*4a079c75SCarlo Caione * In : w0 - character to be printed 135*4a079c75SCarlo Caione * x1 - pointer to console_t structure 136*4a079c75SCarlo Caione * Out : return -1 on error else return character. 137*4a079c75SCarlo Caione * Clobber list : x2 138*4a079c75SCarlo Caione * -------------------------------------------------------- 139*4a079c75SCarlo Caione */ 140*4a079c75SCarlo Caionefunc console_meson_putc 141*4a079c75SCarlo Caione#if ENABLE_ASSERTIONS 142*4a079c75SCarlo Caione cmp x1, #0 143*4a079c75SCarlo Caione ASM_ASSERT(ne) 144*4a079c75SCarlo Caione#endif /* ENABLE_ASSERTIONS */ 145*4a079c75SCarlo Caione ldr x1, [x1, #CONSOLE_T_MESON_BASE] 146*4a079c75SCarlo Caione b console_meson_core_putc 147*4a079c75SCarlo Caioneendfunc console_meson_putc 148*4a079c75SCarlo Caione 149*4a079c75SCarlo Caione /* -------------------------------------------------------- 150*4a079c75SCarlo Caione * int console_meson_core_putc(int c, uintptr_t base_addr) 151*4a079c75SCarlo Caione * Function to output a character over the console. It 152*4a079c75SCarlo Caione * returns the character printed on success or -1 on error. 153*4a079c75SCarlo Caione * In : w0 - character to be printed 154*4a079c75SCarlo Caione * x1 - console base address 155*4a079c75SCarlo Caione * Out : return -1 on error else return character. 156*4a079c75SCarlo Caione * Clobber list : x2 157*4a079c75SCarlo Caione * -------------------------------------------------------- 158*4a079c75SCarlo Caione */ 159*4a079c75SCarlo Caionefunc console_meson_core_putc 160*4a079c75SCarlo Caione#if ENABLE_ASSERTIONS 161*4a079c75SCarlo Caione cmp x1, #0 162*4a079c75SCarlo Caione ASM_ASSERT(ne) 163*4a079c75SCarlo Caione#endif 164*4a079c75SCarlo Caione /* Prepend '\r' to '\n' */ 165*4a079c75SCarlo Caione cmp w0, #0xA 166*4a079c75SCarlo Caione b.ne 2f 167*4a079c75SCarlo Caione /* Wait until the transmit FIFO isn't full */ 168*4a079c75SCarlo Caione1: ldr w2, [x1, #MESON_STATUS_OFFSET] 169*4a079c75SCarlo Caione tbnz w2, #MESON_STATUS_TX_FULL_BIT, 1b 170*4a079c75SCarlo Caione /* Write '\r' if needed */ 171*4a079c75SCarlo Caione mov w2, #0xD 172*4a079c75SCarlo Caione str w2, [x1, #MESON_WFIFO_OFFSET] 173*4a079c75SCarlo Caione /* Wait until the transmit FIFO isn't full */ 174*4a079c75SCarlo Caione2: ldr w2, [x1, #MESON_STATUS_OFFSET] 175*4a079c75SCarlo Caione tbnz w2, #MESON_STATUS_TX_FULL_BIT, 2b 176*4a079c75SCarlo Caione /* Write input character */ 177*4a079c75SCarlo Caione str w0, [x1, #MESON_WFIFO_OFFSET] 178*4a079c75SCarlo Caione ret 179*4a079c75SCarlo Caioneendfunc console_meson_core_putc 180*4a079c75SCarlo Caione 181*4a079c75SCarlo Caione /* --------------------------------------------- 182*4a079c75SCarlo Caione * int console_meson_getc(console_meson_t *console) 183*4a079c75SCarlo Caione * Function to get a character from the console. 184*4a079c75SCarlo Caione * It returns the character grabbed on success 185*4a079c75SCarlo Caione * or -1 if no character is available. 186*4a079c75SCarlo Caione * In : x0 - pointer to console_t structure 187*4a079c75SCarlo Caione * Out: w0 - character if available, else -1 188*4a079c75SCarlo Caione * Clobber list : x0, x1 189*4a079c75SCarlo Caione * --------------------------------------------- 190*4a079c75SCarlo Caione */ 191*4a079c75SCarlo Caionefunc console_meson_getc 192*4a079c75SCarlo Caione#if ENABLE_ASSERTIONS 193*4a079c75SCarlo Caione cmp x0, #0 194*4a079c75SCarlo Caione ASM_ASSERT(ne) 195*4a079c75SCarlo Caione#endif /* ENABLE_ASSERTIONS */ 196*4a079c75SCarlo Caione ldr x0, [x0, #CONSOLE_T_MESON_BASE] 197*4a079c75SCarlo Caione b console_meson_core_getc 198*4a079c75SCarlo Caioneendfunc console_meson_getc 199*4a079c75SCarlo Caione 200*4a079c75SCarlo Caione /* --------------------------------------------- 201*4a079c75SCarlo Caione * int console_meson_core_getc(uintptr_t base_addr) 202*4a079c75SCarlo Caione * Function to get a character from the console. 203*4a079c75SCarlo Caione * It returns the character grabbed on success 204*4a079c75SCarlo Caione * or -1 if no character is available. 205*4a079c75SCarlo Caione * In : x0 - console base address 206*4a079c75SCarlo Caione * Out: w0 - character if available, else -1 207*4a079c75SCarlo Caione * Clobber list : x0, x1 208*4a079c75SCarlo Caione * --------------------------------------------- 209*4a079c75SCarlo Caione */ 210*4a079c75SCarlo Caionefunc console_meson_core_getc 211*4a079c75SCarlo Caione#if ENABLE_ASSERTIONS 212*4a079c75SCarlo Caione cmp x0, #0 213*4a079c75SCarlo Caione ASM_ASSERT(ne) 214*4a079c75SCarlo Caione#endif 215*4a079c75SCarlo Caione /* Is the receive FIFO empty? */ 216*4a079c75SCarlo Caione ldr w1, [x0, #MESON_STATUS_OFFSET] 217*4a079c75SCarlo Caione tbnz w1, #MESON_STATUS_RX_EMPTY_BIT, 1f 218*4a079c75SCarlo Caione /* Read one character from the RX FIFO */ 219*4a079c75SCarlo Caione ldr w0, [x0, #MESON_RFIFO_OFFSET] 220*4a079c75SCarlo Caione ret 221*4a079c75SCarlo Caione1: 222*4a079c75SCarlo Caione mov w0, #ERROR_NO_PENDING_CHAR 223*4a079c75SCarlo Caione ret 224*4a079c75SCarlo Caioneendfunc console_meson_core_getc 225*4a079c75SCarlo Caione 226*4a079c75SCarlo Caione /* --------------------------------------------- 227*4a079c75SCarlo Caione * int console_meson_flush(console_meson_t *console) 228*4a079c75SCarlo Caione * Function to force a write of all buffered 229*4a079c75SCarlo Caione * data that hasn't been output. 230*4a079c75SCarlo Caione * In : x0 - pointer to console_t structure 231*4a079c75SCarlo Caione * Out : return -1 on error else return 0. 232*4a079c75SCarlo Caione * Clobber list : x0, x1 233*4a079c75SCarlo Caione * --------------------------------------------- 234*4a079c75SCarlo Caione */ 235*4a079c75SCarlo Caionefunc console_meson_flush 236*4a079c75SCarlo Caione#if ENABLE_ASSERTIONS 237*4a079c75SCarlo Caione cmp x0, #0 238*4a079c75SCarlo Caione ASM_ASSERT(ne) 239*4a079c75SCarlo Caione#endif /* ENABLE_ASSERTIONS */ 240*4a079c75SCarlo Caione ldr x0, [x0, #CONSOLE_T_MESON_BASE] 241*4a079c75SCarlo Caione b console_meson_core_flush 242*4a079c75SCarlo Caioneendfunc console_meson_flush 243*4a079c75SCarlo Caione 244*4a079c75SCarlo Caione /* --------------------------------------------- 245*4a079c75SCarlo Caione * int console_meson_core_flush(uintptr_t base_addr) 246*4a079c75SCarlo Caione * Function to force a write of all buffered 247*4a079c75SCarlo Caione * data that hasn't been output. 248*4a079c75SCarlo Caione * In : x0 - console base address 249*4a079c75SCarlo Caione * Out : return -1 on error else return 0. 250*4a079c75SCarlo Caione * Clobber list : x0, x1 251*4a079c75SCarlo Caione * --------------------------------------------- 252*4a079c75SCarlo Caione */ 253*4a079c75SCarlo Caionefunc console_meson_core_flush 254*4a079c75SCarlo Caione#if ENABLE_ASSERTIONS 255*4a079c75SCarlo Caione cmp x0, #0 256*4a079c75SCarlo Caione ASM_ASSERT(ne) 257*4a079c75SCarlo Caione#endif 258*4a079c75SCarlo Caione /* Wait until the transmit FIFO is empty */ 259*4a079c75SCarlo Caione1: ldr w1, [x0, #MESON_STATUS_OFFSET] 260*4a079c75SCarlo Caione tbz w1, #MESON_STATUS_TX_EMPTY_BIT, 1b 261*4a079c75SCarlo Caione mov w0, #0 262*4a079c75SCarlo Caione ret 263*4a079c75SCarlo Caioneendfunc console_meson_core_flush 264