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