From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from foss.arm.com (foss.arm.com [217.140.101.70]) by ml01.01.org (Postfix) with ESMTP id DCC4E821AC for ; Tue, 13 Dec 2016 17:56:17 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3D5E5F; Tue, 13 Dec 2016 17:56:17 -0800 (PST) Received: from usa.arm.com (unknown [10.119.48.27]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id AD6273F45C; Tue, 13 Dec 2016 17:56:16 -0800 (PST) From: Daniil Egranov To: edk2-devel@lists.01.org Cc: leif.lindholm@linaro.org, ryan.harkin@linaro.org, Daniil Egranov Date: Tue, 13 Dec 2016 19:56:09 -0600 Message-Id: <1481680569-89827-1-git-send-email-daniil.egranov@arm.com> X-Mailer: git-send-email 2.7.4 Subject: [PATCH v3] ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe: Set Marvell Yukon MAC address X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Dec 2016 01:56:18 -0000 Changed code structure per Leif Lindholm's request Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Daniil Egranov --- Changelog: v2 Corrected style issues and code structure. v1 The patch reads a valid MAC address form the Juno IOFPGA registers and pushes it into onboard Marvell Yukon NIC. .../ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c | 270 +++++++++++++++++++++ .../Drivers/ArmJunoDxe/ArmJunoDxeInternal.h | 13 + 2 files changed, 283 insertions(+) diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c index b97f044..bc3a433 100644 --- a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c @@ -15,7 +15,9 @@ #include "ArmJunoDxeInternal.h" #include +#include #include +#include #include #include @@ -69,6 +71,271 @@ STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = { EFI_EVENT mAcpiRegistration = NULL; /** + This function reads PCI ID of the controller. + + @param[in] PciIo PCI IO protocol handle + @param[in] PciId Looking for specified PCI ID Vendor/Device +**/ +STATIC +EFI_STATUS +ReadMarvellYoukonPciId ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 PciId + ) +{ + UINT32 DevicePciId; + EFI_STATUS Status; + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + PCI_VENDOR_ID_OFFSET, + 1, + &DevicePciId); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DevicePciId != PciId) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + This function searches for Marvell Yukon NIC on the Juno + platform and returns PCI IO protocol handle for the controller. + + @param[out] PciIo PCI IO protocol handle +**/ +STATIC +EFI_STATUS +GetMarvellYukonPciIoProtocol ( + OUT EFI_PCI_IO_PROTOCOL **PciIo + ) +{ + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN HIndex; + EFI_STATUS Status; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + if (EFI_ERROR (Status)) { + return (Status); + } + + for (HIndex = 0; HIndex < HandleCount; ++HIndex) { + Status = gBS->OpenProtocol ( + HandleBuffer[HIndex], + &gEfiPciIoProtocolGuid, + (VOID **) PciIo, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + continue; + } + + Status = ReadMarvellYoukonPciId (*PciIo, JUNO_MARVELL_YUKON_ID); + if (EFI_ERROR (Status)) { + // According to UEFI Spec 2.6 for EFI_BOOT_SERVICES.OpenProtocol(): + // when protocol was opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL attribute, + // the caller is not required to close the protocol interface with + // EFI_BOOT_SERVICES.CloseProtocol(). + continue; + } else { + break; + } + } + + gBS->FreePool (HandleBuffer); + + return Status; +} + +/** + This function restore the original controller attributes and free resources + + @param[in] PciIo PCI IO protocol handle + @param[in] PciAttr PCI controller attributes. + @param[in] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR +**/ +STATIC +VOID +FreePciResources ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT64 PciAttr, + IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor + ) +{ + // According to UEFI Spec 2.6 for EFI_BOOT_SERVICES.OpenProtocol(): + // when protocol was opened with EFI_OPEN_PROTOCOL_GET_PROTOCOL attribute, + // the caller is not required to close the protocol interface with + // EFI_BOOT_SERVICES.CloseProtocol(). + + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + PciAttr, + NULL + ); + + if (AcpiResDescriptor != NULL) { + gBS->FreePool (AcpiResDescriptor); + } +} + +/** + This function provides PCI MMIO base address, old PCI controller attributes + and ACPI resource descriptors for the BAR. + + @param[in] PciIo PCI IO protocol handle + @param[out] PciRegBase PCI base MMIO address + @param[out] OldPciAttr Old PCI controller attributes. + @param[out] AcpiResDescriptor ACPI 2.0 resource descriptors for the BAR +**/ +STATIC +EFI_STATUS +GetPciResources ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT32 *PciRegBase, + OUT UINT64 *OldPciAttr, + OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **AcpiResDescriptor + ) +{ + UINT64 AttrSupports; + EFI_STATUS Status; + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationGet, + 0, + OldPciAttr); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &AttrSupports); + if (EFI_ERROR (Status)) { + return Status; + } + + AttrSupports &= EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + AttrSupports, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciIo->GetBarAttributes (PciIo, 0, &AttrSupports, (VOID**)AcpiResDescriptor); + if (EFI_ERROR (Status)) { + FreePciResources (PciIo, *OldPciAttr, NULL); + return Status; + } + + if ((*AcpiResDescriptor)->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && + (*AcpiResDescriptor)->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && + !((*AcpiResDescriptor)->SpecificFlag & ACPI_SPECFLAG_PREFETCHABLE)) { + *PciRegBase = (*AcpiResDescriptor)->AddrRangeMin; + } else { + FreePciResources (PciIo, *OldPciAttr, *AcpiResDescriptor); + Status = EFI_UNSUPPORTED; + } + + return Status; +} + +/** + This function reads MAC address from IOFPGA and writes it to Marvell Yukon NIC + + @param[in] PciRegBase PCI base MMIO address +**/ +STATIC +EFI_STATUS +WriteMacAddress ( + IN UINT32 PciRegBase + ) +{ + UINT32 MacHigh; + UINT32 MacLow; + + // Read MAC address from IOFPGA + MacHigh= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H); + MacLow = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L); + + // Set software reset control register to protect from deactivation + // the config write state + MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR); + + // Convert to Marvell MAC Address register format + MacHigh = SwapBytes32 ((MacHigh & 0xFFFF) << 16 | + (MacLow & 0xFFFF0000) >> 16); + MacLow = SwapBytes32 (MacLow) >> 16; + + // Set MAC Address + MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_ENABLE); + MmioWrite32 (PciRegBase + R_MAC, MacHigh); + MmioWrite32 (PciRegBase + R_MAC_MAINT, MacHigh); + MmioWrite32 (PciRegBase + R_MAC + R_MAC_LOW, MacLow); + MmioWrite32 (PciRegBase + R_MAC_MAINT + R_MAC_LOW, MacLow); + MmioWrite8 (PciRegBase + R_TST_CTRL_1, TST_CFG_WRITE_DISABLE); + + // Initiate device reset + MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_SET); + MmioWrite16 (PciRegBase + R_CONTROL_STATUS, CS_RESET_CLR); + + return EFI_SUCCESS; +} + +/** + The function reads MAC address from Juno IOFPGA registers and writes it + into Marvell Yukon NIC. +**/ +STATIC +EFI_STATUS +ArmJunoSetNicMacAddress () +{ + + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiResDescriptor; + UINT64 OldPciAttr; + EFI_PCI_IO_PROTOCOL* PciIo; + UINT32 PciRegBase; + EFI_STATUS Status; + + Status = GetMarvellYukonPciIoProtocol (&PciIo); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetPciResources (PciIo, &PciRegBase, &OldPciAttr, &AcpiResDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = WriteMacAddress (PciRegBase); + if (EFI_ERROR (Status)) { + return Status; + } + + FreePciResources (PciIo, OldPciAttr, AcpiResDescriptor); + + return EFI_SUCCESS; +} + +/** Notification function of the event defined as belonging to the EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in the entry point of the driver. @@ -106,6 +373,9 @@ OnEndOfDxe ( Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE); ASSERT_EFI_ERROR (Status); + + Status = ArmJunoSetNicMacAddress (); + ASSERT_EFI_ERROR (Status); } STATIC diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h index 662c413..df02770 100644 --- a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h +++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h @@ -29,6 +29,19 @@ #include +#define ACPI_SPECFLAG_PREFETCHABLE 0x06 +#define JUNO_MARVELL_YUKON_ID 0x438011AB /* Juno Marvell PCI Dev ID */ +#define TST_CFG_WRITE_ENABLE 0x02 /* Enable Config Write */ +#define TST_CFG_WRITE_DISABLE 0x00 /* Disable Config Write */ +#define CS_RESET_CLR 0x02 /* SW Reset Clear */ +#define CS_RESET_SET 0x00 /* SW Reset Set */ +#define R_CONTROL_STATUS 0x0004 /* Control/Status Register */ +#define R_MAC 0x0100 /* MAC Address */ +#define R_MAC_MAINT 0x0110 /* MAC Address Maintenance */ +#define R_MAC_LOW 0x04 /* MAC Address Low Register Offset */ +#define R_TST_CTRL_1 0x0158 /* Test Control Register 1 */ + + EFI_STATUS PciEmulationEntryPoint ( VOID -- 2.7.4