+/**\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
+ 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