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