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