xref: /optee_os/core/drivers/cdns_uart.c (revision 3639b55f101b2c3bba33740ec7bf5440b3125efc)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
23481d2f6SSoren Brinkmann /*
33481d2f6SSoren Brinkmann  * Copyright (c) 2016, Xilinx Inc.
43481d2f6SSoren Brinkmann  * All rights reserved.
53481d2f6SSoren Brinkmann  *
63481d2f6SSoren Brinkmann  * Redistribution and use in source and binary forms, with or without
73481d2f6SSoren Brinkmann  * modification, are permitted provided that the following conditions are met:
83481d2f6SSoren Brinkmann  *
93481d2f6SSoren Brinkmann  * 1. Redistributions of source code must retain the above copyright notice,
103481d2f6SSoren Brinkmann  * this list of conditions and the following disclaimer.
113481d2f6SSoren Brinkmann  *
123481d2f6SSoren Brinkmann  * 2. Redistributions in binary form must reproduce the above copyright notice,
133481d2f6SSoren Brinkmann  * this list of conditions and the following disclaimer in the documentation
143481d2f6SSoren Brinkmann  * and/or other materials provided with the distribution.
153481d2f6SSoren Brinkmann  *
163481d2f6SSoren Brinkmann  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173481d2f6SSoren Brinkmann  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183481d2f6SSoren Brinkmann  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193481d2f6SSoren Brinkmann  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
203481d2f6SSoren Brinkmann  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
213481d2f6SSoren Brinkmann  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
223481d2f6SSoren Brinkmann  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
233481d2f6SSoren Brinkmann  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
243481d2f6SSoren Brinkmann  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
253481d2f6SSoren Brinkmann  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
263481d2f6SSoren Brinkmann  * POSSIBILITY OF SUCH DAMAGE.
273481d2f6SSoren Brinkmann  */
2862fff454SJerome Forissier #include <assert.h>
293481d2f6SSoren Brinkmann #include <drivers/cdns_uart.h>
303481d2f6SSoren Brinkmann #include <io.h>
318d94060aSEtienne Carriere #include <keep.h>
3262fff454SJerome Forissier #include <mm/core_mmu.h>
333481d2f6SSoren Brinkmann #include <util.h>
343481d2f6SSoren Brinkmann 
353481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL		0
363481d2f6SSoren Brinkmann #define CDNS_UART_MODE			4
373481d2f6SSoren Brinkmann #define CDNS_UART_IEN			8
383481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_STATUS		0x14
393481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS	0x2c
403481d2f6SSoren Brinkmann #define CDNS_UART_FIFO			0x30
413481d2f6SSoren Brinkmann 
423481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_RXRES		BIT(0)
433481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_TXRES		BIT(1)
443481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_RXEN		BIT(2)
453481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_TXEN		BIT(4)
463481d2f6SSoren Brinkmann 
473481d2f6SSoren Brinkmann #define CDNS_UART_MODE_8BIT		(0 << 1)
483481d2f6SSoren Brinkmann #define CDNS_UART_MODE_PARITY_NONE	(0x4 << 3)
493481d2f6SSoren Brinkmann #define CDNS_UART_MODE_1STP		(0 << 6)
503481d2f6SSoren Brinkmann 
513481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_TFUL	BIT(4)
523481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_TEMPTY	BIT(3)
533481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_REMPTY	BIT(1)
543481d2f6SSoren Brinkmann 
553481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_RXTRIG		BIT(0)
563481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_RXTOUT		BIT(8)
573481d2f6SSoren Brinkmann 
5862fff454SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip)
593481d2f6SSoren Brinkmann {
6062fff454SJerome Forissier 	struct cdns_uart_data *pd =
6162fff454SJerome Forissier 		container_of(chip, struct cdns_uart_data, chip);
6262fff454SJerome Forissier 
6362fff454SJerome Forissier 	return io_pa_or_va(&pd->base);
6462fff454SJerome Forissier }
6562fff454SJerome Forissier 
6662fff454SJerome Forissier static void cdns_uart_flush(struct serial_chip *chip)
6762fff454SJerome Forissier {
6862fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
6962fff454SJerome Forissier 
70918bb3a5SEtienne Carriere 	while (!(io_read32(base + CDNS_UART_CHANNEL_STATUS) &
713481d2f6SSoren Brinkmann 		 CDNS_UART_CHANNEL_STATUS_TEMPTY))
723481d2f6SSoren Brinkmann 		;
733481d2f6SSoren Brinkmann }
743481d2f6SSoren Brinkmann 
7562fff454SJerome Forissier static bool cdns_uart_have_rx_data(struct serial_chip *chip)
763481d2f6SSoren Brinkmann {
7762fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
783481d2f6SSoren Brinkmann 
79918bb3a5SEtienne Carriere 	return !(io_read32(base + CDNS_UART_CHANNEL_STATUS) &
8062fff454SJerome Forissier 		 CDNS_UART_CHANNEL_STATUS_REMPTY);
813481d2f6SSoren Brinkmann }
823481d2f6SSoren Brinkmann 
8362fff454SJerome Forissier static int cdns_uart_getchar(struct serial_chip *chip)
843481d2f6SSoren Brinkmann {
8562fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
8662fff454SJerome Forissier 
8762fff454SJerome Forissier 	while (!cdns_uart_have_rx_data(chip))
8862fff454SJerome Forissier 		;
89918bb3a5SEtienne Carriere 	return io_read32(base + CDNS_UART_FIFO) & 0xff;
9062fff454SJerome Forissier }
9162fff454SJerome Forissier 
9262fff454SJerome Forissier static void cdns_uart_putc(struct serial_chip *chip, int ch)
9362fff454SJerome Forissier {
9462fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
9562fff454SJerome Forissier 
963481d2f6SSoren Brinkmann 	/* Wait until there is space in the FIFO */
97918bb3a5SEtienne Carriere 	while (io_read32(base + CDNS_UART_CHANNEL_STATUS) &
983481d2f6SSoren Brinkmann 	       CDNS_UART_CHANNEL_STATUS_TFUL)
993481d2f6SSoren Brinkmann 		;
1003481d2f6SSoren Brinkmann 
1013481d2f6SSoren Brinkmann 	/* Send the character */
102918bb3a5SEtienne Carriere 	io_write32(base + CDNS_UART_FIFO, ch);
1033481d2f6SSoren Brinkmann }
1043481d2f6SSoren Brinkmann 
1053481d2f6SSoren Brinkmann 
10662fff454SJerome Forissier static const struct serial_ops cdns_uart_ops = {
10762fff454SJerome Forissier 	.flush = cdns_uart_flush,
10862fff454SJerome Forissier 	.getchar = cdns_uart_getchar,
10962fff454SJerome Forissier 	.have_rx_data = cdns_uart_have_rx_data,
11062fff454SJerome Forissier 	.putc = cdns_uart_putc,
11162fff454SJerome Forissier };
112*3639b55fSJerome Forissier DECLARE_KEEP_PAGER(cdns_uart_ops);
11362fff454SJerome Forissier 
11462fff454SJerome Forissier /*
11562fff454SJerome Forissier  * we rely on the bootloader having set up the HW correctly, we just enable
11662fff454SJerome Forissier  * transmitter/receiver here, just in case.
11762fff454SJerome Forissier  */
11862fff454SJerome Forissier void cdns_uart_init(struct cdns_uart_data *pd, paddr_t base, uint32_t uart_clk,
11962fff454SJerome Forissier 		uint32_t baud_rate)
1203481d2f6SSoren Brinkmann {
12162fff454SJerome Forissier 	pd->base.pa = base;
12262fff454SJerome Forissier 	pd->chip.ops = &cdns_uart_ops;
12362fff454SJerome Forissier 
12462fff454SJerome Forissier 	if (!uart_clk || !baud_rate)
12562fff454SJerome Forissier 		return;
12662fff454SJerome Forissier 
12762fff454SJerome Forissier 	/* Enable UART and RX/TX */
128918bb3a5SEtienne Carriere 	io_write32(base + CDNS_UART_CONTROL,
129918bb3a5SEtienne Carriere 		   CDNS_UART_CONTROL_RXEN | CDNS_UART_CONTROL_TXEN);
13062fff454SJerome Forissier 
13162fff454SJerome Forissier 	cdns_uart_flush(&pd->chip);
1323481d2f6SSoren Brinkmann }
133