driver/uart: Introduce a way for mainboard to override the baudrate
[coreboot.git] / src / soc / imgtec / pistachio / uart.c
blobf610f6a05d089d97686d299202ee3dccdfb2547f
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2003 Eric Biederman
5 * Copyright (C) 2006-2010 coresystems GmbH
6 * Copyright (C) 2014 Imagination Technologies
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.
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.
19 #include <arch/io.h>
20 #include <boot/coreboot_tables.h>
21 #include <console/console.h>
22 #include <console/uart.h>
23 #include <device/device.h>
24 #include <delay.h>
25 #include <drivers/uart/uart8250reg.h>
27 /* Should support 8250, 16450, 16550, 16550A type UARTs */
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.
33 #define SINGLE_CHAR_TIMEOUT (50 * 1000)
34 #define FIFO_TIMEOUT (16 * SINGLE_CHAR_TIMEOUT)
35 #define UART_SHIFT 2
37 #define GEN_ACCESSOR(name, idx) \
38 static inline uint8_t read_##name(unsigned base_port) \
39 { \
40 return read8(base_port + (idx << UART_SHIFT)); \
41 } \
43 static inline void write_##name(unsigned base_port, uint8_t val) \
44 { \
45 write8(base_port + (idx << UART_SHIFT), val); \
48 GEN_ACCESSOR(rbr, UART8250_RBR)
49 GEN_ACCESSOR(tbr, UART8250_TBR)
50 GEN_ACCESSOR(ier, UART8250_IER)
51 GEN_ACCESSOR(fcr, UART8250_FCR)
52 GEN_ACCESSOR(lcr, UART8250_LCR)
53 GEN_ACCESSOR(mcr, UART8250_MCR)
54 GEN_ACCESSOR(lsr, UART8250_LSR)
55 GEN_ACCESSOR(dll, UART8250_DLL)
56 GEN_ACCESSOR(dlm, UART8250_DLM)
58 static int uart8250_mem_can_tx_byte(unsigned base_port)
60 return read_lsr(base_port) & UART8250_LSR_THRE;
63 static void uart8250_mem_tx_byte(unsigned base_port, unsigned char data)
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);
71 static void uart8250_mem_tx_flush(unsigned base_port)
73 unsigned long int i = FIFO_TIMEOUT;
74 while (i-- && !(read_lsr(base_port) & UART8250_LSR_TEMT))
75 udelay(1);
78 static int uart8250_mem_can_rx_byte(unsigned base_port)
80 return read_lsr(base_port) & UART8250_LSR_DR;
83 static unsigned char uart8250_mem_rx_byte(unsigned base_port)
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;
94 static void uart8250_mem_init(unsigned base_port, unsigned divisor)
96 /* Disable interrupts */
97 write_ier(base_port, 0x0);
98 /* Enable FIFOs */
99 write_fcr(base_port, UART8250_FCR_FIFO_EN);
101 /* Assert DTR and RTS so the other end is happy */
102 write_mcr(base_port, UART8250_MCR_DTR | UART8250_MCR_RTS);
104 /* DLAB on */
105 write_lcr(base_port, UART8250_LCR_DLAB | CONFIG_TTYS0_LCS);
107 write_dll(base_port, divisor & 0xFF);
108 write_dlm(base_port, (divisor >> 8) & 0xFF);
110 /* Set to 3 for 8N1 */
111 write_lcr(base_port, CONFIG_TTYS0_LCS);
114 unsigned int uart_platform_refclk(void)
116 /* 1.8433179 MHz */
117 return 1843318;
120 void uart_init(int idx)
122 u32 base = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
123 if (!base)
124 return;
126 unsigned int div;
127 div = uart_baudrate_divisor(get_uart_baudrate(),
128 uart_platform_refclk(), 16);
129 uart8250_mem_init(base, div);
132 void uart_tx_byte(int idx, unsigned char data)
134 uart8250_mem_tx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS, data);
137 unsigned char uart_rx_byte(int idx)
139 return uart8250_mem_rx_byte(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
142 void uart_tx_flush(int idx)
144 uart8250_mem_tx_flush(CONFIG_CONSOLE_SERIAL_UART_ADDRESS);
147 #ifndef __PRE_RAM__
148 void uart_fill_lb(void *data)
150 struct lb_serial serial;
151 serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
152 serial.baseaddr = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
153 serial.baud = get_uart_baudrate();
154 serial.regwidth = 1 << UART_SHIFT;
155 lb_add_serial(&serial, data);
157 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
159 #endif