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