blob: a7fc3466f37f202f1f807457cd820fbff8303978 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer85b0fa12010-12-17 00:08:21 +00002
Eric Biederman8ca8d762003-04-22 19:02:15 +00003#include <arch/io.h>
Kyösti Mälkkic8cf5912018-06-04 06:02:01 +03004#include <boot/coreboot_tables.h>
Elyes Haouas69451f12022-10-07 10:08:53 +02005#include <commonlib/bsd/helpers.h>
Kyösti Mälkki1d7541f2014-02-17 21:34:42 +02006#include <console/uart.h>
Elyes Haouas69451f12022-10-07 10:08:53 +02007#include <stdint.h>
8
Kyösti Mälkkibea6bf02014-01-30 15:45:16 +02009#include "uart8250reg.h"
Rudolf Marek7f0e9302011-09-02 23:23:41 +020010
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000011/* Should support 8250, 16450, 16550, 16550A type UARTs */
Eric Biederman8ca8d762003-04-22 19:02:15 +000012
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020013/* Expected character delay at 1200bps is 9ms for a working UART
14 * and no flow-control. Assume UART as stuck if shift register
15 * or FIFO takes more than 50ms per character to appear empty.
16 *
17 * Estimated that inb() from UART takes 1 microsecond.
18 */
19#define SINGLE_CHAR_TIMEOUT (50 * 1000)
20#define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
21
Martin Roth38ddbfb2019-10-23 21:41:00 -060022static int uart8250_can_tx_byte(unsigned int base_port)
Eric Biederman8ca8d762003-04-22 19:02:15 +000023{
Gabe Black77ffa0d2013-09-30 21:25:49 -070024 return inb(base_port + UART8250_LSR) & UART8250_LSR_THRE;
Eric Biederman8ca8d762003-04-22 19:02:15 +000025}
26
Martin Roth38ddbfb2019-10-23 21:41:00 -060027static void uart8250_tx_byte(unsigned int base_port, unsigned char data)
Eric Biederman8ca8d762003-04-22 19:02:15 +000028{
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020029 unsigned long int i = SINGLE_CHAR_TIMEOUT;
30 while (i-- && !uart8250_can_tx_byte(base_port));
Gabe Black77ffa0d2013-09-30 21:25:49 -070031 outb(data, base_port + UART8250_TBR);
Eric Biederman8ca8d762003-04-22 19:02:15 +000032}
33
Martin Roth38ddbfb2019-10-23 21:41:00 -060034static void uart8250_tx_flush(unsigned int base_port)
Eric Biederman8ca8d762003-04-22 19:02:15 +000035{
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020036 unsigned long int i = FIFO_TIMEOUT;
Gabe Black77ffa0d2013-09-30 21:25:49 -070037 while (i-- && !(inb(base_port + UART8250_LSR) & UART8250_LSR_TEMT));
Eric Biederman8ca8d762003-04-22 19:02:15 +000038}
39
Martin Roth38ddbfb2019-10-23 21:41:00 -060040static int uart8250_can_rx_byte(unsigned int base_port)
Greg Watsone54d55b2004-03-13 03:40:51 +000041{
Gabe Black77ffa0d2013-09-30 21:25:49 -070042 return inb(base_port + UART8250_LSR) & UART8250_LSR_DR;
Greg Watsone54d55b2004-03-13 03:40:51 +000043}
44
Martin Roth38ddbfb2019-10-23 21:41:00 -060045static unsigned char uart8250_rx_byte(unsigned int base_port)
Greg Watsone54d55b2004-03-13 03:40:51 +000046{
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020047 unsigned long int i = SINGLE_CHAR_TIMEOUT;
Werner Zeh43314ff2017-05-17 10:13:24 +020048 while (i && !uart8250_can_rx_byte(base_port))
49 i--;
Patrick Georgi472efa62012-02-16 20:44:20 +010050
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020051 if (i)
Gabe Black77ffa0d2013-09-30 21:25:49 -070052 return inb(base_port + UART8250_RBR);
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020053 else
54 return 0x0;
Greg Watsone54d55b2004-03-13 03:40:51 +000055}
56
Martin Roth38ddbfb2019-10-23 21:41:00 -060057static void uart8250_init(unsigned int base_port, unsigned int divisor)
Eric Biederman8ca8d762003-04-22 19:02:15 +000058{
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000059 /* Disable interrupts */
Gabe Black77ffa0d2013-09-30 21:25:49 -070060 outb(0x0, base_port + UART8250_IER);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000061 /* Enable FIFOs */
Gabe Black77ffa0d2013-09-30 21:25:49 -070062 outb(UART8250_FCR_FIFO_EN, base_port + UART8250_FCR);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000063
Stefan Reinauerebafa4d2006-10-07 00:13:24 +000064 /* assert DTR and RTS so the other end is happy */
Gabe Black77ffa0d2013-09-30 21:25:49 -070065 outb(UART8250_MCR_DTR | UART8250_MCR_RTS, base_port + UART8250_MCR);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000066
67 /* DLAB on */
Gabe Black77ffa0d2013-09-30 21:25:49 -070068 outb(UART8250_LCR_DLAB | CONFIG_TTYS0_LCS, base_port + UART8250_LCR);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000069
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020070 /* Set Baud Rate Divisor. 12 ==> 9600 Baud */
Gabe Black77ffa0d2013-09-30 21:25:49 -070071 outb(divisor & 0xFF, base_port + UART8250_DLL);
72 outb((divisor >> 8) & 0xFF, base_port + UART8250_DLM);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000073
74 /* Set to 3 for 8N1 */
Gabe Black77ffa0d2013-09-30 21:25:49 -070075 outb(CONFIG_TTYS0_LCS, base_port + UART8250_LCR);
Eric Biederman8ca8d762003-04-22 19:02:15 +000076}
Eric Biederman5cd81732004-03-11 15:01:31 +000077
Martin Roth38ddbfb2019-10-23 21:41:00 -060078static const unsigned int bases[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
Kyösti Mälkki47707492014-02-15 07:53:18 +020079
Felix Helde3a12472020-09-11 15:47:09 +020080uintptr_t uart_platform_base(unsigned int idx)
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +020081{
Kyösti Mälkki70342a72014-03-14 22:28:29 +020082 if (idx < ARRAY_SIZE(bases))
83 return bases[idx];
84 return 0;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +020085}
86
Felix Helde3a12472020-09-11 15:47:09 +020087void uart_init(unsigned int idx)
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000088{
Julius Wernercd49cce2019-03-05 16:53:33 -080089 if (!CONFIG(DRIVERS_UART_8250IO_SKIP_INIT)) {
Nico Huberbc97b4e2016-09-28 22:15:07 +020090 unsigned int div;
Julien Viard de Galbert235daa42018-02-20 11:45:48 +010091 div = uart_baudrate_divisor(get_uart_baudrate(),
Nico Huberbc97b4e2016-09-28 22:15:07 +020092 uart_platform_refclk(), uart_input_clock_divider());
93 uart8250_init(uart_platform_base(idx), div);
94 }
Kyösti Mälkki47707492014-02-15 07:53:18 +020095}
96
Felix Helde3a12472020-09-11 15:47:09 +020097void uart_tx_byte(unsigned int idx, unsigned char data)
Kyösti Mälkki47707492014-02-15 07:53:18 +020098{
Kyösti Mälkki70342a72014-03-14 22:28:29 +020099 uart8250_tx_byte(uart_platform_base(idx), data);
Kyösti Mälkki47707492014-02-15 07:53:18 +0200100}
101
Felix Helde3a12472020-09-11 15:47:09 +0200102unsigned char uart_rx_byte(unsigned int idx)
Kyösti Mälkki47707492014-02-15 07:53:18 +0200103{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200104 return uart8250_rx_byte(uart_platform_base(idx));
Kyösti Mälkki47707492014-02-15 07:53:18 +0200105}
106
Felix Helde3a12472020-09-11 15:47:09 +0200107void uart_tx_flush(unsigned int idx)
Kyösti Mälkki47707492014-02-15 07:53:18 +0200108{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200109 uart8250_tx_flush(uart_platform_base(idx));
Stefan Reinauer85b0fa12010-12-17 00:08:21 +0000110}
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200111
Arthur Heymans9948c522022-10-24 14:37:40 +0200112enum cb_err fill_lb_serial(struct lb_serial *serial)
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200113{
Arthur Heymans9948c522022-10-24 14:37:40 +0200114 serial->type = LB_SERIAL_TYPE_IO_MAPPED;
115 serial->baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
116 serial->baud = get_uart_baudrate();
117 serial->regwidth = 1;
118 serial->input_hertz = uart_platform_refclk();
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200119
Arthur Heymans9948c522022-10-24 14:37:40 +0200120 return CB_SUCCESS;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200121}