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