11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 224bb7516Swangwen /* 324bb7516Swangwen * Copyright (C) 2017 Marvell International Ltd. 424bb7516Swangwen * All rights reserved. 524bb7516Swangwen * 624bb7516Swangwen * Redistribution and use in source and binary forms, with or without 724bb7516Swangwen * modification, are permitted provided that the following conditions are met: 824bb7516Swangwen * 924bb7516Swangwen * 1. Redistributions of source code must retain the above copyright notice, 1024bb7516Swangwen * this list of conditions and the following disclaimer. 1124bb7516Swangwen * 1224bb7516Swangwen * 2. Redistributions in binary form must reproduce the above copyright notice, 1324bb7516Swangwen * this list of conditions and the following disclaimer in the documentation 1424bb7516Swangwen * and/or other materials provided with the distribution. 1524bb7516Swangwen * 1624bb7516Swangwen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1724bb7516Swangwen * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1824bb7516Swangwen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1924bb7516Swangwen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2024bb7516Swangwen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2124bb7516Swangwen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2224bb7516Swangwen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2324bb7516Swangwen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2424bb7516Swangwen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2524bb7516Swangwen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2624bb7516Swangwen * POSSIBILITY OF SUCH DAMAGE. 2724bb7516Swangwen */ 2824bb7516Swangwen #include <assert.h> 2924bb7516Swangwen #include <drivers/mvebu_uart.h> 3024bb7516Swangwen #include <io.h> 3124bb7516Swangwen #include <keep.h> 3224bb7516Swangwen #include <kernel/dt.h> 3324bb7516Swangwen #include <stdlib.h> 3424bb7516Swangwen #include <trace.h> 3524bb7516Swangwen #include <types_ext.h> 3624bb7516Swangwen #include <util.h> 3724bb7516Swangwen 3824bb7516Swangwen /* MVEBU UART Registers */ 3924bb7516Swangwen #define UART_RX_REG 0x00 4024bb7516Swangwen #define UART_TX_REG 0x04 4124bb7516Swangwen #define UART_CTRL_REG 0x08 4224bb7516Swangwen #define UART_STATUS_REG 0x0c 4324bb7516Swangwen #define UART_BAUD_REG 0x10 4424bb7516Swangwen #define UART_POSSR_REG 0x14 4524bb7516Swangwen 4624bb7516Swangwen /* Line Status Register bits */ 4724bb7516Swangwen #define UARTLSR_TXFIFOFULL (1 << 11) /* Tx Fifo Full */ 4824bb7516Swangwen #define UARTLSR_TXFIFOEMPTY (1 << 13) 4924bb7516Swangwen #define UARTLSR_TXEMPTY (1 << 6) 5024bb7516Swangwen #define UART_RX_READY (1 << 4) 5124bb7516Swangwen 5224bb7516Swangwen /* UART Control Register bits */ 5324bb7516Swangwen #define UART_CTRL_RXFIFO_RESET (1 << 14) 5424bb7516Swangwen #define UART_CTRL_TXFIFO_RESET (1 << 15) 5524bb7516Swangwen 5624bb7516Swangwen static vaddr_t chip_to_base(struct serial_chip *chip) 5724bb7516Swangwen { 5824bb7516Swangwen struct mvebu_uart_data *pd = 5924bb7516Swangwen container_of(chip, struct mvebu_uart_data, chip); 6024bb7516Swangwen 6124bb7516Swangwen return io_pa_or_va(&pd->base); 6224bb7516Swangwen } 6324bb7516Swangwen 6424bb7516Swangwen static void mvebu_uart_flush(struct serial_chip *chip) 6524bb7516Swangwen { 6624bb7516Swangwen vaddr_t base = chip_to_base(chip); 6724bb7516Swangwen 6824bb7516Swangwen /* 6924bb7516Swangwen * Wait for the transmit FIFO to be empty. 7024bb7516Swangwen * It can happen that Linux initializes the OP-TEE driver with the 7124bb7516Swangwen * console UART disabled; avoid an infinite loop by checking the UART 7224bb7516Swangwen * enabled flag. Checking it in the loop makes the code safe against 7324bb7516Swangwen * asynchronous disable. 7424bb7516Swangwen */ 75*918bb3a5SEtienne Carriere while (!(io_read32(base + UART_STATUS_REG) & UARTLSR_TXFIFOEMPTY)) 7624bb7516Swangwen ; 7724bb7516Swangwen } 7824bb7516Swangwen 7924bb7516Swangwen static bool mvebu_uart_have_rx_data(struct serial_chip *chip) 8024bb7516Swangwen { 8124bb7516Swangwen vaddr_t base = chip_to_base(chip); 8224bb7516Swangwen 83*918bb3a5SEtienne Carriere return (io_read32(base + UART_STATUS_REG) & UART_RX_READY); 8424bb7516Swangwen } 8524bb7516Swangwen 8624bb7516Swangwen static int mvebu_uart_getchar(struct serial_chip *chip) 8724bb7516Swangwen { 8824bb7516Swangwen vaddr_t base = chip_to_base(chip); 8924bb7516Swangwen 9024bb7516Swangwen while (!mvebu_uart_have_rx_data(chip)) 9124bb7516Swangwen ; 92*918bb3a5SEtienne Carriere return io_read32(base + UART_RX_REG) & 0xff; 9324bb7516Swangwen } 9424bb7516Swangwen 9524bb7516Swangwen static void mvebu_uart_putc(struct serial_chip *chip, int ch) 9624bb7516Swangwen { 9724bb7516Swangwen vaddr_t base = chip_to_base(chip); 9824bb7516Swangwen 9924bb7516Swangwen uint32_t tmp; 10024bb7516Swangwen /* wait for space in tx FIFO */ 10124bb7516Swangwen do { 102*918bb3a5SEtienne Carriere tmp = io_read32(base + UART_STATUS_REG); 10324bb7516Swangwen tmp &= UARTLSR_TXFIFOFULL; 10424bb7516Swangwen } while (tmp == UARTLSR_TXFIFOFULL); 10524bb7516Swangwen 106*918bb3a5SEtienne Carriere io_write32(base + UART_TX_REG, ch); 10724bb7516Swangwen } 10824bb7516Swangwen 10924bb7516Swangwen static const struct serial_ops mvebu_uart_ops = { 11024bb7516Swangwen .flush = mvebu_uart_flush, 11124bb7516Swangwen .getchar = mvebu_uart_getchar, 11224bb7516Swangwen .have_rx_data = mvebu_uart_have_rx_data, 11324bb7516Swangwen .putc = mvebu_uart_putc, 11424bb7516Swangwen }; 11524bb7516Swangwen KEEP_PAGER(mvebu_uart_ops); 11624bb7516Swangwen 11724bb7516Swangwen void mvebu_uart_init(struct mvebu_uart_data *pd, paddr_t pbase, 11824bb7516Swangwen uint32_t uart_clk, uint32_t baud_rate) 11924bb7516Swangwen { 12024bb7516Swangwen vaddr_t base; 12124bb7516Swangwen uint32_t dll = 0; 12224bb7516Swangwen 12324bb7516Swangwen pd->base.pa = pbase; 12424bb7516Swangwen pd->chip.ops = &mvebu_uart_ops; 12524bb7516Swangwen 12624bb7516Swangwen base = io_pa_or_va(&pd->base); 12724bb7516Swangwen 12824bb7516Swangwen dll = (uart_clk / (baud_rate << 4)) & 0x3FF; 12924bb7516Swangwen 13024bb7516Swangwen /* init UART */ 131*918bb3a5SEtienne Carriere io_clrsetbits32(base + UART_BAUD_REG, 0x3FF, dll); 13224bb7516Swangwen 13324bb7516Swangwen /* set UART to default 16x scheme */ 134*918bb3a5SEtienne Carriere io_write32(base + UART_POSSR_REG, 0); 13524bb7516Swangwen 13624bb7516Swangwen /* reset FIFO */ 137*918bb3a5SEtienne Carriere io_write32(base + UART_CTRL_REG, 138*918bb3a5SEtienne Carriere UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET); 13924bb7516Swangwen 14024bb7516Swangwen /* No Parity, 1 stop */ 141*918bb3a5SEtienne Carriere io_write32(base + UART_CTRL_REG, 0); 14224bb7516Swangwen 14324bb7516Swangwen mvebu_uart_flush(&pd->chip); 14424bb7516Swangwen } 145