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 46 /* Line Status Register bits */ 47 #define UARTLSR_TXFIFOFULL (1 << 11) /* Tx Fifo Full */ 48 #define UARTLSR_TXFIFOEMPTY (1 << 13) 49 #define UARTLSR_TXEMPTY (1 << 6) 50 #define UART_RX_READY (1 << 4) 51 52 /* UART Control Register bits */ 53 #define UART_CTRL_RXFIFO_RESET (1 << 14) 54 #define UART_CTRL_TXFIFO_RESET (1 << 15) 55 56 static vaddr_t chip_to_base(struct serial_chip *chip) 57 { 58 struct mvebu_uart_data *pd = 59 container_of(chip, struct mvebu_uart_data, chip); 60 61 return io_pa_or_va(&pd->base); 62 } 63 64 static void mvebu_uart_flush(struct serial_chip *chip) 65 { 66 vaddr_t base = chip_to_base(chip); 67 68 /* 69 * Wait for the transmit FIFO to be empty. 70 * It can happen that Linux initializes the OP-TEE driver with the 71 * console UART disabled; avoid an infinite loop by checking the UART 72 * enabled flag. Checking it in the loop makes the code safe against 73 * asynchronous disable. 74 */ 75 while (!(read32(base + UART_STATUS_REG) & UARTLSR_TXFIFOEMPTY)) 76 ; 77 } 78 79 static bool mvebu_uart_have_rx_data(struct serial_chip *chip) 80 { 81 vaddr_t base = chip_to_base(chip); 82 83 return (read32(base + UART_STATUS_REG) & UART_RX_READY); 84 } 85 86 static int mvebu_uart_getchar(struct serial_chip *chip) 87 { 88 vaddr_t base = chip_to_base(chip); 89 90 while (!mvebu_uart_have_rx_data(chip)) 91 ; 92 return read32(base + UART_RX_REG) & 0xff; 93 } 94 95 static void mvebu_uart_putc(struct serial_chip *chip, int ch) 96 { 97 vaddr_t base = chip_to_base(chip); 98 99 uint32_t tmp; 100 /* wait for space in tx FIFO */ 101 do { 102 tmp = read32(base + UART_STATUS_REG); 103 tmp &= UARTLSR_TXFIFOFULL; 104 } while (tmp == UARTLSR_TXFIFOFULL); 105 106 write32(ch, base + UART_TX_REG); 107 } 108 109 static const struct serial_ops mvebu_uart_ops = { 110 .flush = mvebu_uart_flush, 111 .getchar = mvebu_uart_getchar, 112 .have_rx_data = mvebu_uart_have_rx_data, 113 .putc = mvebu_uart_putc, 114 }; 115 KEEP_PAGER(mvebu_uart_ops); 116 117 void mvebu_uart_init(struct mvebu_uart_data *pd, paddr_t pbase, 118 uint32_t uart_clk, uint32_t baud_rate) 119 { 120 vaddr_t base; 121 uint32_t tmp = 0; 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); 128 129 dll = (uart_clk / (baud_rate << 4)) & 0x3FF; 130 131 /* init UART */ 132 tmp = read32(base + UART_BAUD_REG); 133 tmp &= ~0x3FF; 134 tmp |= dll; 135 write32(tmp, base + UART_BAUD_REG); /* set baud rate divisor */ 136 137 /* set UART to default 16x scheme */ 138 write32(0, base + UART_POSSR_REG); 139 140 /* reset FIFO */ 141 write32((UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET), 142 base + UART_CTRL_REG); 143 144 /* No Parity, 1 stop */ 145 write32(0, base + UART_CTRL_REG); 146 147 mvebu_uart_flush(&pd->chip); 148 } 149