From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: None (no SPF record) identity=mailfrom; client-ip=2a00:1450:4864:20::541; helo=mail-ed1-x541.google.com; envelope-from=pete@akeo.ie; receiver=edk2-devel@lists.01.org Received: from mail-ed1-x541.google.com (mail-ed1-x541.google.com [IPv6:2a00:1450:4864:20::541]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 059B82194D3B3 for ; Tue, 29 Jan 2019 08:27:41 -0800 (PST) Received: by mail-ed1-x541.google.com with SMTP id x30so16504009edx.2 for ; Tue, 29 Jan 2019 08:27:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=akeo-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=AMVVAMRcYbzdr3BMMq7iYQaRO1aKrv6JSgGbMMILLHg=; b=JQKhToxLo5KrZBgG12w/KnMA5VUU5TmXpjI0TdualSQ6IlA+qjgLhGJ+TFbTIqVEKz 0wwbXnp6T5y3vrZm9V7UPDnzpSkXtasWi3ItlPG2azjyOKJGwRpSYJBRAybawERkDpfl xpc78/D1FX3xIUHVwrFV5U8MN0Kqn5ra1aVON5yp8BBXvVQd/fE/mUR3nBEOBP1gTCEh um8Zal7iZgkEEwAo7Y56WcwttVVKrvcMf4d+1zVbninTK2CdOQK0KlkT1UCYoipdvn9D xXB0hz5v3qCeO2MrTKAz6Pqr+v2YmNlWatrkTATlYbror2Gd7V43reznu3l6iHjixrLU yJMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=AMVVAMRcYbzdr3BMMq7iYQaRO1aKrv6JSgGbMMILLHg=; b=lkYby2YaTCdDEsAYAtWLKQMKteWI22aB8QjY9EsL1k66ZEjQMY/zdtyyiQH+rTKq+R CBfIn3QN30D13zdtqpdYr/klIO1S6wNiD+GITRzkEz/XNgk509mOIytk4Fve12CMMQx1 rIWm9wWiceRjAITvf1QNeESnpcskz6Or9KUPRxreWHMEKn2yTHcntYyDyPY32kdUFxjD 9FmPEi3PGZhgiqTbqArhh9Hcw2zzxLi60vinwmw2bcb0CBQqVQggkH1/XTmlV6duvLgA on21z0ojfg23etPIpPYW42/0BrYJNCAdcQdGk/qsBPlpP8gqYzOkLIlKqZusZlv/tpH+ 6ZlQ== X-Gm-Message-State: AJcUukfwXL0Qt/ds+OIjYbU9o9CmhAS68DZl9ic7fuwJjsOlNDGPdOxD 2SNJRpZzBnJEZSgVYcG8l5cbn9kq4LM= X-Google-Smtp-Source: ALg8bN7Rrjo5S5OyYN2gv5t5FlDYUqN8ov/0dGEnC1dTXD1JqEbU+JSjC0UcR5g6f3pZQMRWbQgJlw== X-Received: by 2002:a17:906:b208:: with SMTP id p8mr23438792ejz.17.1548779260018; Tue, 29 Jan 2019 08:27:40 -0800 (PST) Received: from localhost.localdomain ([84.203.95.186]) by smtp.gmail.com with ESMTPSA id p16-v6sm8303056eju.73.2019.01.29.08.27.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 Jan 2019 08:27:38 -0800 (PST) From: Pete Batard To: edk2-devel@lists.01.org Date: Tue, 29 Jan 2019 16:26:45 +0000 Message-Id: <20190129162655.3800-14-pete@akeo.ie> X-Mailer: git-send-email 2.17.0.windows.1 In-Reply-To: <20190129162655.3800-1-pete@akeo.ie> References: <20190129162655.3800-1-pete@akeo.ie> Subject: [PATCH v4 edk2-platforms 13/23] Platform/Raspberry/Pi3: Add Device Tree driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 Jan 2019 16:27:42 -0000 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Pete Batard --- Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.c | 364 ++++++++++++++++++++ Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.inf | 53 +++ 2 files changed, 417 insertions(+) diff --git a/Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.c b/Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.c new file mode 100644 index 000000000000..eb5698cb505b --- /dev/null +++ b/Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.c @@ -0,0 +1,364 @@ +/** @file + * + * Copyright (c) 2017, Andrey Warkentin + * Copyright (c) 2016, Linaro, Ltd. All rights reserved. + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + **/ +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +STATIC VOID *mFdtImage; + +STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol; + +STATIC +VOID +UpdateMacAddress ( + VOID + ) +{ + INTN Node; + INTN Retval; + EFI_STATUS Status; + UINT8 MacAddress[6]; + + // + // Locate the node that the 'ethernet' alias refers to + // + Node = fdt_path_offset (mFdtImage, "ethernet"); + if (Node < 0) { + DEBUG ((DEBUG_ERROR, "%a: failed to locate 'ethernet' alias\n", __FUNCTION__)); + return; + } + + // + // Get the MAC address from the firmware + // + Status = mFwProtocol->GetMacAddress (MacAddress); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to retrieve MAC address\n", __FUNCTION__)); + return; + } + + Retval = fdt_setprop (mFdtImage, Node, "mac-address", MacAddress, + sizeof MacAddress); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "%a: failed to create 'mac-address' property (%d)\n", + __FUNCTION__, Retval)); + return; + } + + DEBUG ((DEBUG_INFO, "%a: setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", + __FUNCTION__, MacAddress[0], MacAddress[1], MacAddress[2], MacAddress[3], + MacAddress[4], MacAddress[5])); +} + +STATIC +VOID +CleanMemoryNodes ( + VOID + ) +{ + INTN Node; + INT32 Retval; + + Node = fdt_path_offset (mFdtImage, "/memory"); + if (Node < 0) { + return; + } + + /* + * Remove bogus memory nodes which can make the booted + * OS go crazy and ignore the UEFI map. + */ + DEBUG ((DEBUG_INFO, "Removing bogus /memory\n")); + Retval = fdt_del_node (mFdtImage, Node); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "Failed to remove /memory\n")); + } +} + +STATIC +VOID +SanitizePSCI ( + VOID + ) +{ + INTN Node; + INTN Root; + INT32 Retval; + + Root = fdt_path_offset (mFdtImage, "/"); + ASSERT (Root >= 0); + if (Root < 0) { + return; + } + + Node = fdt_path_offset (mFdtImage, "/psci"); + if (Node < 0) { + Node = fdt_add_subnode (mFdtImage, Root, "psci"); + } + + ASSERT (Node >= 0); + if (Node < 0) { + DEBUG ((DEBUG_ERROR, "Couldn't find/create /psci\n")); + return; + } + + Retval = fdt_setprop_string (mFdtImage, Node, "compatible", "arm,psci-1.0"); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "Couldn't set /psci compatible property\n")); + return; + } + + Retval = fdt_setprop_string (mFdtImage, Node, "method", "smc"); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "Couldn't set /psci method property\n")); + return; + } + + Root = fdt_path_offset (mFdtImage, "/cpus"); + if (Root < 0) { + DEBUG ((DEBUG_ERROR, "No CPUs to update with PSCI enable-method?\n")); + return; + } + + Node = fdt_first_subnode (mFdtImage, Root); + while (Node >= 0) { + if (fdt_setprop_string (mFdtImage, Node, "enable-method", "psci") != 0) { + DEBUG ((DEBUG_ERROR, "Failed to update enable-method for a CPU\n")); + return; + } + + fdt_delprop (mFdtImage, Node, "cpu-release-addr"); + Node = fdt_next_subnode (mFdtImage, Node); + } +} + +STATIC +VOID +CleanSimpleFramebuffer ( + VOID + ) +{ + INTN Node; + INT32 Retval; + + /* + * Should look for nodes by kind and remove aliases + * by matching against device. + */ + Node = fdt_path_offset (mFdtImage, "display0"); + if (Node < 0) { + return; + } + + /* + * Remove bogus GPU-injected simple-framebuffer, which + * doesn't reflect the framebuffer built by UEFI. + */ + DEBUG ((DEBUG_INFO, "Removing bogus display0\n")); + Retval = fdt_del_node (mFdtImage, Node); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "Failed to remove display0\n")); + return; + } + + Node = fdt_path_offset (mFdtImage, "/aliases"); + if (Node < 0) { + DEBUG ((DEBUG_ERROR, "Couldn't find /aliases to remove display0\n")); + return; + } + + Retval = fdt_delprop (mFdtImage, Node, "display0"); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "Failed to remove display0 alias\n")); + } +} + +#define MAX_CMDLINE_SIZE 512 + +STATIC +VOID +UpdateBootArgs ( + VOID + ) +{ + INTN Node; + INTN Retval; + EFI_STATUS Status; + CHAR8 *CommandLine; + + // + // Locate the /chosen node + // + Node = fdt_path_offset (mFdtImage, "/chosen"); + if (Node < 0) { + DEBUG ((DEBUG_ERROR, "%a: failed to locate /chosen node\n", __FUNCTION__)); + return; + } + + // + // If /chosen/bootargs already exists, we want to add a space character + // before adding the firmware supplied arguments. However, the RpiFirmware + // protocol expects a 32-bit aligned buffer. So let's allocate 4 bytes of + // slack, and skip the first 3 when passing this buffer into libfdt. + // + CommandLine = AllocatePool (MAX_CMDLINE_SIZE) + 4; + if (!CommandLine) { + DEBUG ((DEBUG_ERROR, "%a: failed to allocate memory\n", __FUNCTION__)); + return; + } + + // + // Get the command line from the firmware + // + Status = mFwProtocol->GetCommandLine (MAX_CMDLINE_SIZE, CommandLine + 4); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to retrieve command line\n", __FUNCTION__)); + return; + } + + if (AsciiStrLen (CommandLine + 4) == 0) { + DEBUG ((DEBUG_INFO, "%a: empty command line received\n", __FUNCTION__)); + return; + } + + CommandLine[3] = ' '; + + Retval = fdt_appendprop_string (mFdtImage, Node, "bootargs", &CommandLine[3]); + if (Retval != 0) { + DEBUG ((DEBUG_ERROR, "%a: failed to set /chosen/bootargs property (%d)\n", + __FUNCTION__, Retval)); + } + + DEBUG_CODE_BEGIN (); + CONST CHAR8 *Prop; + INT32 Length; + INT32 Index; + + Node = fdt_path_offset (mFdtImage, "/chosen"); + ASSERT (Node >= 0); + + Prop = fdt_getprop (mFdtImage, Node, "bootargs", &Length); + ASSERT (Prop != NULL); + + DEBUG ((DEBUG_INFO, "Command line set from firmware (length %d):\n'", Length)); + + for (Index = 0; Index < Length; Index++, Prop++) { + if (*Prop == '\0') { + continue; + } + DEBUG ((DEBUG_INFO, "%c", *Prop)); + } + + DEBUG ((DEBUG_INFO, "'\n")); + DEBUG_CODE_END (); + + FreePool (CommandLine - 4); +} + + +/** + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +FdtDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *FdtImage; + UINTN FdtSize; + INT32 Retval; + BOOLEAN Internal; + + Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid, NULL, + (VOID**)&mFwProtocol); + ASSERT_EFI_ERROR (Status); + + Internal = FALSE; + FdtImage = (VOID*)(UINTN)PcdGet32 (PcdFdtBaseAddress); + Retval = fdt_check_header (FdtImage); + if (Retval == 0) { + /* + * Have FDT passed via config.txt. + */ + FdtSize = fdt_totalsize (FdtImage); + DEBUG ((DEBUG_INFO, "DTB passed via config.txt of 0x%lx bytes\n", FdtSize)); + Status = EFI_SUCCESS; + } else { + Internal = TRUE; + DEBUG ((DEBUG_INFO, "No/bad FDT at %p (%a), trying internal DTB...\n", + FdtImage, fdt_strerror (Retval))); + Status = GetSectionFromAnyFv (&gRaspberryPiFdtFileGuid, EFI_SECTION_RAW, 0, + &FdtImage, &FdtSize); + if (Status == EFI_SUCCESS) { + if (fdt_check_header (FdtImage) != 0) { + Status = EFI_INCOMPATIBLE_VERSION; + } + } + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to locate device tree: %r\n", Status)); + return Status; + } + + /* + * Probably overkill. + */ + FdtSize += EFI_PAGE_SIZE * 2; + Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, + EFI_SIZE_TO_PAGES (FdtSize), (EFI_PHYSICAL_ADDRESS*)&mFdtImage); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to allocate new device tree: %r\n", Status)); + return Status; + } + + Retval = fdt_open_into (FdtImage, mFdtImage, FdtSize); + ASSERT (Retval == 0); + + SanitizePSCI (); + CleanMemoryNodes (); + CleanSimpleFramebuffer (); + UpdateMacAddress (); + if (Internal) { + /* + * A GPU-provided DTB already has the full command line. + */ + UpdateBootArgs (); + } + + DEBUG ((DEBUG_INFO, "Installed FDT is at %p\n", mFdtImage)); + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, mFdtImage); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.inf b/Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.inf new file mode 100644 index 000000000000..5a90ba1b4ae8 --- /dev/null +++ b/Platform/Raspberry/Pi3/Drivers/FdtDxe/FdtDxe.inf @@ -0,0 +1,53 @@ +#/** @file +# +# Copyright (c) 2017, Andrei Warkentin +# Copyright (c) 2016, Linaro, Ltd. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = FdtDxe + FILE_GUID = 8505280f-109e-437e-9fe4-1aa09c7074d9 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FdtDxeInitialize + +[Sources] + FdtDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Raspberry/Pi3/RPi3.dec + +[LibraryClasses] + BaseLib + DebugLib + DxeServicesLib + FdtLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Guids] + gFdtTableGuid + gRaspberryPiFdtFileGuid + +[Protocols] + gRaspberryPiFirmwareProtocolGuid ## CONSUMES + +[Depex] + gRaspberryPiFirmwareProtocolGuid + +[FixedPcd] + gRaspberryPiTokenSpaceGuid.PcdFdtBaseAddress -- 2.17.0.windows.1