1598cee48SBryan O'Donoghue /* 2598cee48SBryan O'Donoghue * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. 3598cee48SBryan O'Donoghue * 4598cee48SBryan O'Donoghue * SPDX-License-Identifier: BSD-3-Clause 5598cee48SBryan O'Donoghue */ 609d40e0eSAntonio Nino Diaz 7598cee48SBryan O'Donoghue #include <stdint.h> 809d40e0eSAntonio Nino Diaz 9598cee48SBryan O'Donoghue #include <platform_def.h> 1009d40e0eSAntonio Nino Diaz 1109d40e0eSAntonio Nino Diaz #include <arch.h> 1209d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 1309d40e0eSAntonio Nino Diaz 14598cee48SBryan O'Donoghue #include <imx_uart.h> 15598cee48SBryan O'Donoghue 16598cee48SBryan O'Donoghue /* TX/RX FIFO threshold */ 17598cee48SBryan O'Donoghue #define TX_RX_THRESH 2 18598cee48SBryan O'Donoghue 19598cee48SBryan O'Donoghue struct clk_div_factors { 20598cee48SBryan O'Donoghue uint32_t fcr_div; 21598cee48SBryan O'Donoghue uint32_t bmr_div; 22598cee48SBryan O'Donoghue }; 23598cee48SBryan O'Donoghue 24598cee48SBryan O'Donoghue static struct clk_div_factors clk_div[] = { 25598cee48SBryan O'Donoghue { 26598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV1, 27598cee48SBryan O'Donoghue .bmr_div = 1, 28598cee48SBryan O'Donoghue }, 29598cee48SBryan O'Donoghue { 30598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV2, 31598cee48SBryan O'Donoghue .bmr_div = 2, 32598cee48SBryan O'Donoghue }, 33598cee48SBryan O'Donoghue { 34598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV3, 35598cee48SBryan O'Donoghue .bmr_div = 3, 36598cee48SBryan O'Donoghue }, 37598cee48SBryan O'Donoghue { 38598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV4, 39598cee48SBryan O'Donoghue .bmr_div = 4, 40598cee48SBryan O'Donoghue }, 41598cee48SBryan O'Donoghue { 42598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV5, 43598cee48SBryan O'Donoghue .bmr_div = 5, 44598cee48SBryan O'Donoghue }, 45598cee48SBryan O'Donoghue { 46598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV6, 47598cee48SBryan O'Donoghue .bmr_div = 6, 48598cee48SBryan O'Donoghue }, 49598cee48SBryan O'Donoghue { 50598cee48SBryan O'Donoghue .fcr_div = IMX_UART_FCR_RFDIV7, 51598cee48SBryan O'Donoghue .bmr_div = 7, 52598cee48SBryan O'Donoghue }, 53598cee48SBryan O'Donoghue }; 54598cee48SBryan O'Donoghue 55598cee48SBryan O'Donoghue static void write_reg(uintptr_t base, uint32_t offset, uint32_t val) 56598cee48SBryan O'Donoghue { 57598cee48SBryan O'Donoghue mmio_write_32(base + offset, val); 58598cee48SBryan O'Donoghue } 59598cee48SBryan O'Donoghue 60598cee48SBryan O'Donoghue static uint32_t read_reg(uintptr_t base, uint32_t offset) 61598cee48SBryan O'Donoghue { 62598cee48SBryan O'Donoghue return mmio_read_32(base + offset); 63598cee48SBryan O'Donoghue } 64598cee48SBryan O'Donoghue 6570086dc4SYing-Chun Liu (PaulLiu) int console_imx_uart_core_init(uintptr_t base_addr, unsigned int uart_clk, 66598cee48SBryan O'Donoghue unsigned int baud_rate) 67598cee48SBryan O'Donoghue { 68598cee48SBryan O'Donoghue uint32_t val; 69598cee48SBryan O'Donoghue uint8_t clk_idx = 1; 70598cee48SBryan O'Donoghue 71598cee48SBryan O'Donoghue /* Reset UART */ 72598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR2_OFFSET, 0); 73598cee48SBryan O'Donoghue do { 74598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_CR2_OFFSET); 75598cee48SBryan O'Donoghue } while (!(val & IMX_UART_CR2_SRST)); 76598cee48SBryan O'Donoghue 77598cee48SBryan O'Donoghue /* Enable UART */ 78598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN); 79598cee48SBryan O'Donoghue 80598cee48SBryan O'Donoghue /* Ignore RTS, 8N1, enable tx/rx, disable reset */ 81598cee48SBryan O'Donoghue val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | 82598cee48SBryan O'Donoghue IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST); 83598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR2_OFFSET, val); 84598cee48SBryan O'Donoghue 85598cee48SBryan O'Donoghue /* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */ 86598cee48SBryan O'Donoghue val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL; 87598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR3_OFFSET, val); 88598cee48SBryan O'Donoghue 89598cee48SBryan O'Donoghue /* Set CTS FIFO trigger to 32 bytes bits 15:10 */ 90598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000); 91598cee48SBryan O'Donoghue 92598cee48SBryan O'Donoghue /* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */ 93598cee48SBryan O'Donoghue val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | 94598cee48SBryan O'Donoghue clk_div[clk_idx].fcr_div; 95598cee48SBryan O'Donoghue #ifdef IMX_UART_DTE 96598cee48SBryan O'Donoghue /* Set DTE (bit6 = 1) */ 97598cee48SBryan O'Donoghue val |= IMX_UART_FCR_DCEDTE; 98598cee48SBryan O'Donoghue #endif 99598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_FCR_OFFSET, val); 100598cee48SBryan O'Donoghue 101598cee48SBryan O'Donoghue /* 102598cee48SBryan O'Donoghue * The equation for BAUD rate calculation is 103598cee48SBryan O'Donoghue * RefClk = Supplied clock / FCR_DIVx 104598cee48SBryan O'Donoghue * 105598cee48SBryan O'Donoghue * BAUD = Refclk 106598cee48SBryan O'Donoghue * ------------ 107598cee48SBryan O'Donoghue * 16 x (UBMR + 1/ UBIR + 1) 108598cee48SBryan O'Donoghue * 109598cee48SBryan O'Donoghue * We write 0x0f into UBIR to remove the 16 mult 110598cee48SBryan O'Donoghue * BAUD = 6000000 111598cee48SBryan O'Donoghue * ------------ 112598cee48SBryan O'Donoghue * 16 x (UBMR + 1/ 15 + 1) 113598cee48SBryan O'Donoghue */ 114598cee48SBryan O'Donoghue 115598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f); 116598cee48SBryan O'Donoghue val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1; 117598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_BMR_OFFSET, val); 118598cee48SBryan O'Donoghue 119598cee48SBryan O'Donoghue return 0; 120598cee48SBryan O'Donoghue } 121598cee48SBryan O'Donoghue 122598cee48SBryan O'Donoghue /* -------------------------------------------------------- 123598cee48SBryan O'Donoghue * int console_core_putc(int c, uintptr_t base_addr) 124598cee48SBryan O'Donoghue * Function to output a character over the console. It 125598cee48SBryan O'Donoghue * returns the character printed on success or -1 on error. 126598cee48SBryan O'Donoghue * In : r0 - character to be printed 127598cee48SBryan O'Donoghue * r1 - console base address 128598cee48SBryan O'Donoghue * Out : return -1 on error else return character. 129598cee48SBryan O'Donoghue * Clobber list : r2 130598cee48SBryan O'Donoghue * -------------------------------------------------------- 131598cee48SBryan O'Donoghue */ 13270086dc4SYing-Chun Liu (PaulLiu) int console_imx_uart_core_putc(int c, uintptr_t base_addr) 133598cee48SBryan O'Donoghue { 134598cee48SBryan O'Donoghue uint32_t val; 135598cee48SBryan O'Donoghue 136598cee48SBryan O'Donoghue if (c == '\n') 13770086dc4SYing-Chun Liu (PaulLiu) console_imx_uart_core_putc('\r', base_addr); 138598cee48SBryan O'Donoghue 139598cee48SBryan O'Donoghue /* Write data */ 140598cee48SBryan O'Donoghue write_reg(base_addr, IMX_UART_TXD_OFFSET, c); 141598cee48SBryan O'Donoghue 142598cee48SBryan O'Donoghue /* Wait for transmit */ 143598cee48SBryan O'Donoghue do { 144598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_STAT2_OFFSET); 145598cee48SBryan O'Donoghue } while (!(val & IMX_UART_STAT2_TXDC)); 146598cee48SBryan O'Donoghue 147598cee48SBryan O'Donoghue return 0; 148598cee48SBryan O'Donoghue } 149598cee48SBryan O'Donoghue 150598cee48SBryan O'Donoghue /* 151598cee48SBryan O'Donoghue * Function to get a character from the console. 152598cee48SBryan O'Donoghue * It returns the character grabbed on success 153598cee48SBryan O'Donoghue * or -1 on error. 154598cee48SBryan O'Donoghue * In : r0 - console base address 155598cee48SBryan O'Donoghue * Clobber list : r0, r1 156598cee48SBryan O'Donoghue * --------------------------------------------- 157598cee48SBryan O'Donoghue */ 15870086dc4SYing-Chun Liu (PaulLiu) int console_imx_uart_core_getc(uintptr_t base_addr) 159598cee48SBryan O'Donoghue { 160598cee48SBryan O'Donoghue uint32_t val; 161598cee48SBryan O'Donoghue 162598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_TS_OFFSET); 163598cee48SBryan O'Donoghue if (val & IMX_UART_TS_RXEMPTY) 164598cee48SBryan O'Donoghue return -1; 165598cee48SBryan O'Donoghue 166598cee48SBryan O'Donoghue val = read_reg(base_addr, IMX_UART_RXD_OFFSET); 167598cee48SBryan O'Donoghue return (int)(val & 0x000000FF); 168598cee48SBryan O'Donoghue } 169598cee48SBryan O'Donoghue 170598cee48SBryan O'Donoghue /* 171598cee48SBryan O'Donoghue * Function to force a write of all buffered 172598cee48SBryan O'Donoghue * data that hasn't been output. 173598cee48SBryan O'Donoghue * In : r0 - console base address 174*831b0e98SJimmy Brisson * Out : void 175598cee48SBryan O'Donoghue * Clobber list : r0, r1 176598cee48SBryan O'Donoghue * --------------------------------------------- 177598cee48SBryan O'Donoghue */ 178*831b0e98SJimmy Brisson void console_imx_uart_core_flush(uintptr_t base_addr) 179598cee48SBryan O'Donoghue { 180598cee48SBryan O'Donoghue } 181598cee48SBryan O'Donoghue 182