1*24bb7516Swangwen /* 2*24bb7516Swangwen * Copyright (C) 2017 Marvell International Ltd. 3*24bb7516Swangwen * All rights reserved. 4*24bb7516Swangwen * 5*24bb7516Swangwen * Redistribution and use in source and binary forms, with or without 6*24bb7516Swangwen * modification, are permitted provided that the following conditions are met: 7*24bb7516Swangwen * 8*24bb7516Swangwen * 1. Redistributions of source code must retain the above copyright notice, 9*24bb7516Swangwen * this list of conditions and the following disclaimer. 10*24bb7516Swangwen * 11*24bb7516Swangwen * 2. Redistributions in binary form must reproduce the above copyright notice, 12*24bb7516Swangwen * this list of conditions and the following disclaimer in the documentation 13*24bb7516Swangwen * and/or other materials provided with the distribution. 14*24bb7516Swangwen * 15*24bb7516Swangwen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16*24bb7516Swangwen * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*24bb7516Swangwen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*24bb7516Swangwen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19*24bb7516Swangwen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*24bb7516Swangwen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*24bb7516Swangwen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*24bb7516Swangwen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*24bb7516Swangwen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*24bb7516Swangwen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*24bb7516Swangwen * POSSIBILITY OF SUCH DAMAGE. 26*24bb7516Swangwen */ 27*24bb7516Swangwen #include <assert.h> 28*24bb7516Swangwen #include <drivers/mvebu_uart.h> 29*24bb7516Swangwen #include <io.h> 30*24bb7516Swangwen #include <keep.h> 31*24bb7516Swangwen #include <kernel/dt.h> 32*24bb7516Swangwen #include <stdlib.h> 33*24bb7516Swangwen #include <trace.h> 34*24bb7516Swangwen #include <types_ext.h> 35*24bb7516Swangwen #include <util.h> 36*24bb7516Swangwen 37*24bb7516Swangwen /* MVEBU UART Registers */ 38*24bb7516Swangwen #define UART_RX_REG 0x00 39*24bb7516Swangwen #define UART_TX_REG 0x04 40*24bb7516Swangwen #define UART_CTRL_REG 0x08 41*24bb7516Swangwen #define UART_STATUS_REG 0x0c 42*24bb7516Swangwen #define UART_BAUD_REG 0x10 43*24bb7516Swangwen #define UART_POSSR_REG 0x14 44*24bb7516Swangwen 45*24bb7516Swangwen /* Line Status Register bits */ 46*24bb7516Swangwen #define UARTLSR_TXFIFOFULL (1 << 11) /* Tx Fifo Full */ 47*24bb7516Swangwen #define UARTLSR_TXFIFOEMPTY (1 << 13) 48*24bb7516Swangwen #define UARTLSR_TXEMPTY (1 << 6) 49*24bb7516Swangwen #define UART_RX_READY (1 << 4) 50*24bb7516Swangwen 51*24bb7516Swangwen /* UART Control Register bits */ 52*24bb7516Swangwen #define UART_CTRL_RXFIFO_RESET (1 << 14) 53*24bb7516Swangwen #define UART_CTRL_TXFIFO_RESET (1 << 15) 54*24bb7516Swangwen 55*24bb7516Swangwen static vaddr_t chip_to_base(struct serial_chip *chip) 56*24bb7516Swangwen { 57*24bb7516Swangwen struct mvebu_uart_data *pd = 58*24bb7516Swangwen container_of(chip, struct mvebu_uart_data, chip); 59*24bb7516Swangwen 60*24bb7516Swangwen return io_pa_or_va(&pd->base); 61*24bb7516Swangwen } 62*24bb7516Swangwen 63*24bb7516Swangwen static void mvebu_uart_flush(struct serial_chip *chip) 64*24bb7516Swangwen { 65*24bb7516Swangwen vaddr_t base = chip_to_base(chip); 66*24bb7516Swangwen 67*24bb7516Swangwen /* 68*24bb7516Swangwen * Wait for the transmit FIFO to be empty. 69*24bb7516Swangwen * It can happen that Linux initializes the OP-TEE driver with the 70*24bb7516Swangwen * console UART disabled; avoid an infinite loop by checking the UART 71*24bb7516Swangwen * enabled flag. Checking it in the loop makes the code safe against 72*24bb7516Swangwen * asynchronous disable. 73*24bb7516Swangwen */ 74*24bb7516Swangwen while (!(read32(base + UART_STATUS_REG) & UARTLSR_TXFIFOEMPTY)) 75*24bb7516Swangwen ; 76*24bb7516Swangwen } 77*24bb7516Swangwen 78*24bb7516Swangwen static bool mvebu_uart_have_rx_data(struct serial_chip *chip) 79*24bb7516Swangwen { 80*24bb7516Swangwen vaddr_t base = chip_to_base(chip); 81*24bb7516Swangwen 82*24bb7516Swangwen return (read32(base + UART_STATUS_REG) & UART_RX_READY); 83*24bb7516Swangwen } 84*24bb7516Swangwen 85*24bb7516Swangwen static int mvebu_uart_getchar(struct serial_chip *chip) 86*24bb7516Swangwen { 87*24bb7516Swangwen vaddr_t base = chip_to_base(chip); 88*24bb7516Swangwen 89*24bb7516Swangwen while (!mvebu_uart_have_rx_data(chip)) 90*24bb7516Swangwen ; 91*24bb7516Swangwen return read32(base + UART_RX_REG) & 0xff; 92*24bb7516Swangwen } 93*24bb7516Swangwen 94*24bb7516Swangwen static void mvebu_uart_putc(struct serial_chip *chip, int ch) 95*24bb7516Swangwen { 96*24bb7516Swangwen vaddr_t base = chip_to_base(chip); 97*24bb7516Swangwen 98*24bb7516Swangwen uint32_t tmp; 99*24bb7516Swangwen /* wait for space in tx FIFO */ 100*24bb7516Swangwen do { 101*24bb7516Swangwen tmp = read32(base + UART_STATUS_REG); 102*24bb7516Swangwen tmp &= UARTLSR_TXFIFOFULL; 103*24bb7516Swangwen } while (tmp == UARTLSR_TXFIFOFULL); 104*24bb7516Swangwen 105*24bb7516Swangwen write32(ch, base + UART_TX_REG); 106*24bb7516Swangwen } 107*24bb7516Swangwen 108*24bb7516Swangwen static const struct serial_ops mvebu_uart_ops = { 109*24bb7516Swangwen .flush = mvebu_uart_flush, 110*24bb7516Swangwen .getchar = mvebu_uart_getchar, 111*24bb7516Swangwen .have_rx_data = mvebu_uart_have_rx_data, 112*24bb7516Swangwen .putc = mvebu_uart_putc, 113*24bb7516Swangwen }; 114*24bb7516Swangwen KEEP_PAGER(mvebu_uart_ops); 115*24bb7516Swangwen 116*24bb7516Swangwen void mvebu_uart_init(struct mvebu_uart_data *pd, paddr_t pbase, 117*24bb7516Swangwen uint32_t uart_clk, uint32_t baud_rate) 118*24bb7516Swangwen { 119*24bb7516Swangwen vaddr_t base; 120*24bb7516Swangwen uint32_t tmp = 0; 121*24bb7516Swangwen uint32_t dll = 0; 122*24bb7516Swangwen 123*24bb7516Swangwen pd->base.pa = pbase; 124*24bb7516Swangwen pd->chip.ops = &mvebu_uart_ops; 125*24bb7516Swangwen 126*24bb7516Swangwen base = io_pa_or_va(&pd->base); 127*24bb7516Swangwen 128*24bb7516Swangwen dll = (uart_clk / (baud_rate << 4)) & 0x3FF; 129*24bb7516Swangwen 130*24bb7516Swangwen /* init UART */ 131*24bb7516Swangwen tmp = read32(base + UART_BAUD_REG); 132*24bb7516Swangwen tmp &= ~0x3FF; 133*24bb7516Swangwen tmp |= dll; 134*24bb7516Swangwen write32(tmp, base + UART_BAUD_REG); /* set baud rate divisor */ 135*24bb7516Swangwen 136*24bb7516Swangwen /* set UART to default 16x scheme */ 137*24bb7516Swangwen write32(0, base + UART_POSSR_REG); 138*24bb7516Swangwen 139*24bb7516Swangwen /* reset FIFO */ 140*24bb7516Swangwen write32((UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET), 141*24bb7516Swangwen base + UART_CTRL_REG); 142*24bb7516Swangwen 143*24bb7516Swangwen /* No Parity, 1 stop */ 144*24bb7516Swangwen write32(0, base + UART_CTRL_REG); 145*24bb7516Swangwen 146*24bb7516Swangwen mvebu_uart_flush(&pd->chip); 147*24bb7516Swangwen } 148