xref: /optee_os/core/drivers/cdns_uart.c (revision c2e4eb43b7b7211345cd38ceceac97773bd78d2c)
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
41*c2e4eb43SAnton Rybakov #define CDNS_UART_SIZE			0x34
423481d2f6SSoren Brinkmann 
433481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_RXRES		BIT(0)
443481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_TXRES		BIT(1)
453481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_RXEN		BIT(2)
463481d2f6SSoren Brinkmann #define CDNS_UART_CONTROL_TXEN		BIT(4)
473481d2f6SSoren Brinkmann 
483481d2f6SSoren Brinkmann #define CDNS_UART_MODE_8BIT		(0 << 1)
493481d2f6SSoren Brinkmann #define CDNS_UART_MODE_PARITY_NONE	(0x4 << 3)
503481d2f6SSoren Brinkmann #define CDNS_UART_MODE_1STP		(0 << 6)
513481d2f6SSoren Brinkmann 
523481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_TFUL	BIT(4)
533481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_TEMPTY	BIT(3)
543481d2f6SSoren Brinkmann #define CDNS_UART_CHANNEL_STATUS_REMPTY	BIT(1)
553481d2f6SSoren Brinkmann 
563481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_RXTRIG		BIT(0)
573481d2f6SSoren Brinkmann #define CDNS_UART_IRQ_RXTOUT		BIT(8)
583481d2f6SSoren Brinkmann 
chip_to_base(struct serial_chip * chip)5962fff454SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip)
603481d2f6SSoren Brinkmann {
6162fff454SJerome Forissier 	struct cdns_uart_data *pd =
6262fff454SJerome Forissier 		container_of(chip, struct cdns_uart_data, chip);
6362fff454SJerome Forissier 
64*c2e4eb43SAnton Rybakov 	return io_pa_or_va(&pd->base, CDNS_UART_SIZE);
6562fff454SJerome Forissier }
6662fff454SJerome Forissier 
cdns_uart_flush(struct serial_chip * chip)6762fff454SJerome Forissier static void cdns_uart_flush(struct serial_chip *chip)
6862fff454SJerome Forissier {
6962fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
7062fff454SJerome Forissier 
71918bb3a5SEtienne Carriere 	while (!(io_read32(base + CDNS_UART_CHANNEL_STATUS) &
723481d2f6SSoren Brinkmann 		 CDNS_UART_CHANNEL_STATUS_TEMPTY))
733481d2f6SSoren Brinkmann 		;
743481d2f6SSoren Brinkmann }
753481d2f6SSoren Brinkmann 
cdns_uart_have_rx_data(struct serial_chip * chip)7662fff454SJerome Forissier static bool cdns_uart_have_rx_data(struct serial_chip *chip)
773481d2f6SSoren Brinkmann {
7862fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
793481d2f6SSoren Brinkmann 
80918bb3a5SEtienne Carriere 	return !(io_read32(base + CDNS_UART_CHANNEL_STATUS) &
8162fff454SJerome Forissier 		 CDNS_UART_CHANNEL_STATUS_REMPTY);
823481d2f6SSoren Brinkmann }
833481d2f6SSoren Brinkmann 
cdns_uart_getchar(struct serial_chip * chip)8462fff454SJerome Forissier static int cdns_uart_getchar(struct serial_chip *chip)
853481d2f6SSoren Brinkmann {
8662fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
8762fff454SJerome Forissier 
8862fff454SJerome Forissier 	while (!cdns_uart_have_rx_data(chip))
8962fff454SJerome Forissier 		;
90918bb3a5SEtienne Carriere 	return io_read32(base + CDNS_UART_FIFO) & 0xff;
9162fff454SJerome Forissier }
9262fff454SJerome Forissier 
cdns_uart_putc(struct serial_chip * chip,int ch)9362fff454SJerome Forissier static void cdns_uart_putc(struct serial_chip *chip, int ch)
9462fff454SJerome Forissier {
9562fff454SJerome Forissier 	vaddr_t base = chip_to_base(chip);
9662fff454SJerome Forissier 
973481d2f6SSoren Brinkmann 	/* Wait until there is space in the FIFO */
98918bb3a5SEtienne Carriere 	while (io_read32(base + CDNS_UART_CHANNEL_STATUS) &
993481d2f6SSoren Brinkmann 	       CDNS_UART_CHANNEL_STATUS_TFUL)
1003481d2f6SSoren Brinkmann 		;
1013481d2f6SSoren Brinkmann 
1023481d2f6SSoren Brinkmann 	/* Send the character */
103918bb3a5SEtienne Carriere 	io_write32(base + CDNS_UART_FIFO, ch);
1043481d2f6SSoren Brinkmann }
1053481d2f6SSoren Brinkmann 
1063481d2f6SSoren Brinkmann 
10762fff454SJerome Forissier static const struct serial_ops cdns_uart_ops = {
10862fff454SJerome Forissier 	.flush = cdns_uart_flush,
10962fff454SJerome Forissier 	.getchar = cdns_uart_getchar,
11062fff454SJerome Forissier 	.have_rx_data = cdns_uart_have_rx_data,
11162fff454SJerome Forissier 	.putc = cdns_uart_putc,
11262fff454SJerome Forissier };
1133639b55fSJerome Forissier DECLARE_KEEP_PAGER(cdns_uart_ops);
11462fff454SJerome Forissier 
11562fff454SJerome Forissier /*
11662fff454SJerome Forissier  * we rely on the bootloader having set up the HW correctly, we just enable
11762fff454SJerome Forissier  * transmitter/receiver here, just in case.
11862fff454SJerome Forissier  */
cdns_uart_init(struct cdns_uart_data * pd,paddr_t base,uint32_t uart_clk,uint32_t baud_rate)11962fff454SJerome Forissier void cdns_uart_init(struct cdns_uart_data *pd, paddr_t base, uint32_t uart_clk,
12062fff454SJerome Forissier 		uint32_t baud_rate)
1213481d2f6SSoren Brinkmann {
12262fff454SJerome Forissier 	pd->base.pa = base;
12362fff454SJerome Forissier 	pd->chip.ops = &cdns_uart_ops;
12462fff454SJerome Forissier 
12562fff454SJerome Forissier 	if (!uart_clk || !baud_rate)
12662fff454SJerome Forissier 		return;
12762fff454SJerome Forissier 
12862fff454SJerome Forissier 	/* Enable UART and RX/TX */
129918bb3a5SEtienne Carriere 	io_write32(base + CDNS_UART_CONTROL,
130918bb3a5SEtienne Carriere 		   CDNS_UART_CONTROL_RXEN | CDNS_UART_CONTROL_TXEN);
13162fff454SJerome Forissier 
13262fff454SJerome Forissier 	cdns_uart_flush(&pd->chip);
1333481d2f6SSoren Brinkmann }
134