]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
MdeModulePkg: Source fixes and cleanup for ARMGCC compiles
[mirror_edk2.git] / MdeModulePkg / Library / BaseSerialPortLib16550 / BaseSerialPortLib16550.c
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 - 2014, 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_RTS BIT1
44 #define R_UART_LSR 5
45 #define B_UART_LSR_RXRDY BIT0
46 #define B_UART_LSR_TXRDY BIT5
47 #define B_UART_LSR_TEMT BIT6
48 #define R_UART_MSR 6
49 #define B_UART_MSR_CTS BIT4
50 #define B_UART_MSR_DSR BIT5
51
52 //
53 // 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
54 //
55 typedef struct {
56 UINT8 Device;
57 UINT8 Function;
58 UINT16 PowerManagementStatusAndControlRegister;
59 } PCI_UART_DEVICE_INFO;
60
61 /**
62 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
63 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
64 parameter Offset is added to the base address of the 16550 registers that is specified
65 by PcdSerialRegisterBase.
66
67 @param Base The base address register of UART device.
68 @param Offset The offset of the 16550 register to read.
69
70 @return The value read from the 16550 register.
71
72 **/
73 UINT8
74 SerialPortReadRegister (
75 UINTN Base,
76 UINTN Offset
77 )
78 {
79 if (PcdGetBool (PcdSerialUseMmio)) {
80 return MmioRead8 (Base + Offset);
81 } else {
82 return IoRead8 (Base + Offset);
83 }
84 }
85
86 /**
87 Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
88 MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
89 parameter Offset is added to the base address of the 16550 registers that is specified
90 by PcdSerialRegisterBase.
91
92 @param Base The base address register of UART device.
93 @param Offset The offset of the 16550 register to write.
94 @param Value The value to write to the 16550 register specified by Offset.
95
96 @return The value written to the 16550 register.
97
98 **/
99 UINT8
100 SerialPortWriteRegister (
101 UINTN Base,
102 UINTN Offset,
103 UINT8 Value
104 )
105 {
106 if (PcdGetBool (PcdSerialUseMmio)) {
107 return MmioWrite8 (Base + Offset, Value);
108 } else {
109 return IoWrite8 (Base + Offset, Value);
110 }
111 }
112
113 /**
114 Update the value of an 16-bit PCI configuration register in a PCI device. If the
115 PCI Configuration register specified by PciAddress is already programmed with a
116 non-zero value, then return the current value. Otherwise update the PCI configuration
117 register specified by PciAddress with the value specified by Value and return the
118 value programmed into the PCI configuration register. All values must be masked
119 using the bitmask specified by Mask.
120
121 @param PciAddress PCI Library address of the PCI Configuration register to update.
122 @param Value The value to program into the PCI Configuration Register.
123 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
124
125 **/
126 UINT16
127 SerialPortLibUpdatePciRegister16 (
128 UINTN PciAddress,
129 UINT16 Value,
130 UINT16 Mask
131 )
132 {
133 UINT16 CurrentValue;
134
135 CurrentValue = PciRead16 (PciAddress) & Mask;
136 if (CurrentValue != 0) {
137 return CurrentValue;
138 }
139 return PciWrite16 (PciAddress, Value & Mask);
140 }
141
142 /**
143 Update the value of an 32-bit PCI configuration register in a PCI device. If the
144 PCI Configuration register specified by PciAddress is already programmed with a
145 non-zero value, then return the current value. Otherwise update the PCI configuration
146 register specified by PciAddress with the value specified by Value and return the
147 value programmed into the PCI configuration register. All values must be masked
148 using the bitmask specified by Mask.
149
150 @param PciAddress PCI Library address of the PCI Configuration register to update.
151 @param Value The value to program into the PCI Configuration Register.
152 @param Mask Bitmask of the bits to check and update in the PCI configuration register.
153
154 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
155
156 **/
157 UINT32
158 SerialPortLibUpdatePciRegister32 (
159 UINTN PciAddress,
160 UINT32 Value,
161 UINT32 Mask
162 )
163 {
164 UINT32 CurrentValue;
165
166 CurrentValue = PciRead32 (PciAddress) & Mask;
167 if (CurrentValue != 0) {
168 return CurrentValue;
169 }
170 return PciWrite32 (PciAddress, Value & Mask);
171 }
172
173 /**
174 Retrieve the I/O or MMIO base address register for the PCI UART device.
175
176 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
177 Device if they are not already enabled.
178
179 @return The base address register of the UART device.
180
181 **/
182 UINTN
183 GetSerialRegisterBase (
184 VOID
185 )
186 {
187 UINTN PciLibAddress;
188 UINTN BusNumber;
189 UINTN SubordinateBusNumber;
190 UINT32 ParentIoBase;
191 UINT32 ParentIoLimit;
192 UINT16 ParentMemoryBase;
193 UINT16 ParentMemoryLimit;
194 UINT32 IoBase;
195 UINT32 IoLimit;
196 UINT16 MemoryBase;
197 UINT16 MemoryLimit;
198 UINTN SerialRegisterBase;
199 UINTN BarIndex;
200 UINT32 RegisterBaseMask;
201 PCI_UART_DEVICE_INFO *DeviceInfo;
202
203 //
204 // Get PCI Device Info
205 //
206 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
207
208 //
209 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
210 //
211 if (DeviceInfo->Device == 0xff) {
212 return (UINTN)PcdGet64 (PcdSerialRegisterBase);
213 }
214
215 //
216 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
217 //
218 ParentMemoryBase = 0 >> 16;
219 ParentMemoryLimit = 0xfff00000 >> 16;
220 ParentIoBase = 0 >> 12;
221 ParentIoLimit = 0xf000 >> 12;
222
223 //
224 // Enable I/O and MMIO in PCI Bridge
225 // Assume Root Bus Numer is Zero.
226 //
227 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
228 //
229 // Compute PCI Lib Address to PCI to PCI Bridge
230 //
231 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
232
233 //
234 // Retrieve and verify the bus numbers in the PCI to PCI Bridge
235 //
236 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
237 SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
238 if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {
239 return 0;
240 }
241
242 //
243 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
244 //
245 if (PcdGetBool (PcdSerialUseMmio)) {
246 MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;
247 MemoryBase = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xfff0;
248
249 //
250 // If PCI Bridge MMIO window is disabled, then return 0
251 //
252 if (MemoryLimit < MemoryBase) {
253 return 0;
254 }
255
256 //
257 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
258 //
259 if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {
260 return 0;
261 }
262 ParentMemoryBase = MemoryBase;
263 ParentMemoryLimit = MemoryLimit;
264 } else {
265 IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
266 if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
267 IoLimit = IoLimit >> 4;
268 } else {
269 IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);
270 }
271 IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
272 if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
273 IoBase = IoBase >> 4;
274 } else {
275 IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);
276 }
277
278 //
279 // If PCI Bridge I/O window is disabled, then return 0
280 //
281 if (IoLimit < IoBase) {
282 return 0;
283 }
284
285 //
286 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
287 //
288 if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {
289 return 0;
290 }
291 ParentIoBase = IoBase;
292 ParentIoLimit = IoLimit;
293 }
294 }
295
296 //
297 // Compute PCI Lib Address to PCI UART
298 //
299 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
300
301 //
302 // Find the first IO or MMIO BAR
303 //
304 RegisterBaseMask = 0xFFFFFFF0;
305 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {
306 SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);
307 if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {
308 //
309 // MMIO BAR is found
310 //
311 RegisterBaseMask = 0xFFFFFFF0;
312 break;
313 }
314
315 if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {
316 //
317 // IO BAR is found
318 //
319 RegisterBaseMask = 0xFFFFFFF8;
320 break;
321 }
322 }
323
324 //
325 // MMIO or IO BAR is not found.
326 //
327 if (BarIndex == PCI_MAX_BAR) {
328 return 0;
329 }
330
331 //
332 // Program UART BAR
333 //
334 SerialRegisterBase = SerialPortLibUpdatePciRegister32 (
335 PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,
336 (UINT32)PcdGet64 (PcdSerialRegisterBase),
337 RegisterBaseMask
338 );
339
340 //
341 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
342 //
343 if (PcdGetBool (PcdSerialUseMmio)) {
344 if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {
345 return 0;
346 }
347 } else {
348 if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {
349 return 0;
350 }
351 }
352
353 //
354 // Enable I/O and MMIO in PCI UART Device if they are not already enabled
355 //
356 PciOr16 (
357 PciLibAddress + PCI_COMMAND_OFFSET,
358 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
359 );
360
361 //
362 // Force D0 state if a Power Management and Status Register is specified
363 //
364 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
365 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
366 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
367 //
368 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
369 //
370 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
371 }
372 }
373
374 //
375 // Get PCI Device Info
376 //
377 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
378
379 //
380 // Enable I/O or MMIO in PCI Bridge
381 // Assume Root Bus Numer is Zero.
382 //
383 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
384 //
385 // Compute PCI Lib Address to PCI to PCI Bridge
386 //
387 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
388
389 //
390 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
391 //
392 PciOr16 (
393 PciLibAddress + PCI_COMMAND_OFFSET,
394 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
395 );
396
397 //
398 // Force D0 state if a Power Management and Status Register is specified
399 //
400 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
401 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
402 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
403 }
404 }
405
406 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
407 }
408
409 return SerialRegisterBase;
410 }
411
412 /**
413 Return whether the hardware flow control signal allows writing.
414
415 @param SerialRegisterBase The base address register of UART device.
416
417 @retval TRUE The serial port is writable.
418 @retval FALSE The serial port is not writable.
419 **/
420 BOOLEAN
421 SerialPortWritable (
422 UINTN SerialRegisterBase
423 )
424 {
425 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
426 if (PcdGetBool (PcdSerialDetectCable)) {
427 //
428 // Wait for both DSR and CTS to be set
429 // DSR is set if a cable is connected.
430 // CTS is set if it is ok to transmit data
431 //
432 // DSR CTS Description Action
433 // === === ======================================== ========
434 // 0 0 No cable connected. Wait
435 // 0 1 No cable connected. Wait
436 // 1 0 Cable connected, but not clear to send. Wait
437 // 1 1 Cable connected, and clear to send. Transmit
438 //
439 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
440 } else {
441 //
442 // Wait for both DSR and CTS to be set OR for DSR to be clear.
443 // DSR is set if a cable is connected.
444 // CTS is set if it is ok to transmit data
445 //
446 // DSR CTS Description Action
447 // === === ======================================== ========
448 // 0 0 No cable connected. Transmit
449 // 0 1 No cable connected. Transmit
450 // 1 0 Cable connected, but not clear to send. Wait
451 // 1 1 Cable connected, and clar to send. Transmit
452 //
453 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
454 }
455 }
456
457 return TRUE;
458 }
459
460 /**
461 Initialize the serial device hardware.
462
463 If no initialization is required, then return RETURN_SUCCESS.
464 If the serial device was successfully initialized, then return RETURN_SUCCESS.
465 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
466
467 @retval RETURN_SUCCESS The serial device was initialized.
468 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
469
470 **/
471 RETURN_STATUS
472 EFIAPI
473 SerialPortInitialize (
474 VOID
475 )
476 {
477 RETURN_STATUS Status;
478 UINTN SerialRegisterBase;
479 UINT32 Divisor;
480 UINT32 CurrentDivisor;
481 BOOLEAN Initialized;
482
483 //
484 // Perform platform specific initialization required to enable use of the 16550 device
485 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
486 //
487 Status = PlatformHookSerialPortInitialize ();
488 if (RETURN_ERROR (Status)) {
489 return Status;
490 }
491
492 //
493 // Calculate divisor for baud generator
494 // Ref_Clk_Rate / Baud_Rate / 16
495 //
496 Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
497 if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
498 Divisor++;
499 }
500
501 //
502 // Get the base address of the serial port in either I/O or MMIO space
503 //
504 SerialRegisterBase = GetSerialRegisterBase ();
505 if (SerialRegisterBase ==0) {
506 return RETURN_DEVICE_ERROR;
507 }
508
509 //
510 // See if the serial port is already initialized
511 //
512 Initialized = TRUE;
513 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
514 Initialized = FALSE;
515 }
516 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
517 CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
518 CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
519 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
520 if (CurrentDivisor != Divisor) {
521 Initialized = FALSE;
522 }
523 if (Initialized) {
524 return RETURN_SUCCESS;
525 }
526
527 //
528 // Wait for the serial port to be ready.
529 // Verify that both the transmit FIFO and the shift register are empty.
530 //
531 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
532
533 //
534 // Configure baud rate
535 //
536 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
537 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
538 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
539
540 //
541 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
542 // Strip reserved bits from PcdSerialLineControl
543 //
544 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
545
546 //
547 // Enable and reset FIFOs
548 // Strip reserved bits from PcdSerialFifoControl
549 //
550 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
551 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
552
553 //
554 // Put Modem Control Register(MCR) into its reset state of 0x00.
555 //
556 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);
557
558 return RETURN_SUCCESS;
559 }
560
561 /**
562 Write data from buffer to serial device.
563
564 Writes NumberOfBytes data bytes from Buffer to the serial device.
565 The number of bytes actually written to the serial device is returned.
566 If the return value is less than NumberOfBytes, then the write operation failed.
567
568 If Buffer is NULL, then ASSERT().
569
570 If NumberOfBytes is zero, then return 0.
571
572 @param Buffer Pointer to the data buffer to be written.
573 @param NumberOfBytes Number of bytes to written to the serial device.
574
575 @retval 0 NumberOfBytes is 0.
576 @retval >0 The number of bytes written to the serial device.
577 If this value is less than NumberOfBytes, then the read operation failed.
578
579 **/
580 UINTN
581 EFIAPI
582 SerialPortWrite (
583 IN UINT8 *Buffer,
584 IN UINTN NumberOfBytes
585 )
586 {
587 UINTN SerialRegisterBase;
588 UINTN Result;
589 UINTN Index;
590 UINTN FifoSize;
591
592 if (Buffer == NULL) {
593 return 0;
594 }
595
596 SerialRegisterBase = GetSerialRegisterBase ();
597 if (SerialRegisterBase ==0) {
598 return 0;
599 }
600
601 if (NumberOfBytes == 0) {
602 //
603 // Flush the hardware
604 //
605
606 //
607 // Wait for both the transmit FIFO and shift register empty.
608 //
609 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
610
611 //
612 // Wait for the hardware flow control signal
613 //
614 while (!SerialPortWritable (SerialRegisterBase));
615 return 0;
616 }
617
618 //
619 // Compute the maximum size of the Tx FIFO
620 //
621 FifoSize = 1;
622 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
623 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
624 FifoSize = 16;
625 } else {
626 FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
627 }
628 }
629
630 Result = NumberOfBytes;
631 while (NumberOfBytes != 0) {
632 //
633 // Wait for the serial port to be ready, to make sure both the transmit FIFO
634 // and shift register empty.
635 //
636 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);
637
638 //
639 // Fill then entire Tx FIFO
640 //
641 for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
642 //
643 // Wait for the hardware flow control signal
644 //
645 while (!SerialPortWritable (SerialRegisterBase));
646
647 //
648 // Write byte to the transmit buffer.
649 //
650 SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
651 }
652 }
653 return Result;
654 }
655
656 /**
657 Reads data from a serial device into a buffer.
658
659 @param Buffer Pointer to the data buffer to store the data read from the serial device.
660 @param NumberOfBytes Number of bytes to read from the serial device.
661
662 @retval 0 NumberOfBytes is 0.
663 @retval >0 The number of bytes read from the serial device.
664 If this value is less than NumberOfBytes, then the read operation failed.
665
666 **/
667 UINTN
668 EFIAPI
669 SerialPortRead (
670 OUT UINT8 *Buffer,
671 IN UINTN NumberOfBytes
672 )
673 {
674 UINTN SerialRegisterBase;
675 UINTN Result;
676 UINT8 Mcr;
677
678 if (NULL == Buffer) {
679 return 0;
680 }
681
682 SerialRegisterBase = GetSerialRegisterBase ();
683 if (SerialRegisterBase ==0) {
684 return 0;
685 }
686
687 Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
688
689 for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
690 //
691 // Wait for the serial port to have some data.
692 //
693 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
694 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
695 //
696 // Set RTS to let the peer send some data
697 //
698 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
699 }
700 }
701 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
702 //
703 // Clear RTS to prevent peer from sending data
704 //
705 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
706 }
707
708 //
709 // Read byte from the receive buffer.
710 //
711 *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
712 }
713
714 return Result;
715 }
716
717
718 /**
719 Polls a serial device to see if there is any data waiting to be read.
720
721 Polls aserial device to see if there is any data waiting to be read.
722 If there is data waiting to be read from the serial device, then TRUE is returned.
723 If there is no data waiting to be read from the serial device, then FALSE is returned.
724
725 @retval TRUE Data is waiting to be read from the serial device.
726 @retval FALSE There is no data waiting to be read from the serial device.
727
728 **/
729 BOOLEAN
730 EFIAPI
731 SerialPortPoll (
732 VOID
733 )
734 {
735 UINTN SerialRegisterBase;
736
737 SerialRegisterBase = GetSerialRegisterBase ();
738 if (SerialRegisterBase ==0) {
739 return FALSE;
740 }
741
742 //
743 // Read the serial port status
744 //
745 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
746 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
747 //
748 // Clear RTS to prevent peer from sending data
749 //
750 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
751 }
752 return TRUE;
753 }
754
755 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
756 //
757 // Set RTS to let the peer send some data
758 //
759 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
760 }
761
762 return FALSE;
763 }