These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / core / uart.c
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 /** @file
27  *
28  * 16550-compatible UART
29  *
30  */
31
32 #include <unistd.h>
33 #include <errno.h>
34 #include <ipxe/uart.h>
35
36 /** Timeout for transmit holding register to become empty */
37 #define UART_THRE_TIMEOUT_MS 100
38
39 /** Timeout for transmitter to become empty */
40 #define UART_TEMT_TIMEOUT_MS 1000
41
42 /**
43  * Transmit data
44  *
45  * @v uart              UART
46  * @v data              Data
47  */
48 void uart_transmit ( struct uart *uart, uint8_t data ) {
49         unsigned int i;
50         uint8_t lsr;
51
52         /* Wait for transmitter holding register to become empty */
53         for ( i = 0 ; i < UART_THRE_TIMEOUT_MS ; i++ ) {
54                 lsr = uart_read ( uart, UART_LSR );
55                 if ( lsr & UART_LSR_THRE )
56                         break;
57                 mdelay ( 1 );
58         }
59
60         /* Transmit data (even if we timed out) */
61         uart_write ( uart, UART_THR, data );
62 }
63
64 /**
65  * Flush data
66  *
67  * @v uart              UART
68  */
69 void uart_flush ( struct uart *uart ) {
70         unsigned int i;
71         uint8_t lsr;
72
73         /* Wait for transmitter and receiver to become empty */
74         for ( i = 0 ; i < UART_TEMT_TIMEOUT_MS ; i++ ) {
75                 uart_read ( uart, UART_RBR );
76                 lsr = uart_read ( uart, UART_LSR );
77                 if ( ( lsr & UART_LSR_TEMT ) && ! ( lsr & UART_LSR_DR ) )
78                         break;
79         }
80 }
81
82 /**
83  * Check for existence of UART
84  *
85  * @v uart              UART
86  * @ret rc              Return status code
87  */
88 int uart_exists ( struct uart *uart ) {
89
90         /* Fail if no UART port is defined */
91         if ( ! uart->base )
92                 return -ENODEV;
93
94         /* Fail if UART scratch register seems not to be present */
95         uart_write ( uart, UART_SCR, 0x18 );
96         if ( uart_read ( uart, UART_SCR ) != 0x18 )
97                 return -ENODEV;
98         uart_write ( uart, UART_SCR, 0xae );
99         if ( uart_read ( uart, UART_SCR ) != 0xae )
100                 return -ENODEV;
101
102         return 0;
103 }
104
105 /**
106  * Initialise UART
107  *
108  * @v uart              UART
109  * @v baud              Baud rate, or zero to leave unchanged
110  * @v lcr               Line control register value, or zero to leave unchanged
111  * @ret rc              Return status code
112  */
113 int uart_init ( struct uart *uart, unsigned int baud, uint8_t lcr ) {
114         uint8_t dlm;
115         uint8_t dll;
116         int rc;
117
118         /* Check for existence of UART */
119         if ( ( rc = uart_exists ( uart ) ) != 0 )
120                 return rc;
121
122         /* Configure divisor and line control register, if applicable */
123         if ( ! lcr )
124                 lcr = uart_read ( uart, UART_LCR );
125         uart->lcr = lcr;
126         uart_write ( uart, UART_LCR, ( lcr | UART_LCR_DLAB ) );
127         if ( baud ) {
128                 uart->divisor = ( UART_MAX_BAUD / baud );
129                 dlm = ( ( uart->divisor >> 8 ) & 0xff );
130                 dll = ( ( uart->divisor >> 0 ) & 0xff );
131                 uart_write ( uart, UART_DLM, dlm );
132                 uart_write ( uart, UART_DLL, dll );
133         } else {
134                 dlm = uart_read ( uart, UART_DLM );
135                 dll = uart_read ( uart, UART_DLL );
136                 uart->divisor = ( ( dlm << 8 ) | dll );
137         }
138         uart_write ( uart, UART_LCR, ( lcr & ~UART_LCR_DLAB ) );
139
140         /* Disable interrupts */
141         uart_write ( uart, UART_IER, 0 );
142
143         /* Enable FIFOs */
144         uart_write ( uart, UART_FCR, UART_FCR_FE );
145
146         /* Assert DTR and RTS */
147         uart_write ( uart, UART_MCR, ( UART_MCR_DTR | UART_MCR_RTS ) );
148
149         /* Flush any stale data */
150         uart_flush ( uart );
151
152         return 0;
153 }