xref: /optee_os/core/drivers/mvebu_uart.c (revision c2e4eb43b7b7211345cd38ceceac97773bd78d2c)
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
45*c2e4eb43SAnton Rybakov #define UART_SIZE		0x18
4624bb7516Swangwen 
4724bb7516Swangwen /* Line Status Register bits */
4824bb7516Swangwen #define UARTLSR_TXFIFOFULL	(1 << 11)       /* Tx Fifo Full */
4924bb7516Swangwen #define UARTLSR_TXFIFOEMPTY	(1 << 13)
5024bb7516Swangwen #define UARTLSR_TXEMPTY		(1 << 6)
5124bb7516Swangwen #define UART_RX_READY		(1 << 4)
5224bb7516Swangwen 
5324bb7516Swangwen /* UART Control Register bits */
5424bb7516Swangwen #define UART_CTRL_RXFIFO_RESET	(1 << 14)
5524bb7516Swangwen #define UART_CTRL_TXFIFO_RESET	(1 << 15)
5624bb7516Swangwen 
chip_to_base(struct serial_chip * chip)5724bb7516Swangwen static vaddr_t chip_to_base(struct serial_chip *chip)
5824bb7516Swangwen {
5924bb7516Swangwen 	struct mvebu_uart_data *pd =
6024bb7516Swangwen 		container_of(chip, struct mvebu_uart_data, chip);
6124bb7516Swangwen 
62*c2e4eb43SAnton Rybakov 	return io_pa_or_va(&pd->base, UART_SIZE);
6324bb7516Swangwen }
6424bb7516Swangwen 
mvebu_uart_flush(struct serial_chip * chip)6524bb7516Swangwen static void mvebu_uart_flush(struct serial_chip *chip)
6624bb7516Swangwen {
6724bb7516Swangwen 	vaddr_t base = chip_to_base(chip);
6824bb7516Swangwen 
6924bb7516Swangwen 	/*
7024bb7516Swangwen 	 * Wait for the transmit FIFO to be empty.
7124bb7516Swangwen 	 * It can happen that Linux initializes the OP-TEE driver with the
7224bb7516Swangwen 	 * console UART disabled; avoid an infinite loop by checking the UART
7324bb7516Swangwen 	 * enabled flag. Checking it in the loop makes the code safe against
7424bb7516Swangwen 	 * asynchronous disable.
7524bb7516Swangwen 	 */
76918bb3a5SEtienne Carriere 	while (!(io_read32(base + UART_STATUS_REG) & UARTLSR_TXFIFOEMPTY))
7724bb7516Swangwen 		;
7824bb7516Swangwen }
7924bb7516Swangwen 
mvebu_uart_have_rx_data(struct serial_chip * chip)8024bb7516Swangwen static bool mvebu_uart_have_rx_data(struct serial_chip *chip)
8124bb7516Swangwen {
8224bb7516Swangwen 	vaddr_t base = chip_to_base(chip);
8324bb7516Swangwen 
84918bb3a5SEtienne Carriere 	return (io_read32(base + UART_STATUS_REG) & UART_RX_READY);
8524bb7516Swangwen }
8624bb7516Swangwen 
mvebu_uart_getchar(struct serial_chip * chip)8724bb7516Swangwen static int mvebu_uart_getchar(struct serial_chip *chip)
8824bb7516Swangwen {
8924bb7516Swangwen 	vaddr_t base = chip_to_base(chip);
9024bb7516Swangwen 
9124bb7516Swangwen 	while (!mvebu_uart_have_rx_data(chip))
9224bb7516Swangwen 		;
93918bb3a5SEtienne Carriere 	return io_read32(base + UART_RX_REG) & 0xff;
9424bb7516Swangwen }
9524bb7516Swangwen 
mvebu_uart_putc(struct serial_chip * chip,int ch)9624bb7516Swangwen static void mvebu_uart_putc(struct serial_chip *chip, int ch)
9724bb7516Swangwen {
9824bb7516Swangwen 	vaddr_t base = chip_to_base(chip);
9924bb7516Swangwen 
10024bb7516Swangwen 	uint32_t tmp;
10124bb7516Swangwen 	/* wait for space in tx FIFO */
10224bb7516Swangwen 	do {
103918bb3a5SEtienne Carriere 		tmp = io_read32(base + UART_STATUS_REG);
10424bb7516Swangwen 		tmp &= UARTLSR_TXFIFOFULL;
10524bb7516Swangwen 	} while (tmp == UARTLSR_TXFIFOFULL);
10624bb7516Swangwen 
107918bb3a5SEtienne Carriere 	io_write32(base + UART_TX_REG, ch);
10824bb7516Swangwen }
10924bb7516Swangwen 
11024bb7516Swangwen static const struct serial_ops mvebu_uart_ops = {
11124bb7516Swangwen 	.flush = mvebu_uart_flush,
11224bb7516Swangwen 	.getchar = mvebu_uart_getchar,
11324bb7516Swangwen 	.have_rx_data = mvebu_uart_have_rx_data,
11424bb7516Swangwen 	.putc = mvebu_uart_putc,
11524bb7516Swangwen };
1163639b55fSJerome Forissier DECLARE_KEEP_PAGER(mvebu_uart_ops);
11724bb7516Swangwen 
mvebu_uart_init(struct mvebu_uart_data * pd,paddr_t pbase,uint32_t uart_clk,uint32_t baud_rate)11824bb7516Swangwen void mvebu_uart_init(struct mvebu_uart_data *pd, paddr_t pbase,
11924bb7516Swangwen 		uint32_t uart_clk, uint32_t baud_rate)
12024bb7516Swangwen {
12124bb7516Swangwen 	vaddr_t base;
12224bb7516Swangwen 	uint32_t dll = 0;
12324bb7516Swangwen 
12424bb7516Swangwen 	pd->base.pa = pbase;
12524bb7516Swangwen 	pd->chip.ops = &mvebu_uart_ops;
12624bb7516Swangwen 
127*c2e4eb43SAnton Rybakov 	base = io_pa_or_va(&pd->base, UART_SIZE);
12824bb7516Swangwen 
12924bb7516Swangwen 	dll = (uart_clk / (baud_rate << 4)) & 0x3FF;
13024bb7516Swangwen 
13124bb7516Swangwen 	/* init UART  */
132918bb3a5SEtienne Carriere 	io_clrsetbits32(base + UART_BAUD_REG, 0x3FF, dll);
13324bb7516Swangwen 
13424bb7516Swangwen 	/* set UART to default 16x scheme */
135918bb3a5SEtienne Carriere 	io_write32(base + UART_POSSR_REG, 0);
13624bb7516Swangwen 
13724bb7516Swangwen 	/* reset FIFO */
138918bb3a5SEtienne Carriere 	io_write32(base + UART_CTRL_REG,
139918bb3a5SEtienne Carriere 		   UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET);
14024bb7516Swangwen 
14124bb7516Swangwen 	/* No Parity, 1 stop */
142918bb3a5SEtienne Carriere 	io_write32(base + UART_CTRL_REG, 0);
14324bb7516Swangwen 
14424bb7516Swangwen 	mvebu_uart_flush(&pd->chip);
14524bb7516Swangwen }
146