3dbee0b464f1f738f0bd4e49d332657e6aad4eb8
[coreboot.git] / src / lib / uart8250.c
1 /* Should support 8250, 16450, 16550, 16550A type uarts */
2 #include <arch/io.h>
3 #include <uart8250.h>
4
5 /* Data */
6 #define UART_RBR 0x00
7 #define UART_TBR 0x00
8
9 /* Control */
10 #define UART_IER 0x01
11 #define UART_IIR 0x02
12 #define UART_FCR 0x02
13 #define UART_LCR 0x03
14 #define UART_MCR 0x04
15 #define UART_DLL 0x00
16 #define UART_DLM 0x01
17
18 /* Status */
19 #define UART_LSR 0x05
20 #define UART_MSR 0x06
21 #define UART_SCR 0x07
22
23 static inline int uart8250_can_tx_byte(unsigned base_port)
24 {
25         return inb(base_port + UART_LSR) & 0x20;
26 }
27
28 static inline void uart8250_wait_to_tx_byte(unsigned base_port)
29 {
30         while(!uart8250_can_tx_byte(base_port))
31                 ;
32 }
33
34 static inline void uart8250_wait_until_sent(unsigned base_port)
35 {
36         while(!(inb(base_port + UART_LSR) & 0x40))
37                 ;
38 }
39
40 void uart8250_tx_byte(unsigned base_port, unsigned char data)
41 {
42         uart8250_wait_to_tx_byte(base_port);
43         outb(data, base_port + UART_TBR);
44         /* Make certain the data clears the fifos */
45         uart8250_wait_until_sent(base_port);
46 }
47
48 int uart8250_can_rx_byte(unsigned base_port)
49 {
50         return inb(base_port + UART_LSR) & 0x01;
51 }
52
53 unsigned char uart8250_rx_byte(unsigned base_port)
54 {
55         while(!uart8250_can_rx_byte(base_port))
56                 ;
57         return inb(base_port + UART_RBR);
58 }
59
60 void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs)
61 {
62         lcs &= 0x7f;
63         /* disable interrupts */
64         outb(0x0, base_port + UART_IER);
65         /* enable fifo's */
66         outb(0x01, base_port + UART_FCR);
67         /* assert DTR and RTS so the other end is happy */
68         outb(0x03, base_port + UART_MCR);
69         /* Set Baud Rate Divisor to 12 ==> 115200 Baud */
70         outb(0x80 | lcs, base_port + UART_LCR);
71         outb(divisor & 0xFF,   base_port + UART_DLL);
72         outb((divisor >> 8) & 0xFF,    base_port + UART_DLM);
73         outb(lcs, base_port + UART_LCR);
74 }
75
76 /* Initialize a generic uart */
77 void init_uart8250(unsigned base_port, struct uart8250 *uart)
78 {
79         int divisor;
80         int lcs;
81         divisor = 115200/(uart->baud ? uart->baud: 1);
82         lcs = 3;
83         if (base_port == CONFIG_TTYS0_BASE) {
84                 /* Don't reinitialize the console serial port,
85                  * This is espeically nasty in SMP.
86                  */
87                 return;
88         }
89         uart8250_init(base_port, divisor, lcs);
90 }