1 /** @file
2   Serial I/O Port library functions with base address discovered from FDT
3 
4   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
5   Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.<BR>
6   Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
7   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
8 
9   SPDX-License-Identifier: BSD-2-Clause-Patent
10 
11 **/
12 
13 #include <Base.h>
14 
15 #include <Library/PcdLib.h>
16 #include <Library/PL011UartLib.h>
17 #include <Library/SerialPortLib.h>
18 #include <libfdt.h>
19 
20 RETURN_STATUS
21 EFIAPI
SerialPortInitialize(VOID)22 SerialPortInitialize (
23   VOID
24   )
25 {
26   //
27   // This SerialPortInitialize() function is completely empty, for a number of
28   // reasons:
29   // - if we are executing from flash, it is hard to keep state (i.e., store the
30   //   discovered base address in a global), and the most robust way to deal
31   //   with this is to discover the base address at every Write ();
32   // - calls to the Write() function in this module may be issued before this
33   //   initialization function is called: this is not a problem when the base
34   //   address of the UART is hardcoded, and only the baud rate may be wrong,
35   //   but if we don't know the base address yet, we may be poking into memory
36   //   that does not tolerate being poked into;
37   // - SEC and PEI phases produce debug output only, so with debug disabled, no
38   //   initialization (or device tree parsing) is performed at all.
39   //
40   // Note that this means that on *every* Write () call, the device tree will be
41   // parsed and the UART re-initialized. However, this is a small price to pay
42   // for having serial debug output on a UART with no fixed base address.
43   //
44   return RETURN_SUCCESS;
45 }
46 
47 STATIC
48 UINT64
SerialPortGetBaseAddress(VOID)49 SerialPortGetBaseAddress (
50   VOID
51   )
52 {
53   UINT64              BaudRate;
54   UINT32              ReceiveFifoDepth;
55   EFI_PARITY_TYPE     Parity;
56   UINT8               DataBits;
57   EFI_STOP_BITS_TYPE  StopBits;
58   VOID                *DeviceTreeBase;
59   INT32               Node, Prev;
60   INT32               Len;
61   CONST CHAR8         *Compatible;
62   CONST CHAR8         *NodeStatus;
63   CONST CHAR8         *CompatibleItem;
64   CONST UINT64        *RegProperty;
65   UINTN               UartBase;
66   RETURN_STATUS       Status;
67 
68   DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
69 
70   if ((DeviceTreeBase == NULL) || (fdt_check_header (DeviceTreeBase) != 0)) {
71     return 0;
72   }
73 
74   //
75   // Enumerate all FDT nodes looking for a PL011 and capture its base address
76   //
77   for (Prev = 0;; Prev = Node) {
78     Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
79     if (Node < 0) {
80       break;
81     }
82 
83     Compatible = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
84     if (Compatible == NULL) {
85       continue;
86     }
87 
88     //
89     // Iterate over the NULL-separated items in the compatible string
90     //
91     for (CompatibleItem = Compatible; CompatibleItem < Compatible + Len;
92       CompatibleItem += 1 + AsciiStrLen (CompatibleItem)) {
93 
94       if (AsciiStrCmp (CompatibleItem, "arm,pl011") == 0) {
95         NodeStatus = fdt_getprop (DeviceTreeBase, Node, "status", &Len);
96         if (NodeStatus != NULL && AsciiStrCmp (NodeStatus, "okay") != 0) {
97           continue;
98         }
99 
100         RegProperty = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
101         if (Len != 16) {
102           return 0;
103         }
104         UartBase = (UINTN)fdt64_to_cpu (ReadUnaligned64 (RegProperty));
105 
106         BaudRate = (UINTN)FixedPcdGet64 (PcdUartDefaultBaudRate);
107         ReceiveFifoDepth = 0; // Use the default value for Fifo depth
108         Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity);
109         DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);
110         StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits);
111 
112         Status = PL011UartInitializePort (
113                    UartBase,
114                    FixedPcdGet32 (PL011UartClkInHz),
115                    &BaudRate,
116                    &ReceiveFifoDepth,
117                    &Parity,
118                    &DataBits,
119                    &StopBits
120                    );
121         if (!EFI_ERROR (Status)) {
122           return UartBase;
123         }
124       }
125     }
126   }
127   return 0;
128 }
129 
130 /**
131   Write data to serial device.
132 
133   @param  Buffer           Point of data buffer which need to be written.
134   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
135 
136   @retval 0                Write data failed.
137   @retval !0               Actual number of bytes written to serial device.
138 
139 **/
140 UINTN
141 EFIAPI
SerialPortWrite(IN UINT8 * Buffer,IN UINTN NumberOfBytes)142 SerialPortWrite (
143   IN UINT8     *Buffer,
144   IN UINTN     NumberOfBytes
145   )
146 {
147   UINT64 SerialRegisterBase;
148 
149   SerialRegisterBase = SerialPortGetBaseAddress ();
150   if (SerialRegisterBase != 0) {
151     return PL011UartWrite ((UINTN)SerialRegisterBase, Buffer, NumberOfBytes);
152   }
153   return 0;
154 }
155 
156 /**
157   Read data from serial device and save the data in buffer.
158 
159   @param  Buffer           Point of data buffer which need to be written.
160   @param  NumberOfBytes    Size of Buffer[].
161 
162   @retval 0                Read data failed.
163   @retval !0               Actual number of bytes read from serial device.
164 
165 **/
166 UINTN
167 EFIAPI
SerialPortRead(OUT UINT8 * Buffer,IN UINTN NumberOfBytes)168 SerialPortRead (
169   OUT UINT8     *Buffer,
170   IN  UINTN     NumberOfBytes
171 )
172 {
173   return 0;
174 }
175 
176 /**
177   Check to see if any data is available to be read from the debug device.
178 
179   @retval TRUE       At least one byte of data is available to be read
180   @retval FALSE      No data is available to be read
181 
182 **/
183 BOOLEAN
184 EFIAPI
SerialPortPoll(VOID)185 SerialPortPoll (
186   VOID
187   )
188 {
189   return FALSE;
190 }
191 
192 /**
193   Sets the control bits on a serial device.
194 
195   @param[in] Control            Sets the bits of Control that are settable.
196 
197   @retval RETURN_SUCCESS        The new control bits were set on the serial device.
198   @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
199   @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
200 
201 **/
202 RETURN_STATUS
203 EFIAPI
SerialPortSetControl(IN UINT32 Control)204 SerialPortSetControl (
205   IN UINT32 Control
206   )
207 {
208   return RETURN_UNSUPPORTED;
209 }
210 
211 /**
212   Retrieve the status of the control bits on a serial device.
213 
214   @param[out] Control           A pointer to return the current control signals from the serial device.
215 
216   @retval RETURN_SUCCESS        The control bits were read from the serial device.
217   @retval RETURN_UNSUPPORTED    The serial device does not support this operation.
218   @retval RETURN_DEVICE_ERROR   The serial device is not functioning correctly.
219 
220 **/
221 RETURN_STATUS
222 EFIAPI
SerialPortGetControl(OUT UINT32 * Control)223 SerialPortGetControl (
224   OUT UINT32 *Control
225   )
226 {
227   return RETURN_UNSUPPORTED;
228 }
229 
230 /**
231   Sets the baud rate, receive FIFO depth, transmit/receive time out, parity,
232   data bits, and stop bits on a serial device.
233 
234   @param BaudRate           The requested baud rate. A BaudRate value of 0 will use the
235                             device's default interface speed.
236                             On output, the value actually set.
237   @param ReceiveFifoDepth   The requested depth of the FIFO on the receive side of the
238                             serial interface. A ReceiveFifoDepth value of 0 will use
239                             the device's default FIFO depth.
240                             On output, the value actually set.
241   @param Timeout            The requested time out for a single character in microseconds.
242                             This timeout applies to both the transmit and receive side of the
243                             interface. A Timeout value of 0 will use the device's default time
244                             out value.
245                             On output, the value actually set.
246   @param Parity             The type of parity to use on this serial device. A Parity value of
247                             DefaultParity will use the device's default parity value.
248                             On output, the value actually set.
249   @param DataBits           The number of data bits to use on the serial device. A DataBits
250                             value of 0 will use the device's default data bit setting.
251                             On output, the value actually set.
252   @param StopBits           The number of stop bits to use on this serial device. A StopBits
253                             value of DefaultStopBits will use the device's default number of
254                             stop bits.
255                             On output, the value actually set.
256 
257   @retval RETURN_SUCCESS            The new attributes were set on the serial device.
258   @retval RETURN_UNSUPPORTED        The serial device does not support this operation.
259   @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an unsupported value.
260   @retval RETURN_DEVICE_ERROR       The serial device is not functioning correctly.
261 
262 **/
263 RETURN_STATUS
264 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)265 SerialPortSetAttributes (
266   IN OUT UINT64             *BaudRate,
267   IN OUT UINT32             *ReceiveFifoDepth,
268   IN OUT UINT32             *Timeout,
269   IN OUT EFI_PARITY_TYPE    *Parity,
270   IN OUT UINT8              *DataBits,
271   IN OUT EFI_STOP_BITS_TYPE *StopBits
272   )
273 {
274   return RETURN_UNSUPPORTED;
275 }
276 
277