• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 - 2016, 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 #define FRACTION_PART_SIZE_IN_BITS  6
24 #define FRACTION_PART_MASK          ((1 << FRACTION_PART_SIZE_IN_BITS) - 1)
25 
26 //
27 // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE is the only
28 // control bit that is not supported.
29 //
30 STATIC CONST UINT32 mInvalidControlBits = EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
31 
32 /**
33 
34   Initialise the serial port to the specified settings.
35   The serial port is re-configured only if the specified settings
36   are different from the current settings.
37   All unspecified settings will be set to the default values.
38 
39   @param  UartBase                The base address of the serial device.
40   @param  UartClkInHz             The clock in Hz for the serial device.
41                                   Ignored if the PCD PL011UartInteger is not 0
42   @param  BaudRate                The baud rate of the serial device. If the
43                                   baud rate is not supported, the speed will be
44                                   reduced to the nearest supported one and the
45                                   variable's value will be updated accordingly.
46   @param  ReceiveFifoDepth        The number of characters the device will
47                                   buffer on input.  Value of 0 will use the
48                                   device's default FIFO depth.
49   @param  Parity                  If applicable, this is the EFI_PARITY_TYPE
50                                   that is computed or checked as each character
51                                   is transmitted or received. If the device
52                                   does not support parity, the value is the
53                                   default parity value.
54   @param  DataBits                The number of data bits in each character.
55   @param  StopBits                If applicable, the EFI_STOP_BITS_TYPE number
56                                   of stop bits per character.
57                                   If the device does not support stop bits, the
58                                   value is the default stop bit value.
59 
60   @retval RETURN_SUCCESS            All attributes were set correctly on the
61                                     serial device.
62   @retval RETURN_INVALID_PARAMETER  One or more of the attributes has an
63                                     unsupported value.
64 
65 **/
66 RETURN_STATUS
67 EFIAPI
PL011UartInitializePort(IN UINTN UartBase,IN UINT32 UartClkInHz,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)68 PL011UartInitializePort (
69   IN     UINTN               UartBase,
70   IN     UINT32              UartClkInHz,
71   IN OUT UINT64              *BaudRate,
72   IN OUT UINT32              *ReceiveFifoDepth,
73   IN OUT EFI_PARITY_TYPE     *Parity,
74   IN OUT UINT8               *DataBits,
75   IN OUT EFI_STOP_BITS_TYPE  *StopBits
76   )
77 {
78   UINT32      LineControl;
79   UINT32      Divisor;
80   UINT32      Integer;
81   UINT32      Fractional;
82   UINT32      HardwareFifoDepth;
83 
84   HardwareFifoDepth = (PL011_UARTPID2_VER (MmioRead32 (UartBase + UARTPID2)) \
85                        > PL011_VER_R1P4) \
86                       ? 32 : 16 ;
87   // The PL011 supports a buffer of 1, 16 or 32 chars. Therefore we can accept
88   // 1 char buffer as the minimum FIFO size. Because everything can be rounded
89   // down, there is no maximum FIFO size.
90   if ((*ReceiveFifoDepth == 0) || (*ReceiveFifoDepth >= HardwareFifoDepth)) {
91     // Enable FIFO
92     LineControl = PL011_UARTLCR_H_FEN;
93     *ReceiveFifoDepth = HardwareFifoDepth;
94   } else {
95     // Disable FIFO
96     LineControl = 0;
97     // Nothing else to do. 1 byte FIFO is default.
98     *ReceiveFifoDepth = 1;
99   }
100 
101   //
102   // Parity
103   //
104   switch (*Parity) {
105   case DefaultParity:
106     *Parity = NoParity;
107   case NoParity:
108     // Nothing to do. Parity is disabled by default.
109     break;
110   case EvenParity:
111     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_EPS);
112     break;
113   case OddParity:
114     LineControl |= PL011_UARTLCR_H_PEN;
115     break;
116   case MarkParity:
117     LineControl |= (  PL011_UARTLCR_H_PEN \
118                     | PL011_UARTLCR_H_SPS \
119                     | PL011_UARTLCR_H_EPS);
120     break;
121   case SpaceParity:
122     LineControl |= (PL011_UARTLCR_H_PEN | PL011_UARTLCR_H_SPS);
123     break;
124   default:
125     return RETURN_INVALID_PARAMETER;
126   }
127 
128   //
129   // Data Bits
130   //
131   switch (*DataBits) {
132   case 0:
133     *DataBits = 8;
134   case 8:
135     LineControl |= PL011_UARTLCR_H_WLEN_8;
136     break;
137   case 7:
138     LineControl |= PL011_UARTLCR_H_WLEN_7;
139     break;
140   case 6:
141     LineControl |= PL011_UARTLCR_H_WLEN_6;
142     break;
143   case 5:
144     LineControl |= PL011_UARTLCR_H_WLEN_5;
145     break;
146   default:
147     return RETURN_INVALID_PARAMETER;
148   }
149 
150   //
151   // Stop Bits
152   //
153   switch (*StopBits) {
154   case DefaultStopBits:
155     *StopBits = OneStopBit;
156   case OneStopBit:
157     // Nothing to do. One stop bit is enabled by default.
158     break;
159   case TwoStopBits:
160     LineControl |= PL011_UARTLCR_H_STP2;
161     break;
162   case OneFiveStopBits:
163     // Only 1 or 2 stop bits are supported
164   default:
165     return RETURN_INVALID_PARAMETER;
166   }
167 
168   // Don't send the LineControl value to the PL011 yet,
169   // wait until after the Baud Rate setting.
170   // This ensures we do not mess up the UART settings halfway through
171   // in the rare case when there is an error with the Baud Rate.
172 
173   //
174   // Baud Rate
175   //
176 
177   // If PL011 Integer value has been defined then always ignore the BAUD rate
178   if (FixedPcdGet32 (PL011UartInteger) != 0) {
179     Integer = FixedPcdGet32 (PL011UartInteger);
180     Fractional = FixedPcdGet32 (PL011UartFractional);
181   } else {
182     // If BAUD rate is zero then replace it with the system default value
183     if (*BaudRate == 0) {
184       *BaudRate = FixedPcdGet32 (PcdSerialBaudRate);
185       if (*BaudRate == 0) {
186         return RETURN_INVALID_PARAMETER;
187       }
188     }
189     if (0 == UartClkInHz) {
190       return RETURN_INVALID_PARAMETER;
191     }
192 
193     Divisor = (UartClkInHz * 4) / *BaudRate;
194     Integer = Divisor >> FRACTION_PART_SIZE_IN_BITS;
195     Fractional = Divisor & FRACTION_PART_MASK;
196   }
197 
198   //
199   // If PL011 is already initialized, check the current settings
200   // and re-initialize only if the settings are different.
201   //
202   if (((MmioRead32 (UartBase + UARTCR) & PL011_UARTCR_UARTEN) != 0) &&
203        (MmioRead32 (UartBase + UARTLCR_H) == LineControl) &&
204        (MmioRead32 (UartBase + UARTIBRD) == Integer) &&
205        (MmioRead32 (UartBase + UARTFBRD) == Fractional)) {
206     // Nothing to do - already initialized with correct attributes
207     return RETURN_SUCCESS;
208   }
209 
210   // Wait for the end of transmission
211   while ((MmioRead32 (UartBase + UARTFR) & PL011_UARTFR_TXFE) == 0);
212 
213   // Disable UART: "The UARTLCR_H, UARTIBRD, and UARTFBRD registers must not be changed
214   // when the UART is enabled"
215   MmioWrite32 (UartBase + UARTCR, 0);
216 
217   // Set Baud Rate Registers
218   MmioWrite32 (UartBase + UARTIBRD, Integer);
219   MmioWrite32 (UartBase + UARTFBRD, Fractional);
220 
221   // No parity, 1 stop, no fifo, 8 data bits
222   MmioWrite32 (UartBase + UARTLCR_H, LineControl);
223 
224   // Clear any pending errors
225   MmioWrite32 (UartBase + UARTECR, 0);
226 
227   // Enable Tx, Rx, and UART overall
228   MmioWrite32 (UartBase + UARTCR,
229                PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN);
230 
231   return RETURN_SUCCESS;
232 }
233 
234 /**
235 
236   Assert or deassert the control signals on a serial port.
237   The following control signals are set according their bit settings :
238   . Request to Send
239   . Data Terminal Ready
240 
241   @param[in]  UartBase  UART registers base address
242   @param[in]  Control   The following bits are taken into account :
243                         . EFI_SERIAL_REQUEST_TO_SEND : assert/deassert the
244                           "Request To Send" control signal if this bit is
245                           equal to one/zero.
246                         . EFI_SERIAL_DATA_TERMINAL_READY : assert/deassert
247                           the "Data Terminal Ready" control signal if this
248                           bit is equal to one/zero.
249                         . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : enable/disable
250                           the hardware loopback if this bit is equal to
251                           one/zero.
252                         . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : not supported.
253                         . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : enable/
254                           disable the hardware flow control based on CTS (Clear
255                           To Send) and RTS (Ready To Send) control signals.
256 
257   @retval  RETURN_SUCCESS      The new control bits were set on the device.
258   @retval  RETURN_UNSUPPORTED  The device does not support this operation.
259 
260 **/
261 RETURN_STATUS
262 EFIAPI
PL011UartSetControl(IN UINTN UartBase,IN UINT32 Control)263 PL011UartSetControl (
264     IN UINTN   UartBase,
265     IN UINT32  Control
266   )
267 {
268   UINT32  Bits;
269 
270   if (Control & (mInvalidControlBits)) {
271     return RETURN_UNSUPPORTED;
272   }
273 
274   Bits = MmioRead32 (UartBase + UARTCR);
275 
276   if (Control & EFI_SERIAL_REQUEST_TO_SEND) {
277     Bits |= PL011_UARTCR_RTS;
278   } else {
279     Bits &= ~PL011_UARTCR_RTS;
280   }
281 
282   if (Control & EFI_SERIAL_DATA_TERMINAL_READY) {
283     Bits |= PL011_UARTCR_DTR;
284   } else {
285     Bits &= ~PL011_UARTCR_DTR;
286   }
287 
288   if (Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
289     Bits |= PL011_UARTCR_LBE;
290   } else {
291     Bits &= ~PL011_UARTCR_LBE;
292   }
293 
294   if (Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
295     Bits |= (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
296   } else {
297     Bits &= ~(PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN);
298   }
299 
300   MmioWrite32 (UartBase + UARTCR, Bits);
301 
302   return RETURN_SUCCESS;
303 }
304 
305 /**
306 
307   Retrieve the status of the control bits on a serial device.
308 
309   @param[in]   UartBase  UART registers base address
310   @param[out]  Control   Status of the control bits on a serial device :
311 
312                          . EFI_SERIAL_DATA_CLEAR_TO_SEND,
313                            EFI_SERIAL_DATA_SET_READY,
314                            EFI_SERIAL_RING_INDICATE,
315                            EFI_SERIAL_CARRIER_DETECT,
316                            EFI_SERIAL_REQUEST_TO_SEND,
317                            EFI_SERIAL_DATA_TERMINAL_READY
318                            are all related to the DTE (Data Terminal Equipment)
319                            and DCE (Data Communication Equipment) modes of
320                            operation of the serial device.
321                          . EFI_SERIAL_INPUT_BUFFER_EMPTY : equal to one if the
322                            receive buffer is empty, 0 otherwise.
323                          . EFI_SERIAL_OUTPUT_BUFFER_EMPTY : equal to one if the
324                            transmit buffer is empty, 0 otherwise.
325                          . EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE : equal to one if
326                            the hardware loopback is enabled (the ouput feeds the
327                            receive buffer), 0 otherwise.
328                          . EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE : equal to one if
329                            a loopback is accomplished by software, 0 otherwise.
330                          . EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE : equal to
331                            one if the hardware flow control based on CTS (Clear
332                            To Send) and RTS (Ready To Send) control signals is
333                            enabled, 0 otherwise.
334 
335   @retval RETURN_SUCCESS  The control bits were read from the serial device.
336 
337 **/
338 RETURN_STATUS
339 EFIAPI
PL011UartGetControl(IN UINTN UartBase,OUT UINT32 * Control)340 PL011UartGetControl (
341     IN UINTN     UartBase,
342     OUT UINT32  *Control
343   )
344 {
345   UINT32      FlagRegister;
346   UINT32      ControlRegister;
347 
348 
349   FlagRegister = MmioRead32 (UartBase + UARTFR);
350   ControlRegister = MmioRead32 (UartBase + UARTCR);
351 
352   *Control = 0;
353 
354   if ((FlagRegister & PL011_UARTFR_CTS) == PL011_UARTFR_CTS) {
355     *Control |= EFI_SERIAL_CLEAR_TO_SEND;
356   }
357 
358   if ((FlagRegister & PL011_UARTFR_DSR) == PL011_UARTFR_DSR) {
359     *Control |= EFI_SERIAL_DATA_SET_READY;
360   }
361 
362   if ((FlagRegister & PL011_UARTFR_RI) == PL011_UARTFR_RI) {
363     *Control |= EFI_SERIAL_RING_INDICATE;
364   }
365 
366   if ((FlagRegister & PL011_UARTFR_DCD) == PL011_UARTFR_DCD) {
367     *Control |= EFI_SERIAL_CARRIER_DETECT;
368   }
369 
370   if ((ControlRegister & PL011_UARTCR_RTS) == PL011_UARTCR_RTS) {
371     *Control |= EFI_SERIAL_REQUEST_TO_SEND;
372   }
373 
374   if ((ControlRegister & PL011_UARTCR_DTR) == PL011_UARTCR_DTR) {
375     *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
376   }
377 
378   if ((FlagRegister & PL011_UARTFR_RXFE) == PL011_UARTFR_RXFE) {
379     *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
380   }
381 
382   if ((FlagRegister & PL011_UARTFR_TXFE) == PL011_UARTFR_TXFE) {
383     *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
384   }
385 
386   if ((ControlRegister & (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN))
387        == (PL011_UARTCR_CTSEN | PL011_UARTCR_RTSEN)) {
388     *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
389   }
390 
391   if ((ControlRegister & PL011_UARTCR_LBE) == PL011_UARTCR_LBE) {
392     *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
393   }
394 
395   return RETURN_SUCCESS;
396 }
397 
398 /**
399   Write data to serial device.
400 
401   @param  Buffer           Point of data buffer which need to be written.
402   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
403 
404   @retval 0                Write data failed.
405   @retval !0               Actual number of bytes written to serial device.
406 
407 **/
408 UINTN
409 EFIAPI
PL011UartWrite(IN UINTN UartBase,IN UINT8 * Buffer,IN UINTN NumberOfBytes)410 PL011UartWrite (
411   IN  UINTN    UartBase,
412   IN UINT8     *Buffer,
413   IN UINTN     NumberOfBytes
414   )
415 {
416   UINT8* CONST Final = &Buffer[NumberOfBytes];
417 
418   while (Buffer < Final) {
419     // Wait until UART able to accept another char
420     while ((MmioRead32 (UartBase + UARTFR) & UART_TX_FULL_FLAG_MASK));
421 
422     MmioWrite8 (UartBase + UARTDR, *Buffer++);
423   }
424 
425   return NumberOfBytes;
426 }
427 
428 /**
429   Read data from serial device and save the data in buffer.
430 
431   @param  Buffer           Point of data buffer which need to be written.
432   @param  NumberOfBytes    Number of output bytes which are cached in Buffer.
433 
434   @retval 0                Read data failed.
435   @retval !0               Actual number of bytes read from serial device.
436 
437 **/
438 UINTN
439 EFIAPI
PL011UartRead(IN UINTN UartBase,OUT UINT8 * Buffer,IN UINTN NumberOfBytes)440 PL011UartRead (
441   IN  UINTN     UartBase,
442   OUT UINT8     *Buffer,
443   IN  UINTN     NumberOfBytes
444   )
445 {
446   UINTN   Count;
447 
448   for (Count = 0; Count < NumberOfBytes; Count++, Buffer++) {
449     while ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) != 0);
450     *Buffer = MmioRead8 (UartBase + UARTDR);
451   }
452 
453   return NumberOfBytes;
454 }
455 
456 /**
457   Check to see if any data is available to be read from the debug device.
458 
459   @retval TRUE       At least one byte of data is available to be read
460   @retval FALSE      No data is available to be read
461 
462 **/
463 BOOLEAN
464 EFIAPI
PL011UartPoll(IN UINTN UartBase)465 PL011UartPoll (
466   IN  UINTN     UartBase
467   )
468 {
469   return ((MmioRead32 (UartBase + UARTFR) & UART_RX_EMPTY_FLAG_MASK) == 0);
470 }
471