1 /** @file
2   Serial I/O Port library functions with no library constructor/destructor
3 
4   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
5   Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include <Library/DebugLib.h>
18 #include <Library/IoLib.h>
19 #include <Library/PcdLib.h>
20 
21 #include <Drivers/PL011Uart.h>
22 
23 //
24 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only
25 // control bit that is not supported.
26 //
27 STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
28 
29 /*
30 
31   Initialise the serial port to the specified settings.
32   All unspecified settings will be set to the default values.
33 
34   @return    Always return EFI_SUCCESS or EFI_INVALID_PARAMETER.
35 
36 **/
37 RETURN_STATUS
38 EFIAPI
PL011UartInitializePort(IN OUT UINTN UartBase,IN OUT UINT64 * BaudRate,IN OUT UINT32 * ReceiveFifoDepth,IN OUT EFI_PARITY_TYPE * Parity,IN OUT UINT8 * DataBits,IN OUT EFI_STOP_BITS_TYPE * StopBits)39 PL011UartInitializePort (
40   IN OUT UINTN               UartBase,
41   IN OUT UINT64              *BaudRate,
42   IN OUT UINT32              *ReceiveFifoDepth,
43   IN OUT EFI_PARITY_TYPE     *Parity,
44   IN OUT UINT8               *DataBits,
45   IN OUT EFI_STOP_BITS_TYPE  *StopBits
46   )
47 {
48   UINT32      LineControl;
49   UINT32      Divisor;
50 
51   LineControl = 0;
52 
53   // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
54   // 1 char buffer as the minimum fifo size. Because everything can be rounded down,
55   // there is no maximum fifo size.
56   if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= 32)) {
57     LineControl |= PL011_UARTLCR_H_FEN;
58     if (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) > PL011_VER_R1P4)
59       *ReceiveFifoDepth = 32;
60     else
61       *ReceiveFifoDepth = 16;
62   } else {
63     ASSERT (*ReceiveFifoDepth < 32);
64     // Nothing else to do. 1 byte fifo is default.
65     *ReceiveFifoDepth = 1;
66   }
67 
68   //
69   // Parity
70   //
71   switch (*Parity) {
72   case DefaultParity:
73     *Parity = NoParity;
74   case NoParity:
75     // Nothing to do. Parity is disabled by default.
76     break;
77   case EvenParity:
78     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
79     break;
80   case OddParity:
81     LineControl |= PL011_UARTLCR_H_PEN;
82     break;
83   case MarkParity:
84     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS | PL011_UARTLCR_H_EPS);
85     break;
86   case SpaceParity:
87     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
88     break;
89   default:
90     return RETURN_INVALID_PARAMETER;
91   }
92 
93   //
94   // Data Bits
95   //
96   switch (*DataBits) {
97   case 0:
98     *DataBits = 8;
99   case 8:
100     LineControl |= PL011_UARTLCR_H_WLEN_8;
101     break;
102   case 7:
103     LineControl |= PL011_UARTLCR_H_WLEN_7;
104     break;
105   case 6:
106     LineControl |= PL011_UARTLCR_H_WLEN_6;
107     break;
108   case 5:
109     LineControl |= PL011_UARTLCR_H_WLEN_5;
110     break;
111   default:
112     return RETURN_INVALID_PARAMETER;
113   }
114 
115   //
116   // Stop Bits
117   //
118   switch (*StopBits) {
119   case DefaultStopBits:
120     *StopBits = OneStopBit;
121   case OneStopBit:
122     // Nothing to do. One stop bit is enabled by default.
123     break;
124   case TwoStopBits:
125     LineControl |= PL011_UARTLCR_H_STP2;
126     break;
127   case OneFiveStopBits:
128     // Only 1 or 2 stops bits are supported
129   default:
130     return RETURN_INVALID_PARAMETER;
131   }
132 
133   // Don't send the LineControl value to the PL011 yet,
134   // wait until after the Baud Rate setting.
135   // This ensures we do not mess up the UART settings halfway through
136   // in the rare case when there is an error with the Baud Rate.
137 
138   //
139   // Baud Rate
140   //
141 
142   // If PL011 Integral value has been defined then always ignore the BAUD rate
143   if (PcdGet32 (PL011UartInteger) != 0) {
144       MmioWrite32 (UartBase + UARTIBRD, PcdGet32 (PL011UartInteger));
145       MmioWrite32 (UartBase + UARTFBRD, PcdGet32 (PL011UartFractional));
146   } else {
147     // If BAUD rate is zero then replace it with the system default value
148     if (*BaudRate == 0) {
149       *BaudRate = PcdGet32 (PcdSerialBaudRate);
150       ASSERT (*BaudRate != 0);
151     }
152 
153     Divisor = (PcdGet32 (PL011UartClkInHz) * 4) / *BaudRate;
154     MmioWrite32 (UartBase + UARTIBRD, Divisor >> 6);
155     MmioWrite32 (UartBase + UARTFBRD, Divisor & 0x3F);
156   }
157 
158   // No parity, 1 stop, no fifo, 8 data bits
159   MmioWrite32 (UartBase + UARTLCR_H, LineControl);
160 
161   // Clear any pending errors
162   MmioWrite32 (UartBase + UARTECR, 0);
163 
164   // Enable tx, rx, and uart overall
165   MmioWrite32 (UartBase + UARTCR, PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
166 
167   return RETURN_SUCCESS;
168 }
169 
170 /**
171 
172   Assert or deassert the control signals on a serial port.
173   The following control signals are set according their bit settings :
174   . Request to Send
175   . Data Terminal Ready
176 
177   @param[in]  UartBase  UART registers base address
178   @param[in]  Control   The following bits are taken into account :
179                         . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the
180                           "Request To Send" control signal if this bit is
181                           equal to one/zero.
182                         . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert
183                           the "Data Terminal Ready" control signal if this
184                           bit is equal to one/zero.
185                         . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable
186                           the hardware loopback if this bit is equal to
187                           one/zero.
188                         . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.
189                         . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/
190                           disable the hardware flow control based on CTS (Clear
191                           To Send) and RTS (Ready To Send) control signals.
192 
193   @retval  RETURN_SUCCESS      The new control bits were set on the serial device.
194   @retval  RETURN_UNSUPPORTED  The serial device does not support this operation.
195 
196 **/
197 RETURN_STATUS
198 EFIAPI
PL011UartSetControl(IN UINTN UartBase,IN UINT32 Control)199 PL011UartSetControl (
200     IN UINTN   UartBase,
201     IN UINT32  Control
202   )
203 {
204   UINT32  Bits;
205 
206   if (Control & (mInvalidControlBits)) {
207     return RETURN_UNSUPPORTED;
208   }
209 
210   Bits = MmioRead32 (UartBase + UARTCR);
211 
212   if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
213     Bits |= PL011_UARTCR_RTS;
214   } else {
215     Bits &= ~PL011_UARTCR_RTS;
216   }
217 
218   if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
219     Bits |= PL011_UARTCR_DTR;
220   } else {
221     Bits &= ~PL011_UARTCR_DTR;
222   }
223 
224   if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
225     Bits |= PL011_UARTCR_LBE;
226   } else {
227     Bits &= ~PL011_UARTCR_LBE;
228   }
229 
230   if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
231     Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
232   } else {
233     Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
234   }
235 
236   MmioWrite32 (UartBase + UARTCR, Bits);
237 
238   return RETURN_SUCCESS;
239 }
240 
241 /**
242 
243   Retrieve the status of the control bits on a serial device.
244 
245   @param[in]   UartBase  UART registers base address
246   @param[out]  Control   Status of the control bits on a serial device :
247 
248                          . EFI_SERIAL_DATA_CLEAR_TO_SEND, EFI_SERIAL_DATA_SET_READY,
249                            EFI_SERIAL_RING_INDICATE, EFI_SERIAL_CARRIER_DETECT,
250                            EFI_SERIAL_REQUEST_TO_SEND, EFI_SERIAL_DATA_TERMINAL_READY
251                            are all related to the DTE (Data Terminal Equipment) and
252                            DCE (Data Communication Equipment) modes of operation of
253                            the serial device.
254                          . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the receive
255                            buffer is empty, 0 otherwise.
256                          . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the transmit
257                            buffer is empty, 0 otherwise.
258                          . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if the
259                            hardware loopback is enabled (the ouput feeds the receive
260                            buffer), 0 otherwise.
261                          . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if a
262                            loopback is accomplished by software, 0 otherwise.
263                          . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to one if the
264                            hardware flow control based on CTS (Clear To Send) and RTS
265                            (Ready To Send) control signals is enabled, 0 otherwise.
266 
267   @retval RETURN_SUCCESS  The control bits were read from the serial device.
268 
269 **/
270 RETURN_STATUS
271 EFIAPI
PL011UartGetControl(IN UINTN UartBase,OUT UINT32 * Control)272 PL011UartGetControl (
273     IN UINTN     UartBase,
274     OUT UINT32  *Control
275   )
276 {
277   UINT32      FlagRegister;
278   UINT32      ControlRegister;
279 
280 
281   FlagRegister = MmioRead32 (UartBase + UARTFR);
282   ControlRegister = MmioRead32 (UartBase + UARTCR);
283 
284   *Control = 0;
285 
286   if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
287     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
288   }
289 
290   if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
291     *Control |= EFI_SERIAL_DATA_SET_READY;
292   }
293 
294   if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
295     *Control |= EFI_SERIAL_RING_INDICATE;
296   }
297 
298   if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
299     *Control |= EFI_SERIAL_CARRIER_DETECT;
300   }
301 
302   if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
303     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
304   }
305 
306   if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
307     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
308   }
309 
310   if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
311     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
312   }
313 
314   if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
315     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
316   }
317 
318   if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
319        == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
320     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
321   }
322 
323   if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
324     *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
325   }
326 
327   return RETURN_SUCCESS;
328 }
329 
330 /**
331   Write data to serial device.
332 
333   @param  Buffer           Point of data buffer which need to be written.
334   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
335 
336   @retval 0                Write data failed.
337   @retval !0               Actual number of bytes written to serial device.
338 
339 **/
340 UINTN
341 EFIAPI
PL011UartWrite(IN UINTN UartBase,IN UINT8 * Buffer,IN UINTN NumberOfBytes)342 PL011UartWrite (
343   IN  UINTN    UartBase,
344   IN UINT8     *Buffer,
345   IN UINTN     NumberOfBytes
346   )
347 {
348   UINT8* CONST Final = &Buffer[NumberOfBytes];
349 
350   while (Buffer < Final) {
351     // Wait until UART able to accept another char
352     while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
353 
354     MmioWrite8 (UartBase + UARTDR, *Buffer++);
355   }
356 
357   return NumberOfBytes;
358 }
359 
360 /**
361   Read data from serial device and save the data in buffer.
362 
363   @param  Buffer           Point of data buffer which need to be written.
364   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
365 
366   @retval 0                Read data failed.
367   @retval !0               Actual number of bytes read from serial device.
368 
369 **/
370 UINTN
371 EFIAPI
PL011UartRead(IN UINTN UartBase,OUT UINT8 * Buffer,IN UINTN NumberOfBytes)372 PL011UartRead (
373   IN  UINTN     UartBase,
374   OUT UINT8     *Buffer,
375   IN  UINTN     NumberOfBytes
376   )
377 {
378   UINTN   Count;
379 
380   for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
381     while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
382     *Buffer = MmioRead8 (UartBase + UARTDR);
383   }
384 
385   return NumberOfBytes;
386 }
387 
388 /**
389   Check to see if any data is available to be read from the debug device.
390 
391   @retval EFI_SUCCESS       At least one byte of data is available to be read
392   @retval EFI_NOT_READY     No data is available to be read
393   @retval EFI_DEVICE_ERROR  The serial device is not functioning properly
394 
395 **/
396 BOOLEAN
397 EFIAPI
PL011UartPoll(IN UINTN UartBase)398 PL011UartPoll (
399   IN  UINTN     UartBase
400   )
401 {
402   return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
403 }
404