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