blob: ac3315a4210601c262367aeafac5db8f8226a1bd [file] [log] [blame]
Stefan Reinauer85b0fa12010-12-17 00:08:21 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2003 Eric Biederman
5 * Copyright (C) 2006-2010 coresystems GmbH
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000015 */
16
Kyösti Mälkki4566d2e2014-04-23 10:28:59 +030017#include <rules.h>
Kyösti Mälkki70342a72014-03-14 22:28:29 +020018#include <stdlib.h>
Eric Biederman8ca8d762003-04-22 19:02:15 +000019#include <arch/io.h>
Kyösti Mälkki1d7541f2014-02-17 21:34:42 +020020#include <console/uart.h>
Rudolf Marek7f0e9302011-09-02 23:23:41 +020021#include <trace.h>
Kyösti Mälkkibea6bf02014-01-30 15:45:16 +020022#include "uart8250reg.h"
Rudolf Marek7f0e9302011-09-02 23:23:41 +020023
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +020024#ifndef __ROMCC__
25#include <boot/coreboot_tables.h>
26#endif
27
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000028/* Should support 8250, 16450, 16550, 16550A type UARTs */
Eric Biederman8ca8d762003-04-22 19:02:15 +000029
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020030/* Expected character delay at 1200bps is 9ms for a working UART
31 * and no flow-control. Assume UART as stuck if shift register
32 * or FIFO takes more than 50ms per character to appear empty.
33 *
34 * Estimated that inb() from UART takes 1 microsecond.
35 */
36#define SINGLE_CHAR_TIMEOUT (50 * 1000)
37#define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
38
Kyösti Mälkki47707492014-02-15 07:53:18 +020039static int uart8250_can_tx_byte(unsigned base_port)
Eric Biederman8ca8d762003-04-22 19:02:15 +000040{
Gabe Black77ffa0d2013-09-30 21:25:49 -070041 return inb(base_port + UART8250_LSR) & UART8250_LSR_THRE;
Eric Biederman8ca8d762003-04-22 19:02:15 +000042}
43
Kyösti Mälkki47707492014-02-15 07:53:18 +020044static void uart8250_tx_byte(unsigned base_port, unsigned char data)
Eric Biederman8ca8d762003-04-22 19:02:15 +000045{
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020046 unsigned long int i = SINGLE_CHAR_TIMEOUT;
47 while (i-- && !uart8250_can_tx_byte(base_port));
Gabe Black77ffa0d2013-09-30 21:25:49 -070048 outb(data, base_port + UART8250_TBR);
Eric Biederman8ca8d762003-04-22 19:02:15 +000049}
50
Kyösti Mälkki47707492014-02-15 07:53:18 +020051static void uart8250_tx_flush(unsigned base_port)
Eric Biederman8ca8d762003-04-22 19:02:15 +000052{
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020053 unsigned long int i = FIFO_TIMEOUT;
Gabe Black77ffa0d2013-09-30 21:25:49 -070054 while (i-- && !(inb(base_port + UART8250_LSR) & UART8250_LSR_TEMT));
Eric Biederman8ca8d762003-04-22 19:02:15 +000055}
56
Kyösti Mälkki47707492014-02-15 07:53:18 +020057static int uart8250_can_rx_byte(unsigned base_port)
Greg Watsone54d55b2004-03-13 03:40:51 +000058{
Gabe Black77ffa0d2013-09-30 21:25:49 -070059 return inb(base_port + UART8250_LSR) & UART8250_LSR_DR;
Greg Watsone54d55b2004-03-13 03:40:51 +000060}
61
Kyösti Mälkki47707492014-02-15 07:53:18 +020062static unsigned char uart8250_rx_byte(unsigned base_port)
Greg Watsone54d55b2004-03-13 03:40:51 +000063{
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020064 unsigned long int i = SINGLE_CHAR_TIMEOUT;
65 while (i-- && !uart8250_can_rx_byte(base_port));
Patrick Georgi472efa62012-02-16 20:44:20 +010066
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020067 if (i)
Gabe Black77ffa0d2013-09-30 21:25:49 -070068 return inb(base_port + UART8250_RBR);
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020069 else
70 return 0x0;
Greg Watsone54d55b2004-03-13 03:40:51 +000071}
72
Kyösti Mälkki47707492014-02-15 07:53:18 +020073static void uart8250_init(unsigned base_port, unsigned divisor)
Eric Biederman8ca8d762003-04-22 19:02:15 +000074{
Rudolf Marek7f0e9302011-09-02 23:23:41 +020075 DISABLE_TRACE;
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000076 /* Disable interrupts */
Gabe Black77ffa0d2013-09-30 21:25:49 -070077 outb(0x0, base_port + UART8250_IER);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000078 /* Enable FIFOs */
Gabe Black77ffa0d2013-09-30 21:25:49 -070079 outb(UART8250_FCR_FIFO_EN, base_port + UART8250_FCR);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000080
Stefan Reinauerebafa4d2006-10-07 00:13:24 +000081 /* assert DTR and RTS so the other end is happy */
Gabe Black77ffa0d2013-09-30 21:25:49 -070082 outb(UART8250_MCR_DTR | UART8250_MCR_RTS, base_port + UART8250_MCR);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000083
84 /* DLAB on */
Gabe Black77ffa0d2013-09-30 21:25:49 -070085 outb(UART8250_LCR_DLAB | CONFIG_TTYS0_LCS, base_port + UART8250_LCR);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000086
Kyösti Mälkki9dd3ef12012-02-07 20:50:22 +020087 /* Set Baud Rate Divisor. 12 ==> 9600 Baud */
Gabe Black77ffa0d2013-09-30 21:25:49 -070088 outb(divisor & 0xFF, base_port + UART8250_DLL);
89 outb((divisor >> 8) & 0xFF, base_port + UART8250_DLM);
Stefan Reinauer85b0fa12010-12-17 00:08:21 +000090
91 /* Set to 3 for 8N1 */
Gabe Black77ffa0d2013-09-30 21:25:49 -070092 outb(CONFIG_TTYS0_LCS, base_port + UART8250_LCR);
Rudolf Marek7f0e9302011-09-02 23:23:41 +020093 ENABLE_TRACE;
Eric Biederman8ca8d762003-04-22 19:02:15 +000094}
Eric Biederman5cd81732004-03-11 15:01:31 +000095
Kyösti Mälkki70342a72014-03-14 22:28:29 +020096static const unsigned bases[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
Kyösti Mälkki47707492014-02-15 07:53:18 +020097
Ronald G. Minnich2adb2972014-10-16 10:53:48 +000098uintptr_t uart_platform_base(int idx)
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +020099{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200100 if (idx < ARRAY_SIZE(bases))
101 return bases[idx];
102 return 0;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200103}
104
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200105void uart_init(int idx)
Stefan Reinauer85b0fa12010-12-17 00:08:21 +0000106{
Nico Huberbc97b4e2016-09-28 22:15:07 +0200107 if (!IS_ENABLED(CONFIG_DRIVERS_UART_8250IO_SKIP_INIT)) {
108 unsigned int div;
109 div = uart_baudrate_divisor(default_baudrate(),
110 uart_platform_refclk(), uart_input_clock_divider());
111 uart8250_init(uart_platform_base(idx), div);
112 }
Kyösti Mälkki47707492014-02-15 07:53:18 +0200113}
114
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200115void uart_tx_byte(int idx, unsigned char data)
Kyösti Mälkki47707492014-02-15 07:53:18 +0200116{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200117 uart8250_tx_byte(uart_platform_base(idx), data);
Kyösti Mälkki47707492014-02-15 07:53:18 +0200118}
119
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200120unsigned char uart_rx_byte(int idx)
Kyösti Mälkki47707492014-02-15 07:53:18 +0200121{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200122 return uart8250_rx_byte(uart_platform_base(idx));
Kyösti Mälkki47707492014-02-15 07:53:18 +0200123}
124
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200125void uart_tx_flush(int idx)
Kyösti Mälkki47707492014-02-15 07:53:18 +0200126{
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200127 uart8250_tx_flush(uart_platform_base(idx));
Stefan Reinauer85b0fa12010-12-17 00:08:21 +0000128}
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200129
Kyösti Mälkki4566d2e2014-04-23 10:28:59 +0300130#if ENV_RAMSTAGE
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200131void uart_fill_lb(void *data)
132{
133 struct lb_serial serial;
134 serial.type = LB_SERIAL_TYPE_IO_MAPPED;
Kyösti Mälkki70342a72014-03-14 22:28:29 +0200135 serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200136 serial.baud = default_baudrate();
Vadim Bendebury9dccf1c2015-01-09 16:54:19 -0800137 serial.regwidth = 1;
Lee Leahy6ec72c92016-05-07 09:04:46 -0700138 serial.input_hertz = uart_platform_refclk();
Lee Leahyf92a98c2016-05-04 11:59:19 -0700139 serial.uart_pci_addr = CONFIG_UART_PCI_ADDR;
Kyösti Mälkkibbf6f3d2014-03-15 01:32:55 +0200140 lb_add_serial(&serial, data);
141
142 lb_add_console(LB_TAG_CONSOLE_SERIAL8250, data);
143}
144#endif