xref: /optee_os/core/drivers/serial8250_uart.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1*1bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
244bd24c5SJames Kung /*
344bd24c5SJames Kung  * Copyright (c) 2015, Linaro Limited
444bd24c5SJames Kung  * All rights reserved.
544bd24c5SJames Kung  *
644bd24c5SJames Kung  * Redistribution and use in source and binary forms, with or without
744bd24c5SJames Kung  * modification, are permitted provided that the following conditions are met:
844bd24c5SJames Kung  *
944bd24c5SJames Kung  * 1. Redistributions of source code must retain the above copyright notice,
1044bd24c5SJames Kung  * this list of conditions and the following disclaimer.
1144bd24c5SJames Kung  *
1244bd24c5SJames Kung  * 2. Redistributions in binary form must reproduce the above copyright notice,
1344bd24c5SJames Kung  * this list of conditions and the following disclaimer in the documentation
1444bd24c5SJames Kung  * and/or other materials provided with the distribution.
1544bd24c5SJames Kung  *
1644bd24c5SJames Kung  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1744bd24c5SJames Kung  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1844bd24c5SJames Kung  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1944bd24c5SJames Kung  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2044bd24c5SJames Kung  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2144bd24c5SJames Kung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2244bd24c5SJames Kung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2344bd24c5SJames Kung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2444bd24c5SJames Kung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2544bd24c5SJames Kung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2644bd24c5SJames Kung  * POSSIBILITY OF SUCH DAMAGE.
2744bd24c5SJames Kung  */
2844bd24c5SJames Kung 
29d66fa083SJerome Forissier #include <compiler.h>
3044bd24c5SJames Kung #include <console.h>
318d94060aSEtienne Carriere #include <drivers/serial8250_uart.h>
3244bd24c5SJames Kung #include <io.h>
338d94060aSEtienne Carriere #include <keep.h>
34d66fa083SJerome Forissier #include <util.h>
3544bd24c5SJames Kung 
3644bd24c5SJames Kung /* uart register defines */
3744bd24c5SJames Kung #define UART_RHR	0x0
3844bd24c5SJames Kung #define UART_THR	0x0
3944bd24c5SJames Kung #define UART_IER	0x4
4044bd24c5SJames Kung #define UART_ISR	0x8
4144bd24c5SJames Kung #define UART_FCR	0x8
4244bd24c5SJames Kung #define UART_LCR	0xc
4344bd24c5SJames Kung #define UART_MCR	0x10
4444bd24c5SJames Kung #define UART_LSR	0x14
4544bd24c5SJames Kung #define UART_MSR	0x18
4644bd24c5SJames Kung #define UART_SPR	0x1c
4744bd24c5SJames Kung 
4844bd24c5SJames Kung /* uart status register bits */
4944bd24c5SJames Kung #define LSR_TEMT	0x40 /* Transmitter empty */
5044bd24c5SJames Kung #define LSR_THRE	0x20 /* Transmit-hold-register empty */
5144bd24c5SJames Kung #define LSR_EMPTY	(LSR_TEMT | LSR_THRE)
5244bd24c5SJames Kung #define LSR_DR		0x01 /* DATA Ready */
5344bd24c5SJames Kung 
54d66fa083SJerome Forissier static vaddr_t chip_to_base(struct serial_chip *chip)
5544bd24c5SJames Kung {
56d66fa083SJerome Forissier 	struct serial8250_uart_data *pd =
57d66fa083SJerome Forissier 		container_of(chip, struct serial8250_uart_data, chip);
58d66fa083SJerome Forissier 
59d66fa083SJerome Forissier 	return io_pa_or_va(&pd->base);
6044bd24c5SJames Kung }
6144bd24c5SJames Kung 
62d66fa083SJerome Forissier static void serial8250_uart_flush(struct serial_chip *chip)
6344bd24c5SJames Kung {
64d66fa083SJerome Forissier 	vaddr_t base = chip_to_base(chip);
65d66fa083SJerome Forissier 
6644bd24c5SJames Kung 	while (1) {
6765d34b1fSJoseph Chen 		uint32_t state = read32(base + UART_LSR);
6844bd24c5SJames Kung 
69d66fa083SJerome Forissier 		/* Wait until transmit FIFO is empty */
7044bd24c5SJames Kung 		if ((state & LSR_EMPTY) == LSR_EMPTY)
7144bd24c5SJames Kung 			break;
7244bd24c5SJames Kung 	}
7344bd24c5SJames Kung }
7444bd24c5SJames Kung 
75d66fa083SJerome Forissier static bool serial8250_uart_have_rx_data(struct serial_chip *chip)
7644bd24c5SJames Kung {
77d66fa083SJerome Forissier 	vaddr_t base = chip_to_base(chip);
78d66fa083SJerome Forissier 
7944bd24c5SJames Kung 	return (read32(base + UART_LSR) & LSR_DR);
8044bd24c5SJames Kung }
8144bd24c5SJames Kung 
82d66fa083SJerome Forissier static int serial8250_uart_getchar(struct serial_chip *chip)
8344bd24c5SJames Kung {
84d66fa083SJerome Forissier 	vaddr_t base = chip_to_base(chip);
8544bd24c5SJames Kung 
86d66fa083SJerome Forissier 	while (!serial8250_uart_have_rx_data(chip)) {
87d66fa083SJerome Forissier 		/* Transmit FIFO is empty, waiting again */
8844bd24c5SJames Kung 		;
8944bd24c5SJames Kung 	}
9065d34b1fSJoseph Chen 	return read32(base + UART_RHR) & 0xff;
9144bd24c5SJames Kung }
9244bd24c5SJames Kung 
93d66fa083SJerome Forissier static void serial8250_uart_putc(struct serial_chip *chip, int ch)
94d66fa083SJerome Forissier {
95d66fa083SJerome Forissier 	vaddr_t base = chip_to_base(chip);
96d66fa083SJerome Forissier 
97d66fa083SJerome Forissier 	serial8250_uart_flush(chip);
98d66fa083SJerome Forissier 
99d66fa083SJerome Forissier 	/* Write out character to transmit FIFO */
10065d34b1fSJoseph Chen 	write32(ch, base + UART_THR);
101d66fa083SJerome Forissier }
102d66fa083SJerome Forissier 
103d66fa083SJerome Forissier static const struct serial_ops serial8250_uart_ops = {
104d66fa083SJerome Forissier 	.flush = serial8250_uart_flush,
105d66fa083SJerome Forissier 	.getchar = serial8250_uart_getchar,
106d66fa083SJerome Forissier 	.have_rx_data = serial8250_uart_have_rx_data,
107d66fa083SJerome Forissier 	.putc = serial8250_uart_putc,
108d66fa083SJerome Forissier };
1098d94060aSEtienne Carriere KEEP_PAGER(serial8250_uart_ops);
110d66fa083SJerome Forissier 
111d66fa083SJerome Forissier void serial8250_uart_init(struct serial8250_uart_data *pd, paddr_t base,
112d66fa083SJerome Forissier 			  uint32_t __unused uart_clk,
113d66fa083SJerome Forissier 			  uint32_t __unused baud_rate)
114d66fa083SJerome Forissier 
115d66fa083SJerome Forissier {
116d66fa083SJerome Forissier 	pd->base.pa = base;
117d66fa083SJerome Forissier 	pd->chip.ops = &serial8250_uart_ops;
118d66fa083SJerome Forissier 
119d66fa083SJerome Forissier 	/*
120d66fa083SJerome Forissier 	 * do nothing, debug uart(uart0) share with normal world,
121d66fa083SJerome Forissier 	 * everything for uart0 is ready now.
122d66fa083SJerome Forissier 	 */
123d66fa083SJerome Forissier }
124