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::52a; helo=mail-ed1-x52a.google.com; envelope-from=pete@akeo.ie; receiver=edk2-devel@lists.01.org Received: from mail-ed1-x52a.google.com (mail-ed1-x52a.google.com [IPv6:2a00:1450:4864:20::52a]) (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 810812194D3B9 for ; Mon, 10 Dec 2018 04:39:18 -0800 (PST) Received: by mail-ed1-x52a.google.com with SMTP id x30so9350960edx.2 for ; Mon, 10 Dec 2018 04:39:18 -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=MwUeiqqya46U6ITsX/7NjGg1WCcJq3HruI/IwZ+2xSI=; b=XwG48/X7VTjygnGpJ2UzE1czRgODzBrHf4bOsmq4+0KyEK8mOGDPv0gYC89G3fo2aA V/XBSJR93Ewq1s1SKlNKyfpvurltXHW23I8kk9iZQvaJzxQVgVRLirr+V7gmSVHE8bDC GdyJcyMwkdBYtfpYcqmyBRfmi9d8yG0H3A5QR7Bl80ZLnlotD1KKbb9kuJpXrZ/BVfDQ y4Gd9JwxLTiipzJO1KKl6nLxHAsVhnGwhpSBtdZMd+3BZVfJ4gQ82937w3yjGB1RsLlx u4SnE6ZV9bBJrsCm6vsNV5w8967n9sYDgLe+yja7Mjo4G6AKG8dhbt1aYhg+Lxk9LA0y YTjg== 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=MwUeiqqya46U6ITsX/7NjGg1WCcJq3HruI/IwZ+2xSI=; b=m5sREC68ZGHH9VZUSBdKaYpI+sE1sjCu8rKmAUijuneelzI3WXcsdmFjtsBH8kypiy 9cpMizrR9Om2+E3AxIzLmdeYwVpALcMaUbj2IKRXgm+gDvOHqj1RAbLhdI+Lg5k3TlMD WjFmB8Xqb0SOue5Y8AFk2Vk5KFFmpGvpttBDPeQCtZugxPx0HuqxbahrGGDwQ4zXe6i0 Okh5wAA2SIK4Mvi14NgMC8hEo0EUVRzO6LazrT8LckeVogHrmHKlW6Gi33/cnF6gXtSQ /G4aR6DvL5qJBQSN7cvRyUFKbW/OZ7kZODunza7qJWcPI4drz23u0cuIDNG/ZPUVwbfj CWyg== X-Gm-Message-State: AA+aEWZwl3/DVNM9Pi/fMjRxoIY3i76CbHC7rR20V6qVfFAMK6w4S9+G IQvy05IsbNlrIRHTsbMPnwuYY8r3/8E= X-Google-Smtp-Source: AFSGD/W1EBiq95nRosY5Hz36ho3u50ulgOkxCAz23iHd+QJpokADt7f3A2w9kEcZTRgLBbKjs0Y9WQ== X-Received: by 2002:a50:ac47:: with SMTP id w7mr11721510edc.260.1544445556604; Mon, 10 Dec 2018 04:39:16 -0800 (PST) Received: from localhost.localdomain ([84.203.68.105]) by smtp.gmail.com with ESMTPSA id e14sm3296949edb.79.2018.12.10.04.39.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 10 Dec 2018 04:39:15 -0800 (PST) From: Pete Batard To: edk2-devel@lists.01.org Date: Mon, 10 Dec 2018 12:38:39 +0000 Message-Id: <20181210123853.4864-7-pete@akeo.ie> X-Mailer: git-send-email 2.17.0.windows.1 In-Reply-To: <20181210123853.4864-1-pete@akeo.ie> References: <20181210123853.4864-1-pete@akeo.ie> Subject: [PATCH v2 edk2-platforms 06/20] Platform/Broadcom/RPi3: Add Interrupt and Device Tree drivers 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: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:19 -0000 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Pete Batard --- Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c | 367 +++++++++++++++++++ Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf | 48 +++ Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c | 370 ++++++++++++++++++++ Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf | 53 +++ 4 files changed, 838 insertions(+) diff --git a/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c new file mode 100644 index 000000000000..dda61665031d --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.c @@ -0,0 +1,367 @@ +/** @file + * + * 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 + +// +// This currently only implements support for the architected timer interrupts +// on the per-CPU interrupt controllers. +// +#define NUM_IRQS (4) + +#ifdef MDE_CPU_AARCH64 +#define ARM_ARCH_EXCEPTION_IRQ EXCEPT_AARCH64_IRQ +#else +#define ARM_ARCH_EXCEPTION_IRQ EXCEPT_ARM_IRQ +#endif + +STATIC CONST +EFI_PHYSICAL_ADDRESS RegBase = FixedPcdGet32 (PcdInterruptBaseAddress); + +// +// Notifications +// +STATIC EFI_EVENT mExitBootServicesEvent; +STATIC HARDWARE_INTERRUPT_HANDLER mRegisteredInterruptHandlers[NUM_IRQS]; + +/** + Shutdown our hardware + + DXE Core will disable interrupts and turn off the timer and disable interrupts + after all the event handlers have run. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +STATIC +VOID +EFIAPI +ExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // Disable all interrupts + MmioWrite32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET, 0); +} + +/** + Enable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt enabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +STATIC +EFI_STATUS +EFIAPI +EnableInterruptSource ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ) +{ + if (Source >= NUM_IRQS) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + MmioOr32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET, 1 << Source); + + return EFI_SUCCESS; +} + + +/** + Disable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt disabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +STATIC +EFI_STATUS +EFIAPI +DisableInterruptSource ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ) +{ + if (Source >= NUM_IRQS) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + MmioAnd32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET, ~(1 << Source)); + + return EFI_SUCCESS; +} + +/** + Register Handler for the specified interrupt source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param Handler Callback for interrupt. NULL to unregister + + @retval EFI_SUCCESS Source was updated to support Handler. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +STATIC +EFI_STATUS +EFIAPI +RegisterInterruptSource ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN HARDWARE_INTERRUPT_HANDLER Handler + ) +{ + if (Source >= NUM_IRQS) { + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + if (Handler == NULL && mRegisteredInterruptHandlers[Source] == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Handler != NULL && mRegisteredInterruptHandlers[Source] != NULL) { + return EFI_ALREADY_STARTED; + } + + mRegisteredInterruptHandlers[Source] = Handler; + return EnableInterruptSource(This, Source); +} + + +/** + Return current state of interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param InterruptState TRUE: source enabled, FALSE: source disabled. + + @retval EFI_SUCCESS InterruptState is valid + @retval EFI_DEVICE_ERROR InterruptState is not valid + +**/ +STATIC +EFI_STATUS +EFIAPI +GetInterruptSourceState ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN BOOLEAN *InterruptState + ) +{ + if (InterruptState == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Source >= NUM_IRQS) { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + *InterruptState = (MmioRead32 (RegBase + BCM2836_INTC_TIMER_CONTROL_OFFSET) & + (1 << Source)) != 0; + + return EFI_SUCCESS; +} + +/** + Signal to the hardware that the End Of Intrrupt state + has been reached. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt EOI'ed. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +STATIC +EFI_STATUS +EFIAPI +EndOfInterrupt ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ) +{ + return EFI_SUCCESS; +} + + +/** + EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor + architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + + @return None + +**/ +STATIC +VOID +EFIAPI +IrqInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + HARDWARE_INTERRUPT_HANDLER InterruptHandler; + HARDWARE_INTERRUPT_SOURCE Source; + UINT32 RegVal; + + RegVal = MmioRead32 (RegBase + BCM2836_INTC_TIMER_PENDING_OFFSET) & + ((1 << NUM_IRQS) - 1); + Source = HighBitSet32 (RegVal); + if (Source < 0) { + return; + } + + InterruptHandler = mRegisteredInterruptHandlers [Source]; + if (InterruptHandler != NULL) { + // Call the registered interrupt handler. + InterruptHandler (Source, SystemContext); + } +} + +// +// The protocol instance produced by this driver +// +STATIC EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = { + RegisterInterruptSource, + EnableInterruptSource, + DisableInterruptSource, + GetInterruptSourceState, + EndOfInterrupt +}; + +STATIC VOID *mCpuArchProtocolNotifyEventRegistration; + +STATIC +VOID +EFIAPI +CpuArchEventProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_CPU_ARCH_PROTOCOL *Cpu; + EFI_STATUS Status; + + // + // Get the CPU protocol that this driver requires. + // + Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); + if (EFI_ERROR (Status)) { + return; + } + + // + // Unregister the default exception handler. + // + Status = Cpu->RegisterInterruptHandler(Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n", + __FUNCTION__, Status)); + ASSERT (FALSE); + return; + } + + // + // Register to receive interrupts + // + Status = Cpu->RegisterInterruptHandler(Cpu, ARM_ARCH_EXCEPTION_IRQ, + IrqInterruptHandler); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n", + __FUNCTION__, Status)); + ASSERT (FALSE); + return; + } +} + + +/** + Initialize the state information for the CPU Architectural Protocol + + @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 +InterruptDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT CpuArchEvent; + + // Make sure the Interrupt Controller Protocol is not already installed in the system. + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); + + Status = gBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gHardwareInterruptProtocolGuid, + &gHardwareInterruptProtocol, + NULL); + ASSERT_EFI_ERROR(Status); + + // + // Install the interrupt handler as soon as the CPU arch protocol appears. + // + CpuArchEvent = EfiCreateProtocolNotifyEvent ( + &gEfiCpuArchProtocolGuid, + TPL_CALLBACK, + CpuArchEventProtocolNotify, + NULL, + &mCpuArchProtocolNotifyEventRegistration + ); + ASSERT (CpuArchEvent != NULL); + + // Register for an ExitBootServicesEvent + Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, + ExitBootServicesEvent, NULL, &mExitBootServicesEvent); + + ASSERT_EFI_ERROR(Status); + + return Status; +} diff --git a/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf new file mode 100644 index 000000000000..831ae1bfeeab --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/Bcm2836InterruptDxe/Bcm2836InterruptDxe.inf @@ -0,0 +1,48 @@ +#/** @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 = 0x00010019 + BASE_NAME = Bcm2836InterruptDxe + FILE_GUID = 3944f2d7-2e09-4fc0-9e98-008375641453 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InterruptDxeInitialize + +[Sources] + Bcm2836InterruptDxe.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + UefiBootServicesTableLib + UefiLib + UefiDriverEntryPoint + +[Protocols] + gHardwareInterruptProtocolGuid ## PRODUCES + gEfiCpuArchProtocolGuid ## CONSUMES ## NOTIFY + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdInterruptBaseAddress + +[Depex] + TRUE diff --git a/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c new file mode 100644 index 000000000000..f2b0117629fd --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.c @@ -0,0 +1,370 @@ +/** @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 +RpiFdtDxeInitialize ( + 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, EfiRuntimeServicesData, + 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/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.inf new file mode 100644 index 000000000000..a79e9ddcdc8a --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/RpiFdtDxe/RpiFdtDxe.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 = 0x00010019 + BASE_NAME = RpiFdtDxe + FILE_GUID = 8505280f-109e-437e-9fe4-1aa09c7074d9 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RpiFdtDxeInitialize + +[Sources] + RpiFdtDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Broadcom/Bcm283x/RaspberryPiPkg.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