+++ /dev/null
-/** @file\r
-*\r
-* Copyright (c) 2013-2015, ARM Limited. All rights reserved.\r
-*\r
-* This program and the accompanying materials\r
-* are licensed and made available under the terms and conditions of the BSD License\r
-* which accompanies this distribution. The full text of the license may be found at\r
-* http://opensource.org/licenses/bsd-license.php\r
-*\r
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#include "ArmJunoDxeInternal.h"\r
-#include <ArmPlatform.h>\r
-\r
-#include <IndustryStandard/Pci.h>\r
-#include <Protocol/DevicePathFromText.h>\r
-#include <Protocol/PciIo.h>\r
-#include <Protocol/PciRootBridgeIo.h>\r
-\r
-#include <Guid/EventGroup.h>\r
-#include <Guid/GlobalVariable.h>\r
-\r
-#include <Library/ArmShellCmdLib.h>\r
-#include <Library/AcpiLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/DevicePathLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/NonDiscoverableDeviceRegistrationLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/IoLib.h>\r
-#include <Library/PrintLib.h>\r
-\r
-\r
-// This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf\r
-STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };\r
-\r
-typedef struct {\r
- ACPI_HID_DEVICE_PATH AcpiDevicePath;\r
- PCI_DEVICE_PATH PciDevicePath;\r
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;\r
-} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;\r
-\r
-STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = {\r
- {\r
- { ACPI_DEVICE_PATH,\r
- ACPI_DP,\r
- { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),\r
- (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) }\r
- },\r
- EISA_PNP_ID (0x0A03),\r
- 0\r
- },\r
- {\r
- { HARDWARE_DEVICE_PATH,\r
- HW_PCI_DP,\r
- { (UINT8) (sizeof (PCI_DEVICE_PATH)),\r
- (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) }\r
- },\r
- 0,\r
- 0\r
- },\r
- {\r
- END_DEVICE_PATH_TYPE,\r
- END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
- { END_DEVICE_PATH_LENGTH, 0 }\r
- }\r
-};\r
-\r
-EFI_EVENT mAcpiRegistration = NULL;\r
-\r
-/**\r
- This function reads PCI ID of the controller.\r
-\r
- @param[in] PciIo PCI IO protocol handle\r
- @param[in] PciId Looking for specified PCI ID Vendor/Device\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-ReadMarvellYoukonPciId (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT32 PciId\r
- )\r
-{\r
- UINT32 DevicePciId;\r
- EFI_STATUS Status;\r
-\r
- Status = PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- PCI_VENDOR_ID_OFFSET,\r
- 1,\r
- &DevicePciId);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if (DevicePciId != PciId) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function searches for Marvell Yukon NIC on the Juno\r
- platform and returns PCI IO protocol handle for the controller.\r
-\r
- @param[out] PciIo PCI IO protocol handle\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-GetMarvellYukonPciIoProtocol (\r
- OUT EFI_PCI_IO_PROTOCOL **PciIo\r
- )\r
-{\r
- UINTN HandleCount;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN HIndex;\r
- EFI_STATUS Status;\r
-\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiPciIoProtocolGuid,\r
- NULL,\r
- &HandleCount,\r
- &HandleBuffer);\r
- if (EFI_ERROR (Status)) {\r
- return (Status);\r
- }\r
-\r
- for (HIndex = 0; HIndex < HandleCount; ++HIndex) {\r
- // If PciIo opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL, the CloseProtocol() is not required\r
- Status = gBS->OpenProtocol (\r
- HandleBuffer[HIndex],\r
- &gEfiPciIoProtocolGuid,\r
- (VOID **) PciIo,\r
- NULL,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- }\r
-\r
- Status = ReadMarvellYoukonPciId (*PciIo, JUNO_MARVELL_YUKON_ID);\r
- if (EFI_ERROR (Status)) {\r
- continue;\r
- } else {\r
- break;\r
- }\r
- }\r
-\r
- gBS->FreePool (HandleBuffer);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This function restore the original controller attributes\r
-\r
- @param[in] PciIo PCI IO protocol handle\r
- @param[in] PciAttr PCI controller attributes.\r
- @param[in] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR\r
-**/\r
-STATIC\r
-VOID\r
-RestorePciDev (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT64 PciAttr\r
- )\r
-{\r
- PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSet,\r
- PciAttr,\r
- NULL\r
- );\r
-}\r
-\r
-/**\r
- This function returns PCI MMIO base address for a controller\r
-\r
- @param[in] PciIo PCI IO protocol handle\r
- @param[out] PciRegBase PCI base MMIO address\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-BarIsDeviceMemory (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- OUT UINT32 *PciRegBase\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor;\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiCurrentDescriptor;\r
-\r
- // Marvell Yukon's Bar0 provides base memory address for control registers\r
- Status = PciIo->GetBarAttributes (PciIo, PCI_BAR_IDX0, NULL, (VOID**)&AcpiResDescriptor);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- AcpiCurrentDescriptor = AcpiResDescriptor;\r
-\r
- // Search for a memory type descriptor\r
- while (AcpiCurrentDescriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
-\r
- // Check if Bar is memory type one and fetch a base address\r
- if (AcpiCurrentDescriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR &&\r
- AcpiCurrentDescriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM &&\r
- !(AcpiCurrentDescriptor->SpecificFlag & ACPI_SPECFLAG_PREFETCHABLE)) {\r
- *PciRegBase = AcpiCurrentDescriptor->AddrRangeMin;\r
- break;\r
- } else {\r
- Status = EFI_UNSUPPORTED;\r
- }\r
-\r
- AcpiCurrentDescriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (AcpiCurrentDescriptor + 1);\r
- }\r
-\r
- gBS->FreePool (AcpiResDescriptor);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This function provides PCI MMIO base address, old PCI controller attributes.\r
-\r
- @param[in] PciIo PCI IO protocol handle\r
- @param[out] PciRegBase PCI base MMIO address\r
- @param[out] OldPciAttr Old PCI controller attributes.\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-InitPciDev (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- OUT UINT32 *PciRegBase,\r
- OUT UINT64 *OldPciAttr\r
- )\r
-{\r
- UINT64 AttrSupports;\r
- EFI_STATUS Status;\r
-\r
- // Get controller's current attributes\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationGet,\r
- 0,\r
- OldPciAttr);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // Fetch supported attributes\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationSupported,\r
- 0,\r
- &AttrSupports);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // Enable EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY and\r
- // EFI_PCI_IO_ATTRIBUTE_BUS_MASTER bits in the PCI Config Header\r
- AttrSupports &= EFI_PCI_DEVICE_ENABLE;\r
- Status = PciIo->Attributes (\r
- PciIo,\r
- EfiPciIoAttributeOperationEnable,\r
- AttrSupports,\r
- NULL);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = BarIsDeviceMemory (PciIo, PciRegBase);\r
- if (EFI_ERROR (Status)) {\r
- RestorePciDev (PciIo, *OldPciAttr);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This function reads MAC address from IOFPGA and writes it to Marvell Yukon NIC\r
-\r
- @param[in] PciRegBase PCI base MMIO address\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-WriteMacAddress (\r
- IN UINT32 PciRegBase\r
- )\r
-{\r
- UINT32 MacHigh;\r
- UINT32 MacLow;\r
-\r
- // Read MAC address from IOFPGA\r
- MacHigh= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);\r
- MacLow = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);\r
-\r
- // Set software reset control register to protect from deactivation\r
- // the config write state\r
- MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);\r
-\r
- // Convert to Marvell MAC Address register format\r
- MacHigh = SwapBytes32 ((MacHigh & 0xFFFF) << 16 |\r
- (MacLow & 0xFFFF0000) >> 16);\r
- MacLow = SwapBytes32 (MacLow) >> 16;\r
-\r
- // Set MAC Address\r
- MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_ENABLE);\r
- MmioWrite32 (PciRegBase + R_MAC, MacHigh);\r
- MmioWrite32 (PciRegBase + R_MAC_MAINT, MacHigh);\r
- MmioWrite32 (PciRegBase + R_MAC + R_MAC_LOW, MacLow);\r
- MmioWrite32 (PciRegBase + R_MAC_MAINT + R_MAC_LOW, MacLow);\r
- MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_DISABLE);\r
-\r
- // Initiate device reset\r
- MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_SET);\r
- MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- The function reads MAC address from Juno IOFPGA registers and writes it\r
- into Marvell Yukon NIC.\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-ArmJunoSetNicMacAddress ()\r
-{\r
- UINT64 OldPciAttr;\r
- EFI_PCI_IO_PROTOCOL* PciIo;\r
- UINT32 PciRegBase;\r
- EFI_STATUS Status;\r
-\r
- Status = GetMarvellYukonPciIoProtocol (&PciIo);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- PciRegBase = 0;\r
- Status = InitPciDev (PciIo, &PciRegBase, &OldPciAttr);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = WriteMacAddress (PciRegBase);\r
-\r
- RestorePciDev (PciIo, OldPciAttr);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Notification function of the event defined as belonging to the\r
- EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in\r
- the entry point of the driver.\r
-\r
- This function is called when an event belonging to the\r
- EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an\r
- event is signalled once at the end of the dispatching of all\r
- drivers (end of the so called DXE phase).\r
-\r
- @param[in] Event Event declared in the entry point of the driver whose\r
- notification function is being invoked.\r
- @param[in] Context NULL\r
-**/\r
-STATIC\r
-VOID\r
-OnEndOfDxe (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_DEVICE_PATH_PROTOCOL* PciRootComplexDevicePath;\r
- EFI_HANDLE Handle;\r
- EFI_STATUS Status;\r
-\r
- //\r
- // PCI Root Complex initialization\r
- // At the end of the DXE phase, we should get all the driver dispatched.\r
- // Force the PCI Root Complex to be initialized. It allows the OS to skip\r
- // this step.\r
- //\r
- PciRootComplexDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) &mPciRootComplexDevicePath;\r
- Status = gBS->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid,\r
- &PciRootComplexDevicePath,\r
- &Handle);\r
-\r
- Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = ArmJunoSetNicMacAddress ();\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "ArmJunoDxe: Failed to set Marvell Yukon NIC MAC address\n"));\r
- }\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-ArmJunoEntryPoint (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS HypBase;\r
- CHAR16 *TextDevicePath;\r
- UINTN TextDevicePathSize;\r
- VOID *Buffer;\r
- UINT32 JunoRevision;\r
- EFI_EVENT EndOfDxeEvent;\r
-\r
- //\r
- // Register the OHCI and EHCI controllers as non-coherent\r
- // non-discoverable devices.\r
- //\r
- Status = RegisterNonDiscoverableMmioDevice (\r
- NonDiscoverableDeviceTypeOhci,\r
- NonDiscoverableDeviceDmaTypeNonCoherent,\r
- NULL,\r
- NULL,\r
- 1,\r
- FixedPcdGet32 (PcdSynopsysUsbOhciBaseAddress),\r
- SIZE_64KB\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = RegisterNonDiscoverableMmioDevice (\r
- NonDiscoverableDeviceTypeEhci,\r
- NonDiscoverableDeviceDmaTypeNonCoherent,\r
- NULL,\r
- NULL,\r
- 1,\r
- FixedPcdGet32 (PcdSynopsysUsbEhciBaseAddress),\r
- SIZE_64KB\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // If a hypervisor has been declared then we need to make sure its region is protected at runtime\r
- //\r
- // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)\r
- // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.\r
- //\r
- if (FixedPcdGet32 (PcdHypFvSize) != 0) {\r
- // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.\r
- // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.\r
- // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded\r
- // to this size then there is a risk some non-runtime memory could be visible to the OS view.\r
- if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {\r
- // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space\r
- // as it contains the Firmware.\r
- Status = gDS->AddMemorySpace (\r
- EfiGcdMemoryTypeSystemMemory,\r
- FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),\r
- EFI_MEMORY_WB | EFI_MEMORY_RUNTIME\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- // We allocate the memory to ensure it is marked as runtime memory\r
- HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);\r
- Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,\r
- EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);\r
- }\r
- } else {\r
- // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned\r
- // on a EFI_PAGE_SIZE boundary (ie: 4KB).\r
- Status = EFI_UNSUPPORTED;\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- // Install dynamic Shell command to run baremetal binaries.\r
- Status = ShellDynCmdRunAxfInstall (ImageHandle);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));\r
- }\r
-\r
- GetJunoRevision(JunoRevision);\r
-\r
- //\r
- // Try to install the ACPI Tables\r
- //\r
- Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Setup R1/R2 options if not already done.\r
- //\r
- if (JunoRevision != JUNO_REVISION_R0) {\r
- // Enable PCI enumeration\r
- PcdSetBool (PcdPciDisableBusEnumeration, FALSE);\r
-\r
- //\r
- // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.\r
- // The "OnEndOfDxe()" function is declared as the call back function.\r
- // It will be called at the end of the DXE phase when an event of the\r
- // same group is signalled to inform about the end of the DXE phase.\r
- // Install the INSTALL_FDT_PROTOCOL protocol.\r
- //\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- OnEndOfDxe,\r
- NULL,\r
- &gEfiEndOfDxeEventGroupGuid,\r
- &EndOfDxeEvent\r
- );\r
-\r
- // Declare the related ACPI Tables\r
- EfiCreateProtocolNotifyEvent (\r
- &gEfiAcpiTableProtocolGuid,\r
- TPL_CALLBACK,\r
- AcpiPciNotificationEvent,\r
- NULL,\r
- &mAcpiRegistration\r
- );\r
- }\r
-\r
- //\r
- // Set up the device path to the FDT.\r
- //\r
- TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoFdtDevicePath);\r
- if (TextDevicePath != NULL) {\r
- TextDevicePathSize = StrSize (TextDevicePath);\r
- Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);\r
- Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
- } else {\r
- Status = EFI_NOT_FOUND;\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- DEBUG (\r
- (EFI_D_ERROR,\r
- "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)\r
- );\r
- return Status;\r
- }\r
-\r
- return Status;\r
-}\r