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