blob: 33660659f8b67c44ff9ee9796baa04347e31a012 [file] [log] [blame]
Angel Ponsa2ee7612020-04-04 18:51:15 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgi40a3e322015-06-22 19:41:29 +02002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Patrick Georgi40a3e322015-06-22 19:41:29 +02004#include <boot/coreboot_tables.h>
Patrick Georgi40a3e322015-06-22 19:41:29 +02005#include <console/uart.h>
6#include <drivers/uart/uart8250reg.h>
7#include <stdint.h>
8
9struct tegra210_uart {
10 union {
11 uint32_t thr; // Transmit holding register.
12 uint32_t rbr; // Receive buffer register.
13 uint32_t dll; // Divisor latch lsb.
14 };
15 union {
16 uint32_t ier; // Interrupt enable register.
17 uint32_t dlm; // Divisor latch msb.
18 };
19 union {
20 uint32_t iir; // Interrupt identification register.
21 uint32_t fcr; // FIFO control register.
22 };
23 uint32_t lcr; // Line control register.
24 uint32_t mcr; // Modem control register.
25 uint32_t lsr; // Line status register.
26 uint32_t msr; // Modem status register.
Stefan Reinauer6a001132017-07-13 02:20:27 +020027} __packed;
Patrick Georgi40a3e322015-06-22 19:41:29 +020028
Patrick Georgi40a3e322015-06-22 19:41:29 +020029static struct tegra210_uart * const uart_ptr =
30 (void *)CONFIG_CONSOLE_SERIAL_TEGRA210_UART_ADDRESS;
31
32static void tegra210_uart_tx_flush(void);
33static int tegra210_uart_tst_byte(void);
34
35static void tegra210_uart_init(void)
36{
37 // Use a hardcoded divisor for now.
Martin Roth57e89092019-10-23 21:45:23 -060038 const unsigned int divisor = 221;
Patrick Georgi40a3e322015-06-22 19:41:29 +020039 const uint8_t line_config = UART8250_LCR_WLS_8; // 8n1
40
41 tegra210_uart_tx_flush();
42
43 // Disable interrupts.
44 write8(&uart_ptr->ier, 0);
45 // Force DTR and RTS to high.
46 write8(&uart_ptr->mcr, UART8250_MCR_DTR | UART8250_MCR_RTS);
47 // Set line configuration, access divisor latches.
48 write8(&uart_ptr->lcr, UART8250_LCR_DLAB | line_config);
49 // Set the divisor.
50 write8(&uart_ptr->dll, divisor & 0xff);
51 write8(&uart_ptr->dlm, (divisor >> 8) & 0xff);
52 // Hide the divisor latches.
53 write8(&uart_ptr->lcr, line_config);
54 // Enable FIFOs, and clear receive and transmit.
55 write8(&uart_ptr->fcr,
56 UART8250_FCR_FIFO_EN |
57 UART8250_FCR_CLEAR_RCVR |
58 UART8250_FCR_CLEAR_XMIT);
59}
60
61static void tegra210_uart_tx_byte(unsigned char data)
62{
63 while (!(read8(&uart_ptr->lsr) & UART8250_LSR_THRE));
64 write8(&uart_ptr->thr, data);
65}
66
67static void tegra210_uart_tx_flush(void)
68{
69 while (!(read8(&uart_ptr->lsr) & UART8250_LSR_TEMT));
70}
71
72static unsigned char tegra210_uart_rx_byte(void)
73{
74 if (!tegra210_uart_tst_byte())
75 return 0;
76 return read8(&uart_ptr->rbr);
77}
78
79static int tegra210_uart_tst_byte(void)
80{
81 return (read8(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR;
82}
83
Felix Helde3a12472020-09-11 15:47:09 +020084void uart_init(unsigned int idx)
Patrick Georgi40a3e322015-06-22 19:41:29 +020085{
86 tegra210_uart_init();
87}
88
Felix Helde3a12472020-09-11 15:47:09 +020089void uart_tx_byte(unsigned int idx, unsigned char data)
Patrick Georgi40a3e322015-06-22 19:41:29 +020090{
91 tegra210_uart_tx_byte(data);
92}
93
Felix Helde3a12472020-09-11 15:47:09 +020094void uart_tx_flush(unsigned int idx)
Patrick Georgi40a3e322015-06-22 19:41:29 +020095{
96 tegra210_uart_tx_flush();
97}
98
Felix Helde3a12472020-09-11 15:47:09 +020099unsigned char uart_rx_byte(unsigned int idx)
Patrick Georgi40a3e322015-06-22 19:41:29 +0200100{
101 return tegra210_uart_rx_byte();
102}
103
Arthur Heymans9948c522022-10-24 14:37:40 +0200104enum cb_err fill_lb_serial(struct lb_serial *serial)
Patrick Georgi40a3e322015-06-22 19:41:29 +0200105{
Arthur Heymans9948c522022-10-24 14:37:40 +0200106 serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED;
107 serial->baseaddr = CONFIG_CONSOLE_SERIAL_TEGRA210_UART_ADDRESS;
108 serial->baud = get_uart_baudrate();
109 serial->regwidth = 4;
110 serial->input_hertz = uart_platform_refclk();
Patrick Georgi40a3e322015-06-22 19:41:29 +0200111
Arthur Heymans9948c522022-10-24 14:37:40 +0200112 return CB_SUCCESS;
Patrick Georgi40a3e322015-06-22 19:41:29 +0200113}