]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmVirtPkg/FdtClientDxe: implement new driver
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Fri, 8 Apr 2016 09:44:49 +0000 (11:44 +0200)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Mon, 11 Apr 2016 16:12:21 +0000 (18:12 +0200)
This implements a new DXE driver FdtClientDxe to produce the FDT client
protocol based on a device tree image supplied by the virt host.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
ArmVirtPkg/FdtClientDxe/FdtClientDxe.c [new file with mode: 0644]
ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf [new file with mode: 0644]

diff --git a/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c
new file mode 100644 (file)
index 0000000..9c589e6
--- /dev/null
@@ -0,0 +1,256 @@
+/** @file\r
+*  FDT client driver\r
+*\r
+*  Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
+*\r
+*  This program and the accompanying materials are\r
+*  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 <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/HobLib.h>\r
+#include <libfdt.h>\r
+\r
+#include <Guid/FdtHob.h>\r
+\r
+#include <Protocol/FdtClient.h>\r
+\r
+STATIC VOID  *mDeviceTreeBase;\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetNodeProperty (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  IN  INT32                   Node,\r
+  IN  CONST CHAR8             *PropertyName,\r
+  OUT CONST VOID              **Prop,\r
+  OUT UINT32                  *PropSize OPTIONAL\r
+  )\r
+{\r
+  INT32 Len;\r
+\r
+  ASSERT (mDeviceTreeBase != NULL);\r
+  ASSERT (Prop != NULL);\r
+\r
+  *Prop = fdt_getprop (mDeviceTreeBase, Node, PropertyName, &Len);\r
+  if (*Prop == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (PropSize != NULL) {\r
+    *PropSize = Len;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+SetNodeProperty (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  IN  INT32                   Node,\r
+  IN  CONST CHAR8             *PropertyName,\r
+  IN  CONST VOID              *Prop,\r
+  IN  UINT32                  PropSize\r
+  )\r
+{\r
+  INT32 Ret;\r
+\r
+  ASSERT (mDeviceTreeBase != NULL);\r
+\r
+  Ret = fdt_setprop (mDeviceTreeBase, Node, PropertyName, Prop, PropSize);\r
+  if (Ret != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FindNextCompatibleNode (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  IN  CONST CHAR8             *CompatibleString,\r
+  IN  INT32                   PrevNode,\r
+  OUT INT32                   *Node\r
+  )\r
+{\r
+  INT32          Prev, Next;\r
+  CONST CHAR8    *Type, *Compatible;\r
+  INT32          Len;\r
+\r
+  ASSERT (mDeviceTreeBase != NULL);\r
+  ASSERT (Node != NULL);\r
+\r
+  for (Prev = PrevNode;; Prev = Next) {\r
+    Next = fdt_next_node (mDeviceTreeBase, Prev, NULL);\r
+    if (Next < 0) {\r
+      break;\r
+    }\r
+\r
+    Type = fdt_getprop (mDeviceTreeBase, Next, "compatible", &Len);\r
+    if (Type == NULL) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // A 'compatible' node may contain a sequence of NUL terminated\r
+    // compatible strings so check each one\r
+    //\r
+    for (Compatible = Type; Compatible < Type + Len && *Compatible;\r
+         Compatible += 1 + AsciiStrLen (Compatible)) {\r
+      if (AsciiStrCmp (CompatibleString, Compatible) == 0) {\r
+        *Node = Next;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FindCompatibleNode (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  IN  CONST CHAR8             *CompatibleString,\r
+  OUT INT32                   *Node\r
+  )\r
+{\r
+  return FindNextCompatibleNode (This, CompatibleString, 0, Node);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FindCompatibleNodeProperty (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  IN  CONST CHAR8             *CompatibleString,\r
+  IN  CONST CHAR8             *PropertyName,\r
+  OUT CONST VOID              **Prop,\r
+  OUT UINT32                  *PropSize OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  INT32             Node;\r
+\r
+  Status = FindCompatibleNode (This, CompatibleString, &Node);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return GetNodeProperty (This, Node, PropertyName, Prop, PropSize);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+FindCompatibleNodeReg (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  IN  CONST CHAR8             *CompatibleString,\r
+  OUT CONST VOID              **Reg,\r
+  OUT UINT32                  *RegElemSize,\r
+  OUT UINT32                  *RegSize\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  ASSERT (RegSize != NULL);\r
+\r
+  //\r
+  // Get the 'reg' property of this node. For now, we will assume\r
+  // 8 byte quantities for base and size, respectively.\r
+  // TODO use #cells root properties instead\r
+  //\r
+  Status = FindCompatibleNodeProperty (This, CompatibleString, "reg", Reg,\r
+             RegSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((*RegSize % 8) != 0) {\r
+    DEBUG ((EFI_D_ERROR,\r
+      "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n",\r
+      __FUNCTION__, CompatibleString, *RegSize));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *RegElemSize = 8;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetOrInsertChosenNode (\r
+  IN  FDT_CLIENT_PROTOCOL     *This,\r
+  OUT INT32                   *Node\r
+  )\r
+{\r
+  INT32 NewNode;\r
+\r
+  ASSERT (mDeviceTreeBase != NULL);\r
+  ASSERT (Node != NULL);\r
+\r
+  NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen");\r
+  if (NewNode < 0) {\r
+    NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen");\r
+  }\r
+\r
+  if (NewNode < 0) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *Node = NewNode;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = {\r
+  GetNodeProperty,\r
+  SetNodeProperty,\r
+  FindCompatibleNode,\r
+  FindNextCompatibleNode,\r
+  FindCompatibleNodeProperty,\r
+  FindCompatibleNodeReg,\r
+  GetOrInsertChosenNode,\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeFdtClientDxe (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  VOID              *Hob;\r
+  VOID              *DeviceTreeBase;\r
+\r
+  Hob = GetFirstGuidHob (&gFdtHobGuid);\r
+  if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
+\r
+  if (fdt_check_header (DeviceTreeBase) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__,\r
+      DeviceTreeBase));\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  mDeviceTreeBase = DeviceTreeBase;\r
+\r
+  DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase));\r
+\r
+  return gBS->InstallProtocolInterface (&ImageHandle, &gFdtClientProtocolGuid,\r
+                EFI_NATIVE_INTERFACE, &mFdtClientProtocol);\r
+}\r
diff --git a/ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf
new file mode 100644 (file)
index 0000000..3647d37
--- /dev/null
@@ -0,0 +1,48 @@
+## @file\r
+#  FDT client driver\r
+#\r
+#  Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials are\r
+#  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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = FdtClientDxe\r
+  FILE_GUID                      = 9A871B00-1C16-4F61-8D2C-93B6654B5AD6\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeFdtClientDxe\r
+\r
+[Sources]\r
+  FdtClientDxe.c\r
+\r
+[Packages]\r
+  ArmVirtPkg/ArmVirtPkg.dec\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  DebugLib\r
+  FdtLib\r
+  HobLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+\r
+[Protocols]\r
+  gFdtClientProtocolGuid                  ## PRODUCES\r
+\r
+[Guids]\r
+  gFdtHobGuid\r
+\r
+[Depex]\r
+  TRUE\r