Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / serial.c
1 /*
2  * The serial port interface routines implement a simple polled i/o
3  * interface to a standard serial port.  Due to the space restrictions
4  * for the boot blocks, no BIOS support is used (since BIOS requires
5  * expensive real/protected mode switches), instead the rudimentary
6  * BIOS support is duplicated here.
7  *
8  * The base address and speed for the i/o port are passed from the
9  * Makefile in the COMCONSOLE and CONSPEED preprocessor macros.  The
10  * line control parameters are currently hard-coded to 8 bits, no
11  * parity, 1 stop bit (8N1).  This can be changed in init_serial().
12  */
13
14 FILE_LICENCE ( GPL2_OR_LATER );
15
16 #include "stddef.h"
17 #include <ipxe/init.h>
18 #include <ipxe/io.h>
19 #include <unistd.h>
20 #include <ipxe/serial.h>
21 #include "config/serial.h"
22
23 /* Set default values if none specified */
24
25 #ifndef COMCONSOLE
26 #define COMCONSOLE      0x3f8
27 #endif
28
29 #ifndef COMSPEED
30 #define COMSPEED        9600
31 #endif
32
33 #ifndef COMDATA
34 #define COMDATA         8
35 #endif
36
37 #ifndef COMPARITY
38 #define COMPARITY       0
39 #endif
40
41 #ifndef COMSTOP
42 #define COMSTOP         1
43 #endif
44
45 #undef UART_BASE
46 #define UART_BASE ( COMCONSOLE )
47
48 #undef UART_BAUD
49 #define UART_BAUD ( COMSPEED )
50
51 #if ((115200%UART_BAUD) != 0)
52 #error Bad ttys0 baud rate
53 #endif
54
55 #define COMBRD (115200/UART_BAUD)
56
57 /* Line Control Settings */
58 #define UART_LCS ( ( ( (COMDATA) - 5 )  << 0 ) | \
59                    ( ( (COMPARITY) )    << 3 ) | \
60                    ( ( (COMSTOP) - 1 )  << 2 ) )
61
62 /* Data */
63 #define UART_RBR 0x00
64 #define UART_TBR 0x00
65
66 /* Control */
67 #define UART_IER 0x01
68 #define UART_IIR 0x02
69 #define UART_FCR 0x02
70 #define UART_LCR 0x03
71 #define UART_MCR 0x04
72 #define UART_DLL 0x00
73 #define UART_DLM 0x01
74
75 /* Status */
76 #define UART_LSR 0x05
77 #define  UART_LSR_TEMPT 0x40    /* Transmitter empty */
78 #define  UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
79 #define  UART_LSR_BI    0x10    /* Break interrupt indicator */
80 #define  UART_LSR_FE    0x08    /* Frame error indicator */
81 #define  UART_LSR_PE    0x04    /* Parity error indicator */
82 #define  UART_LSR_OE    0x02    /* Overrun error indicator */
83 #define  UART_LSR_DR    0x01    /* Receiver data ready */
84
85 #define UART_MSR 0x06
86 #define UART_SCR 0x07
87
88 #if defined(UART_MEM)
89 #define uart_readb(addr) readb((addr))
90 #define uart_writeb(val,addr) writeb((val),(addr))
91 #else
92 #define uart_readb(addr) inb((addr))
93 #define uart_writeb(val,addr) outb((val),(addr))
94 #endif
95
96 /* Boolean for the state of serial driver initialization */
97 int serial_initialized = 0;
98
99 /*
100  * void serial_putc(int ch);
101  *      Write character `ch' to port UART_BASE.
102  */
103 void serial_putc ( int ch ) {
104         int i;
105         int status;
106         i = 1000; /* timeout */
107         while(--i > 0) {
108                 status = uart_readb(UART_BASE + UART_LSR);
109                 if (status & UART_LSR_THRE) { 
110                         /* TX buffer emtpy */
111                         uart_writeb(ch, UART_BASE + UART_TBR);
112                         break;
113                 }
114                 mdelay(2);
115         }
116 }
117
118 /*
119  * int serial_getc(void);
120  *      Read a character from port UART_BASE.
121  */
122 int serial_getc ( void ) {
123         int status;
124         int ch;
125         do {
126                 status = uart_readb(UART_BASE + UART_LSR);
127         } while((status & 1) == 0);
128         ch = uart_readb(UART_BASE + UART_RBR);  /* fetch (first) character */
129         ch &= 0x7f;                             /* remove any parity bits we get */
130         if (ch == 0x7f) {                       /* Make DEL... look like BS */
131                 ch = 0x08;
132         }
133         return ch;
134 }
135
136 /*
137  * int serial_ischar(void);
138  *       If there is a character in the input buffer of port UART_BASE,
139  *       return nonzero; otherwise return 0.
140  */
141 int serial_ischar ( void ) {
142         int status;
143         status = uart_readb(UART_BASE + UART_LSR);      /* line status reg; */
144         return status & 1;              /* rx char available */
145 }
146
147 /*
148  * int serial_init(void);
149  *      Initialize port UART_BASE to speed COMSPEED, line settings 8N1.
150  */
151 static void serial_init ( void ) {
152         int status;
153         int divisor, lcs;
154
155         DBG ( "Serial port %#x initialising\n", UART_BASE );
156
157         divisor = COMBRD;
158         lcs = UART_LCS;
159
160
161 #ifdef COMPRESERVE
162         lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f;
163         uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
164         divisor = (uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE + UART_DLL);
165         uart_writeb(lcs, UART_BASE + UART_LCR);
166 #endif
167
168         /* Set Baud Rate Divisor to COMSPEED, and test to see if the
169          * serial port appears to be present.
170          */
171         uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
172         uart_writeb(0xaa, UART_BASE + UART_DLL);
173         if (uart_readb(UART_BASE + UART_DLL) != 0xaa) {
174                 DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
175                 goto out;
176         }
177         uart_writeb(0x55, UART_BASE + UART_DLL);
178         if (uart_readb(UART_BASE + UART_DLL) != 0x55) {
179                 DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
180                 goto out;
181         }
182         uart_writeb(divisor & 0xff, UART_BASE + UART_DLL);
183         if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) {
184                 DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE );
185                 goto out;
186         }
187         uart_writeb(0xaa, UART_BASE + UART_DLM);
188         if (uart_readb(UART_BASE + UART_DLM) != 0xaa) {
189                 DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
190                 goto out;
191         }
192         uart_writeb(0x55, UART_BASE + UART_DLM);
193         if (uart_readb(UART_BASE + UART_DLM) != 0x55) {
194                 DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
195                 goto out;
196         }
197         uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM);
198         if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) {
199                 DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE );
200                 goto out;
201         }
202         uart_writeb(lcs, UART_BASE + UART_LCR);
203         
204         /* disable interrupts */
205         uart_writeb(0x0, UART_BASE + UART_IER);
206
207         /* enable fifos */
208         uart_writeb(0x01, UART_BASE + UART_FCR);
209
210         /* Set clear to send, so flow control works... */
211         uart_writeb((1<<1), UART_BASE + UART_MCR);
212
213         /* Flush the input buffer. */
214         do {
215                 /* rx buffer reg
216                  * throw away (unconditionally the first time)
217                  */
218                 (void) uart_readb(UART_BASE + UART_RBR);
219                 /* line status reg */
220                 status = uart_readb(UART_BASE + UART_LSR);
221         } while(status & UART_LSR_DR);
222
223         /* Note that serial support has been initialized */
224         serial_initialized = 1;
225  out:
226         return;
227 }
228
229 /*
230  * void serial_fini(void);
231  *      Cleanup our use of the serial port, in particular flush the
232  *      output buffer so we don't accidentially lose characters.
233  */
234 static void serial_fini ( int flags __unused ) {
235         int i, status;
236         /* Flush the output buffer to avoid dropping characters,
237          * if we are reinitializing the serial port.
238          */
239         i = 10000; /* timeout */
240         do {
241                 status = uart_readb(UART_BASE + UART_LSR);
242         } while((--i > 0) && !(status & UART_LSR_TEMPT));
243         /* Don't mark it as disabled; it's still usable */
244 }
245
246 /**
247  * Serial driver initialisation function
248  *
249  * Initialise serial port early on so that it is available to capture
250  * early debug messages.
251  */
252 struct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = {
253         .initialise = serial_init,
254 };
255
256 /** Serial driver startup function */
257 struct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = {
258         .shutdown = serial_fini,
259 };