]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | /* | |
30 | * file: pe_serial.c | |
31 | * Polled-mode 16x50 UART driver. | |
32 | */ | |
33 | ||
34 | #include <machine/machine_routines.h> | |
35 | #include <pexpert/protos.h> | |
36 | #include <pexpert/pexpert.h> | |
37 | ||
38 | struct pe_serial_functions { | |
39 | void (*uart_init) (void); | |
40 | void (*uart_set_baud_rate) (int unit, uint32_t baud_rate); | |
41 | int (*tr0) (void); | |
42 | void (*td0) (int c); | |
43 | int (*rr0) (void); | |
44 | int (*rd0) (void); | |
45 | }; | |
46 | ||
47 | static struct pe_serial_functions *gPESF; | |
48 | ||
49 | static int uart_initted = 0; /* 1 if init'ed */ | |
50 | ||
51 | static unsigned int legacy_uart_enabled = 0; /* 1 Legacy IO based UART is supported on platform */ | |
52 | ||
53 | static boolean_t lpss_uart_supported = 0; /* 1 if LPSS UART is supported on platform */ | |
54 | static unsigned int lpss_uart_enabled = 0; /* 1 if it is LPSS UART is in D0 state */ | |
55 | static void lpss_uart_re_init(void); | |
56 | ||
57 | static boolean_t pcie_uart_enabled = 0; /* 1 if PCIe UART is supported on platform */ | |
58 | ||
59 | #define DEFAULT_UART_BAUD_RATE 115200 | |
60 | ||
61 | static unsigned uart_baud_rate = DEFAULT_UART_BAUD_RATE; | |
62 | ||
63 | // ============================================================================= | |
64 | // Legacy UART support using IO transactions to COM1 or COM2 | |
65 | // ============================================================================= | |
66 | ||
67 | #define LEGACY_UART_PORT_ADDR COM1_PORT_ADDR | |
68 | #define LEGACY_UART_CLOCK 1843200 /* 1.8432 MHz clock */ | |
69 | ||
70 | #define IO_WRITE(r, v) outb(LEGACY_UART_PORT_ADDR + UART_##r, v) | |
71 | #define IO_READ(r) inb(LEGACY_UART_PORT_ADDR + UART_##r) | |
72 | ||
73 | enum { | |
74 | COM1_PORT_ADDR = 0x3f8, | |
75 | COM2_PORT_ADDR = 0x2f8 | |
76 | }; | |
77 | ||
78 | enum { | |
79 | UART_RBR = 0, /* receive buffer Register (R) */ | |
80 | UART_THR = 0, /* transmit holding register (W) */ | |
81 | UART_DLL = 0, /* DLAB = 1, divisor latch (LSB) */ | |
82 | UART_IER = 1, /* interrupt enable register */ | |
83 | UART_DLM = 1, /* DLAB = 1, divisor latch (MSB) */ | |
84 | UART_IIR = 2, /* interrupt ident register (R) */ | |
85 | UART_FCR = 2, /* fifo control register (W) */ | |
86 | UART_LCR = 3, /* line control register */ | |
87 | UART_MCR = 4, /* modem control register */ | |
88 | UART_LSR = 5, /* line status register */ | |
89 | UART_MSR = 6, /* modem status register */ | |
90 | UART_SCR = 7 /* scratch register */ | |
91 | }; | |
92 | ||
93 | enum { | |
94 | UART_LCR_8BITS = 0x03, | |
95 | UART_LCR_DLAB = 0x80 | |
96 | }; | |
97 | ||
98 | enum { | |
99 | UART_MCR_DTR = 0x01, | |
100 | UART_MCR_RTS = 0x02, | |
101 | UART_MCR_OUT1 = 0x04, | |
102 | UART_MCR_OUT2 = 0x08, | |
103 | UART_MCR_LOOP = 0x10 | |
104 | }; | |
105 | ||
106 | enum { | |
107 | UART_LSR_DR = 0x01, | |
108 | UART_LSR_OE = 0x02, | |
109 | UART_LSR_PE = 0x04, | |
110 | UART_LSR_FE = 0x08, | |
111 | UART_LSR_THRE = 0x20 | |
112 | }; | |
113 | ||
114 | enum { | |
115 | UART_CLK_125M_1 = 0x60002, | |
116 | UART_CLK_125M_2 = 0x80060003, | |
117 | }; | |
118 | ||
119 | static int | |
120 | legacy_uart_probe( void ) | |
121 | { | |
122 | /* Verify that the Scratch Register is accessible */ | |
123 | ||
124 | IO_WRITE( SCR, 0x5a ); | |
125 | if (IO_READ(SCR) != 0x5a) { | |
126 | return 0; | |
127 | } | |
128 | IO_WRITE( SCR, 0xa5 ); | |
129 | if (IO_READ(SCR) != 0xa5) { | |
130 | return 0; | |
131 | } | |
132 | return 1; | |
133 | } | |
134 | ||
135 | static void | |
136 | legacy_uart_set_baud_rate( __unused int unit, uint32_t baud_rate ) | |
137 | { | |
138 | const unsigned char lcr = IO_READ( LCR ); | |
139 | unsigned long div; | |
140 | ||
141 | if (baud_rate == 0) { | |
142 | baud_rate = 9600; | |
143 | } | |
144 | div = LEGACY_UART_CLOCK / 16 / baud_rate; | |
145 | IO_WRITE( LCR, lcr | UART_LCR_DLAB ); | |
146 | IO_WRITE( DLM, (unsigned char)(div >> 8)); | |
147 | IO_WRITE( DLL, (unsigned char) div ); | |
148 | IO_WRITE( LCR, lcr & ~UART_LCR_DLAB); | |
149 | } | |
150 | ||
151 | static int | |
152 | legacy_uart_tr0( void ) | |
153 | { | |
154 | return IO_READ(LSR) & UART_LSR_THRE; | |
155 | } | |
156 | ||
157 | static void | |
158 | legacy_uart_td0( int c ) | |
159 | { | |
160 | IO_WRITE( THR, c ); | |
161 | } | |
162 | ||
163 | static void | |
164 | legacy_uart_init( void ) | |
165 | { | |
166 | /* Disable hardware interrupts */ | |
167 | ||
168 | IO_WRITE( MCR, 0 ); | |
169 | IO_WRITE( IER, 0 ); | |
170 | ||
171 | /* Disable FIFO's for 16550 devices */ | |
172 | ||
173 | IO_WRITE( FCR, 0 ); | |
174 | ||
175 | /* Set for 8-bit, no parity, DLAB bit cleared */ | |
176 | ||
177 | IO_WRITE( LCR, UART_LCR_8BITS ); | |
178 | ||
179 | /* Set baud rate */ | |
180 | ||
181 | gPESF->uart_set_baud_rate( 0, uart_baud_rate ); | |
182 | ||
183 | /* Assert DTR# and RTS# lines (OUT2?) */ | |
184 | ||
185 | IO_WRITE( MCR, UART_MCR_DTR | UART_MCR_RTS ); | |
186 | ||
187 | /* Clear any garbage in the input buffer */ | |
188 | ||
189 | IO_READ( RBR ); | |
190 | ||
191 | uart_initted = 1; | |
192 | } | |
193 | ||
194 | static int | |
195 | legacy_uart_rr0( void ) | |
196 | { | |
197 | unsigned char lsr; | |
198 | ||
199 | lsr = IO_READ( LSR ); | |
200 | ||
201 | if (lsr & (UART_LSR_FE | UART_LSR_PE | UART_LSR_OE)) { | |
202 | IO_READ( RBR ); /* discard */ | |
203 | return 0; | |
204 | } | |
205 | ||
206 | return lsr & UART_LSR_DR; | |
207 | } | |
208 | ||
209 | static int | |
210 | legacy_uart_rd0( void ) | |
211 | { | |
212 | return IO_READ( RBR ); | |
213 | } | |
214 | ||
215 | static struct pe_serial_functions legacy_uart_serial_functions = { | |
216 | .uart_init = legacy_uart_init, | |
217 | .uart_set_baud_rate = legacy_uart_set_baud_rate, | |
218 | .tr0 = legacy_uart_tr0, | |
219 | .td0 = legacy_uart_td0, | |
220 | .rr0 = legacy_uart_rr0, | |
221 | .rd0 = legacy_uart_rd0 | |
222 | }; | |
223 | ||
224 | // ============================================================================= | |
225 | // MMIO UART (using PCH LPSS UART2) | |
226 | // ============================================================================= | |
227 | ||
228 | #define MMIO_UART2_BASE_LEGACY 0xFE034000 /* Legacy MMIO Config space */ | |
229 | #define MMIO_UART2_BASE 0xFE036000 /* MMIO Config space */ | |
230 | #define PCI_UART2 0xFE037000 /* PCI Config Space */ | |
231 | ||
232 | #define MMIO_WRITE(r, v) ml_phys_write_word(mmio_uart_base + MMIO_UART_##r, v) | |
233 | #define MMIO_READ(r) ml_phys_read_word(mmio_uart_base + MMIO_UART_##r) | |
234 | ||
235 | enum { | |
236 | MMIO_UART_RBR = 0x0, /* receive buffer Register (R) */ | |
237 | MMIO_UART_THR = 0x0, /* transmit holding register (W) */ | |
238 | MMIO_UART_DLL = 0x0, /* DLAB = 1, divisor latch (LSB) */ | |
239 | MMIO_UART_IER = 0x4, /* interrupt enable register */ | |
240 | MMIO_UART_DLM = 0x4, /* DLAB = 1, divisor latch (MSB) */ | |
241 | MMIO_UART_FCR = 0x8, /* fifo control register (W) */ | |
242 | MMIO_UART_LCR = 0xc, /* line control register */ | |
243 | MMIO_UART_MCR = 0x10, /* modem control register */ | |
244 | MMIO_UART_LSR = 0x14, /* line status register */ | |
245 | MMIO_UART_SCR = 0x1c, /* scratch register */ | |
246 | MMIO_UART_CLK = 0x200, /* clocks register */ | |
247 | MMIO_UART_RST = 0x204 /* Reset register */ | |
248 | }; | |
249 | ||
250 | static vm_offset_t mmio_uart_base = 0; | |
251 | ||
252 | static int | |
253 | mmio_uart_present( void ) | |
254 | { | |
255 | MMIO_WRITE( SCR, 0x5a ); | |
256 | if (MMIO_READ(SCR) != 0x5a) { | |
257 | return 0; | |
258 | } | |
259 | MMIO_WRITE( SCR, 0xa5 ); | |
260 | if (MMIO_READ(SCR) != 0xa5) { | |
261 | return 0; | |
262 | } | |
263 | return 1; | |
264 | } | |
265 | ||
266 | static int | |
267 | mmio_uart_probe( void ) | |
268 | { | |
269 | unsigned new_mmio_uart_base = 0; | |
270 | ||
271 | // if specified, mmio_uart overrides all probing | |
272 | if (PE_parse_boot_argn("mmio_uart", &new_mmio_uart_base, sizeof(new_mmio_uart_base))) { | |
273 | // mmio_uart=0 will disable mmio_uart support | |
274 | if (new_mmio_uart_base == 0) { | |
275 | return 0; | |
276 | } | |
277 | ||
278 | mmio_uart_base = new_mmio_uart_base; | |
279 | return 1; | |
280 | } | |
281 | ||
282 | // probe the two possible MMIO_UART2 addresses | |
283 | mmio_uart_base = MMIO_UART2_BASE; | |
284 | if (mmio_uart_present()) { | |
285 | return 1; | |
286 | } | |
287 | ||
288 | mmio_uart_base = MMIO_UART2_BASE_LEGACY; | |
289 | if (mmio_uart_present()) { | |
290 | return 1; | |
291 | } | |
292 | ||
293 | // no mmio uart found | |
294 | return 0; | |
295 | } | |
296 | ||
297 | static void | |
298 | mmio_uart_set_baud_rate( __unused int unit, __unused uint32_t baud_rate ) | |
299 | { | |
300 | const unsigned char lcr = MMIO_READ( LCR ); | |
301 | unsigned long div; | |
302 | ||
303 | if (baud_rate == 0) { | |
304 | baud_rate = 9600; | |
305 | } | |
306 | div = LEGACY_UART_CLOCK / 16 / baud_rate; | |
307 | ||
308 | MMIO_WRITE( LCR, lcr | UART_LCR_DLAB ); | |
309 | MMIO_WRITE( DLM, (unsigned char)(div >> 8)); | |
310 | MMIO_WRITE( DLL, (unsigned char) div ); | |
311 | MMIO_WRITE( LCR, lcr & ~UART_LCR_DLAB); | |
312 | } | |
313 | ||
314 | static int | |
315 | mmio_uart_tr0( void ) | |
316 | { | |
317 | return MMIO_READ(LSR) & UART_LSR_THRE; | |
318 | } | |
319 | ||
320 | static void | |
321 | mmio_uart_td0( int c ) | |
322 | { | |
323 | MMIO_WRITE( THR, c ); | |
324 | } | |
325 | ||
326 | static void | |
327 | mmio_uart_init( void ) | |
328 | { | |
329 | /* Disable hardware interrupts */ | |
330 | ||
331 | MMIO_WRITE( MCR, 0 ); | |
332 | MMIO_WRITE( IER, 0 ); | |
333 | ||
334 | /* Disable FIFO's for 16550 devices */ | |
335 | ||
336 | MMIO_WRITE( FCR, 0 ); | |
337 | ||
338 | /* Set for 8-bit, no parity, DLAB bit cleared */ | |
339 | ||
340 | MMIO_WRITE( LCR, UART_LCR_8BITS ); | |
341 | ||
342 | /* Leave baud rate as set by firmware unless serialbaud boot-arg overrides */ | |
343 | ||
344 | if (uart_baud_rate != DEFAULT_UART_BAUD_RATE) { | |
345 | gPESF->uart_set_baud_rate( 0, uart_baud_rate ); | |
346 | } | |
347 | ||
348 | /* Assert DTR# and RTS# lines (OUT2?) */ | |
349 | ||
350 | MMIO_WRITE( MCR, UART_MCR_DTR | UART_MCR_RTS ); | |
351 | ||
352 | /* Clear any garbage in the input buffer */ | |
353 | ||
354 | MMIO_READ( RBR ); | |
355 | ||
356 | uart_initted = 1; | |
357 | } | |
358 | ||
359 | static int | |
360 | mmio_uart_rr0( void ) | |
361 | { | |
362 | unsigned char lsr; | |
363 | ||
364 | lsr = MMIO_READ( LSR ); | |
365 | ||
366 | if (lsr & (UART_LSR_FE | UART_LSR_PE | UART_LSR_OE)) { | |
367 | MMIO_READ( RBR ); /* discard */ | |
368 | return 0; | |
369 | } | |
370 | ||
371 | return lsr & UART_LSR_DR; | |
372 | } | |
373 | ||
374 | void | |
375 | lpss_uart_enable( boolean_t on_off ) | |
376 | { | |
377 | unsigned int pmcs_reg; | |
378 | ||
379 | if (!lpss_uart_supported) { | |
380 | return; | |
381 | } | |
382 | ||
383 | pmcs_reg = ml_phys_read_byte(PCI_UART2 + 0x84); | |
384 | if (on_off == FALSE) { | |
385 | pmcs_reg |= 0x03; | |
386 | lpss_uart_enabled = 0; | |
387 | } else { | |
388 | pmcs_reg &= ~(0x03); | |
389 | } | |
390 | ||
391 | ml_phys_write_byte(PCI_UART2 + 0x84, pmcs_reg); | |
392 | pmcs_reg = ml_phys_read_byte(PCI_UART2 + 0x84); | |
393 | ||
394 | if (on_off == TRUE) { | |
395 | lpss_uart_re_init(); | |
396 | lpss_uart_enabled = 1; | |
397 | } | |
398 | } | |
399 | ||
400 | static void | |
401 | lpss_uart_re_init( void ) | |
402 | { | |
403 | uint32_t register_read; | |
404 | ||
405 | MMIO_WRITE(RST, 0x7); /* LPSS UART2 controller out ot reset */ | |
406 | register_read = MMIO_READ(RST); | |
407 | ||
408 | MMIO_WRITE(LCR, UART_LCR_DLAB); /* Set DLAB bit to enable reading/writing of DLL, DLH */ | |
409 | register_read = MMIO_READ(LCR); | |
410 | ||
411 | MMIO_WRITE(DLL, 1); /* Divisor Latch Low Register */ | |
412 | register_read = MMIO_READ(DLL); | |
413 | ||
414 | MMIO_WRITE(DLM, 0); /* Divisor Latch High Register */ | |
415 | register_read = MMIO_READ(DLM); | |
416 | ||
417 | MMIO_WRITE(FCR, 1); /* Enable FIFO */ | |
418 | register_read = MMIO_READ(FCR); | |
419 | ||
420 | MMIO_WRITE(LCR, UART_LCR_8BITS); /* Set 8 bits, clear DLAB */ | |
421 | register_read = MMIO_READ(LCR); | |
422 | ||
423 | MMIO_WRITE(MCR, UART_MCR_RTS); /* Request to send */ | |
424 | register_read = MMIO_READ(MCR); | |
425 | ||
426 | MMIO_WRITE(CLK, UART_CLK_125M_1); /* 1.25M Clock speed */ | |
427 | register_read = MMIO_READ(CLK); | |
428 | ||
429 | MMIO_WRITE(CLK, UART_CLK_125M_2); /* 1.25M Clock speed */ | |
430 | register_read = MMIO_READ(CLK); | |
431 | } | |
432 | ||
433 | static int | |
434 | mmio_uart_rd0( void ) | |
435 | { | |
436 | return MMIO_READ( RBR ); | |
437 | } | |
438 | ||
439 | static struct pe_serial_functions mmio_uart_serial_functions = { | |
440 | .uart_init = mmio_uart_init, | |
441 | .uart_set_baud_rate = mmio_uart_set_baud_rate, | |
442 | .tr0 = mmio_uart_tr0, | |
443 | .td0 = mmio_uart_td0, | |
444 | .rr0 = mmio_uart_rr0, | |
445 | .rd0 = mmio_uart_rd0 | |
446 | }; | |
447 | ||
448 | // ============================================================================= | |
449 | // PCIE_MMIO UART | |
450 | // ============================================================================= | |
451 | ||
452 | #define PCIE_MMIO_UART_BASE 0xFE410000 | |
453 | ||
454 | #define PCIE_MMIO_WRITE(r, v) ml_phys_write_byte(pcie_mmio_uart_base + PCIE_MMIO_UART_##r, v) | |
455 | #define PCIE_MMIO_READ(r) ml_phys_read_byte(pcie_mmio_uart_base + PCIE_MMIO_UART_##r) | |
456 | ||
457 | enum { | |
458 | PCIE_MMIO_UART_RBR = 0x0, /* receive buffer Register (R) */ | |
459 | PCIE_MMIO_UART_THR = 0x0, /* transmit holding register (W) */ | |
460 | PCIE_MMIO_UART_IER = 0x1, /* interrupt enable register */ | |
461 | PCIE_MMIO_UART_FCR = 0x2, /* fifo control register (W) */ | |
462 | PCIE_MMIO_UART_LCR = 0x4, /* line control register */ | |
463 | PCIE_MMIO_UART_MCR = 0x4, /* modem control register */ | |
464 | PCIE_MMIO_UART_LSR = 0x5, /* line status register */ | |
465 | PCIE_MMIO_UART_DLL = 0x8, /* DLAB = 1, divisor latch (LSB) */ | |
466 | PCIE_MMIO_UART_DLM = 0x9, /* DLAB = 1, divisor latch (MSB) */ | |
467 | PCIE_MMIO_UART_SCR = 0x30, /* scratch register */ | |
468 | }; | |
469 | ||
470 | static vm_offset_t pcie_mmio_uart_base = 0; | |
471 | ||
472 | static int | |
473 | pcie_mmio_uart_present( void ) | |
474 | { | |
475 | PCIE_MMIO_WRITE( SCR, 0x5a ); | |
476 | if (PCIE_MMIO_READ(SCR) != 0x5a) { | |
477 | return 0; | |
478 | } | |
479 | PCIE_MMIO_WRITE( SCR, 0xa5 ); | |
480 | if (PCIE_MMIO_READ(SCR) != 0xa5) { | |
481 | return 0; | |
482 | } | |
483 | ||
484 | return 1; | |
485 | } | |
486 | ||
487 | static int | |
488 | pcie_mmio_uart_probe( void ) | |
489 | { | |
490 | unsigned new_pcie_mmio_uart_base = 0; | |
491 | ||
492 | // if specified, pcie_mmio_uart overrides all probing | |
493 | if (PE_parse_boot_argn("pcie_mmio_uart", &new_pcie_mmio_uart_base, sizeof(new_pcie_mmio_uart_base))) { | |
494 | // pcie_mmio_uart=0 will disable pcie_mmio_uart support | |
495 | if (new_pcie_mmio_uart_base == 0) { | |
496 | return 0; | |
497 | } | |
498 | pcie_mmio_uart_base = new_pcie_mmio_uart_base; | |
499 | return 1; | |
500 | } | |
501 | ||
502 | pcie_mmio_uart_base = PCIE_MMIO_UART_BASE; | |
503 | if (pcie_mmio_uart_present()) { | |
504 | return 1; | |
505 | } | |
506 | ||
507 | // no pcie_mmio uart found | |
508 | return 0; | |
509 | } | |
510 | ||
511 | static void | |
512 | pcie_mmio_uart_set_baud_rate( __unused int unit, __unused uint32_t baud_rate ) | |
513 | { | |
514 | const unsigned char lcr = PCIE_MMIO_READ( LCR ); | |
515 | unsigned long div; | |
516 | ||
517 | if (baud_rate == 0) { | |
518 | baud_rate = 9600; | |
519 | } | |
520 | div = LEGACY_UART_CLOCK / 16 / baud_rate; | |
521 | ||
522 | PCIE_MMIO_WRITE( LCR, lcr | UART_LCR_DLAB ); | |
523 | PCIE_MMIO_WRITE( DLM, (unsigned char)(div >> 8)); | |
524 | PCIE_MMIO_WRITE( DLL, (unsigned char) div ); | |
525 | PCIE_MMIO_WRITE( LCR, lcr & ~UART_LCR_DLAB); | |
526 | } | |
527 | ||
528 | static int | |
529 | pcie_mmio_uart_tr0( void ) | |
530 | { | |
531 | return PCIE_MMIO_READ(LSR) & UART_LSR_THRE; | |
532 | } | |
533 | ||
534 | static void | |
535 | pcie_mmio_uart_td0( int c ) | |
536 | { | |
537 | PCIE_MMIO_WRITE( THR, c ); | |
538 | } | |
539 | ||
540 | static void | |
541 | pcie_mmio_uart_init( void ) | |
542 | { | |
543 | uart_initted = 1; | |
544 | } | |
545 | ||
546 | static int | |
547 | pcie_mmio_uart_rr0( void ) | |
548 | { | |
549 | unsigned char lsr; | |
550 | ||
551 | lsr = PCIE_MMIO_READ( LSR ); | |
552 | ||
553 | if (lsr & (UART_LSR_FE | UART_LSR_PE | UART_LSR_OE)) { | |
554 | PCIE_MMIO_READ( RBR ); /* discard */ | |
555 | return 0; | |
556 | } | |
557 | ||
558 | return lsr & UART_LSR_DR; | |
559 | } | |
560 | ||
561 | static int | |
562 | pcie_mmio_uart_rd0( void ) | |
563 | { | |
564 | return PCIE_MMIO_READ( RBR ); | |
565 | } | |
566 | ||
567 | static struct pe_serial_functions pcie_mmio_uart_serial_functions = { | |
568 | .uart_init = pcie_mmio_uart_init, | |
569 | .uart_set_baud_rate = pcie_mmio_uart_set_baud_rate, | |
570 | .tr0 = pcie_mmio_uart_tr0, | |
571 | .td0 = pcie_mmio_uart_td0, | |
572 | .rr0 = pcie_mmio_uart_rr0, | |
573 | .rd0 = pcie_mmio_uart_rd0 | |
574 | }; | |
575 | ||
576 | // ============================================================================= | |
577 | // Generic serial support below | |
578 | // ============================================================================= | |
579 | ||
580 | int | |
581 | serial_init( void ) | |
582 | { | |
583 | unsigned new_uart_baud_rate = 0; | |
584 | ||
585 | if (PE_parse_boot_argn("serialbaud", &new_uart_baud_rate, sizeof(new_uart_baud_rate))) { | |
586 | /* Valid divisor? */ | |
587 | if (!((LEGACY_UART_CLOCK / 16) % new_uart_baud_rate)) { | |
588 | uart_baud_rate = new_uart_baud_rate; | |
589 | } | |
590 | } | |
591 | ||
592 | if (mmio_uart_probe()) { | |
593 | gPESF = &mmio_uart_serial_functions; | |
594 | gPESF->uart_init(); | |
595 | lpss_uart_supported = 1; | |
596 | lpss_uart_enabled = 1; | |
597 | return 1; | |
598 | } else if (legacy_uart_probe()) { | |
599 | gPESF = &legacy_uart_serial_functions; | |
600 | gPESF->uart_init(); | |
601 | legacy_uart_enabled = 1; | |
602 | return 1; | |
603 | } else if (pcie_mmio_uart_probe()) { | |
604 | gPESF = &pcie_mmio_uart_serial_functions; | |
605 | gPESF->uart_init(); | |
606 | pcie_uart_enabled = 1; | |
607 | return 1; | |
608 | } else { | |
609 | return 0; | |
610 | } | |
611 | } | |
612 | ||
613 | static void | |
614 | uart_putc(char c) | |
615 | { | |
616 | if (uart_initted && (legacy_uart_enabled || lpss_uart_enabled || pcie_uart_enabled)) { | |
617 | while (!gPESF->tr0()) { | |
618 | ; /* Wait until THR is empty. */ | |
619 | } | |
620 | gPESF->td0(c); | |
621 | } | |
622 | } | |
623 | ||
624 | static int | |
625 | uart_getc(void) | |
626 | { | |
627 | if (uart_initted && (legacy_uart_enabled || lpss_uart_enabled || pcie_uart_enabled)) { | |
628 | if (!gPESF->rr0()) { | |
629 | return -1; | |
630 | } | |
631 | return gPESF->rd0(); | |
632 | } | |
633 | return -1; | |
634 | } | |
635 | ||
636 | void | |
637 | serial_putc( char c ) | |
638 | { | |
639 | uart_putc(c); | |
640 | } | |
641 | ||
642 | int | |
643 | serial_getc( void ) | |
644 | { | |
645 | return uart_getc(); | |
646 | } |