1*54fd6939SJiyong Park/* 2*54fd6939SJiyong Park * Copyright (C) 2016 Marvell International Ltd. 3*54fd6939SJiyong Park * 4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause 5*54fd6939SJiyong Park * https://spdx.org/licenses 6*54fd6939SJiyong Park */ 7*54fd6939SJiyong Park 8*54fd6939SJiyong Park#include <arch.h> 9*54fd6939SJiyong Park#include <asm_macros.S> 10*54fd6939SJiyong Park#include <console_macros.S> 11*54fd6939SJiyong Park#include <drivers/marvell/uart/a3700_console.h> 12*54fd6939SJiyong Park 13*54fd6939SJiyong Park /* 14*54fd6939SJiyong Park * "core" functions are low-level implementations that don't require 15*54fd6939SJiyong Park * writable memory and are thus safe to call in BL1 crash context. 16*54fd6939SJiyong Park */ 17*54fd6939SJiyong Park .globl console_a3700_core_putc 18*54fd6939SJiyong Park .globl console_a3700_core_init 19*54fd6939SJiyong Park .globl console_a3700_core_getc 20*54fd6939SJiyong Park .globl console_a3700_core_flush 21*54fd6939SJiyong Park 22*54fd6939SJiyong Park .globl console_a3700_putc 23*54fd6939SJiyong Park .globl console_a3700_getc 24*54fd6939SJiyong Park .globl console_a3700_flush 25*54fd6939SJiyong Park 26*54fd6939SJiyong Park /* ----------------------------------------------- 27*54fd6939SJiyong Park * int console_a3700_core_init(unsigned long base_addr, 28*54fd6939SJiyong Park * unsigned int uart_clk, unsigned int baud_rate) 29*54fd6939SJiyong Park * Function to initialize the console without a 30*54fd6939SJiyong Park * C Runtime to print debug information. This 31*54fd6939SJiyong Park * function will be accessed by console_init and 32*54fd6939SJiyong Park * crash reporting. 33*54fd6939SJiyong Park * In: x0 - console base address 34*54fd6939SJiyong Park * w1 - Uart clock in Hz 35*54fd6939SJiyong Park * w2 - Baud rate 36*54fd6939SJiyong Park * Out: return 1 on success 37*54fd6939SJiyong Park * Clobber list : x1, x2, x3 38*54fd6939SJiyong Park * ----------------------------------------------- 39*54fd6939SJiyong Park */ 40*54fd6939SJiyong Parkfunc console_a3700_core_init 41*54fd6939SJiyong Park /* Check the input base address */ 42*54fd6939SJiyong Park cbz x0, init_fail 43*54fd6939SJiyong Park /* Check baud rate and uart clock for sanity */ 44*54fd6939SJiyong Park cbz w1, init_fail 45*54fd6939SJiyong Park cbz w2, init_fail 46*54fd6939SJiyong Park 47*54fd6939SJiyong Park /* Program the baudrate */ 48*54fd6939SJiyong Park /* Divisor = Round(Uartclock / (16 * baudrate)) */ 49*54fd6939SJiyong Park lsl w2, w2, #4 50*54fd6939SJiyong Park add w1, w1, w2, lsr #1 51*54fd6939SJiyong Park udiv w2, w1, w2 52*54fd6939SJiyong Park and w2, w2, #0x3ff /* clear all other bits to use default clock */ 53*54fd6939SJiyong Park 54*54fd6939SJiyong Park str w2, [x0, #UART_BAUD_REG]/* set baud rate divisor */ 55*54fd6939SJiyong Park 56*54fd6939SJiyong Park /* Set UART to default 16X scheme */ 57*54fd6939SJiyong Park mov w3, #0 58*54fd6939SJiyong Park str w3, [x0, #UART_POSSR_REG] 59*54fd6939SJiyong Park 60*54fd6939SJiyong Park /* 61*54fd6939SJiyong Park * Wait for the TX (THR and TSR) to be empty. If wait for 3ms, the TX FIFO is 62*54fd6939SJiyong Park * still not empty, TX FIFO will reset by all means. 63*54fd6939SJiyong Park */ 64*54fd6939SJiyong Park mov w1, #30 /* max time out 30 * 100 us */ 65*54fd6939SJiyong Park2: 66*54fd6939SJiyong Park /* Check whether TX (THR and TSR) is empty */ 67*54fd6939SJiyong Park ldr w3, [x0, #UART_STATUS_REG] 68*54fd6939SJiyong Park and w3, w3, #UARTLSR_TXEMPTY 69*54fd6939SJiyong Park cmp w3, #0 70*54fd6939SJiyong Park b.ne 4f 71*54fd6939SJiyong Park 72*54fd6939SJiyong Park /* Delay */ 73*54fd6939SJiyong Park mov w2, #60000 /* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */ 74*54fd6939SJiyong Park3: 75*54fd6939SJiyong Park sub w2, w2, #1 76*54fd6939SJiyong Park cmp w2, #0 77*54fd6939SJiyong Park b.ne 3b 78*54fd6939SJiyong Park 79*54fd6939SJiyong Park /* Check whether wait timeout expired */ 80*54fd6939SJiyong Park sub w1, w1, #1 81*54fd6939SJiyong Park cmp w1, #0 82*54fd6939SJiyong Park b.ne 2b 83*54fd6939SJiyong Park 84*54fd6939SJiyong Park4: 85*54fd6939SJiyong Park /* Reset FIFO */ 86*54fd6939SJiyong Park mov w3, #UART_CTRL_RXFIFO_RESET 87*54fd6939SJiyong Park orr w3, w3, #UART_CTRL_TXFIFO_RESET 88*54fd6939SJiyong Park str w3, [x0, #UART_CTRL_REG] 89*54fd6939SJiyong Park 90*54fd6939SJiyong Park /* Delay */ 91*54fd6939SJiyong Park mov w2, #2000 92*54fd6939SJiyong Park1: 93*54fd6939SJiyong Park sub w2, w2, #1 94*54fd6939SJiyong Park cmp w2, #0 95*54fd6939SJiyong Park b.ne 1b 96*54fd6939SJiyong Park 97*54fd6939SJiyong Park /* No Parity, 1 Stop */ 98*54fd6939SJiyong Park mov w3, #0 99*54fd6939SJiyong Park str w3, [x0, #UART_CTRL_REG] 100*54fd6939SJiyong Park 101*54fd6939SJiyong Park mov w0, #1 102*54fd6939SJiyong Park ret 103*54fd6939SJiyong Parkinit_fail: 104*54fd6939SJiyong Park mov w0, #0 105*54fd6939SJiyong Park ret 106*54fd6939SJiyong Parkendfunc console_a3700_core_init 107*54fd6939SJiyong Park 108*54fd6939SJiyong Park .globl console_a3700_register 109*54fd6939SJiyong Park 110*54fd6939SJiyong Park /* ----------------------------------------------- 111*54fd6939SJiyong Park * int console_a3700_register(console_t *console, 112*54fd6939SJiyong Park uintptr_t base, uint32_t clk, uint32_t baud) 113*54fd6939SJiyong Park * Function to initialize and register a new a3700 114*54fd6939SJiyong Park * console. Storage passed in for the console struct 115*54fd6939SJiyong Park * *must* be persistent (i.e. not from the stack). 116*54fd6939SJiyong Park * In: x0 - UART register base address 117*54fd6939SJiyong Park * w1 - UART clock in Hz 118*54fd6939SJiyong Park * w2 - Baud rate 119*54fd6939SJiyong Park * x3 - pointer to empty console_t struct 120*54fd6939SJiyong Park * Out: return 1 on success, 0 on error 121*54fd6939SJiyong Park * Clobber list : x0, x1, x2, x6, x7, x14 122*54fd6939SJiyong Park * ----------------------------------------------- 123*54fd6939SJiyong Park */ 124*54fd6939SJiyong Parkfunc console_a3700_register 125*54fd6939SJiyong Park mov x7, x30 126*54fd6939SJiyong Park mov x6, x3 127*54fd6939SJiyong Park cbz x6, register_fail 128*54fd6939SJiyong Park str x0, [x6, #CONSOLE_T_BASE] 129*54fd6939SJiyong Park 130*54fd6939SJiyong Park bl console_a3700_core_init 131*54fd6939SJiyong Park cbz x0, register_fail 132*54fd6939SJiyong Park 133*54fd6939SJiyong Park mov x0, x6 134*54fd6939SJiyong Park mov x30, x7 135*54fd6939SJiyong Park finish_console_register a3700, putc=1, getc=1, flush=1 136*54fd6939SJiyong Park 137*54fd6939SJiyong Parkregister_fail: 138*54fd6939SJiyong Park ret x7 139*54fd6939SJiyong Parkendfunc console_a3700_register 140*54fd6939SJiyong Park 141*54fd6939SJiyong Park /* -------------------------------------------------------- 142*54fd6939SJiyong Park * int console_a3700_core_putc(int c, unsigned int base_addr) 143*54fd6939SJiyong Park * Function to output a character over the console. It 144*54fd6939SJiyong Park * returns the character printed on success or -1 on error. 145*54fd6939SJiyong Park * In : w0 - character to be printed 146*54fd6939SJiyong Park * x1 - console base address 147*54fd6939SJiyong Park * Out : return -1 on error else return character. 148*54fd6939SJiyong Park * Clobber list : x2 149*54fd6939SJiyong Park * -------------------------------------------------------- 150*54fd6939SJiyong Park */ 151*54fd6939SJiyong Parkfunc console_a3700_core_putc 152*54fd6939SJiyong Park /* Check the input parameter */ 153*54fd6939SJiyong Park cbz x1, putc_error 154*54fd6939SJiyong Park 155*54fd6939SJiyong Park /* Prepend '\r' to '\n' */ 156*54fd6939SJiyong Park cmp w0, #0xA 157*54fd6939SJiyong Park b.ne 2f 158*54fd6939SJiyong Park /* Check if the transmit FIFO is full */ 159*54fd6939SJiyong Park1: ldr w2, [x1, #UART_STATUS_REG] 160*54fd6939SJiyong Park and w2, w2, #UARTLSR_TXFIFOFULL 161*54fd6939SJiyong Park cmp w2, #UARTLSR_TXFIFOFULL 162*54fd6939SJiyong Park b.eq 1b 163*54fd6939SJiyong Park mov w2, #0xD /* '\r' */ 164*54fd6939SJiyong Park str w2, [x1, #UART_TX_REG] 165*54fd6939SJiyong Park 166*54fd6939SJiyong Park /* Check if the transmit FIFO is full */ 167*54fd6939SJiyong Park2: ldr w2, [x1, #UART_STATUS_REG] 168*54fd6939SJiyong Park and w2, w2, #UARTLSR_TXFIFOFULL 169*54fd6939SJiyong Park cmp w2, #UARTLSR_TXFIFOFULL 170*54fd6939SJiyong Park b.eq 2b 171*54fd6939SJiyong Park str w0, [x1, #UART_TX_REG] 172*54fd6939SJiyong Park ret 173*54fd6939SJiyong Parkputc_error: 174*54fd6939SJiyong Park mov w0, #-1 175*54fd6939SJiyong Park ret 176*54fd6939SJiyong Parkendfunc console_a3700_core_putc 177*54fd6939SJiyong Park 178*54fd6939SJiyong Park /* -------------------------------------------------------- 179*54fd6939SJiyong Park * int console_a3700_putc(int c, console_t *console) 180*54fd6939SJiyong Park * Function to output a character over the console. It 181*54fd6939SJiyong Park * returns the character printed on success or -1 on error. 182*54fd6939SJiyong Park * In : w0 - character to be printed 183*54fd6939SJiyong Park * x1 - pointer to console_t structure 184*54fd6939SJiyong Park * Out : return -1 on error else return character. 185*54fd6939SJiyong Park * Clobber list : x2 186*54fd6939SJiyong Park * -------------------------------------------------------- 187*54fd6939SJiyong Park */ 188*54fd6939SJiyong Parkfunc console_a3700_putc 189*54fd6939SJiyong Park ldr x1, [x1, #CONSOLE_T_BASE] 190*54fd6939SJiyong Park b console_a3700_core_putc 191*54fd6939SJiyong Parkendfunc console_a3700_putc 192*54fd6939SJiyong Park 193*54fd6939SJiyong Park /* --------------------------------------------- 194*54fd6939SJiyong Park * int console_a3700_core_getc(void) 195*54fd6939SJiyong Park * Function to get a character from the console. 196*54fd6939SJiyong Park * It returns the character grabbed on success 197*54fd6939SJiyong Park * or -1 if no character is available. 198*54fd6939SJiyong Park * In : w0 - console base address 199*54fd6939SJiyong Park * Out : w0 - character if available, else -1 200*54fd6939SJiyong Park * Clobber list : x0, x1 201*54fd6939SJiyong Park * --------------------------------------------- 202*54fd6939SJiyong Park */ 203*54fd6939SJiyong Parkfunc console_a3700_core_getc 204*54fd6939SJiyong Park /* Check if there is a pending character */ 205*54fd6939SJiyong Park ldr w1, [x0, #UART_STATUS_REG] 206*54fd6939SJiyong Park and w1, w1, #UARTLSR_RXRDY 207*54fd6939SJiyong Park cmp w1, #UARTLSR_RXRDY 208*54fd6939SJiyong Park b.ne getc_no_char 209*54fd6939SJiyong Park ldr w0, [x0, #UART_RX_REG] 210*54fd6939SJiyong Park and w0, w0, #0xff 211*54fd6939SJiyong Park ret 212*54fd6939SJiyong Parkgetc_no_char: 213*54fd6939SJiyong Park mov w0, #ERROR_NO_PENDING_CHAR 214*54fd6939SJiyong Park ret 215*54fd6939SJiyong Parkendfunc console_a3700_core_getc 216*54fd6939SJiyong Park 217*54fd6939SJiyong Park /* --------------------------------------------- 218*54fd6939SJiyong Park * int console_a3700_getc(console_t *console) 219*54fd6939SJiyong Park * Function to get a character from the console. 220*54fd6939SJiyong Park * It returns the character grabbed on success 221*54fd6939SJiyong Park * or -1 on if no character is available. 222*54fd6939SJiyong Park * In : x0 - pointer to console_t structure 223*54fd6939SJiyong Park * Out : w0 - character if available, else -1 224*54fd6939SJiyong Park * Clobber list : x0, x1 225*54fd6939SJiyong Park * --------------------------------------------- 226*54fd6939SJiyong Park */ 227*54fd6939SJiyong Parkfunc console_a3700_getc 228*54fd6939SJiyong Park ldr x0, [x0, #CONSOLE_T_BASE] 229*54fd6939SJiyong Park b console_a3700_core_getc 230*54fd6939SJiyong Parkendfunc console_a3700_getc 231*54fd6939SJiyong Park 232*54fd6939SJiyong Park /* --------------------------------------------- 233*54fd6939SJiyong Park * void console_a3700_core_flush(uintptr_t base_addr) 234*54fd6939SJiyong Park * Function to force a write of all buffered 235*54fd6939SJiyong Park * data that hasn't been output. 236*54fd6939SJiyong Park * In : x0 - console base address 237*54fd6939SJiyong Park * Out : void. 238*54fd6939SJiyong Park * Clobber list : x0, x1 239*54fd6939SJiyong Park * --------------------------------------------- 240*54fd6939SJiyong Park */ 241*54fd6939SJiyong Parkfunc console_a3700_core_flush 242*54fd6939SJiyong Park /* Wait for the TX (THR and TSR) to be empty */ 243*54fd6939SJiyong Park1: ldr w1, [x0, #UART_STATUS_REG] 244*54fd6939SJiyong Park and w1, w1, #UARTLSR_TXEMPTY 245*54fd6939SJiyong Park cmp w1, #UARTLSR_TXEMPTY 246*54fd6939SJiyong Park b.ne 1b 247*54fd6939SJiyong Park ret 248*54fd6939SJiyong Parkendfunc console_a3700_core_flush 249*54fd6939SJiyong Park 250*54fd6939SJiyong Park /* --------------------------------------------- 251*54fd6939SJiyong Park * void console_a3700_flush(console_t *console) 252*54fd6939SJiyong Park * Function to force a write of all buffered 253*54fd6939SJiyong Park * data that hasn't been output. 254*54fd6939SJiyong Park * In : x0 - pointer to console_t structure 255*54fd6939SJiyong Park * Out : void. 256*54fd6939SJiyong Park * Clobber list : x0, x1 257*54fd6939SJiyong Park * --------------------------------------------- 258*54fd6939SJiyong Park */ 259*54fd6939SJiyong Parkfunc console_a3700_flush 260*54fd6939SJiyong Park ldr x0, [x0, #CONSOLE_T_BASE] 261*54fd6939SJiyong Park b console_a3700_core_flush 262*54fd6939SJiyong Parkendfunc console_a3700_flush 263*54fd6939SJiyong Park 264