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