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