1*598cee48SBryan O'Donoghue /* 2*598cee48SBryan O'Donoghue * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. 3*598cee48SBryan O'Donoghue * 4*598cee48SBryan O'Donoghue * SPDX-License-Identifier: BSD-3-Clause 5*598cee48SBryan O'Donoghue */ 6*598cee48SBryan O'Donoghue #include <arch.h> 7*598cee48SBryan O'Donoghue #include <stdint.h> 8*598cee48SBryan O'Donoghue #include <mmio.h> 9*598cee48SBryan O'Donoghue #include <platform_def.h> 10*598cee48SBryan O'Donoghue #include <imx_uart.h> 11*598cee48SBryan O'Donoghue 12*598cee48SBryan O'Donoghue /* TX/RX FIFO threshold */ 13*598cee48SBryan O'Donoghue #define TX_RX_THRESH 2 14*598cee48SBryan O'Donoghue 15*598cee48SBryan O'Donoghue struct clk_div_factors { 16*598cee48SBryan O'Donoghue uint32_t fcr_div; 17*598cee48SBryan O'Donoghue uint32_t bmr_div; 18*598cee48SBryan O'Donoghue }; 19*598cee48SBryan O'Donoghue 20*598cee48SBryan O'Donoghue static struct clk_div_factors clk_div[] = { 21*598cee48SBryan O'Donoghue { 22*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV1, 23*598cee48SBryan O'Donoghue .bmr_div = 1, 24*598cee48SBryan O'Donoghue }, 25*598cee48SBryan O'Donoghue { 26*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV2, 27*598cee48SBryan O'Donoghue .bmr_div = 2, 28*598cee48SBryan O'Donoghue }, 29*598cee48SBryan O'Donoghue { 30*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV3, 31*598cee48SBryan O'Donoghue .bmr_div = 3, 32*598cee48SBryan O'Donoghue }, 33*598cee48SBryan O'Donoghue { 34*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV4, 35*598cee48SBryan O'Donoghue .bmr_div = 4, 36*598cee48SBryan O'Donoghue }, 37*598cee48SBryan O'Donoghue { 38*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV5, 39*598cee48SBryan O'Donoghue .bmr_div = 5, 40*598cee48SBryan O'Donoghue }, 41*598cee48SBryan O'Donoghue { 42*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV6, 43*598cee48SBryan O'Donoghue .bmr_div = 6, 44*598cee48SBryan O'Donoghue }, 45*598cee48SBryan O'Donoghue { 46*598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV7, 47*598cee48SBryan O'Donoghue .bmr_div = 7, 48*598cee48SBryan O'Donoghue }, 49*598cee48SBryan O'Donoghue }; 50*598cee48SBryan O'Donoghue 51*598cee48SBryan O'Donoghue static void write_reg(uintptr_t base, uint32_t offset, uint32_t val) 52*598cee48SBryan O'Donoghue { 53*598cee48SBryan O'Donoghue mmio_write_32(base + offset, val); 54*598cee48SBryan O'Donoghue } 55*598cee48SBryan O'Donoghue 56*598cee48SBryan O'Donoghue static uint32_t read_reg(uintptr_t base, uint32_t offset) 57*598cee48SBryan O'Donoghue { 58*598cee48SBryan O'Donoghue return mmio_read_32(base + offset); 59*598cee48SBryan O'Donoghue } 60*598cee48SBryan O'Donoghue 61*598cee48SBryan O'Donoghue int console_core_init(uintptr_t base_addr, unsigned int uart_clk, 62*598cee48SBryan O'Donoghue unsigned int baud_rate) 63*598cee48SBryan O'Donoghue { 64*598cee48SBryan O'Donoghue uint32_t val; 65*598cee48SBryan O'Donoghue uint8_t clk_idx = 1; 66*598cee48SBryan O'Donoghue 67*598cee48SBryan O'Donoghue /* Reset UART */ 68*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR2_OFFSET, 0); 69*598cee48SBryan O'Donoghue do { 70*598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_CR2_OFFSET); 71*598cee48SBryan O'Donoghue } while (!(val & IMX_UART_CR2_SRST)); 72*598cee48SBryan O'Donoghue 73*598cee48SBryan O'Donoghue /* Enable UART */ 74*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN); 75*598cee48SBryan O'Donoghue 76*598cee48SBryan O'Donoghue /* Ignore RTS, 8N1, enable tx/rx, disable reset */ 77*598cee48SBryan O'Donoghue val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | 78*598cee48SBryan O'Donoghue IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST); 79*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR2_OFFSET, val); 80*598cee48SBryan O'Donoghue 81*598cee48SBryan O'Donoghue /* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */ 82*598cee48SBryan O'Donoghue val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL; 83*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR3_OFFSET, val); 84*598cee48SBryan O'Donoghue 85*598cee48SBryan O'Donoghue /* Set CTS FIFO trigger to 32 bytes bits 15:10 */ 86*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000); 87*598cee48SBryan O'Donoghue 88*598cee48SBryan O'Donoghue /* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */ 89*598cee48SBryan O'Donoghue val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | 90*598cee48SBryan O'Donoghue clk_div[clk_idx].fcr_div; 91*598cee48SBryan O'Donoghue #ifdef IMX_UART_DTE 92*598cee48SBryan O'Donoghue /* Set DTE (bit6 = 1) */ 93*598cee48SBryan O'Donoghue val |= IMX_UART_FCR_DCEDTE; 94*598cee48SBryan O'Donoghue #endif 95*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_FCR_OFFSET, val); 96*598cee48SBryan O'Donoghue 97*598cee48SBryan O'Donoghue /* 98*598cee48SBryan O'Donoghue * The equation for BAUD rate calculation is 99*598cee48SBryan O'Donoghue * RefClk = Supplied clock / FCR_DIVx 100*598cee48SBryan O'Donoghue * 101*598cee48SBryan O'Donoghue * BAUD = Refclk 102*598cee48SBryan O'Donoghue * ------------ 103*598cee48SBryan O'Donoghue * 16 x (UBMR + 1/ UBIR + 1) 104*598cee48SBryan O'Donoghue * 105*598cee48SBryan O'Donoghue * We write 0x0f into UBIR to remove the 16 mult 106*598cee48SBryan O'Donoghue * BAUD = 6000000 107*598cee48SBryan O'Donoghue * ------------ 108*598cee48SBryan O'Donoghue * 16 x (UBMR + 1/ 15 + 1) 109*598cee48SBryan O'Donoghue */ 110*598cee48SBryan O'Donoghue 111*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f); 112*598cee48SBryan O'Donoghue val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1; 113*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_BMR_OFFSET, val); 114*598cee48SBryan O'Donoghue 115*598cee48SBryan O'Donoghue return 0; 116*598cee48SBryan O'Donoghue } 117*598cee48SBryan O'Donoghue 118*598cee48SBryan O'Donoghue /* -------------------------------------------------------- 119*598cee48SBryan O'Donoghue * int console_core_putc(int c, uintptr_t base_addr) 120*598cee48SBryan O'Donoghue * Function to output a character over the console. It 121*598cee48SBryan O'Donoghue * returns the character printed on success or -1 on error. 122*598cee48SBryan O'Donoghue * In : r0 - character to be printed 123*598cee48SBryan O'Donoghue * r1 - console base address 124*598cee48SBryan O'Donoghue * Out : return -1 on error else return character. 125*598cee48SBryan O'Donoghue * Clobber list : r2 126*598cee48SBryan O'Donoghue * -------------------------------------------------------- 127*598cee48SBryan O'Donoghue */ 128*598cee48SBryan O'Donoghue int console_core_putc(int c, uintptr_t base_addr) 129*598cee48SBryan O'Donoghue { 130*598cee48SBryan O'Donoghue uint32_t val; 131*598cee48SBryan O'Donoghue 132*598cee48SBryan O'Donoghue if (c == '\n') 133*598cee48SBryan O'Donoghue console_core_putc('\r', base_addr); 134*598cee48SBryan O'Donoghue 135*598cee48SBryan O'Donoghue /* Write data */ 136*598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_TXD_OFFSET, c); 137*598cee48SBryan O'Donoghue 138*598cee48SBryan O'Donoghue /* Wait for transmit */ 139*598cee48SBryan O'Donoghue do { 140*598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_STAT2_OFFSET); 141*598cee48SBryan O'Donoghue } while (!(val & IMX_UART_STAT2_TXDC)); 142*598cee48SBryan O'Donoghue 143*598cee48SBryan O'Donoghue return 0; 144*598cee48SBryan O'Donoghue } 145*598cee48SBryan O'Donoghue 146*598cee48SBryan O'Donoghue /* 147*598cee48SBryan O'Donoghue * Function to get a character from the console. 148*598cee48SBryan O'Donoghue * It returns the character grabbed on success 149*598cee48SBryan O'Donoghue * or -1 on error. 150*598cee48SBryan O'Donoghue * In : r0 - console base address 151*598cee48SBryan O'Donoghue * Clobber list : r0, r1 152*598cee48SBryan O'Donoghue * --------------------------------------------- 153*598cee48SBryan O'Donoghue */ 154*598cee48SBryan O'Donoghue int console_core_getc(uintptr_t base_addr) 155*598cee48SBryan O'Donoghue { 156*598cee48SBryan O'Donoghue uint32_t val; 157*598cee48SBryan O'Donoghue 158*598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_TS_OFFSET); 159*598cee48SBryan O'Donoghue if (val & IMX_UART_TS_RXEMPTY) 160*598cee48SBryan O'Donoghue return -1; 161*598cee48SBryan O'Donoghue 162*598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_RXD_OFFSET); 163*598cee48SBryan O'Donoghue return (int)(val & 0x000000FF); 164*598cee48SBryan O'Donoghue } 165*598cee48SBryan O'Donoghue 166*598cee48SBryan O'Donoghue /* 167*598cee48SBryan O'Donoghue * Function to force a write of all buffered 168*598cee48SBryan O'Donoghue * data that hasn't been output. 169*598cee48SBryan O'Donoghue * In : r0 - console base address 170*598cee48SBryan O'Donoghue * Out : return -1 on error else return 0. 171*598cee48SBryan O'Donoghue * Clobber list : r0, r1 172*598cee48SBryan O'Donoghue * --------------------------------------------- 173*598cee48SBryan O'Donoghue */ 174*598cee48SBryan O'Donoghue int console_core_flush(uintptr_t base_addr) 175*598cee48SBryan O'Donoghue { 176*598cee48SBryan O'Donoghue return 0; 177*598cee48SBryan O'Donoghue } 178*598cee48SBryan O'Donoghue 179