blob: 1f39e8b7e7c46a7b244f428fe5c5c836419cca1d [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
19#include <arch/io.h>
Patrick Georgi146d05d2015-03-30 13:08:18 +020020#include <boot/coreboot_tables.h>
Paul Burtonc1081a42014-06-14 00:08:02 +010021#include <console/console.h>
Patrick Georgi146d05d2015-03-30 13:08:18 +020022#include <console/uart.h>
Paul Burtonc1081a42014-06-14 00:08:02 +010023#include <device/device.h>
24#include <delay.h>
Patrick Georgi146d05d2015-03-30 13:08:18 +020025#include <drivers/uart/uart8250reg.h>
Paul Burtonc1081a42014-06-14 00:08:02 +010026
27/* Should support 8250, 16450, 16550, 16550A type UARTs */
28
29/* Expected character delay at 1200bps is 9ms for a working UART
30 * and no flow-control. Assume UART as stuck if shift register
31 * or FIFO takes more than 50ms per character to appear empty.
32 */
33#define SINGLE_CHAR_TIMEOUT (50 * 1000)
34#define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
35#define UART_SHIFT 2
36
37#define GEN_ACCESSOR(name, idx) \
38static inline uint8_t read_##name(unsigned base_port) \
39{ \
40 return read8(base_port + (idx << UART_SHIFT)); \
41} \
42 \
43static inline void write_##name(unsigned base_port, uint8_t val) \
44{ \
45 write8(base_port + (idx << UART_SHIFT), val); \
46}
47
48GEN_ACCESSOR(rbr, UART8250_RBR)
49GEN_ACCESSOR(tbr, UART8250_TBR)
50GEN_ACCESSOR(ier, UART8250_IER)
51GEN_ACCESSOR(fcr, UART8250_FCR)
52GEN_ACCESSOR(lcr, UART8250_LCR)
53GEN_ACCESSOR(mcr, UART8250_MCR)
54GEN_ACCESSOR(lsr, UART8250_LSR)
55GEN_ACCESSOR(dll, UART8250_DLL)
56GEN_ACCESSOR(dlm, UART8250_DLM)
57
58static int uart8250_mem_can_tx_byte(unsigned base_port)
59{
60 return read_lsr(base_port) & UART8250_LSR_THRE;
61}
62
63static void uart8250_mem_tx_byte(unsigned base_port, unsigned char data)
64{
65 unsigned long int i = SINGLE_CHAR_TIMEOUT;
66 while (i-- && !uart8250_mem_can_tx_byte(base_port))
67 udelay(1);
68 write_tbr(base_port, data);
69}
70
71static void uart8250_mem_tx_flush(unsigned base_port)
72{
73 unsigned long int i = FIFO_TIMEOUT;
74 while (i-- && !(read_lsr(base_port) & UART8250_LSR_TEMT))
75 udelay(1);
76}
77
78static int uart8250_mem_can_rx_byte(unsigned base_port)
79{
80 return read_lsr(base_port) & UART8250_LSR_DR;
81}
82
83static unsigned char uart8250_mem_rx_byte(unsigned base_port)
84{
85 unsigned long int i = SINGLE_CHAR_TIMEOUT;
86 while (i-- && !uart8250_mem_can_rx_byte(base_port))
87 udelay(1);
88 if (i)
89 return read_rbr(base_port);
90 else
91 return 0x0;
92}
93
94static void uart8250_mem_init(unsigned base_port, unsigned divisor)
95{
96 /* Disable interrupts */
97 write_ier(base_port, 0x0);
98 /* Enable FIFOs */
99 write_fcr(base_port, UART8250_FCR_FIFO_EN);
100
101 /* Assert DTR and RTS so the other end is happy */
102 write_mcr(base_port, UART8250_MCR_DTR | UART8250_MCR_RTS);
103
104 /* DLAB on */
105 write_lcr(base_port, UART8250_LCR_DLAB | CONFIG_TTYS0_LCS);
106
107 write_dll(base_port, divisor & 0xFF);
108 write_dlm(base_port, (divisor >> 8) & 0xFF);
109
110 /* Set to 3 for 8N1 */
111 write_lcr(base_port, CONFIG_TTYS0_LCS);
112}
113
Patrick Georgi146d05d2015-03-30 13:08:18 +0200114unsigned int uart_platform_refclk(void)
Paul Burtonc1081a42014-06-14 00:08:02 +0100115{
David Hendricksb9d59bb2015-01-26 07:19:49 -0800116 /* 1.8433179 MHz */
117 return 1843318;
Paul Burtonc1081a42014-06-14 00:08:02 +0100118}
119
Patrick Georgi146d05d2015-03-30 13:08:18 +0200120void uart_init(int idx)
Paul Burtonc1081a42014-06-14 00:08:02 +0100121{
David Hendricksb116a1a2015-01-26 07:11:01 -0800122 u32 base = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
Paul Burtonc1081a42014-06-14 00:08:02 +0100123 if (!base)
124 return;
125
126 unsigned int div;
127 div = uart_baudrate_divisor(CONFIG_TTYS0_BAUD,
128 uart_platform_refclk(), 16);
129 uart8250_mem_init(base, div);
130}
131
Patrick Georgi146d05d2015-03-30 13:08:18 +0200132void uart_tx_byte(int idx, unsigned char data)
Paul Burtonc1081a42014-06-14 00:08:02 +0100133{
David Hendricksb116a1a2015-01-26 07:11:01 -0800134 uart8250_mem_tx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS, data);
Paul Burtonc1081a42014-06-14 00:08:02 +0100135}
136
Patrick Georgi146d05d2015-03-30 13:08:18 +0200137unsigned char uart_rx_byte(int idx)
Paul Burtonc1081a42014-06-14 00:08:02 +0100138{
David Hendricksb116a1a2015-01-26 07:11:01 -0800139 return uart8250_mem_rx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
Paul Burtonc1081a42014-06-14 00:08:02 +0100140}
141
Patrick Georgi146d05d2015-03-30 13:08:18 +0200142void uart_tx_flush(int idx)
Paul Burtonc1081a42014-06-14 00:08:02 +0100143{
David Hendricksb116a1a2015-01-26 07:11:01 -0800144 uart8250_mem_tx_flush(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
Paul Burtonc1081a42014-06-14 00:08:02 +0100145}
146
Patrick Georgi146d05d2015-03-30 13:08:18 +0200147#ifndef __PRE_RAM__
148void uart_fill_lb(void *data)
Paul Burtonc1081a42014-06-14 00:08:02 +0100149{
Patrick Georgi146d05d2015-03-30 13:08:18 +0200150 struct lb_serial serial;
151 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
David Hendricksb116a1a2015-01-26 07:11:01 -0800152 serial.baseaddr = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
Patrick Georgi146d05d2015-03-30 13:08:18 +0200153 serial.baud = default_baudrate();
Vadim Bendebury7271e232015-01-09 16:55:36 -0800154 serial.regwidth = 1 << UART_SHIFT;
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}
Patrick Georgi146d05d2015-03-30 13:08:18 +0200159#endif