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