blob: d5042d546de06eb6a2ed6625f6b3a65d7e44c37b [file] [log] [blame]
Paul Burtonc1081a42014-06-14 00:08:02 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2003 Eric Biederman
5 * Copyright (C) 2006-2010 coresystems GmbH
6 * Copyright (C) 2014 Imagination Technologies
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; version 2 of
11 * the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
Paul Burtonc1081a42014-06-14 00:08:02 +010017 */
18
Kyösti Mälkki13f66502019-03-03 08:01:05 +020019#include <device/mmio.h>
Patrick Georgi146d05d2015-03-30 13:08:18 +020020#include <boot/coreboot_tables.h>
Patrick Georgi146d05d2015-03-30 13:08:18 +020021#include <console/uart.h>
Paul Burtonc1081a42014-06-14 00:08:02 +010022#include <device/device.h>
23#include <delay.h>
Patrick Georgi146d05d2015-03-30 13:08:18 +020024#include <drivers/uart/uart8250reg.h>
Paul Burtonc1081a42014-06-14 00:08:02 +010025
26/* Should support 8250, 16450, 16550, 16550A type UARTs */
27
28/* Expected character delay at 1200bps is 9ms for a working UART
29 * and no flow-control. Assume UART as stuck if shift register
30 * or FIFO takes more than 50ms per character to appear empty.
31 */
32#define SINGLE_CHAR_TIMEOUT (50 * 1000)
33#define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
34#define UART_SHIFT 2
35
36#define GEN_ACCESSOR(name, idx) \
Martin Roth57e89092019-10-23 21:45:23 -060037static inline uint8_t read_##name(unsigned int base_port) \
Paul Burtonc1081a42014-06-14 00:08:02 +010038{ \
Kyösti Mälkkia9506db2019-03-20 20:30:02 +020039 return read8((void *)(base_port + (idx << UART_SHIFT))); \
Paul Burtonc1081a42014-06-14 00:08:02 +010040} \
41 \
Martin Roth57e89092019-10-23 21:45:23 -060042static inline void write_##name(unsigned int base_port, uint8_t val) \
Paul Burtonc1081a42014-06-14 00:08:02 +010043{ \
Kyösti Mälkkia9506db2019-03-20 20:30:02 +020044 write8((void *)(base_port + (idx << UART_SHIFT)), val); \
Paul Burtonc1081a42014-06-14 00:08:02 +010045}
46
47GEN_ACCESSOR(rbr, UART8250_RBR)
48GEN_ACCESSOR(tbr, UART8250_TBR)
49GEN_ACCESSOR(ier, UART8250_IER)
50GEN_ACCESSOR(fcr, UART8250_FCR)
51GEN_ACCESSOR(lcr, UART8250_LCR)
52GEN_ACCESSOR(mcr, UART8250_MCR)
53GEN_ACCESSOR(lsr, UART8250_LSR)
54GEN_ACCESSOR(dll, UART8250_DLL)
55GEN_ACCESSOR(dlm, UART8250_DLM)
56
Martin Roth57e89092019-10-23 21:45:23 -060057static int uart8250_mem_can_tx_byte(unsigned int base_port)
Paul Burtonc1081a42014-06-14 00:08:02 +010058{
59 return read_lsr(base_port) & UART8250_LSR_THRE;
60}
61
Martin Roth57e89092019-10-23 21:45:23 -060062static void uart8250_mem_tx_byte(unsigned int base_port, unsigned char data)
Paul Burtonc1081a42014-06-14 00:08:02 +010063{
64 unsigned long int i = SINGLE_CHAR_TIMEOUT;
65 while (i-- && !uart8250_mem_can_tx_byte(base_port))
66 udelay(1);
67 write_tbr(base_port, data);
68}
69
Martin Roth57e89092019-10-23 21:45:23 -060070static void uart8250_mem_tx_flush(unsigned int base_port)
Paul Burtonc1081a42014-06-14 00:08:02 +010071{
72 unsigned long int i = FIFO_TIMEOUT;
73 while (i-- && !(read_lsr(base_port) & UART8250_LSR_TEMT))
74 udelay(1);
75}
76
Martin Roth57e89092019-10-23 21:45:23 -060077static int uart8250_mem_can_rx_byte(unsigned int base_port)
Paul Burtonc1081a42014-06-14 00:08:02 +010078{
79 return read_lsr(base_port) & UART8250_LSR_DR;
80}
81
Martin Roth57e89092019-10-23 21:45:23 -060082static unsigned char uart8250_mem_rx_byte(unsigned int base_port)
Paul Burtonc1081a42014-06-14 00:08:02 +010083{
84 unsigned long int i = SINGLE_CHAR_TIMEOUT;
85 while (i-- && !uart8250_mem_can_rx_byte(base_port))
86 udelay(1);
87 if (i)
88 return read_rbr(base_port);
89 else
90 return 0x0;
91}
92
Martin Roth57e89092019-10-23 21:45:23 -060093static void uart8250_mem_init(unsigned int base_port, unsigned int divisor)
Paul Burtonc1081a42014-06-14 00:08:02 +010094{
95 /* Disable interrupts */
96 write_ier(base_port, 0x0);
97 /* Enable FIFOs */
98 write_fcr(base_port, UART8250_FCR_FIFO_EN);
99
100 /* Assert DTR and RTS so the other end is happy */
101 write_mcr(base_port, UART8250_MCR_DTR | UART8250_MCR_RTS);
102
103 /* DLAB on */
104 write_lcr(base_port, UART8250_LCR_DLAB | CONFIG_TTYS0_LCS);
105
106 write_dll(base_port, divisor & 0xFF);
107 write_dlm(base_port, (divisor >> 8) & 0xFF);
108
109 /* Set to 3 for 8N1 */
110 write_lcr(base_port, CONFIG_TTYS0_LCS);
111}
112
Patrick Georgi146d05d2015-03-30 13:08:18 +0200113unsigned int uart_platform_refclk(void)
Paul Burtonc1081a42014-06-14 00:08:02 +0100114{
David Hendricksb9d59bb2015-01-26 07:19:49 -0800115 /* 1.8433179 MHz */
116 return 1843318;
Paul Burtonc1081a42014-06-14 00:08:02 +0100117}
118
Patrick Georgi146d05d2015-03-30 13:08:18 +0200119void uart_init(int idx)
Paul Burtonc1081a42014-06-14 00:08:02 +0100120{
David Hendricksb116a1a2015-01-26 07:11:01 -0800121 u32 base = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
Paul Burtonc1081a42014-06-14 00:08:02 +0100122 if (!base)
123 return;
124
125 unsigned int div;
Julien Viard de Galbert235daa42018-02-20 11:45:48 +0100126 div = uart_baudrate_divisor(get_uart_baudrate(),
Paul Burtonc1081a42014-06-14 00:08:02 +0100127 uart_platform_refclk(), 16);
128 uart8250_mem_init(base, div);
129}
130
Patrick Georgi146d05d2015-03-30 13:08:18 +0200131void uart_tx_byte(int idx, unsigned char data)
Paul Burtonc1081a42014-06-14 00:08:02 +0100132{
David Hendricksb116a1a2015-01-26 07:11:01 -0800133 uart8250_mem_tx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS, data);
Paul Burtonc1081a42014-06-14 00:08:02 +0100134}
135
Patrick Georgi146d05d2015-03-30 13:08:18 +0200136unsigned char uart_rx_byte(int idx)
Paul Burtonc1081a42014-06-14 00:08:02 +0100137{
David Hendricksb116a1a2015-01-26 07:11:01 -0800138 return uart8250_mem_rx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
Paul Burtonc1081a42014-06-14 00:08:02 +0100139}
140
Patrick Georgi146d05d2015-03-30 13:08:18 +0200141void uart_tx_flush(int idx)
Paul Burtonc1081a42014-06-14 00:08:02 +0100142{
David Hendricksb116a1a2015-01-26 07:11:01 -0800143 uart8250_mem_tx_flush(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
Paul Burtonc1081a42014-06-14 00:08:02 +0100144}
145
Patrick Georgi146d05d2015-03-30 13:08:18 +0200146void uart_fill_lb(void *data)
Paul Burtonc1081a42014-06-14 00:08:02 +0100147{
Patrick Georgi146d05d2015-03-30 13:08:18 +0200148 struct lb_serial serial;
149 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
David Hendricksb116a1a2015-01-26 07:11:01 -0800150 serial.baseaddr = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
Julien Viard de Galbert235daa42018-02-20 11:45:48 +0100151 serial.baud = get_uart_baudrate();
Vadim Bendebury7271e232015-01-09 16:55:36 -0800152 serial.regwidth = 1 << UART_SHIFT;
Jacob Garber78398272019-07-24 11:12:09 -0600153 serial.input_hertz = uart_platform_refclk();
154 serial.uart_pci_addr = CONFIG_UART_PCI_ADDR;
Patrick Georgi146d05d2015-03-30 13:08:18 +0200155 lb_add_serial(&serial, data);
156
157 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
Paul Burtonc1081a42014-06-14 00:08:02 +0100158}