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