+/** @file\r
+ Serial I/O Port library functions with base address discovered from FDT\r
+\r
+ Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+ Copyright (c) 2012 - 2013, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+#include <Library/PcdLib.h>\r
+#include <Library/SerialPortLib.h>\r
+#include <Library/SerialPortExtLib.h>\r
+#include <libfdt.h>\r
+\r
+#include <Drivers/PL011Uart.h>\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+SerialPortInitialize (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // This SerialPortInitialize() function is completely empty, for a number of\r
+ // reasons:\r
+ // - if we are executing from flash, it is hard to keep state (i.e., store the\r
+ // discovered base address in a global), and the most robust way to deal\r
+ // with this is to discover the base address at every Write ();\r
+ // - calls to the Write() function in this module may be issued before this\r
+ // initialization function is called: this is not a problem when the base\r
+ // address of the UART is hardcoded, and only the baud rate may be wrong,\r
+ // but if we don't know the base address yet, we may be poking into memory\r
+ // that does not tolerate being poked into;\r
+ // - SEC and PEI phases produce debug output only, so with debug disabled, no\r
+ // initialization (or device tree parsing) is performed at all.\r
+ //\r
+ // Note that this means that on *every* Write () call, the device tree will be\r
+ // parsed and the UART re-initialized. However, this is a small price to pay\r
+ // for having serial debug output on a UART with no fixed base address.\r
+ //\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+STATIC\r
+UINT64\r
+SerialPortGetBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINT64 BaudRate;\r
+ UINT32 ReceiveFifoDepth;\r
+ EFI_PARITY_TYPE Parity;\r
+ UINT8 DataBits;\r
+ EFI_STOP_BITS_TYPE StopBits;\r
+ VOID *DeviceTreeBase;\r
+ INT32 Node, Prev;\r
+ INT32 Len;\r
+ CONST CHAR8 *Compatible;\r
+ CONST CHAR8 *CompatibleItem;\r
+ CONST UINT64 *RegProperty;\r
+ UINTN UartBase;\r
+ RETURN_STATUS Status;\r
+\r
+ DeviceTreeBase = (VOID *)(UINTN)FixedPcdGet64 (PcdDeviceTreeInitialBaseAddress);\r
+\r
+ if ((DeviceTreeBase == NULL) || (fdt_check_header (DeviceTreeBase) != 0)) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Enumerate all FDT nodes looking for a PL011 and capture its base address\r
+ //\r
+ for (Prev = 0;; Prev = Node) {\r
+ Node = fdt_next_node (DeviceTreeBase, Prev, NULL);\r
+ if (Node < 0) {\r
+ break;\r
+ }\r
+\r
+ Compatible = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);\r
+ if (Compatible == NULL) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Iterate over the NULL-separated items in the compatible string\r
+ //\r
+ for (CompatibleItem = Compatible; CompatibleItem < Compatible + Len;\r
+ CompatibleItem += 1 + AsciiStrLen (CompatibleItem)) {\r
+\r
+ if (AsciiStrCmp (CompatibleItem, "arm,pl011") == 0) {\r
+ RegProperty = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);\r
+ if (Len != 16) {\r
+ return 0;\r
+ }\r
+ UartBase = (UINTN)fdt64_to_cpu (ReadUnaligned64 (RegProperty));\r
+\r
+ BaudRate = (UINTN)FixedPcdGet64 (PcdUartDefaultBaudRate);\r
+ ReceiveFifoDepth = 0; // Use the default value for Fifo depth\r
+ Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity);\r
+ DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);\r
+ StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits);\r
+\r
+ Status = PL011UartInitializePort (\r
+ UartBase,\r
+ &BaudRate, &ReceiveFifoDepth, &Parity, &DataBits, &StopBits);\r
+ if (!EFI_ERROR (Status)) {\r
+ return UartBase;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Write data to serial device.\r
+\r
+ @param Buffer Point of data buffer which need to be written.\r
+ @param NumberOfBytes Number of output bytes which are cached in Buffer.\r
+\r
+ @retval 0 Write data failed.\r
+ @retval !0 Actual number of bytes written to serial device.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SerialPortWrite (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN NumberOfBytes\r
+ )\r
+{\r
+ UINT64 SerialRegisterBase;\r
+\r
+ SerialRegisterBase = SerialPortGetBaseAddress ();\r
+ if (SerialRegisterBase != 0) {\r
+ return PL011UartWrite ((UINTN)SerialRegisterBase, Buffer, NumberOfBytes);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Read data from serial device and save the data in buffer.\r
+\r
+ @param Buffer Point of data buffer which need to be written.\r
+ @param NumberOfBytes Size of Buffer[].\r
+\r
+ @retval 0 Read data failed.\r
+ @retval !0 Actual number of bytes read from serial device.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SerialPortRead (\r
+ OUT UINT8 *Buffer,\r
+ IN UINTN NumberOfBytes\r
+)\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Check to see if any data is available to be read from the debug device.\r
+\r
+ @retval TRUE At least one byte of data is available to be read\r
+ @retval FALSE No data is available to be read\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+SerialPortPoll (\r
+ VOID\r
+ )\r
+{\r
+ return FALSE;\r
+}\r