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