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