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
chip_to_base(struct serial_chip * chip)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
mvebu_uart_flush(struct serial_chip * chip)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
mvebu_uart_have_rx_data(struct serial_chip * chip)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
mvebu_uart_getchar(struct serial_chip * chip)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
mvebu_uart_putc(struct serial_chip * chip,int ch)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
mvebu_uart_init(struct mvebu_uart_data * pd,paddr_t pbase,uint32_t uart_clk,uint32_t baud_rate)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