From 9f38945fea0905452e7680ed3ea554487a1f6c9b Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Mon, 27 Oct 2014 15:28:07 +0000 Subject: ArmPlatformPkg/ArmJunoPkg: Added Juno development board support ARM 64bit development platform. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16249 6f19259b-4bc3-4df7-8a09-765794883524 --- .../ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c | 81 ++++ .../ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf | 76 ++++ .../Drivers/ArmJunoDxe/ArmJunoDxeInternal.h | 36 ++ .../ArmJunoPkg/Drivers/ArmJunoDxe/InstallFdt.c | 423 ++++++++++++++++++ .../ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.c | 486 +++++++++++++++++++++ .../ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.h | 284 ++++++++++++ .../Drivers/ArmJunoDxe/PciRootBridgeIo.c | 299 +++++++++++++ .../GenericWatchdogDxe/GenericWatchdogDxe.c | 354 +++++++++++++++ .../GenericWatchdogDxe/GenericWatchdogDxe.inf | 54 +++ 9 files changed, 2093 insertions(+) create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/InstallFdt.c create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.c create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.h create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciRootBridgeIo.c create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c create mode 100644 ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf (limited to 'ArmPlatformPkg/ArmJunoPkg/Drivers') diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c new file mode 100644 index 0000000000..70d632927a --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c @@ -0,0 +1,81 @@ +/** @file +* +* Copyright (c) 2013-2014, ARM Limited. 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 "ArmJunoDxeInternal.h" +#include + +EFI_STATUS +EFIAPI +ArmJunoEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS HypBase; + + Status = PciEmulationEntryPoint (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If a hypervisor has been declared then we need to make sure its region is protected at runtime + // + // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/) + // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1. + // + if (FixedPcdGet32 (PcdHypFvSize) != 0) { + // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region. + // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself. + // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded + // to this size then there is a risk some non-runtime memory could be visible to the OS view. + if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) { + // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space + // as it contains the Firmware. + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeSystemMemory, + FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize), + EFI_MEMORY_WB | EFI_MEMORY_RUNTIME + ); + if (!EFI_ERROR (Status)) { + // We allocate the memory to ensure it is marked as runtime memory + HypBase = FixedPcdGet32 (PcdHypFvBaseAddress); + Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode, + EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase); + } + } else { + // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned + // on a EFI_PAGE_SIZE boundary (ie: 4KB). + Status = EFI_UNSUPPORTED; + ASSERT_EFI_ERROR (Status); + } + + if (EFI_ERROR (Status)) { + return Status; + } + } + + // Install dynamic Shell command to run baremetal binaries. + Status = ShellDynCmdRunAxfInstall (ImageHandle); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n")); + } + + // Try to install the Flat Device Tree (FDT). This function actually installs the + // UEFI Driver Binding Protocol. + Status = JunoFdtInstall (ImageHandle); + + return Status; +} diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf new file mode 100644 index 0000000000..bf930d23d9 --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf @@ -0,0 +1,76 @@ +# +# Copyright (c) 2013-2014, ARM Limited. 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 = 0x00010005 + BASE_NAME = ArmJunoDxe + FILE_GUID = 1484ebe8-2681-45f1-a2e5-12ecad893b62 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = ArmJunoEntryPoint + +[Sources.common] + ArmJunoDxe.c + InstallFdt.c + PciEmulation.c + PciRootBridgeIo.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPlatformPkg/ArmJunoPkg/ArmJuno.dec + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmShellCmdRunAxfLib + BaseMemoryLib + BdsLib + DebugLib + DmaLib + DxeServicesTableLib + FdtLib + IoLib + PcdLib + PrintLib + SerialPortLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiLib + UefiDriverEntryPoint + +[Guids] + gArmGlobalVariableGuid + gEfiEndOfDxeEventGroupGuid + gEfiFileInfoGuid + gFdtTableGuid + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiDevicePathFromTextProtocolGuid + gEfiPciIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid + +[FixedPcd] + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + + gArmTokenSpaceGuid.PcdHypFvBaseAddress + gArmTokenSpaceGuid.PcdHypFvSize + + gArmJunoTokenSpaceGuid.PcdSynopsysUsbEhciBaseAddress + gArmJunoTokenSpaceGuid.PcdSynopsysUsbOhciBaseAddress + + gArmPlatformTokenSpaceGuid.PcdFdtDevicePath + +[Depex] + TRUE diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h new file mode 100644 index 0000000000..5ebb5161f8 --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h @@ -0,0 +1,36 @@ +/** @file +* +* Copyright (c) 2013-2014, ARM Limited. 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. +* +**/ + +#ifndef __ARM_JUNO_DXE_INTERNAL_H__ +#define __ARM_JUNO_DXE_INTERNAL_H__ + +#include + +#include +#include +#include + +#include + +EFI_STATUS +PciEmulationEntryPoint ( + VOID + ); + +EFI_STATUS +JunoFdtInstall ( + IN EFI_HANDLE ImageHandle + ); + +#endif // __ARM_JUNO_DXE_INTERNAL_H__ diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/InstallFdt.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/InstallFdt.c new file mode 100644 index 0000000000..a4220a1895 --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/InstallFdt.c @@ -0,0 +1,423 @@ +/** @file +* +* Copyright (c) 2014, ARM Limited. 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 "ArmJunoDxeInternal.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define FDT_DEFAULT_FILENAME L"juno" + +#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype))) + +// Hardware Vendor Device Path node for the Juno NOR Flash. We use the Juno NOR Flash if the user +// has not specified another filesystem location into the UEFI Variable 'Fdt'. +// The Juno NOR Flash has its own filesystem format (supported by ArmPlatformPkg/FileSystem/BootMonFs). +STATIC CONST struct { + VENDOR_DEVICE_PATH NorGuid; + EFI_DEVICE_PATH End; +} mJunoNorFlashDevicePath = { + { + { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } }, + {0xE7223039, 0x5836, 0x41E1, { 0xB5, 0x42, 0xD7, 0xEC, 0x73, 0x6C, 0x5E, 0x59} } + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } } +}; + +STATIC EFI_DEVICE_PATH* mFdtFileSystemDevicePath = NULL; +STATIC CHAR16* mFdtFileName = NULL; + +STATIC BOOLEAN mFdtTableInstalled = FALSE; + +/** + See definition EFI_DRIVER_BINDING_PROTOCOL.Supported() +**/ +EFI_STATUS +EFIAPI +JunoFdtSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + // + // Check if the Handle support the Simple File System Protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // Check if a DevicePath is attached to the handle + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&DevicePath, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Check if the Device Path is the one from the NOR Flash + if (CompareMem (mFdtFileSystemDevicePath, DevicePath, GetDevicePathSize (mFdtFileSystemDevicePath)) != 0) { + return EFI_NOT_FOUND; + } + + gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle); + return Status; +} + +/** + This function is used to print messages back to the user. + + We use the Serial terminal for these messages as the gST->ConOut might not be initialized at this stage. + + @param Message Message to display to the user +**/ +STATIC +VOID +PrintMessage ( + IN CHAR8* Message, + ... + ) +{ + UINTN CharCount; + CHAR8 Buffer[100]; + VA_LIST Marker; + + VA_START (Marker, Message); + CharCount = AsciiVSPrint (Buffer, sizeof (Buffer), Message, Marker); + VA_END (Marker); + + SerialPortWrite ((UINT8*)Buffer, CharCount); +} + +/** + See definition EFI_DRIVER_BINDING_PROTOCOL.Start () +**/ +EFI_STATUS +EFIAPI +JunoFdtStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *BootMonFs; + EFI_FILE_PROTOCOL *Fs; + EFI_FILE_PROTOCOL *File; + UINTN Size; + EFI_PHYSICAL_ADDRESS FdtBlob; + EFI_FILE_INFO *FileInfo; + + if (mFdtTableInstalled) { + return EFI_ALREADY_STARTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&BootMonFs, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // Try to Open the volume and get root directory + Status = BootMonFs->OpenVolume (BootMonFs, &Fs); + if (EFI_ERROR (Status)) { + PrintMessage ("Warning: Fail to open file system that should contain FDT file.\n"); + goto UNLOAD_PROTOCOL; + } + + File = NULL; + Status = Fs->Open (Fs, &File, mFdtFileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + PrintMessage ("Warning: Fail to load FDT file '%s'.\n", mFdtFileName); + goto UNLOAD_PROTOCOL; + } + + Size = 0; + File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL); + FileInfo = AllocatePool (Size); + Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo); + if (EFI_ERROR (Status)) { + goto UNLOAD_PROTOCOL; + } + + // Get the file size + Size = FileInfo->FileSize; + FreePool (FileInfo); + + // The FDT blob is attached to the Configuration Table. It is better to load it as Runtime Service Data + // to prevent the kernel to overwrite its data + Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (Size), &FdtBlob); + if (!EFI_ERROR (Status)) { + Status = File->Read (File, &Size, (VOID*)(UINTN)(FdtBlob)); + if (EFI_ERROR (Status)) { + gBS->FreePages (FdtBlob, EFI_SIZE_TO_PAGES (Size)); + } else { + // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on + // production device and this ASSERT() becomes not valid. + ASSERT (fdt_check_header ((VOID*)(UINTN)(FdtBlob)) == 0); + + // Ensure the Size of the Device Tree is smaller than the size of the read file + ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlob) <= Size); + + // Install the FDT into the Configuration Table + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, (VOID*)(UINTN)(FdtBlob)); + if (!EFI_ERROR (Status)) { + mFdtTableInstalled = TRUE; + } + } + } + +UNLOAD_PROTOCOL: + // We do not need the FileSystem protocol + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleFileSystemProtocolGuid, + DriverBinding->ImageHandle, + ControllerHandle); + + return Status; +} + +/** + See definition EFI_DRIVER_BINDING_PROTOCOL.Stop() +**/ +EFI_STATUS +EFIAPI +JunoFdtStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + UINTN Index; + VOID* FdtBlob; + UINTN FdtSize; + + // Look for FDT Table + for (Index = 0; Index < gST->NumberOfTableEntries; Index++) { + // Check for correct GUID type + if (CompareGuid (&gFdtTableGuid, &(gST->ConfigurationTable[Index].VendorGuid))) { + FdtBlob = gST->ConfigurationTable[Index].VendorTable; + FdtSize = (UINTN)fdt_totalsize (FdtBlob); + + // Uninstall the FDT Configuration Table + gBS->InstallConfigurationTable (&gFdtTableGuid, NULL); + + // Free the memory + gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)FdtBlob, EFI_SIZE_TO_PAGES (FdtSize)); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +// +// Driver Binding Protocol for Juno FDT support +// +EFI_DRIVER_BINDING_PROTOCOL mJunoFdtBinding = { + JunoFdtSupported, + JunoFdtStart, + JunoFdtStop, + 0xa, + NULL, + NULL +}; + +/** + Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group. + + This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +STATIC +VOID +EFIAPI +OnEndOfDxe ( + EFI_EVENT Event, + VOID *Context + ) +{ + EFI_DEVICE_PATH *DevicePathNode; + EFI_HANDLE Handle; + EFI_STATUS Status; + UINTN VariableSize; + CHAR16* FdtDevicePathStr; + EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; + + // + // Read the 'FDT' UEFI Variable to know where we should we read the blob from. + // The 'Fdt' variable contains either the full device path or only the filename of the FDT. + // If 'Fdt' only contains the filename then we assume its location is on the NOR Flash. + // + VariableSize = 0; + Status = gRT->GetVariable (L"Fdt", &gArmGlobalVariableGuid, NULL, &VariableSize, mFdtFileSystemDevicePath); + if (Status == EFI_BUFFER_TOO_SMALL) { + // Get the environment variable value + mFdtFileSystemDevicePath = AllocatePool (VariableSize); + if (mFdtFileSystemDevicePath != NULL) { + Status = gRT->GetVariable (L"Fdt", &gArmGlobalVariableGuid, NULL, &VariableSize, mFdtFileSystemDevicePath); + if (EFI_ERROR (Status)) { + FreePool (mFdtFileSystemDevicePath); + ASSERT_EFI_ERROR (Status); + return; + } + } else { + ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES); + return; + } + } else if (Status == EFI_NOT_FOUND) { + // If the 'Fdt' variable does not exist then we get the FDT location from the PCD + FdtDevicePathStr = (CHAR16*)PcdGetPtr (PcdFdtDevicePath); + + Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + // Conversion of the Device Path string into EFI Device Path + mFdtFileSystemDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (FdtDevicePathStr); + } + + if (mFdtFileSystemDevicePath != NULL) { + // Look for the FDT filename that should be contained into the FilePath device path node + DevicePathNode = mFdtFileSystemDevicePath; + while (!IsDevicePathEnd (DevicePathNode)) { + if (IS_DEVICE_PATH_NODE (DevicePathNode, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) { + // Extract the name from the File Path Node. The name of the Filename is the size of the + // device path node minus the size of the device path node header. + mFdtFileName = AllocateCopyPool ( + DevicePathNodeLength (DevicePathNode) - sizeof(EFI_DEVICE_PATH_PROTOCOL), + ((FILEPATH_DEVICE_PATH*)DevicePathNode)->PathName); + if (mFdtFileName == NULL) { + ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES); + return; + } + + // We remove the FilePath device path node from the FileSystem Device Path + // because it will never match a device path installed by the FileSystem driver + SetDevicePathEndNode (DevicePathNode); + break; + } + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + + // The UEFI Variable might just contain the FDT filename. In this case we assume the FileSystem is + // the NOR Flash based one (ie: BootMonFs). + // If it was only containing the FilePath device node then the previous condition should have + // replaced it by the End Device Path Node. + if (IsDevicePathEndType (mFdtFileSystemDevicePath)) { + mFdtFileSystemDevicePath = (EFI_DEVICE_PATH*)&mJunoNorFlashDevicePath; + } + } else { + // Fallback on the NOR Flash filesystem + mFdtFileSystemDevicePath = (EFI_DEVICE_PATH*)&mJunoNorFlashDevicePath; + } + + // If the FDT FileName has been provided during the FileSystem identification + if (mFdtFileName == NULL) { + mFdtFileName = AllocateCopyPool (StrSize (FDT_DEFAULT_FILENAME), FDT_DEFAULT_FILENAME); + if (mFdtFileName == NULL) { + ASSERT_EFI_ERROR (Status); + return; + } + } + + // Install the Binding protocol to verify when the FileSystem that contains the FDT has been installed + Status = gBS->InstallMultipleProtocolInterfaces ( + &gImageHandle, + &gEfiDriverBindingProtocolGuid, &mJunoFdtBinding, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + // + // Force to connect the FileSystem that contains the FDT + // + BdsConnectDevicePath (mFdtFileSystemDevicePath, &Handle, NULL); +} + +EFI_STATUS +JunoFdtInstall ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_EVENT EndOfDxeEvent; + + // Register the event handling function to set the End Of DXE flag. + // We wait until the end of the DXE phase to load the FDT to make sure + // all the required drivers (NOR Flash, UEFI Variable, BootMonFs) are dispatched + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnEndOfDxe, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.c new file mode 100644 index 0000000000..7c2d756fe1 --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.c @@ -0,0 +1,486 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2013 - 2014, ARM 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 "PciEmulation.h" + +#define HOST_CONTROLLER_OPERATION_REG_SIZE 0x44 + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + PCI_DEVICE_PATH PciDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_IO_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_PCI_IO_DEVICE_PATH DevicePath; + EFI_PCI_IO_PROTOCOL PciIoProtocol; + PCI_TYPE00 *ConfigSpace; + PCI_ROOT_BRIDGE RootBridge; + UINTN Segment; +} EFI_PCI_IO_PRIVATE_DATA; + +#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, EFI_PCI_IO_PRIVATE_DATA, PciIoProtocol, EFI_PCI_IO_PRIVATE_DATA_SIGNATURE) + +EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{ + { + { ACPI_DEVICE_PATH, ACPI_DP, { sizeof (ACPI_HID_DEVICE_PATH), 0 } }, + EISA_PNP_ID(0x0A03), // HID + 0 // UID + }, + { + { HARDWARE_DEVICE_PATH, HW_PCI_DP, { sizeof (PCI_DEVICE_PATH), 0 } }, + 0, + 0 + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} } +}; + +STATIC +VOID +ConfigureUSBHost ( + VOID + ) +{ +} + + +EFI_STATUS +PciIoPollMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoPollIo ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + return PciRootBridgeIoMemRead (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, //Fix me ConfigSpace + Count, + Buffer + ); +} + +EFI_STATUS +PciIoMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + return PciRootBridgeIoMemWrite (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, //Fix me ConfigSpace + Count, + Buffer + ); +} + +EFI_STATUS +PciIoIoRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoIoWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoPciRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + EFI_STATUS Status; + + Status = PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Count, + TRUE, + (PTR)(UINTN)Buffer, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset) //Fix me ConfigSpace + ); + return Status; +} + +EFI_STATUS +PciIoPciWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + return PciRootBridgeIoMemRW ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Count, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), //Fix me ConfigSpace + TRUE, + (PTR)(UINTN)Buffer + ); +} + +EFI_STATUS +PciIoCopyMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + DMA_MAP_OPERATION DmaOperation; + + if (Operation == EfiPciIoOperationBusMasterRead) { + DmaOperation = MapOperationBusMasterRead; + } else if (Operation == EfiPciIoOperationBusMasterWrite) { + DmaOperation = MapOperationBusMasterWrite; + } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) { + DmaOperation = MapOperationBusMasterCommonBuffer; + } else { + return EFI_INVALID_PARAMETER; + } + return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping); +} + +EFI_STATUS +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return DmaUnmap (Mapping); +} + +EFI_STATUS +PciIoAllocateBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { + // Check this + return EFI_UNSUPPORTED; + } + + return DmaAllocateBuffer (MemoryType, Pages, HostAddress); +} + + +EFI_STATUS +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + return DmaFreeBuffer (Pages, HostAddress); +} + + +EFI_STATUS +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + if (SegmentNumber != NULL) { + *SegmentNumber = Private->Segment; + } + + if (BusNumber != NULL) { + *BusNumber = 0xff; + } + + if (DeviceNumber != NULL) { + *DeviceNumber = 0; + } + + if (FunctionNumber != NULL) { + *FunctionNumber = 0; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ) +{ + switch (Operation) { + case EfiPciIoAttributeOperationGet: + case EfiPciIoAttributeOperationSupported: + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + // We are not a real PCI device so just say things we kind of do + *Result = EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_DEVICE_ENABLE; + break; + + case EfiPciIoAttributeOperationSet: + case EfiPciIoAttributeOperationEnable: + case EfiPciIoAttributeOperationDisable: + // Since we are not a real PCI device no enable/set or disable operations exist. + return EFI_SUCCESS; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + }; + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_PCI_IO_PROTOCOL PciIoTemplate = +{ + PciIoPollMem, + PciIoPollIo, + { PciIoMemRead, PciIoMemWrite }, + { PciIoIoRead, PciIoIoWrite }, + { PciIoPciRead, PciIoPciWrite }, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, + 0 +}; + +EFI_STATUS +PciInstallDevice ( + IN UINTN DeviceId, + IN PHYSICAL_ADDRESS MemoryStart, + IN UINT64 MemorySize, + IN UINTN ClassCode1, + IN UINTN ClassCode2, + IN UINTN ClassCode3 + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_PCI_IO_PRIVATE_DATA *Private; + + // Configure USB host + ConfigureUSBHost (); + + // Create a private structure + Private = AllocatePool (sizeof (EFI_PCI_IO_PRIVATE_DATA)); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; // Fill in signature + Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; // Fake Root Bridge structure needs a signature too + Private->RootBridge.MemoryStart = MemoryStart; // Get the USB capability register base + Private->Segment = 0; // Default to segment zero + + // Calculate the total size of the USB controller (OHCI + EHCI). + Private->RootBridge.MemorySize = MemorySize; //CapabilityLength + (HOST_CONTROLLER_OPERATION_REG_SIZE + ((4 * PhysicalPorts) - 1)); + + // Create fake PCI config space: OHCI + EHCI + Private->ConfigSpace = AllocateZeroPool (sizeof (PCI_TYPE00)); + if (Private->ConfigSpace == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool (Private); + return Status; + } + + // + // Configure PCI config space: OHCI + EHCI + // + Private->ConfigSpace->Hdr.VendorId = 0x3530; //TODO: Define one + Private->ConfigSpace->Hdr.DeviceId = 0x3530; //TODO: Define one + Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1; + Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2; + Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3; + Private->ConfigSpace->Device.Bar[0] = MemoryStart; + + Handle = NULL; + + // Unique device path. + CopyMem (&Private->DevicePath, &PciIoDevicePathTemplate, sizeof (PciIoDevicePathTemplate)); + Private->DevicePath.AcpiDevicePath.UID = 0; + Private->DevicePath.PciDevicePath.Device = DeviceId; + + // Copy protocol structure + CopyMem (&Private->PciIoProtocol, &PciIoTemplate, sizeof (PciIoTemplate)); + + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEfiPciIoProtocolGuid, &Private->PciIoProtocol, + &gEfiDevicePathProtocolGuid, &Private->DevicePath, + NULL); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PciEmulationEntryPoint InstallMultipleProtocolInterfaces () failed.\n")); + } + + return Status; +} + +EFI_STATUS +PciEmulationEntryPoint ( + VOID + ) +{ + EFI_STATUS Status; + + Status = PciInstallDevice (0, FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress), SIZE_64KB, PCI_IF_OHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install OHCI device.\n")); + } + + Status = PciInstallDevice (1, FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress), SIZE_64KB, PCI_IF_EHCI, PCI_CLASS_SERIAL_USB, PCI_CLASS_SERIAL); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PciEmulation: failed to install EHCI device.\n")); + } + + return Status; +} diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.h b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.h new file mode 100644 index 0000000000..de2855d01d --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciEmulation.h @@ -0,0 +1,284 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2013 - 2014, ARM 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. + +**/ + +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "ArmJunoDxeInternal.h" + +#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFFULL +#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFEULL +#define EFI_RESOURCE_SATISFIED 0x0000000000000000ULL + + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + + +#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2 + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesc; +} ACPI_CONFIG_INFO; + + +#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath; + + UINT8 StartBus; + UINT8 EndBus; + UINT16 Type; + UINT32 MemoryStart; + UINT32 MemorySize; + UINTN IoOffset; + UINT32 IoStart; + UINT32 IoSize; + UINT64 PciAttributes; + + ACPI_CONFIG_INFO *Config; + +} PCI_ROOT_BRIDGE; + + +#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE) + + +typedef union { + UINT8 volatile *Buffer; + UINT8 volatile *Ui8; + UINT16 volatile *Ui16; + UINT32 volatile *Ui32; + UINT64 volatile *Ui64; + UINTN volatile Ui; +} PTR; + + + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ); + +BOOLEAN +PciIoMemAddressValid ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Address + ); + +EFI_STATUS +EmulatePciIoForEhci ( + INTN MvPciIfMaxIf + ); + +#endif diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciRootBridgeIo.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciRootBridgeIo.c new file mode 100644 index 0000000000..f1eaceff28 --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/PciRootBridgeIo.c @@ -0,0 +1,299 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. 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 "PciEmulation.h" + +BOOLEAN +PciRootBridgeMemAddressValid ( + IN PCI_ROOT_BRIDGE *Private, + IN UINT64 Address + ) +{ + if ((Address >= Private->MemoryStart) && (Address < (Private->MemoryStart + Private->MemorySize))) { + return TRUE; + } + + return FALSE; +} + + +EFI_STATUS +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ) +{ + UINTN Stride; + UINTN InStride; + UINTN OutStride; + + Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride = (UINTN)1 << Width; + InStride = InStrideFlag ? Stride : 0; + OutStride = OutStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiPciWidthUint8: + for (;Count > 0; Count--, In.Buffer += InStride, Out.Buffer += OutStride) { + *In.Ui8 = *Out.Ui8; + } + break; + case EfiPciWidthUint16: + for (;Count > 0; Count--, In.Buffer += InStride, Out.Buffer += OutStride) { + *In.Ui16 = *Out.Ui16; + } + break; + case EfiPciWidthUint32: + for (;Count > 0; Count--, In.Buffer += InStride, Out.Buffer += OutStride) { + *In.Ui32 = *Out.Ui32; + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.Buffer = Buffer; + Out.Buffer = (VOID *)(UINTN) Address; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.Buffer = (VOID *)(UINTN) Address; + Out.Buffer = Buffer; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c new file mode 100644 index 0000000000..827d27e2ca --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c @@ -0,0 +1,354 @@ +/** @file +* +* Copyright (c) 2013-2014, ARM Limited. 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 +#include + +#include +#include + +#include + +// The number of 100ns periods (the unit of time passed to these functions) +// in a second +#define TIME_UNITS_PER_SECOND 10000000 + +// Tick frequency of the generic timer that is the basis of the generic watchdog +UINTN mTimerFrequencyHz = 0; + +// In cases where the compare register was set manually, information about +// how long the watchdog was asked to wait cannot be retrieved from hardware. +// It is therefore stored here. 0 means the timer is not running. +UINT64 mNumTimerTicks = 0; + +EFI_HARDWARE_INTERRUPT_PROTOCOL *mInterruptProtocol; + +EFI_STATUS +WatchdogWriteOffsetRegister ( + UINT32 Value + ) +{ + return MmioWrite32 (GENERIC_WDOG_OFFSET_REG, Value); +} + +EFI_STATUS +WatchdogWriteCompareRegister ( + UINT64 Value + ) +{ + return MmioWrite64 (GENERIC_WDOG_COMPARE_VALUE_REG, Value); +} + +EFI_STATUS +WatchdogEnable ( + VOID + ) +{ + return MmioWrite32 (GENERIC_WDOG_CONTROL_STATUS_REG, GENERIC_WDOG_ENABLED); +} + +EFI_STATUS +WatchdogDisable ( + VOID + ) +{ + return MmioWrite32 (GENERIC_WDOG_CONTROL_STATUS_REG, GENERIC_WDOG_DISABLED); +} + +/** + On exiting boot services we must make sure the Watchdog Timer + is stopped. +**/ +VOID +EFIAPI +WatchdogExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + WatchdogDisable (); + mNumTimerTicks = 0; +} + +/* + This function is called when the watchdog's first signal (WS0) goes high. + It uses the ResetSystem Runtime Service to reset the board. +*/ +VOID +EFIAPI +WatchdogInterruptHandler ( + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + STATIC CONST CHAR16 ResetString[] = L"The generic watchdog timer ran out."; + + WatchdogDisable (); + + mInterruptProtocol->EndOfInterrupt (mInterruptProtocol, Source); + + gRT->ResetSystem ( + EfiResetCold, + EFI_TIMEOUT, + StrSize (ResetString), + &ResetString + ); + + // If we got here then the reset didn't work + ASSERT (FALSE); +} + +/** + This function registers the handler NotifyFunction so it is called every time + the watchdog timer expires. It also passes the amount of time since the last + handler call to the NotifyFunction. + If NotifyFunction is not NULL and a handler is not already registered, + then the new handler is registered and EFI_SUCCESS is returned. + If NotifyFunction is NULL, and a handler is already registered, + then that handler is unregistered. + If an attempt is made to register a handler when a handler is already registered, + then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fires. + This function executes at TPL_HIGH_LEVEL. The DXE + Core will register a handler for the timer interrupt, + so it can know how much time has passed. This + information is used to signal timer based events. + NULL will unregister the handler. + + @retval EFI_SUCCESS The watchdog timer handler was registered. + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already + registered. + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not + previously registered. + +**/ +EFI_STATUS +EFIAPI +WatchdogRegisterHandler ( + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction + ) +{ + // ERROR: This function is not supported. + // The watchdog will reset the board + return EFI_UNSUPPORTED; +} + +/** + This function sets the amount of time to wait before firing the watchdog + timer to TimerPeriod 100 nS units. If TimerPeriod is 0, then the watchdog + timer is disabled. + + @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod The amount of time in 100 nS units to wait before the watchdog + timer is fired. If TimerPeriod is zero, then the watchdog + timer is disabled. + + @retval EFI_SUCCESS The watchdog timer has been programmed to fire in Time + 100 nS units. + @retval EFI_DEVICE_ERROR A watchdog timer could not be programmed due to a device + error. + +**/ +EFI_STATUS +EFIAPI +WatchdogSetTimerPeriod ( + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod // In 100ns units + ) +{ + UINTN TimerVal; + EFI_STATUS Status; + + // if TimerPerdiod is 0, this is a request to stop the watchdog. + if (TimerPeriod == 0) { + mNumTimerTicks = 0; + return WatchdogDisable (); + } + + // Work out how many timer ticks will equate to TimerPeriod + mNumTimerTicks = (mTimerFrequencyHz * TimerPeriod) / TIME_UNITS_PER_SECOND; + + // + // If the number of required ticks is greater than the max number the + // watchdog's offset register (WOR) can hold, we need to manually compute and + // set the compare register (WCV) + // + if (mNumTimerTicks > MAX_UINT32) { + // + // We need to enable the watchdog *before* writing to the compare register, + // because enabling the watchdog causes an "explicit refresh", which + // clobbers the compare register (WCV). In order to make sure this doesn't + // trigger an interrupt, set the offset to max. + // + Status = WatchdogWriteOffsetRegister (MAX_UINT32); + if (EFI_ERROR (Status)) { + return Status; + } + WatchdogEnable (); + TimerVal = ArmGenericTimerGetTimerVal (); + Status = WatchdogWriteCompareRegister (TimerVal + mNumTimerTicks); + } else { + Status = WatchdogWriteOffsetRegister ((UINT32)mNumTimerTicks); + WatchdogEnable (); + } + + return Status; +} + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod A pointer to the timer period to retrieve in 100 + ns units. If 0 is returned, then the timer is + currently disabled. + + + @retval EFI_SUCCESS The timer period was returned in TimerPeriod. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +EFI_STATUS +EFIAPI +WatchdogGetTimerPeriod ( + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = ((TIME_UNITS_PER_SECOND / mTimerFrequencyHz) * mNumTimerTicks); + + return EFI_SUCCESS; +} + +/** + Interface structure for the Watchdog Architectural Protocol. + + @par Protocol Description: + This protocol provides a service to set the amount of time to wait + before firing the watchdog timer, and it also provides a service to + register a handler that is invoked when the watchdog timer fires. + + @par When the watchdog timer fires, control will be passed to a handler + if one has been registered. If no handler has been registered, + or the registered handler returns, then the system will be + reset by calling the Runtime Service ResetSystem(). + + @param RegisterHandler + Registers a handler that will be called each time the + watchdogtimer interrupt fires. TimerPeriod defines the minimum + time between timer interrupts, so TimerPeriod will also + be the minimum time between calls to the registered + handler. + NOTE: If the watchdog resets the system in hardware, then + this function will not have any chance of executing. + + @param SetTimerPeriod + Sets the period of the timer interrupt in 100 nS units. + This function is optional, and may return EFI_UNSUPPORTED. + If this function is supported, then the timer period will + be rounded up to the nearest supported timer period. + + @param GetTimerPeriod + Retrieves the period of the timer interrupt in 100 nS units. + +**/ +EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer = { + (EFI_WATCHDOG_TIMER_REGISTER_HANDLER) WatchdogRegisterHandler, + (EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD) WatchdogSetTimerPeriod, + (EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD) WatchdogGetTimerPeriod +}; + +EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL; + +EFI_STATUS +EFIAPI +GenericWatchdogEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + // + // Make sure the Watchdog Timer Architectural Protocol has not been installed + // in the system yet. + // This will avoid conflicts with the universal watchdog + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiWatchdogTimerArchProtocolGuid); + + mTimerFrequencyHz = ArmGenericTimerGetTimerFreq (); + ASSERT (mTimerFrequencyHz != 0); + + // Register for an ExitBootServicesEvent + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, + WatchdogExitBootServicesEvent, NULL, &EfiExitBootServicesEvent + ); + if (!EFI_ERROR (Status)) { + // Install interrupt handler + Status = gBS->LocateProtocol ( + &gHardwareInterruptProtocolGuid, + NULL, + (VOID **)&mInterruptProtocol + ); + if (!EFI_ERROR (Status)) { + Status = mInterruptProtocol->RegisterInterruptSource ( + mInterruptProtocol, + FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum), + WatchdogInterruptHandler + ); + if (!EFI_ERROR (Status)) { + // Install the Timer Architectural Protocol onto a new handle + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiWatchdogTimerArchProtocolGuid, &gWatchdogTimer, + NULL + ); + } + } + } + + if (EFI_ERROR (Status)) { + // The watchdog failed to initialize + ASSERT (FALSE); + } + + mNumTimerTicks = 0; + WatchdogDisable (); + + return Status; +} diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf b/ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf new file mode 100644 index 0000000000..82f226fb56 --- /dev/null +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf @@ -0,0 +1,54 @@ +# +# Copyright (c) 2013-2014, ARM Limited. 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 = 0x00010016 + BASE_NAME = GenericWatchdogDxe + FILE_GUID = 0619f5c2-4858-4caa-a86a-73a21a18df6b + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = GenericWatchdogEntry + +[Sources.common] + GenericWatchdogDxe.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPlatformPkg/ArmJunoPkg/ArmJuno.dec + +[LibraryClasses] + ArmGenericTimerCounterLib + BaseLib + BaseMemoryLib + DebugLib + IoLib + PcdLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + +[FixedPcd] + gArmJunoTokenSpaceGuid.PcdGenericWatchdogControlBase + gArmJunoTokenSpaceGuid.PcdGenericWatchdogRefreshBase + gArmJunoTokenSpaceGuid.PcdGenericWatchdogEl2IntrNum + +[Protocols] + gEfiWatchdogTimerArchProtocolGuid + gHardwareInterruptProtocolGuid + +[Depex] + gHardwareInterruptProtocolGuid -- cgit v1.2.3