]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPlatformPkg/ArmJunoDxe: Set Marvell Yukon MAC address
authorDaniil Egranov <daniil.egranov@linaro.org>
Mon, 9 Jan 2017 21:20:51 +0000 (15:20 -0600)
committerLeif Lindholm <leif.lindholm@linaro.org>
Tue, 10 Jan 2017 22:27:58 +0000 (22:27 +0000)
The patch reads a valid MAC address from the Juno IOFPGA registers
and pushes it into onboard Marvell Yukon NIC.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Daniil Egranov <daniil.egranov@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxeInternal.h

index b97f044004341cfe3b645c8bbf4fcabf4671088d..47ff5871e30f869aaad69b3c7c1b47adec84a8da 100644 (file)
@@ -15,7 +15,9 @@
 #include "ArmJunoDxeInternal.h"\r
 #include <ArmPlatform.h>\r
 \r
 #include "ArmJunoDxeInternal.h"\r
 #include <ArmPlatform.h>\r
 \r
+#include <IndustryStandard/Pci.h>\r
 #include <Protocol/DevicePathFromText.h>\r
 #include <Protocol/DevicePathFromText.h>\r
+#include <Protocol/PciIo.h>\r
 #include <Protocol/PciRootBridgeIo.h>\r
 \r
 #include <Guid/EventGroup.h>\r
 #include <Protocol/PciRootBridgeIo.h>\r
 \r
 #include <Guid/EventGroup.h>\r
@@ -68,6 +70,290 @@ STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = {
 \r
 EFI_EVENT mAcpiRegistration = NULL;\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
+  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
 /**\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
@@ -106,6 +392,9 @@ OnEndOfDxe (
 \r
   Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE);\r
   ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = ArmJunoSetNicMacAddress ();\r
+  ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
 STATIC\r
 }\r
 \r
 STATIC\r
index 662c41377f45a522bfac63103746f5b79e0ffa5e..df0277067e3444707cc07cddf0333a47c6864199 100644 (file)
 \r
 #include <IndustryStandard/Acpi.h>\r
 \r
 \r
 #include <IndustryStandard/Acpi.h>\r
 \r
+#define ACPI_SPECFLAG_PREFETCHABLE    0x06\r
+#define JUNO_MARVELL_YUKON_ID         0x438011AB /* Juno Marvell PCI Dev ID */\r
+#define TST_CFG_WRITE_ENABLE          0x02       /* Enable Config Write */\r
+#define TST_CFG_WRITE_DISABLE         0x00       /* Disable Config Write */\r
+#define CS_RESET_CLR                  0x02       /* SW Reset Clear */\r
+#define CS_RESET_SET                  0x00       /* SW Reset Set */\r
+#define R_CONTROL_STATUS              0x0004     /* Control/Status Register */\r
+#define R_MAC                         0x0100     /* MAC Address */\r
+#define R_MAC_MAINT                   0x0110     /* MAC Address Maintenance */\r
+#define R_MAC_LOW                     0x04       /* MAC Address Low Register Offset */\r
+#define R_TST_CTRL_1                  0x0158     /* Test Control Register 1 */\r
+\r
+\r
 EFI_STATUS\r
 PciEmulationEntryPoint (\r
   VOID\r
 EFI_STATUS\r
 PciEmulationEntryPoint (\r
   VOID\r