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