]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
MdePkg/BaseSerialPortLib16550: Support UARTs with a register stride greater than...
[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
cd68e4a8 5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
467d15ae 6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Base.h>\r
31122d8c 17#include <IndustryStandard/Pci.h>\r
467d15ae 18#include <Library/SerialPortLib.h>\r
19#include <Library/PcdLib.h>\r
20#include <Library/IoLib.h>\r
31122d8c 21#include <Library/PciLib.h>\r
467d15ae 22#include <Library/PlatformHookLib.h>\r
31122d8c
LG
23#include <Library/BaseLib.h>\r
24\r
25//\r
26// PCI Defintions.\r
27//\r
28#define PCI_BRIDGE_32_BIT_IO_SPACE 0x01\r
467d15ae 29\r
30//\r
31// 16550 UART register offsets and bitfields\r
32//\r
33#define R_UART_RXBUF 0\r
34#define R_UART_TXBUF 0\r
35#define R_UART_BAUD_LOW 0\r
36#define R_UART_BAUD_HIGH 1\r
37#define R_UART_FCR 2\r
38#define B_UART_FCR_FIFOE BIT0\r
39#define B_UART_FCR_FIFO64 BIT5\r
40#define R_UART_LCR 3\r
41#define B_UART_LCR_DLAB BIT7\r
42#define R_UART_MCR 4\r
43#define B_UART_MCR_RTS BIT1\r
44#define R_UART_LSR 5\r
45#define B_UART_LSR_RXRDY BIT0\r
46#define B_UART_LSR_TXRDY BIT5\r
47#define B_UART_LSR_TEMT BIT6\r
48#define R_UART_MSR 6\r
49#define B_UART_MSR_CTS BIT4\r
784ce127 50#define B_UART_MSR_DSR BIT5\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
62 Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from \r
63 MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The\r
64 parameter Offset is added to the base address of the 16550 registers that is specified \r
65 by PcdSerialRegisterBase. \r
66 \r
74a6d860 67 @param Base The base address register of UART device.\r
467d15ae 68 @param Offset The offset of the 16550 register to read.\r
69\r
70 @return The value read from the 16550 register.\r
71\r
72**/\r
73UINT8\r
74SerialPortReadRegister (\r
31122d8c 75 UINTN Base,\r
467d15ae 76 UINTN Offset\r
77 )\r
78{\r
79 if (PcdGetBool (PcdSerialUseMmio)) {\r
cd68e4a8 80 return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));\r
467d15ae 81 } else {\r
cd68e4a8 82 return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));\r
467d15ae 83 }\r
84}\r
85\r
86/**\r
87 Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to\r
88 MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The\r
89 parameter Offset is added to the base address of the 16550 registers that is specified \r
90 by PcdSerialRegisterBase. \r
91 \r
74a6d860 92 @param Base The base address register of UART device.\r
e25fb2c0 93 @param Offset The offset of the 16550 register to write.\r
94 @param Value The value to write to the 16550 register specified by Offset.\r
467d15ae 95\r
96 @return The value written to the 16550 register.\r
97\r
98**/\r
99UINT8\r
100SerialPortWriteRegister (\r
31122d8c 101 UINTN Base,\r
467d15ae 102 UINTN Offset,\r
103 UINT8 Value\r
104 )\r
105{\r
106 if (PcdGetBool (PcdSerialUseMmio)) {\r
cd68e4a8 107 return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);\r
467d15ae 108 } else {\r
cd68e4a8 109 return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);\r
467d15ae 110 }\r
111}\r
112\r
31122d8c
LG
113/**\r
114 Update the value of an 16-bit PCI configuration register in a PCI device. If the \r
115 PCI Configuration register specified by PciAddress is already programmed with a \r
116 non-zero value, then return the current value. Otherwise update the PCI configuration \r
117 register specified by PciAddress with the value specified by Value and return the\r
118 value programmed into the PCI configuration register. All values must be masked \r
119 using the bitmask specified by Mask.\r
120\r
121 @param PciAddress PCI Library address of the PCI Configuration register to update.\r
122 @param Value The value to program into the PCI Configuration Register.\r
123 @param Mask Bitmask of the bits to check and update in the PCI configuration register.\r
124\r
125**/\r
126UINT16\r
127SerialPortLibUpdatePciRegister16 (\r
128 UINTN PciAddress,\r
129 UINT16 Value,\r
130 UINT16 Mask\r
131 )\r
132{\r
133 UINT16 CurrentValue;\r
134 \r
135 CurrentValue = PciRead16 (PciAddress) & Mask;\r
136 if (CurrentValue != 0) {\r
137 return CurrentValue;\r
138 }\r
139 return PciWrite16 (PciAddress, Value & Mask);\r
140}\r
141\r
142/**\r
143 Update the value of an 32-bit PCI configuration register in a PCI device. If the \r
144 PCI Configuration register specified by PciAddress is already programmed with a \r
145 non-zero value, then return the current value. Otherwise update the PCI configuration \r
146 register specified by PciAddress with the value specified by Value and return the\r
147 value programmed into the PCI configuration register. All values must be masked \r
148 using the bitmask specified by Mask.\r
149\r
150 @param PciAddress PCI Library address of the PCI Configuration register to update.\r
151 @param Value The value to program into the PCI Configuration Register.\r
152 @param Mask Bitmask of the bits to check and update in the PCI configuration register.\r
153\r
154 @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.\r
155\r
156**/\r
157UINT32\r
158SerialPortLibUpdatePciRegister32 (\r
159 UINTN PciAddress,\r
160 UINT32 Value,\r
161 UINT32 Mask\r
162 )\r
163{\r
164 UINT32 CurrentValue;\r
165 \r
166 CurrentValue = PciRead32 (PciAddress) & Mask;\r
167 if (CurrentValue != 0) {\r
168 return CurrentValue;\r
169 }\r
170 return PciWrite32 (PciAddress, Value & Mask);\r
171}\r
172\r
173/**\r
174 Retrieve the I/O or MMIO base address register for the PCI UART device. \r
175 \r
176 This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART \r
177 Device if they are not already enabled. \r
178 \r
74a6d860 179 @return The base address register of the UART device.\r
31122d8c
LG
180\r
181**/\r
182UINTN\r
183GetSerialRegisterBase (\r
184 VOID\r
185 )\r
186{\r
187 UINTN PciLibAddress;\r
31122d8c
LG
188 UINTN BusNumber;\r
189 UINTN SubordinateBusNumber;\r
190 UINT32 ParentIoBase;\r
191 UINT32 ParentIoLimit;\r
192 UINT16 ParentMemoryBase;\r
193 UINT16 ParentMemoryLimit;\r
194 UINT32 IoBase;\r
195 UINT32 IoLimit;\r
196 UINT16 MemoryBase;\r
197 UINT16 MemoryLimit;\r
198 UINTN SerialRegisterBase;\r
199 UINTN BarIndex;\r
200 UINT32 RegisterBaseMask;\r
201 PCI_UART_DEVICE_INFO *DeviceInfo;\r
202\r
203 //\r
204 // Get PCI Device Info\r
205 //\r
206 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);\r
207 \r
208 //\r
209 // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase\r
210 // \r
211 if (DeviceInfo->Device == 0xff) {\r
212 return (UINTN)PcdGet64 (PcdSerialRegisterBase);\r
213 }\r
214\r
215 //\r
216 // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB\r
217 //\r
218 ParentMemoryBase = 0 >> 16;\r
219 ParentMemoryLimit = 0xfff00000 >> 16;\r
220 ParentIoBase = 0 >> 12;\r
221 ParentIoLimit = 0xf000 >> 12;\r
222 \r
223 //\r
224 // Enable I/O and MMIO in PCI Bridge\r
225 // Assume Root Bus Numer is Zero. \r
226 //\r
227 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {\r
228 //\r
229 // Compute PCI Lib Address to PCI to PCI Bridge\r
230 //\r
231 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);\r
232 \r
233 //\r
234 // Retrieve and verify the bus numbers in the PCI to PCI Bridge\r
235 //\r
31122d8c
LG
236 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);\r
237 SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);\r
238 if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {\r
239 return 0;\r
240 }\r
241\r
242 //\r
243 // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge\r
244 //\r
245 if (PcdGetBool (PcdSerialUseMmio)) {\r
c9e0bba3
LG
246 MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;\r
247 MemoryBase = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xfff0;\r
31122d8c
LG
248\r
249 //\r
250 // If PCI Bridge MMIO window is disabled, then return 0\r
251 //\r
252 if (MemoryLimit < MemoryBase) {\r
253 return 0;\r
254 }\r
255 \r
256 //\r
257 // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0\r
258 // \r
259 if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {\r
260 return 0;\r
261 }\r
262 ParentMemoryBase = MemoryBase;\r
263 ParentMemoryLimit = MemoryLimit;\r
264 } else {\r
c9e0bba3 265 IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));\r
31122d8c
LG
266 if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {\r
267 IoLimit = IoLimit >> 4;\r
268 } else {\r
c9e0bba3 269 IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);\r
31122d8c 270 }\r
c9e0bba3 271 IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));\r
31122d8c
LG
272 if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {\r
273 IoBase = IoBase >> 4;\r
274 } else {\r
c9e0bba3 275 IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);\r
31122d8c
LG
276 }\r
277 \r
278 //\r
279 // If PCI Bridge I/O window is disabled, then return 0\r
280 //\r
281 if (IoLimit < IoBase) {\r
282 return 0;\r
283 }\r
284 \r
285 //\r
286 // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0\r
287 // \r
288 if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {\r
289 return 0;\r
290 }\r
291 ParentIoBase = IoBase;\r
292 ParentIoLimit = IoLimit;\r
293 }\r
294 }\r
295\r
296 //\r
297 // Compute PCI Lib Address to PCI UART\r
298 //\r
299 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);\r
300 \r
301 //\r
302 // Find the first IO or MMIO BAR\r
303 //\r
304 RegisterBaseMask = 0xFFFFFFF0;\r
305 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {\r
306 SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);\r
307 if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {\r
308 //\r
309 // MMIO BAR is found\r
310 //\r
311 RegisterBaseMask = 0xFFFFFFF0;\r
312 break;\r
313 }\r
314\r
315 if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {\r
316 //\r
317 // IO BAR is found\r
318 //\r
319 RegisterBaseMask = 0xFFFFFFF8;\r
320 break;\r
321 }\r
322 }\r
323\r
324 //\r
325 // MMIO or IO BAR is not found.\r
326 //\r
327 if (BarIndex == PCI_MAX_BAR) {\r
328 return 0;\r
329 }\r
330\r
331 //\r
332 // Program UART BAR\r
333 // \r
334 SerialRegisterBase = SerialPortLibUpdatePciRegister32 (\r
335 PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,\r
336 (UINT32)PcdGet64 (PcdSerialRegisterBase), \r
337 RegisterBaseMask\r
338 );\r
339\r
340 //\r
341 // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge\r
342 // \r
343 if (PcdGetBool (PcdSerialUseMmio)) {\r
344 if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {\r
345 return 0;\r
346 }\r
347 } else {\r
348 if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {\r
349 return 0;\r
350 }\r
351 }\r
352 \r
353 //\r
354 // Enable I/O and MMIO in PCI UART Device if they are not already enabled\r
355 //\r
356 PciOr16 (\r
357 PciLibAddress + PCI_COMMAND_OFFSET,\r
358 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE\r
359 );\r
360\r
361 //\r
362 // Force D0 state if a Power Management and Status Register is specified\r
363 //\r
364 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {\r
365 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {\r
366 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));\r
367 //\r
368 // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs\r
369 //\r
370 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));\r
371 }\r
372 }\r
373 \r
374 //\r
375 // Get PCI Device Info\r
376 //\r
377 DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);\r
378\r
379 //\r
380 // Enable I/O or MMIO in PCI Bridge\r
381 // Assume Root Bus Numer is Zero. \r
382 //\r
383 for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {\r
384 //\r
385 // Compute PCI Lib Address to PCI to PCI Bridge\r
386 //\r
387 PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);\r
388 \r
389 //\r
390 // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge\r
391 //\r
392 PciOr16 (\r
393 PciLibAddress + PCI_COMMAND_OFFSET, \r
394 PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE\r
395 );\r
396 \r
397 //\r
398 // Force D0 state if a Power Management and Status Register is specified\r
399 //\r
400 if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {\r
401 if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {\r
402 PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));\r
403 }\r
404 }\r
405 \r
406 BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);\r
407 }\r
408 \r
409 return SerialRegisterBase;\r
410}\r
411\r
e5010d30
RN
412/**\r
413 Return whether the hardware flow control signal allows writing.\r
414\r
74a6d860
LG
415 @param SerialRegisterBase The base address register of UART device.\r
416\r
e5010d30
RN
417 @retval TRUE The serial port is writable.\r
418 @retval FALSE The serial port is not writable.\r
419**/\r
420BOOLEAN\r
421SerialPortWritable (\r
31122d8c 422 UINTN SerialRegisterBase\r
e5010d30
RN
423 )\r
424{\r
425 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
426 if (PcdGetBool (PcdSerialDetectCable)) {\r
427 //\r
428 // Wait for both DSR and CTS to be set\r
429 // DSR is set if a cable is connected.\r
430 // CTS is set if it is ok to transmit data\r
431 //\r
432 // DSR CTS Description Action\r
433 // === === ======================================== ========\r
434 // 0 0 No cable connected. Wait\r
435 // 0 1 No cable connected. Wait\r
436 // 1 0 Cable connected, but not clear to send. Wait\r
437 // 1 1 Cable connected, and clear to send. Transmit\r
438 //\r
31122d8c 439 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
440 } else {\r
441 //\r
442 // Wait for both DSR and CTS to be set OR for DSR to be clear. \r
443 // DSR is set if a cable is connected.\r
444 // CTS is set if it is ok to transmit data\r
445 //\r
446 // DSR CTS Description Action\r
447 // === === ======================================== ========\r
448 // 0 0 No cable connected. Transmit\r
449 // 0 1 No cable connected. Transmit\r
450 // 1 0 Cable connected, but not clear to send. Wait\r
451 // 1 1 Cable connected, and clar to send. Transmit\r
452 //\r
31122d8c 453 return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));\r
e5010d30
RN
454 }\r
455 }\r
456\r
457 return TRUE;\r
458}\r
459\r
467d15ae 460/**\r
461 Initialize the serial device hardware.\r
462 \r
463 If no initialization is required, then return RETURN_SUCCESS.\r
e5010d30 464 If the serial device was successfully initialized, then return RETURN_SUCCESS.\r
467d15ae 465 If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.\r
466 \r
467 @retval RETURN_SUCCESS The serial device was initialized.\r
468 @retval RETURN_DEVICE_ERROR The serial device could not be initialized.\r
469\r
470**/\r
471RETURN_STATUS\r
472EFIAPI\r
473SerialPortInitialize (\r
474 VOID\r
475 )\r
476{\r
477 RETURN_STATUS Status;\r
31122d8c
LG
478 UINTN SerialRegisterBase;\r
479 UINT32 Divisor;\r
480 UINT32 CurrentDivisor; \r
467d15ae 481 BOOLEAN Initialized;\r
482\r
483 //\r
484 // Perform platform specific initialization required to enable use of the 16550 device\r
485 // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.\r
486 //\r
487 Status = PlatformHookSerialPortInitialize ();\r
488 if (RETURN_ERROR (Status)) {\r
489 return Status;\r
490 }\r
491\r
31122d8c
LG
492 //\r
493 // Calculate divisor for baud generator\r
494 // Ref_Clk_Rate / Baud_Rate / 16\r
495 //\r
496 Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);\r
497 if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {\r
498 Divisor++;\r
499 }\r
500\r
501 //\r
502 // Get the base address of the serial port in either I/O or MMIO space\r
503 //\r
504 SerialRegisterBase = GetSerialRegisterBase ();\r
505 if (SerialRegisterBase ==0) {\r
506 return RETURN_DEVICE_ERROR;\r
507 }\r
508\r
467d15ae 509 //\r
510 // See if the serial port is already initialized\r
511 //\r
512 Initialized = TRUE;\r
31122d8c 513 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {\r
467d15ae 514 Initialized = FALSE;\r
515 }\r
31122d8c
LG
516 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));\r
517 CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;\r
518 CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);\r
519 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));\r
520 if (CurrentDivisor != Divisor) {\r
467d15ae 521 Initialized = FALSE;\r
522 }\r
523 if (Initialized) {\r
524 return RETURN_SUCCESS;\r
525 }\r
31122d8c
LG
526\r
527 //\r
528 // Wait for the serial port to be ready.\r
529 // Verify that both the transmit FIFO and the shift register are empty.\r
530 //\r
531 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));\r
467d15ae 532 \r
533 //\r
534 // Configure baud rate\r
535 //\r
31122d8c
LG
536 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);\r
537 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));\r
538 SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));\r
467d15ae 539\r
540 //\r
541 // Clear DLAB and configure Data Bits, Parity, and Stop Bits.\r
542 // Strip reserved bits from PcdSerialLineControl\r
543 //\r
31122d8c 544 SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));\r
467d15ae 545\r
546 //\r
547 // Enable and reset FIFOs\r
548 // Strip reserved bits from PcdSerialFifoControl\r
549 //\r
31122d8c
LG
550 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);\r
551 SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));\r
467d15ae 552\r
553 //\r
554 // Put Modem Control Register(MCR) into its reset state of 0x00.\r
555 // \r
31122d8c
LG
556 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);\r
557\r
467d15ae 558 return RETURN_SUCCESS;\r
559}\r
560\r
561/**\r
562 Write data from buffer to serial device. \r
31122d8c 563\r
467d15ae 564 Writes NumberOfBytes data bytes from Buffer to the serial device. \r
565 The number of bytes actually written to the serial device is returned.\r
566 If the return value is less than NumberOfBytes, then the write operation failed.\r
567\r
568 If Buffer is NULL, then ASSERT(). \r
569\r
570 If NumberOfBytes is zero, then return 0.\r
571\r
572 @param Buffer Pointer to the data buffer to be written.\r
573 @param NumberOfBytes Number of bytes to written to the serial device.\r
574\r
575 @retval 0 NumberOfBytes is 0.\r
576 @retval >0 The number of bytes written to the serial device. \r
577 If this value is less than NumberOfBytes, then the read operation failed.\r
578\r
579**/\r
580UINTN\r
581EFIAPI\r
582SerialPortWrite (\r
583 IN UINT8 *Buffer,\r
584 IN UINTN NumberOfBytes\r
31122d8c 585 )\r
467d15ae 586{\r
31122d8c
LG
587 UINTN SerialRegisterBase;\r
588 UINTN Result;\r
589 UINTN Index;\r
590 UINTN FifoSize;\r
467d15ae 591\r
592 if (Buffer == NULL) {\r
593 return 0;\r
594 }\r
595\r
31122d8c
LG
596 SerialRegisterBase = GetSerialRegisterBase ();\r
597 if (SerialRegisterBase ==0) {\r
598 return 0;\r
599 }\r
600 \r
e5010d30
RN
601 if (NumberOfBytes == 0) {\r
602 //\r
603 // Flush the hardware\r
604 //\r
605\r
606 //\r
607 // Wait for both the transmit FIFO and shift register empty.\r
608 //\r
31122d8c 609 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
610\r
611 //\r
612 // Wait for the hardware flow control signal\r
613 //\r
31122d8c 614 while (!SerialPortWritable (SerialRegisterBase));\r
e5010d30
RN
615 return 0;\r
616 }\r
617\r
467d15ae 618 //\r
619 // Compute the maximum size of the Tx FIFO\r
620 //\r
621 FifoSize = 1;\r
622 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {\r
623 if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {\r
624 FifoSize = 16;\r
625 } else {\r
31122d8c 626 FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);\r
467d15ae 627 }\r
628 }\r
db662a64 629\r
467d15ae 630 Result = NumberOfBytes;\r
631 while (NumberOfBytes != 0) {\r
632 //\r
633 // Wait for the serial port to be ready, to make sure both the transmit FIFO\r
634 // and shift register empty.\r
635 //\r
31122d8c 636 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);\r
467d15ae 637\r
638 //\r
639 // Fill then entire Tx FIFO\r
640 //\r
641 for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {\r
e5010d30
RN
642 //\r
643 // Wait for the hardware flow control signal\r
644 //\r
31122d8c 645 while (!SerialPortWritable (SerialRegisterBase));\r
e5010d30 646\r
467d15ae 647 //\r
648 // Write byte to the transmit buffer.\r
649 //\r
31122d8c 650 SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);\r
467d15ae 651 }\r
652 }\r
653 return Result;\r
654}\r
655\r
656/**\r
657 Reads data from a serial device into a buffer.\r
658\r
659 @param Buffer Pointer to the data buffer to store the data read from the serial device.\r
660 @param NumberOfBytes Number of bytes to read from the serial device.\r
661\r
662 @retval 0 NumberOfBytes is 0.\r
663 @retval >0 The number of bytes read from the serial device. \r
664 If this value is less than NumberOfBytes, then the read operation failed.\r
665\r
666**/\r
667UINTN\r
668EFIAPI\r
669SerialPortRead (\r
670 OUT UINT8 *Buffer,\r
671 IN UINTN NumberOfBytes\r
31122d8c 672 )\r
467d15ae 673{\r
31122d8c 674 UINTN SerialRegisterBase;\r
467d15ae 675 UINTN Result;\r
676 UINT8 Mcr;\r
677\r
678 if (NULL == Buffer) {\r
679 return 0;\r
680 }\r
681\r
31122d8c
LG
682 SerialRegisterBase = GetSerialRegisterBase ();\r
683 if (SerialRegisterBase ==0) {\r
684 return 0;\r
685 }\r
686\r
687 Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);\r
467d15ae 688 \r
689 for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {\r
690 //\r
691 // Wait for the serial port to have some data.\r
692 //\r
31122d8c 693 while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {\r
467d15ae 694 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
695 //\r
696 // Set RTS to let the peer send some data\r
697 //\r
31122d8c 698 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));\r
467d15ae 699 }\r
700 }\r
701 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
702 //\r
703 // Clear RTS to prevent peer from sending data\r
704 //\r
31122d8c 705 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);\r
467d15ae 706 }\r
707 \r
708 //\r
709 // Read byte from the receive buffer.\r
710 //\r
31122d8c 711 *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);\r
467d15ae 712 }\r
713 \r
714 return Result;\r
715}\r
716\r
31122d8c 717\r
467d15ae 718/**\r
719 Polls a serial device to see if there is any data waiting to be read.\r
720\r
721 Polls aserial device to see if there is any data waiting to be read.\r
722 If there is data waiting to be read from the serial device, then TRUE is returned.\r
723 If there is no data waiting to be read from the serial device, then FALSE is returned.\r
724\r
725 @retval TRUE Data is waiting to be read from the serial device.\r
726 @retval FALSE There is no data waiting to be read from the serial device.\r
727\r
728**/\r
729BOOLEAN\r
730EFIAPI\r
731SerialPortPoll (\r
732 VOID\r
733 )\r
734{\r
31122d8c
LG
735 UINTN SerialRegisterBase;\r
736 \r
737 SerialRegisterBase = GetSerialRegisterBase ();\r
738 if (SerialRegisterBase ==0) {\r
739 return FALSE;\r
740 }\r
741\r
467d15ae 742 //\r
743 // Read the serial port status\r
744 //\r
31122d8c 745 if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {\r
467d15ae 746 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
747 //\r
748 // Clear RTS to prevent peer from sending data\r
749 //\r
31122d8c 750 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));\r
467d15ae 751 }\r
752 return TRUE;\r
753 } \r
754 \r
755 if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {\r
756 //\r
757 // Set RTS to let the peer send some data\r
758 //\r
31122d8c 759 SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));\r
467d15ae 760 }\r
761 \r
762 return FALSE;\r
763}\r