]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c
Renamed ArmPlatformPkg/ArmVirtualizationPkg into ArmVirtPkg
[mirror_edk2.git] / ArmVirtPkg / Library / FdtPL011SerialPortLib / EarlyFdtPL011SerialPortLib.c
diff --git a/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c b/ArmVirtPkg/Library/FdtPL011SerialPortLib/EarlyFdtPL011SerialPortLib.c
new file mode 100644 (file)
index 0000000..ba6d277
--- /dev/null
@@ -0,0 +1,185 @@
+/** @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