Adjust memory layout for 2.6.22+ kernels with 32KB setup code
[mknbi.git] / serial.c
1 #ifdef  CONSOLE_SERIAL
2 #include "etherboot.h"
3 #include "linux-asm-io.h"
4
5 /*
6  * The serial port interface routines implement a simple polled i/o
7  * interface to a standard serial port.  Due to the space restrictions
8  * for the boot blocks, no BIOS support is used (since BIOS requires
9  * expensive real/protected mode switches), instead the rudimentary
10  * BIOS support is duplicated here.
11  *
12  * The base address and speed for the i/o port are passed from the
13  * Makefile in the COMCONSOLE and CONSPEED preprocessor macros.  The
14  * line control parameters are currently hard-coded to 8 bits, no
15  * parity, 1 stop bit (8N1).  This can be changed in serial_init().
16  */
17
18 static int found = 0;
19
20 #define UART_BASE COMCONSOLE
21
22 #ifndef CONSPEED
23 #define CONSPEED 115200
24 #endif
25
26 #if ((115200%CONSPEED) != 0)
27 #error Bad ttys0 baud rate
28 #endif
29
30 #define COMBRD (115200/CONSPEED)
31
32 /* Line Control Settings */
33 #ifndef COMPARM
34 /* Set 8bit, 1 stop bit, no parity */
35 #define COMPARM 0x03
36 #endif
37
38 #define UART_LCS COMPARM
39
40 /* Data */
41 #define UART_RBR 0x00
42 #define UART_TBR 0x00
43
44 /* Control */
45 #define UART_IER 0x01
46 #define UART_IIR 0x02
47 #define UART_FCR 0x02
48 #define UART_LCR 0x03
49 #define UART_MCR 0x04
50 #define UART_DLL 0x00
51 #define UART_DLM 0x01
52
53 /* Status */
54 #define UART_LSR 0x05
55 #define UART_MSR 0x06
56 #define UART_SCR 0x07
57
58 /*
59  * void serial_putc(int ch);
60  *      Write character `ch' to port COMCONSOLE.
61  */
62 void serial_putc(int ch)
63 {
64         int i;
65         int status;
66         if (!found) {
67                 /* no serial interface */
68                 return;
69         }
70         i = 10000; /* timeout */
71         while(--i > 0) {
72                 status = inb(COMCONSOLE + UART_LSR);
73                 if (status & (1 << 5)) { 
74                         /* TX buffer emtpy */
75                         outb(ch, COMCONSOLE + UART_TBR);
76                         break;
77                 }
78         }
79 }
80
81 /*
82  * int serial_getc(void);
83  *      Read a character from port COMCONSOLE.
84  */
85 int serial_getc(void)
86 {
87         int status;
88         int ch;
89         do {
90                 status = inb(COMCONSOLE + UART_LSR);
91         } while((status & 1) == 0);
92         ch = inb(COMCONSOLE + UART_RBR);        /* fetch (first) character */
93         ch &= 0x7f;                             /* remove any parity bits we get */
94         if (ch == 0x7f) {                       /* Make DEL... look like BS */
95                 ch = 0x08;
96         }
97         return ch;
98 }
99
100 /*
101  * int serial_ischar(void);
102  *       If there is a character in the input buffer of port COMCONSOLE,
103  *       return nonzero; otherwise return 0.
104  */
105 int serial_ischar(void)
106 {
107         int status;
108         if (!found)
109                 return 0;
110         status = inb(COMCONSOLE + UART_LSR);    /* line status reg; */
111         return status & 1;              /* rx char available */
112 }
113
114 #if     !defined(COMBRD) && defined(CONSPEED)
115 /* Recent GNU as versions with ELF output format define / as a comment
116  * character, because some misguided spec says so.  Do it the easy way and
117  * just check for the usual values.  This is only compiled by gcc, so
118  * #elif can be used (bcc doesn't understand it).  */
119 #if     (CONSPEED == 115200)
120 #define COMBRD 1
121 #elif   (CONSPEED == 57600)
122 #define COMBRD 2
123 #elif   (CONSPEED == 38400)
124 #define COMBRD 3
125 #elif   (CONSPEED == 19200)
126 #define COMBRD 6
127 #elif   (CONSPEED == 9600)
128 #define COMBRD 12
129 #elif   (CONSPEED == 2400)
130 #define COMBRD 48
131 #elif   (CONSPEED == 1200)
132 #define COMBRD 96
133 #elif   (CONSPEED == 300)
134 #define COMBRD 384
135 #else
136 #error Add your unusual baud rate to the table in serial.S!
137 #define COMBRD  (115200 / CONSPEED)
138 #endif
139 #endif
140
141
142 /*
143  * int serial_init(void);
144  *      Initialize port COMCONSOLE to speed CONSPEED, line settings 8N1.
145  */
146 int serial_init(void)
147 {
148         int initialized = 0;
149         int status;
150         int divisor, lcs;
151
152         divisor = COMBRD;
153         lcs = UART_LCS;
154
155
156 #ifdef COMPRESERVE
157         lcs = inb(COMCONSOLE + UART_LCR) & 0x7f;
158         outb(0x80 | lcs, COMCONSOLE + UART_LCR);
159         divisor = (inb(COMCONSOLE + UART_DLM) << 8) | inb(COMCONSOLE + UART_DLL);
160         outb(lcs, COMCONSOLE + UART_LCR);
161 #endif
162
163         /* Set Baud Rate Divisor to CONSPEED, and test to see if the
164          * serial port appears to be present.
165          */
166         outb(0x80 | lcs, COMCONSOLE + UART_LCR);
167         outb(0xaa, COMCONSOLE + UART_DLL);
168         if (inb(COMCONSOLE + UART_DLL) != 0xaa) 
169                 goto out;
170         outb(0x55, COMCONSOLE + UART_DLL);
171         if (inb(COMCONSOLE + UART_DLL) != 0x55)
172                 goto out;
173         outb(divisor & 0xff, COMCONSOLE + UART_DLL);
174         if (inb(COMCONSOLE + UART_DLL) != (divisor & 0xff))
175                 goto out;
176         outb(0xaa, COMCONSOLE + UART_DLM);
177         if (inb(COMCONSOLE + UART_DLM) != 0xaa) 
178                 goto out;
179         outb(0x55, COMCONSOLE + UART_DLM);
180         if (inb(COMCONSOLE + UART_DLM) != 0x55)
181                 goto out;
182         outb((divisor >> 8) & 0xff, COMCONSOLE + UART_DLM);
183         if (inb(COMCONSOLE + UART_DLM) != ((divisor >> 8) & 0xff))
184                 goto out;
185         outb(lcs, COMCONSOLE + UART_LCR);
186         
187         /* disable interrupts */
188         outb(0x0, COMCONSOLE + UART_IER);
189
190         /* disable fifo's */
191         outb(0x00, COMCONSOLE + UART_FCR);
192
193         /* Set clear to send, so flow control works... */
194         outb((1<<1), COMCONSOLE + UART_MCR);
195
196
197         /* Flush the input buffer. */
198         do {
199                 /* rx buffer reg
200                  * throw away (unconditionally the first time)
201                  */
202                 inb(COMCONSOLE + UART_RBR);
203                 /* line status reg */
204                 status = inb(COMCONSOLE + UART_LSR);
205         } while(status & 1);
206         initialized = 1;
207  out:
208         found = initialized;
209         return initialized;
210 }
211
212 /*
213  * void serial_fini(void);
214  *      Cleanup our use of the serial port, in particular flush the
215  *      output buffer so we don't accidentially loose characters.
216  */
217 void serial_fini(void)
218 {
219         int i, status;
220         if (!found) {
221                 /* no serial interface */
222                 return;
223         }
224         /* Flush the output buffer to avoid dropping characters,
225          * if we are reinitializing the serial port.
226          */
227         i = 10000; /* timeout */
228         do {
229                 status = inb(COMCONSOLE + UART_LSR);
230         } while((--i > 0) || (!(status & (1 << 6))));
231         found = 0;
232 }
233 #endif