]> git.proxmox.com Git - mirror_edk2.git/blame - CorebootModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
CorebootModulePkg: Add BaseSerialPortLib16550
[mirror_edk2.git] / CorebootModulePkg / Library / BaseSerialPortLib16550 / BaseSerialPortLib16550.c
CommitLineData
12460e22
LL
1/** @file
2 16550 UART Serial Port library functions
3
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include <Base.h>
17#include <IndustryStandard/Pci.h>
18#include <Library/SerialPortLib.h>
19#include <Library/PcdLib.h>
20#include <Library/IoLib.h>
21#include <Library/PciLib.h>
22#include <Library/PlatformHookLib.h>
23#include <Library/BaseLib.h>
24
25//
26// PCI Defintions.
27//
28#define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
29
30//
31// 16550 UART register offsets and bitfields
32//
33#define R_UART_RXBUF 0
34#define R_UART_TXBUF 0
35#define R_UART_BAUD_LOW 0
36#define R_UART_BAUD_HIGH 1
37#define R_UART_FCR 2
38#define B_UART_FCR_FIFOE BIT0
39#define B_UART_FCR_FIFO64 BIT5
40#define R_UART_LCR 3
41#define B_UART_LCR_DLAB BIT7
42#define R_UART_MCR 4
43#define B_UART_MCR_DTRC BIT0
44#define B_UART_MCR_RTS BIT1
45#define R_UART_LSR 5
46#define B_UART_LSR_RXRDY BIT0
47#define B_UART_LSR_TXRDY BIT5
48#define B_UART_LSR_TEMT BIT6
49#define R_UART_MSR 6
50#define B_UART_MSR_CTS BIT4
51#define B_UART_MSR_DSR BIT5
52#define B_UART_MSR_RI BIT6
53#define B_UART_MSR_DCD BIT7
54
55//
56// 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
57//
58typedef struct {
59 UINT8 Device;
60 UINT8 Function;
61 UINT16 PowerManagementStatusAndControlRegister;
62} PCI_UART_DEVICE_INFO;
63
64/**
65 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
66 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
67 parameter Offset is added to the base address of the 16550 registers that is specified
68 by PcdSerialRegisterBase.
69
70 @param Base The base address register of UART device.
71 @param Offset The offset of the 16550 register to read.
72
73 @return The value read from the 16550 register.
74
75**/
76UINT8
77SerialPortReadRegister (
78 UINTN Base,
79 UINTN Offset
80 )
81{
82 if (PcdGetBool (PcdSerialUseMmio)) {
83 return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
84 } else {
85 return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
86 }
87}
88
89/**
90 Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
91 MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
92 parameter Offset is added to the base address of the 16550 registers that is specified
93 by PcdSerialRegisterBase.
94
95 @param Base The base address register of UART device.
96 @param Offset The offset of the 16550 register to write.
97 @param Value The value to write to the 16550 register specified by Offset.
98
99 @return The value written to the 16550 register.
100
101**/
102UINT8
103SerialPortWriteRegister (
104 UINTN Base,
105 UINTN Offset,
106 UINT8 Value
107 )
108{
109 if (PcdGetBool (PcdSerialUseMmio)) {
110 return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
111 } else {
112 return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
113 }
114}
115
116/**
117 Update the value of an 16-bit PCI configuration register in a PCI device. If the
118 PCI Configuration register specified by PciAddress is already programmed with a
119 non-zero value, then return the current value. Otherwise update the PCI configuration
120 register specified by PciAddress with the value specified by Value and return the
121 value programmed into the PCI configuration register. All values must be masked
122 using the bitmask specified by Mask.
123
124 @param PciAddress PCI Library address of the PCI Configuration register to update.
125 @param Value The value to program into the PCI Configuration Register.
126 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
127
128**/
129UINT16
130SerialPortLibUpdatePciRegister16 (
131 UINTN PciAddress,
132 UINT16 Value,
133 UINT16 Mask
134 )
135{
136 UINT16 CurrentValue;
137
138 CurrentValue = PciRead16 (PciAddress) & Mask;
139 if (CurrentValue != 0) {
140 return CurrentValue;
141 }
142 return PciWrite16 (PciAddress, Value & Mask);
143}
144
145/**
146 Update the value of an 32-bit PCI configuration register in a PCI device. If the
147 PCI Configuration register specified by PciAddress is already programmed with a
148 non-zero value, then return the current value. Otherwise update the PCI configuration
149 register specified by PciAddress with the value specified by Value and return the
150 value programmed into the PCI configuration register. All values must be masked
151 using the bitmask specified by Mask.
152
153 @param PciAddress PCI Library address of the PCI Configuration register to update.
154 @param Value The value to program into the PCI Configuration Register.
155 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
156
157 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
158
159**/
160UINT32
161SerialPortLibUpdatePciRegister32 (
162 UINTN PciAddress,
163 UINT32 Value,
164 UINT32 Mask
165 )
166{
167 UINT32 CurrentValue;
168
169 CurrentValue = PciRead32 (PciAddress) & Mask;
170 if (CurrentValue != 0) {
171 return CurrentValue;
172 }
173 return PciWrite32 (PciAddress, Value & Mask);
174}
175
176/**
177 Retrieve the I/O or MMIO base address register for the PCI UART device.
178
179 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
180 Device if they are not already enabled.
181
182 @return The base address register of the UART device.
183
184**/
185UINTN
186GetSerialRegisterBase (
187 VOID
188 )
189{
190 UINTN PciLibAddress;
191 UINTN BusNumber;
192 UINTN SubordinateBusNumber;
193 UINT32 ParentIoBase;
194 UINT32 ParentIoLimit;
195 UINT16 ParentMemoryBase;
196 UINT16 ParentMemoryLimit;
197 UINT32 IoBase;
198 UINT32 IoLimit;
199 UINT16 MemoryBase;
200 UINT16 MemoryLimit;
201 UINTN SerialRegisterBase;
202 UINTN BarIndex;
203 UINT32 RegisterBaseMask;
204 PCI_UART_DEVICE_INFO *DeviceInfo;
205
206 //
207 // Get PCI Device Info
208 //
209 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
210
211 //
212 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
213 //
214 if (DeviceInfo->Device == 0xff) {
215 return (UINTN)PcdGet64 (PcdSerialRegisterBase);
216 }
217
218 //
219 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
220 //
221 ParentMemoryBase = 0 >> 16;
222 ParentMemoryLimit = 0xfff00000 >> 16;
223 ParentIoBase = 0 >> 12;
224 ParentIoLimit = 0xf000 >> 12;
225
226 //
227 // Enable I/O and MMIO in PCI Bridge
228 // Assume Root Bus Numer is Zero.
229 //
230 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
231 //
232 // Compute PCI Lib Address to PCI to PCI Bridge
233 //
234 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
235
236 //
237 // Retrieve and verify the bus numbers in the PCI to PCI Bridge
238 //
239 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
240 SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
241 if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {
242 return 0;
243 }
244
245 //
246 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
247 //
248 if (PcdGetBool (PcdSerialUseMmio)) {
249 MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;
250 MemoryBase = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xfff0;
251
252 //
253 // If PCI Bridge MMIO window is disabled, then return 0
254 //
255 if (MemoryLimit < MemoryBase) {
256 return 0;
257 }
258
259 //
260 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
261 //
262 if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {
263 return 0;
264 }
265 ParentMemoryBase = MemoryBase;
266 ParentMemoryLimit = MemoryLimit;
267 } else {
268 IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
269 if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
270 IoLimit = IoLimit >> 4;
271 } else {
272 IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);
273 }
274 IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
275 if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
276 IoBase = IoBase >> 4;
277 } else {
278 IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);
279 }
280
281 //
282 // If PCI Bridge I/O window is disabled, then return 0
283 //
284 if (IoLimit < IoBase) {
285 return 0;
286 }
287
288 //
289 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
290 //
291 if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {
292 return 0;
293 }
294 ParentIoBase = IoBase;
295 ParentIoLimit = IoLimit;
296 }
297 }
298
299 //
300 // Compute PCI Lib Address to PCI UART
301 //
302 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
303
304 //
305 // Find the first IO or MMIO BAR
306 //
307 RegisterBaseMask = 0xFFFFFFF0;
308 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {
309 SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);
310 if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {
311 //
312 // MMIO BAR is found
313 //
314 RegisterBaseMask = 0xFFFFFFF0;
315 break;
316 }
317
318 if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {
319 //
320 // IO BAR is found
321 //
322 RegisterBaseMask = 0xFFFFFFF8;
323 break;
324 }
325 }
326
327 //
328 // MMIO or IO BAR is not found.
329 //
330 if (BarIndex == PCI_MAX_BAR) {
331 return 0;
332 }
333
334 //
335 // Program UART BAR
336 //
337 SerialRegisterBase = SerialPortLibUpdatePciRegister32 (
338 PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,
339 (UINT32)PcdGet64 (PcdSerialRegisterBase),
340 RegisterBaseMask
341 );
342
343 //
344 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
345 //
346 if (PcdGetBool (PcdSerialUseMmio)) {
347 if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {
348 return 0;
349 }
350 } else {
351 if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {
352 return 0;
353 }
354 }
355
356 //
357 // Enable I/O and MMIO in PCI UART Device if they are not already enabled
358 //
359 PciOr16 (
360 PciLibAddress + PCI_COMMAND_OFFSET,
361 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
362 );
363
364 //
365 // Force D0 state if a Power Management and Status Register is specified
366 //
367 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
368 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
369 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
370 //
371 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
372 //
373 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
374 }
375 }
376
377 //
378 // Get PCI Device Info
379 //
380 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
381
382 //
383 // Enable I/O or MMIO in PCI Bridge
384 // Assume Root Bus Numer is Zero.
385 //
386 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
387 //
388 // Compute PCI Lib Address to PCI to PCI Bridge
389 //
390 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
391
392 //
393 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
394 //
395 PciOr16 (
396 PciLibAddress + PCI_COMMAND_OFFSET,
397 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
398 );
399
400 //
401 // Force D0 state if a Power Management and Status Register is specified
402 //
403 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
404 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
405 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
406 }
407 }
408
409 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
410 }
411
412 return SerialRegisterBase;
413}
414
415/**
416 Return whether the hardware flow control signal allows writing.
417
418 @param SerialRegisterBase The base address register of UART device.
419
420 @retval TRUE The serial port is writable.
421 @retval FALSE The serial port is not writable.
422**/
423BOOLEAN
424SerialPortWritable (
425 UINTN SerialRegisterBase
426 )
427{
428 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
429 if (PcdGetBool (PcdSerialDetectCable)) {
430 //
431 // Wait for both DSR and CTS to be set
432 // DSR is set if a cable is connected.
433 // CTS is set if it is ok to transmit data
434 //
435 // DSR CTS Description Action
436 // === === ======================================== ========
437 // 0 0 No cable connected. Wait
438 // 0 1 No cable connected. Wait
439 // 1 0 Cable connected, but not clear to send. Wait
440 // 1 1 Cable connected, and clear to send. Transmit
441 //
442 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
443 } else {
444 //
445 // Wait for both DSR and CTS to be set OR for DSR to be clear.
446 // DSR is set if a cable is connected.
447 // CTS is set if it is ok to transmit data
448 //
449 // DSR CTS Description Action
450 // === === ======================================== ========
451 // 0 0 No cable connected. Transmit
452 // 0 1 No cable connected. Transmit
453 // 1 0 Cable connected, but not clear to send. Wait
454 // 1 1 Cable connected, and clar to send. Transmit
455 //
456 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
457 }
458 }
459
460 return TRUE;
461}
462
463/**
464 Initialize the serial device hardware.
465
466 If no initialization is required, then return RETURN_SUCCESS.
467 If the serial device was successfully initialized, then return RETURN_SUCCESS.
468 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
469
470 @retval RETURN_SUCCESS The serial device was initialized.
471 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
472
473**/
474RETURN_STATUS
475EFIAPI
476SerialPortInitialize (
477 VOID
478 )
479{
480 RETURN_STATUS Status;
481 UINTN SerialRegisterBase;
482 UINT32 Divisor;
483 UINT32 CurrentDivisor;
484 BOOLEAN Initialized;
485
486 //
487 // Perform platform specific initialization required to enable use of the 16550 device
488 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
489 //
490 Status = PlatformHookSerialPortInitialize ();
491 if (RETURN_ERROR (Status)) {
492 return Status;
493 }
494
495 //
496 // Calculate divisor for baud generator
497 // Ref_Clk_Rate / Baud_Rate / 16
498 //
499 Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
500 if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
501 Divisor++;
502 }
503
504 //
505 // Get the base address of the serial port in either I/O or MMIO space
506 //
507 SerialRegisterBase = GetSerialRegisterBase ();
508 if (SerialRegisterBase ==0) {
509 return RETURN_DEVICE_ERROR;
510 }
511
512 //
513 // See if the serial port is already initialized
514 //
515 Initialized = TRUE;
516 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
517 Initialized = FALSE;
518 }
519 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
520 CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
521 CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
522 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
523 if (CurrentDivisor != Divisor) {
524 Initialized = FALSE;
525 }
526 if (Initialized) {
527 return RETURN_SUCCESS;
528 }
529
530 //
531 // Wait for the serial port to be ready.
532 // Verify that both the transmit FIFO and the shift register are empty.
533 //
534 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
535
536 //
537 // Configure baud rate
538 //
539 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
540 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
541 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
542
543 //
544 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
545 // Strip reserved bits from PcdSerialLineControl
546 //
547 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
548
549 //
550 // Enable and reset FIFOs
551 // Strip reserved bits from PcdSerialFifoControl
552 //
553 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
554 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
555
556 //
557 // Put Modem Control Register(MCR) into its reset state of 0x00.
558 //
559 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);
560
561 return RETURN_SUCCESS;
562}
563
564/**
565 Write data from buffer to serial device.
566
567 Writes NumberOfBytes data bytes from Buffer to the serial device.
568 The number of bytes actually written to the serial device is returned.
569 If the return value is less than NumberOfBytes, then the write operation failed.
570
571 If Buffer is NULL, then ASSERT().
572
573 If NumberOfBytes is zero, then return 0.
574
575 @param Buffer Pointer to the data buffer to be written.
576 @param NumberOfBytes Number of bytes to written to the serial device.
577
578 @retval 0 NumberOfBytes is 0.
579 @retval >0 The number of bytes written to the serial device.
580 If this value is less than NumberOfBytes, then the write operation failed.
581
582**/
583UINTN
584EFIAPI
585SerialPortWrite (
586 IN UINT8 *Buffer,
587 IN UINTN NumberOfBytes
588 )
589{
590 UINTN SerialRegisterBase;
591 UINTN Result;
592 UINTN Index;
593 UINTN FifoSize;
594
595 if (Buffer == NULL) {
596 return 0;
597 }
598
599 SerialRegisterBase = GetSerialRegisterBase ();
600 if (SerialRegisterBase ==0) {
601 return 0;
602 }
603
604 if (NumberOfBytes == 0) {
605 //
606 // Flush the hardware
607 //
608
609 //
610 // Wait for both the transmit FIFO and shift register empty.
611 //
612 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
613
614 //
615 // Wait for the hardware flow control signal
616 //
617 while (!SerialPortWritable (SerialRegisterBase));
618 return 0;
619 }
620
621 //
622 // Compute the maximum size of the Tx FIFO
623 //
624 FifoSize = 1;
625 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
626 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
627 FifoSize = 16;
628 } else {
629 FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
630 }
631 }
632
633 Result = NumberOfBytes;
634 while (NumberOfBytes != 0) {
635 //
636 // Wait for the serial port to be ready, to make sure both the transmit FIFO
637 // and shift register empty.
638 //
639 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);
640
641 //
642 // Fill then entire Tx FIFO
643 //
644 for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
645 //
646 // Wait for the hardware flow control signal
647 //
648 while (!SerialPortWritable (SerialRegisterBase));
649
650 //
651 // Write byte to the transmit buffer.
652 //
653 SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
654 }
655 }
656 return Result;
657}
658
659/**
660 Reads data from a serial device into a buffer.
661
662 @param Buffer Pointer to the data buffer to store the data read from the serial device.
663 @param NumberOfBytes Number of bytes to read from the serial device.
664
665 @retval 0 NumberOfBytes is 0.
666 @retval >0 The number of bytes read from the serial device.
667 If this value is less than NumberOfBytes, then the read operation failed.
668
669**/
670UINTN
671EFIAPI
672SerialPortRead (
673 OUT UINT8 *Buffer,
674 IN UINTN NumberOfBytes
675 )
676{
677 UINTN SerialRegisterBase;
678 UINTN Result;
679 UINT8 Mcr;
680
681 if (NULL == Buffer) {
682 return 0;
683 }
684
685 SerialRegisterBase = GetSerialRegisterBase ();
686 if (SerialRegisterBase ==0) {
687 return 0;
688 }
689
690 Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
691
692 for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
693 //
694 // Wait for the serial port to have some data.
695 //
696 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
697 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
698 //
699 // Set RTS to let the peer send some data
700 //
701 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
702 }
703 }
704 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
705 //
706 // Clear RTS to prevent peer from sending data
707 //
708 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
709 }
710
711 //
712 // Read byte from the receive buffer.
713 //
714 *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
715 }
716
717 return Result;
718}
719
720
721/**
722 Polls a serial device to see if there is any data waiting to be read.
723
724 Polls aserial device to see if there is any data waiting to be read.
725 If there is data waiting to be read from the serial device, then TRUE is returned.
726 If there is no data waiting to be read from the serial device, then FALSE is returned.
727
728 @retval TRUE Data is waiting to be read from the serial device.
729 @retval FALSE There is no data waiting to be read from the serial device.
730
731**/
732BOOLEAN
733EFIAPI
734SerialPortPoll (
735 VOID
736 )
737{
738 UINTN SerialRegisterBase;
739
740 SerialRegisterBase = GetSerialRegisterBase ();
741 if (SerialRegisterBase ==0) {
742 return FALSE;
743 }
744
745 //
746 // Read the serial port status
747 //
748 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
749 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
750 //
751 // Clear RTS to prevent peer from sending data
752 //
753 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
754 }
755 return TRUE;
756 }
757
758 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
759 //
760 // Set RTS to let the peer send some data
761 //
762 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
763 }
764
765 return FALSE;
766}
767
768/**
769 Sets the control bits on a serial device.
770
771 @param Control Sets the bits of Control that are settable.
772
773 @retval RETURN_SUCCESS The new control bits were set on the serial device.
774 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
775 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
776
777**/
778RETURN_STATUS
779EFIAPI
780SerialPortSetControl (
781 IN UINT32 Control
782 )
783{
784 UINTN SerialRegisterBase;
785 UINT8 Mcr;
786
787 //
788 // First determine the parameter is invalid.
789 //
790 if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
791 EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
792 return RETURN_UNSUPPORTED;
793 }
794
795 SerialRegisterBase = GetSerialRegisterBase ();
796 if (SerialRegisterBase ==0) {
797 return RETURN_UNSUPPORTED;
798 }
799
800 //
801 // Read the Modem Control Register.
802 //
803 Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
804 Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
805
806 if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
807 Mcr |= B_UART_MCR_DTRC;
808 }
809
810 if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
811 Mcr |= B_UART_MCR_RTS;
812 }
813
814 //
815 // Write the Modem Control Register.
816 //
817 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
818
819 return RETURN_SUCCESS;
820}
821
822/**
823 Retrieve the status of the control bits on a serial device.
824
825 @param Control A pointer to return the current control signals from the serial device.
826
827 @retval RETURN_SUCCESS The control bits were read from the serial device.
828 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
829 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
830
831**/
832RETURN_STATUS
833EFIAPI
834SerialPortGetControl (
835 OUT UINT32 *Control
836 )
837{
838 UINTN SerialRegisterBase;
839 UINT8 Msr;
840 UINT8 Mcr;
841 UINT8 Lsr;
842
843 SerialRegisterBase = GetSerialRegisterBase ();
844 if (SerialRegisterBase ==0) {
845 return RETURN_UNSUPPORTED;
846 }
847
848 *Control = 0;
849
850 //
851 // Read the Modem Status Register.
852 //
853 Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
854
855 if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
856 *Control |= EFI_SERIAL_CLEAR_TO_SEND;
857 }
858
859 if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
860 *Control |= EFI_SERIAL_DATA_SET_READY;
861 }
862
863 if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
864 *Control |= EFI_SERIAL_RING_INDICATE;
865 }
866
867 if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
868 *Control |= EFI_SERIAL_CARRIER_DETECT;
869 }
870
871 //
872 // Read the Modem Control Register.
873 //
874 Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
875
876 if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
877 *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
878 }
879
880 if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
881 *Control |= EFI_SERIAL_REQUEST_TO_SEND;
882 }
883
884 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
885 *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
886 }
887
888 //
889 // Read the Line Status Register.
890 //
891 Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
892
893 if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
894 *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
895 }
896
897 if ((Lsr & B_UART_LSR_RXRDY) == 0) {
898 *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
899 }
900
901 return RETURN_SUCCESS;
902}
903
904/**
905 Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
906 data bits, and stop bits on a serial device.
907
908 @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
909 device's default interface speed.
910 On output, the value actually set.
911 @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the
912 serial interface. A ReceiveFifoDepth value of 0 will use
913 the device's default FIFO depth.
914 On output, the value actually set.
915 @param Timeout The requested time out for a single character in microseconds.
916 This timeout applies to both the transmit and receive side of the
917 interface. A Timeout value of 0 will use the device's default time
918 out value.
919 On output, the value actually set.
920 @param Parity The type of parity to use on this serial device. A Parity value of
921 DefaultParity will use the device's default parity value.
922 On output, the value actually set.
923 @param DataBits The number of data bits to use on the serial device. A DataBits
924 vaule of 0 will use the device's default data bit setting.
925 On output, the value actually set.
926 @param StopBits The number of stop bits to use on this serial device. A StopBits
927 value of DefaultStopBits will use the device's default number of
928 stop bits.
929 On output, the value actually set.
930
931 @retval RETURN_SUCCESS The new attributes were set on the serial device.
932 @retval RETURN_UNSUPPORTED The serial device does not support this operation.
933 @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
934 @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
935
936**/
937RETURN_STATUS
938EFIAPI
939SerialPortSetAttributes (
940 IN OUT UINT64 *BaudRate,
941 IN OUT UINT32 *ReceiveFifoDepth,
942 IN OUT UINT32 *Timeout,
943 IN OUT EFI_PARITY_TYPE *Parity,
944 IN OUT UINT8 *DataBits,
945 IN OUT EFI_STOP_BITS_TYPE *StopBits
946 )
947{
948 UINTN SerialRegisterBase;
949 UINT32 SerialBaudRate;
950 UINTN Divisor;
951 UINT8 Lcr;
952 UINT8 LcrData;
953 UINT8 LcrParity;
954 UINT8 LcrStop;
955
956 SerialRegisterBase = GetSerialRegisterBase ();
957 if (SerialRegisterBase ==0) {
958 return RETURN_UNSUPPORTED;
959 }
960
961 //
962 // Check for default settings and fill in actual values.
963 //
964 if (*BaudRate == 0) {
965 *BaudRate = PcdGet32 (PcdSerialBaudRate);
966 }
967 SerialBaudRate = (UINT32) *BaudRate;
968
969 if (*DataBits == 0) {
970 LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
971 *DataBits = LcrData + 5;
972 } else {
973 if ((*DataBits < 5) || (*DataBits > 8)) {
974 return RETURN_INVALID_PARAMETER;
975 }
976 //
977 // Map 5..8 to 0..3
978 //
979 LcrData = (UINT8) (*DataBits - (UINT8) 5);
980 }
981
982 if (*Parity == DefaultParity) {
983 LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
984 switch (LcrParity) {
985 case 0:
986 *Parity = NoParity;
987 break;
988
989 case 3:
990 *Parity = EvenParity;
991 break;
992
993 case 1:
994 *Parity = OddParity;
995 break;
996
997 case 7:
998 *Parity = SpaceParity;
999 break;
1000
1001 case 5:
1002 *Parity = MarkParity;
1003 break;
1004
1005 default:
1006 break;
1007 }
1008 } else {
1009 switch (*Parity) {
1010 case NoParity:
1011 LcrParity = 0;
1012 break;
1013
1014 case EvenParity:
1015 LcrParity = 3;
1016 break;
1017
1018 case OddParity:
1019 LcrParity = 1;
1020 break;
1021
1022 case SpaceParity:
1023 LcrParity = 7;
1024 break;
1025
1026 case MarkParity:
1027 LcrParity = 5;
1028 break;
1029
1030 default:
1031 return RETURN_INVALID_PARAMETER;
1032 }
1033 }
1034
1035 if (*StopBits == DefaultStopBits) {
1036 LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
1037 switch (LcrStop) {
1038 case 0:
1039 *StopBits = OneStopBit;
1040 break;
1041
1042 case 1:
1043 if (*DataBits == 5) {
1044 *StopBits = OneFiveStopBits;
1045 } else {
1046 *StopBits = TwoStopBits;
1047 }
1048 break;
1049
1050 default:
1051 break;
1052 }
1053 } else {
1054 switch (*StopBits) {
1055 case OneStopBit:
1056 LcrStop = 0;
1057 break;
1058
1059 case OneFiveStopBits:
1060 case TwoStopBits:
1061 LcrStop = 1;
1062 break;
1063
1064 default:
1065 return RETURN_INVALID_PARAMETER;
1066 }
1067 }
1068
1069 //
1070 // Calculate divisor for baud generator
1071 // Ref_Clk_Rate / Baud_Rate / 16
1072 //
1073 Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);
1074 if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {
1075 Divisor++;
1076 }
1077
1078 //
1079 // Configure baud rate
1080 //
1081 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
1082 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
1083 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
1084
1085 //
1086 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
1087 // Strip reserved bits from line control value
1088 //
1089 Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
1090 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
1091
1092 return RETURN_SUCCESS;
1093}
1094