xref: /optee_os/core/drivers/mvebu_uart.c (revision 24bb751635df538d8dae943a728c00941e0cd280)
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