public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Leif Lindholm" <leif@nuviainc.com>
To: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: devel@edk2.groups.io
Subject: Re: [PATCH edk2-platforms v3 3/8] Platform/ARM/JunoPkg: incorporate SiI3132 SATA controller driver
Date: Mon, 4 May 2020 11:57:34 +0100	[thread overview]
Message-ID: <20200504105734.GC21486@vanye> (raw)
In-Reply-To: <20200430171650.24139-4-ard.biesheuvel@arm.com>

On Thu, Apr 30, 2020 at 19:16:44 +0200, Ard Biesheuvel wrote:
> Juno is the only user of the SiI3132 SATA controller driver, which
> is not quite fit for reuse in its current state. So incorporate it
> into JunoPkg so we will be able to drop it from the core EDK2
> repository.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Reviewed-by: Leif Lindholm <leif@nuviainc.com>
> ---
>  Platform/ARM/JunoPkg/ArmJuno.dec                                 |   4 +-
>  Platform/ARM/JunoPkg/ArmJuno.dsc                                 |   2 +-
>  Platform/ARM/JunoPkg/ArmJuno.fdf                                 |   2 +-
>  Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c      | 179 +++++
>  Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c        | 546 +++++++++++++
>  Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h        | 286 +++++++
>  Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf   |  38 +
>  Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c | 834 ++++++++++++++++++++
>  8 files changed, 1888 insertions(+), 3 deletions(-)
> 
> diff --git a/Platform/ARM/JunoPkg/ArmJuno.dec b/Platform/ARM/JunoPkg/ArmJuno.dec
> index 27fe75790721..37ea6857366f 100644
> --- a/Platform/ARM/JunoPkg/ArmJuno.dec
> +++ b/Platform/ARM/JunoPkg/ArmJuno.dec
> @@ -28,6 +28,9 @@ [Guids.common]
>  [PcdsFeatureFlag.common]
>    gArmJunoTokenSpaceGuid.PcdPciMaxPayloadFixup|FALSE|BOOLEAN|0x00000013
>  
> +  gArmJunoTokenSpaceGuid.PcdSataSiI3132FeaturePMPSupport|FALSE|BOOLEAN|0x00000018
> +  gArmJunoTokenSpaceGuid.PcdSataSiI3132FeatureDirectCommandIssuing|FALSE|BOOLEAN|0x00000019
> +
>  [PcdsFixedAtBuild.common]
>    gArmJunoTokenSpaceGuid.PcdPcieControlBaseAddress|0x7FF20000|UINT64|0x0000000B
>    gArmJunoTokenSpaceGuid.PcdPcieRootPortBaseAddress|0x7FF30000|UINT64|0x0000000C
> @@ -54,4 +57,3 @@ [PcdsFixedAtBuild.common]
>    #
>    # For a list of mode numbers look in HdLcdArmJuno.c
>    gArmJunoTokenSpaceGuid.PcdArmHdLcdMaxMode|0|UINT32|0x00000017
> -
> diff --git a/Platform/ARM/JunoPkg/ArmJuno.dsc b/Platform/ARM/JunoPkg/ArmJuno.dsc
> index 954faca1bbfa..1c39da4897ed 100644
> --- a/Platform/ARM/JunoPkg/ArmJuno.dsc
> +++ b/Platform/ARM/JunoPkg/ArmJuno.dsc
> @@ -314,7 +314,7 @@ [Components.common]
>    # SATA Controller
>    #
>    MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
> -  EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf
> +  Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf
>  
>    #
>    # NVMe boot devices
> diff --git a/Platform/ARM/JunoPkg/ArmJuno.fdf b/Platform/ARM/JunoPkg/ArmJuno.fdf
> index 7c128b2c5bff..d771cbf35790 100644
> --- a/Platform/ARM/JunoPkg/ArmJuno.fdf
> +++ b/Platform/ARM/JunoPkg/ArmJuno.fdf
> @@ -184,7 +184,7 @@ [FV.FvMain]
>    # SATA Controller
>    #
>    INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
> -  INF EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf
> +  INF Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf
>  
>    #
>    # NVMe boot devices
> diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c
> new file mode 100644
> index 000000000000..944e827f7170
> --- /dev/null
> +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c
> @@ -0,0 +1,179 @@
> +/** @file
> +  UEFI Component Name(2) protocol implementation for Silicon Image I3132 SATA controller
> +
> +  WARNING:
> +  This driver fails to follow the UEFI driver model without a good
> +  reason, and only remains in the tree because it is still used by
> +  a small number of platforms. It will be removed when no longer used.
> +  New platforms should not use it, and no one should use this as
> +  reference code for developing new drivers.
> +
> +  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "SataSiI3132.h"
> +
> +//
> +// EFI Component Name Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSataSiI3132ComponentName = {
> +  SataSiI3132ComponentNameGetDriverName,
> +  SataSiI3132ComponentNameGetControllerName,
> +  "eng"
> +};
> +
> +//
> +// EFI Component Name 2 Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSataSiI3132ComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SataSiI3132ComponentNameGetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SataSiI3132ComponentNameGetControllerName,
> +  "en"
> +};
> +
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSataSiI3132DriverNameTable[] = {
> +  { "eng;en", L"Pci SATA Silicon Image 3132 Driver" },
> +  { NULL , NULL }
> +};
> +
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the driver.
> +
> +  This function retrieves the user readable name of a driver in the form of a
> +  Unicode string. If the driver specified by This has a user readable name in
> +  the language specified by Language, then a pointer to the driver name is
> +  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> +  by This does not support the language specified by Language,
> +  then EFI_UNSUPPORTED is returned.
> +
> +  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> +  @param  Language[in]          A pointer to a Null-terminated ASCII string
> +                                array indicating the language. This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified
> +                                in RFC 4646 or ISO 639-2 language code format.
> +
> +  @param  DriverName[out]       A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                driver specified by This in the language
> +                                specified by Language.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
> +                                This and the language specified by Language was
> +                                returned in DriverName.
> +
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER DriverName is NULL.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132ComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  )
> +{
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           mSataSiI3132DriverNameTable,
> +           DriverName,
> +           (BOOLEAN)(This == &gSataSiI3132ComponentName)
> +           );
> +}
> +
> +/**
> +  Retrieves a Unicode string that is the user readable name of the controller
> +  that is being managed by a driver.
> +
> +  This function retrieves the user readable name of the controller specified by
> +  ControllerHandle and ChildHandle in the form of a Unicode string. If the
> +  driver specified by This has a user readable name in the language specified by
> +  Language, then a pointer to the controller name is returned in ControllerName,
> +  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
> +  managing the controller specified by ControllerHandle and ChildHandle,
> +  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
> +  support the language specified by Language, then EFI_UNSUPPORTED is returned.
> +
> +  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> +  @param  ControllerHandle[in]  The handle of a controller that the driver
> +                                specified by This is managing.  This handle
> +                                specifies the controller whose name is to be
> +                                returned.
> +
> +  @param  ChildHandle[in]       The handle of the child controller to retrieve
> +                                the name of.  This is an optional parameter that
> +                                may be NULL.  It will be NULL for device
> +                                drivers.  It will also be NULL for a bus drivers
> +                                that wish to retrieve the name of the bus
> +                                controller.  It will not be NULL for a bus
> +                                driver that wishes to retrieve the name of a
> +                                child controller.
> +
> +  @param  Language[in]          A pointer to a Null-terminated ASCII string
> +                                array indicating the language.  This is the
> +                                language of the driver name that the caller is
> +                                requesting, and it must match one of the
> +                                languages specified in SupportedLanguages. The
> +                                number of languages supported by a driver is up
> +                                to the driver writer. Language is specified in
> +                                RFC 4646 or ISO 639-2 language code format.
> +
> +  @param  ControllerName[out]   A pointer to the Unicode string to return.
> +                                This Unicode string is the name of the
> +                                controller specified by ControllerHandle and
> +                                ChildHandle in the language specified by
> +                                Language from the point of view of the driver
> +                                specified by This.
> +
> +  @retval EFI_SUCCESS           The Unicode string for the user readable name in
> +                                the language specified by Language for the
> +                                driver specified by This was returned in
> +                                DriverName.
> +
> +  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
> +
> +  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
> +                                EFI_HANDLE.
> +
> +  @retval EFI_INVALID_PARAMETER Language is NULL.
> +
> +  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
> +                                managing the controller specified by
> +                                ControllerHandle and ChildHandle.
> +
> +  @retval EFI_UNSUPPORTED       The driver specified by This does not support
> +                                the language specified by Language.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132ComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> +  IN  EFI_HANDLE                                      ControllerHandle,
> +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> +  IN  CHAR8                                           *Language,
> +  OUT CHAR16                                          **ControllerName
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c
> new file mode 100644
> index 000000000000..ad7cc1cd75a1
> --- /dev/null
> +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c
> @@ -0,0 +1,546 @@
> +/** @file
> +  PCIe Sata support for the Silicon Image I3132
> +
> +  WARNING:
> +  This driver fails to follow the UEFI driver model without a good
> +  reason, and only remains in the tree because it is still used by
> +  a small number of platforms. It will be removed when no longer used.
> +  New platforms should not use it, and no one should use this as
> +  reference code for developing new drivers.
> +
> +  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "SataSiI3132.h"
> +
> +#include <IndustryStandard/Acpi10.h>
> +
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/DxeServicesTableLib.h>
> +#include <Library/BaseLib.h>
> +
> +#define ACPI_SPECFLAG_PREFETCHABLE      0x06
> +
> +EFI_DRIVER_BINDING_PROTOCOL
> +gSataSiI3132DriverBinding = {
> +  SataSiI3132DriverBindingSupported,
> +  SataSiI3132DriverBindingStart,
> +  SataSiI3132DriverBindingStop,
> +  0x30,
> +  NULL,
> +  NULL
> +};
> +
> +EFI_STATUS
> +SataSiI3132PortConstructor (
> +  IN  SATA_SI3132_INSTANCE *SataSiI3132Instance,
> +  IN  UINTN                Index
> +  )
> +{
> +  EFI_STATUS            Status;
> +  SATA_SI3132_PORT      *Port;
> +  VOID                  *HostPRB;
> +  EFI_PHYSICAL_ADDRESS  PhysAddrHostPRB;
> +  VOID                  *PciAllocMappingPRB;
> +  UINTN                 NumberOfBytes;
> +
> +  Port = &(SataSiI3132Instance->Ports[Index]);
> +
> +  Port->Index    = Index;
> +  Port->RegBase  = Index * 0x2000;
> +  Port->Instance = SataSiI3132Instance;
> +  InitializeListHead (&(Port->Devices));
> +
> +  NumberOfBytes = sizeof (SATA_SI3132_PRB);
> +  Status = SataSiI3132Instance->PciIo->AllocateBuffer (
> +             SataSiI3132Instance->PciIo, AllocateAnyPages, EfiBootServicesData,
> +             EFI_SIZE_TO_PAGES (NumberOfBytes), &HostPRB, 0
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Check the alignment of the PCI Buffer
> +  ASSERT (((UINTN)HostPRB & (0x1000 - 1)) == 0);
> +  Status = SataSiI3132Instance->PciIo->Map (
> +             SataSiI3132Instance->PciIo, EfiPciIoOperationBusMasterCommonBuffer, HostPRB,
> +             &NumberOfBytes, &PhysAddrHostPRB, &PciAllocMappingPRB
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Port->HostPRB            = HostPRB;
> +  Port->PhysAddrHostPRB    = PhysAddrHostPRB;
> +  Port->PciAllocMappingPRB = PciAllocMappingPRB;
> +
> +  return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +SataSiI3132Constructor (
> +  IN  EFI_PCI_IO_PROTOCOL     *PciIo,
> +  OUT SATA_SI3132_INSTANCE**  SataSiI3132Instance
> +  )
> +{
> +  SATA_SI3132_INSTANCE    *Instance;
> +  EFI_ATA_PASS_THRU_MODE  *AtaPassThruMode;
> +
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Instance = (SATA_SI3132_INSTANCE*)AllocateZeroPool (sizeof (SATA_SI3132_INSTANCE));
> +  if (Instance == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Instance->Signature           = SATA_SII3132_SIGNATURE;
> +  Instance->PciIo               = PciIo;
> +
> +  AtaPassThruMode = (EFI_ATA_PASS_THRU_MODE*)AllocatePool (sizeof (EFI_ATA_PASS_THRU_MODE));
> +  AtaPassThruMode->Attributes = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;
> +  AtaPassThruMode->IoAlign = 0x1000;
> +
> +  // Initialize SiI3132 ports
> +  SataSiI3132PortConstructor (Instance, 0);
> +  SataSiI3132PortConstructor (Instance, 1);
> +
> +  // Set ATA Pass Thru Protocol
> +  Instance->AtaPassThruProtocol.Mode            = AtaPassThruMode;
> +  Instance->AtaPassThruProtocol.PassThru        = SiI3132AtaPassThru;
> +  Instance->AtaPassThruProtocol.GetNextPort     = SiI3132GetNextPort;
> +  Instance->AtaPassThruProtocol.GetNextDevice   = SiI3132GetNextDevice;
> +  Instance->AtaPassThruProtocol.BuildDevicePath = SiI3132BuildDevicePath;
> +  Instance->AtaPassThruProtocol.GetDevice       = SiI3132GetDevice;
> +  Instance->AtaPassThruProtocol.ResetPort       = SiI3132ResetPort;
> +  Instance->AtaPassThruProtocol.ResetDevice     = SiI3132ResetDevice;
> +
> +  *SataSiI3132Instance = Instance;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +SiI3132SoftResetCommand (
> +  IN   SATA_SI3132_PORT *Port,
> +  OUT  UINT32* Signature
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_ATA_PASS_THRU_COMMAND_PACKET  Packet;
> +  EFI_ATA_STATUS_BLOCK              Asb;
> +  EFI_ATA_COMMAND_BLOCK             Acb;
> +  CONST UINT16                      PortMultiplierPort = 0;
> +
> +  ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
> +
> +  Acb.Reserved1[1] = 0;
> +
> +  Packet.Asb      = &Asb;
> +  Packet.Acb      = &Acb;
> +  Packet.Timeout  = 100000;
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET;
> +
> +  Status = SiI3132AtaPassThruCommand (Port->Instance, Port, PortMultiplierPort, &Packet, 0);
> +
> +  if (Status == EFI_SUCCESS) {
> +    *Signature = (Asb.AtaCylinderHigh << 24) | (Asb.AtaCylinderLow << 16) |
> +                 (Asb.AtaSectorNumber << 8 ) | (Asb.AtaSectorCount);
> +  }
> +  return Status;
> +}
> +
> +EFI_STATUS
> +SataSiI3132PortInitialization (
> +  IN SATA_SI3132_PORT *Port
> +  )
> +{
> +  UINT32                  Value32;
> +  SATA_SI3132_DEVICE*     Device;
> +  UINT32                  Signature;
> +  EFI_STATUS              Status;
> +  EFI_PCI_IO_PROTOCOL*    PciIo;
> +
> +  Status = SiI3132HwResetPort (Port);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  PciIo = Port->Instance->PciIo;
> +
> +  // Is a device is present ?
> +  Status = SATA_PORT_READ32 (Port->RegBase + SII3132_PORT_SSTATUS_REG, &Value32);
> +  if (!EFI_ERROR (Status) && (Value32 & 0x3)) {
> +    // Do a soft reset to see if it is a port multiplier
> +    SATA_TRACE ("SataSiI3132PortInitialization: soft reset - it is a port multiplier\n");
> +    Status = SiI3132SoftResetCommand (Port, &Signature);
> +    if (!EFI_ERROR (Status)) {
> +      if (Signature == SII3132_PORT_SIGNATURE_PMP) {
> +        SATA_TRACE ("SataSiI3132PortInitialization(): a Port Multiplier is present");
> +        if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
> +          ASSERT (0); // Not supported yet
> +        } else {
> +          return EFI_UNSUPPORTED;
> +        }
> +      } else if (Signature == SII3132_PORT_SIGNATURE_ATAPI) {
> +        ASSERT (0); // Not supported yet
> +        SATA_TRACE ("SataSiI3132PortInitialization(): an ATAPI device is present");
> +        return EFI_UNSUPPORTED;
> +      } else if (Signature == SII3132_PORT_SIGNATURE_ATA) {
> +        SATA_TRACE ("SataSiI3132PortInitialization(): an ATA device is present");
> +      } else {
> +        SATA_TRACE ("SataSiI3132PortInitialization(): Present device unknown!");
> +        ASSERT (0); // Not supported
> +        return EFI_UNSUPPORTED;
> +      }
> +
> +      // Create Device
> +      Device            = (SATA_SI3132_DEVICE*)AllocatePool (sizeof (SATA_SI3132_DEVICE));
> +      Device->Index     = Port->Index; //TODO: Could need to be fixed when SATA Port Multiplier support
> +      Device->Port      = Port;
> +      Device->BlockSize = 0;
> +
> +      // Attached the device to the Sata Port
> +      InsertTailList (&Port->Devices, &Device->Link);
> +
> +      SATA_TRACE ("SataSiI3132PortInitialization(): Port Ready");
> +    }
> +  }
> +  return Status;
> +}
> +
> +EFI_STATUS
> +SataSiI3132Initialization (
> +  IN SATA_SI3132_INSTANCE* SataSiI3132Instance
> +  )
> +{
> +  UINTN                 Index;
> +  EFI_PCI_IO_PROTOCOL*  PciIo;
> +
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PciIo = SataSiI3132Instance->PciIo;
> +
> +  // Turn Off GPIO
> +  SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_FLASHADDR_REG, 0x0);
> +
> +  // Clear Global Control Register
> +  SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_CONTROL_REG, 0x0);
> +
> +  for (Index = 0; Index < SATA_SII3132_MAXPORT; Index++) {
> +    SataSiI3132PortInitialization (&(SataSiI3132Instance->Ports[Index]));
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Test to see if this driver supports ControllerHandle.
> +
> +  @param  This                 Protocol instance pointer.
> +  @param  Controller           Handle of device to test.
> +  @param  RemainingDevicePath  Not used.
> +
> +  @return EFI_SUCCESS          This driver supports this device.
> +  @return EFI_UNSUPPORTED      This driver does not support this device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132DriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS              Status;
> +  EFI_PCI_IO_PROTOCOL     *PciIo;
> +  UINT32                   PciID;
> +
> +  //
> +  // Test whether there is PCI IO Protocol attached on the controller handle.
> +  //
> +  Status = gBS->OpenProtocol (
> +                Controller,
> +                &gEfiPciIoProtocolGuid,
> +                (VOID **) &PciIo,
> +                This->DriverBindingHandle,
> +                Controller,
> +                EFI_OPEN_PROTOCOL_BY_DRIVER
> +                );
> +  if (EFI_ERROR (Status)) {
> +      return Status;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                      PciIo,
> +                      EfiPciIoWidthUint32,
> +                      PCI_VENDOR_ID_OFFSET,
> +                      1,
> +                      &PciID
> +                      );
> +  if (EFI_ERROR (Status)) {
> +      Status = EFI_UNSUPPORTED;
> +      goto ON_EXIT;
> +  }
> +
> +  //
> +  // Test whether the controller belongs to SATA Mass Storage type
> +  //
> +  if (PciID != ((SATA_SII3132_DEVICE_ID << 16) | SATA_SII3132_VENDOR_ID)) {
> +      Status = EFI_UNSUPPORTED;
> +  }
> +
> +ON_EXIT:
> +  gBS->CloseProtocol (
> +       Controller,
> +       &gEfiPciIoProtocolGuid,
> +       This->DriverBindingHandle,
> +       Controller
> +       );
> +
> +  return Status;
> +}
> +
> +BOOLEAN mbStarted = FALSE;
> +
> +/**
> +  Starting the Pci SATA Driver.
> +
> +  @param  This                 Protocol instance pointer.
> +  @param  Controller           Handle of device to test.
> +  @param  RemainingDevicePath  Not used.
> +
> +  @return EFI_SUCCESS          supports this device.
> +  @return EFI_UNSUPPORTED      do not support this device.
> +  @return EFI_DEVICE_ERROR     cannot be started due to device Error.
> +  @return EFI_OUT_OF_RESOURCES cannot allocate resources.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132DriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS              Status;
> +  EFI_PCI_IO_PROTOCOL     *PciIo;
> +  UINT64                  Supports;
> +  UINT64                  OriginalPciAttributes;
> +  BOOLEAN                 PciAttributesSaved;
> +  UINT32                  PciID;
> +  SATA_SI3132_INSTANCE    *SataSiI3132Instance = NULL;
> +
> +  SATA_TRACE ("SataSiI3132DriverBindingStart()");
> +
> +  //TODO: Find a nicer way to do it !
> +  if (mbStarted) {
> +    return EFI_SUCCESS; // Don't restart me !
> +  }
> +
> +  //
> +  // Open the PciIo Protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +                Controller,
> +                &gEfiPciIoProtocolGuid,
> +                (VOID **) &PciIo,
> +                This->DriverBindingHandle,
> +                Controller,
> +                EFI_OPEN_PROTOCOL_BY_DRIVER
> +                );
> +  if (EFI_ERROR (Status)) {
> +      return Status;
> +  }
> +
> +  PciAttributesSaved = FALSE;
> +  //
> +  // Save original PCI attributes
> +  //
> +  Status = PciIo->Attributes (
> +                  PciIo,
> +                  EfiPciIoAttributeOperationGet,
> +                  0,
> +                  &OriginalPciAttributes
> +                  );
> +  if (EFI_ERROR (Status)) {
> +      goto CLOSE_PCIIO;
> +  }
> +  PciAttributesSaved = TRUE;
> +
> +  Status = PciIo->Attributes (
> +                  PciIo,
> +                  EfiPciIoAttributeOperationSupported,
> +                  0,
> +                  &Supports
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +      Supports &= EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
> +      Status = PciIo->Attributes (
> +                        PciIo,
> +                        EfiPciIoAttributeOperationEnable,
> +                        Supports,
> +                        NULL
> +                        );
> +  }
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_ERROR, "SataSiI3132DriverBindingStart: failed to enable controller\n"));
> +    goto CLOSE_PCIIO;
> +  }
> +
> +  //
> +  // Get the Pci device class code.
> +  //
> +  Status = PciIo->Pci.Read (
> +                      PciIo,
> +                      EfiPciIoWidthUint32,
> +                      PCI_VENDOR_ID_OFFSET,
> +                      1,
> +                      &PciID
> +                      );
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_UNSUPPORTED;
> +    goto CLOSE_PCIIO;
> +  }
> +
> +  //
> +  // Test whether the controller belongs to SATA Mass Storage type
> +  //
> +  if (PciID != ((SATA_SII3132_DEVICE_ID << 16) | SATA_SII3132_VENDOR_ID)) {
> +    Status = EFI_UNSUPPORTED;
> +    goto CLOSE_PCIIO;
> +  }
> +
> +  // Create SiI3132 Sata Instance
> +  Status = SataSiI3132Constructor (PciIo, &SataSiI3132Instance);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Initialize SiI3132 Sata Controller
> +  Status = SataSiI3132Initialization (SataSiI3132Instance);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Install Ata Pass Thru Protocol
> +  Status = gBS->InstallProtocolInterface (
> +              &Controller,
> +              &gEfiAtaPassThruProtocolGuid,
> +              EFI_NATIVE_INTERFACE,
> +              &(SataSiI3132Instance->AtaPassThruProtocol)
> +              );
> +  if (EFI_ERROR (Status)) {
> +    goto FREE_POOL;
> +  }
> +
> +/*  //
> +  // Create event to stop the HC when exit boot service.
> +  //
> +  Status = gBS->CreateEventEx (
> +                EVT_NOTIFY_SIGNAL,
> +                TPL_NOTIFY,
> +                EhcExitBootService,
> +                Ehc,
> +                &gEfiEventExitBootServicesGuid,
> +                &Ehc->ExitBootServiceEvent
> +                );
> +  if (EFI_ERROR (Status)) {
> +      goto UNINSTALL_USBHC;
> +  }*/
> +
> +  mbStarted = TRUE;
> +
> +  SATA_TRACE ("SataSiI3132DriverBindingStart() Success!");
> +  return EFI_SUCCESS;
> +
> +FREE_POOL:
> +  //TODO: Free SATA Instance
> +
> +CLOSE_PCIIO:
> +  if (PciAttributesSaved) {
> +      //
> +      // Restore original PCI attributes
> +      //
> +      PciIo->Attributes (
> +                      PciIo,
> +                      EfiPciIoAttributeOperationSet,
> +                      OriginalPciAttributes,
> +                      NULL
> +                      );
> +  }
> +
> +  gBS->CloseProtocol (
> +       Controller,
> +       &gEfiPciIoProtocolGuid,
> +       This->DriverBindingHandle,
> +       Controller
> +       );
> +
> +  return Status;
> +}
> +
> +/**
> +  Stop this driver on ControllerHandle. Support stopping any child handles
> +  created by this driver.
> +
> +  @param  This                 Protocol instance pointer.
> +  @param  Controller           Handle of device to stop driver on.
> +  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
> +  @param  ChildHandleBuffer    List of handles for the children we need to stop.
> +
> +  @return EFI_SUCCESS          Success.
> +  @return EFI_DEVICE_ERROR     Fail.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132DriverBindingStop (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN UINTN                       NumberOfChildren,
> +  IN EFI_HANDLE                  *ChildHandleBuffer
> +  )
> +{
> +  SATA_TRACE ("SataSiI3132DriverBindingStop()");
> +  return EFI_UNSUPPORTED;
> +}
> +
> +/**
> +  Entry point of this driver
> +
> +  @param ImageHandle     Handle of driver image
> +  @param SystemTable     Point to EFI_SYSTEM_TABLE
> +
> +  @retval EFI_OUT_OF_RESOURCES  Can not allocate memory resource
> +  @retval EFI_DEVICE_ERROR      Can not install the protocol instance
> +  @retval EFI_SUCCESS           Success to initialize the Pci host bridge.
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitializeSataSiI3132 (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  SATA_TRACE ("InitializeSataSiI3132 ()");
> +
> +  return EfiLibInstallDriverBindingComponentName2 (
> +         ImageHandle,
> +         SystemTable,
> +         &gSataSiI3132DriverBinding,
> +         ImageHandle,
> +         &gSataSiI3132ComponentName,
> +         &gSataSiI3132ComponentName2
> +         );
> +}
> diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h
> new file mode 100644
> index 000000000000..f799fe84a047
> --- /dev/null
> +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h
> @@ -0,0 +1,286 @@
> +/** @file
> +  Header containing the structure specific to the Silicon Image I3132 Sata PCI card
> +
> +  WARNING:
> +  This driver fails to follow the UEFI driver model without a good
> +  reason, and only remains in the tree because it is still used by
> +  a small number of platforms. It will be removed when no longer used.
> +  New platforms should not use it, and no one should use this as
> +  reference code for developing new drivers.
> +
> +  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __SATASII3132_H
> +#define __SATASII3132_H
> +
> +#include <PiDxe.h>
> +
> +#include <Protocol/AtaPassThru.h>
> +#include <Protocol/PciIo.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include <IndustryStandard/Pci.h>
> +
> +#define SATA_SII3132_DEVICE_ID      0x3132
> +#define SATA_SII3132_VENDOR_ID      0x1095
> +
> +#define SII3132_PORT_SIGNATURE_PMP      0x96690101
> +#define SII3132_PORT_SIGNATURE_ATAPI    0xEB140101
> +#define SII3132_PORT_SIGNATURE_ATA      0x00000101
> +
> +/*
> + * Silicon Image SiI3132 Registers
> + */
> +#define SII3132_GLOBAL_CONTROL_REG              0x40
> +#define SII3132_GLOBAL_FLASHADDR_REG            0x70
> +
> +#define SII3132_PORT_STATUS_REG                 0x1000
> +#define SII3132_PORT_CONTROLSET_REG             0x1000
> +#define SII3132_PORT_CONTROLCLEAR_REG           0x1004
> +#define SII3132_PORT_INTSTATUS_REG              0x1008
> +#define SII3132_PORT_ENABLEINT_REG              0x1010
> +#define SII3132_PORT_INTCLEAR_REG               0x1014
> +#define SII3132_PORT_32BITACTIVADDR_REG         0x101C
> +#define SII3132_PORT_CMDEXECFIFO_REG            0x1020
> +#define SII3132_PORT_CMDERROR_REG               0x1024
> +#define SII3132_PORT_ERRCOUNTDECODE             0x1040
> +#define SII3132_PORT_ERRCOUNTCRC                0x1044
> +#define SII3132_PORT_ERRCOUNTHANDSHAKE          0x1048
> +#define SII3132_PORT_SLOTSTATUS_REG             0x1800
> +#define SII3132_PORT_CMDACTIV_REG               0x1C00
> +#define SII3132_PORT_SSTATUS_REG                0x1F04
> +
> +#define SII3132_PORT_CONTROL_RESET              (1 << 0)
> +#define SII3132_PORT_DEVICE_RESET               (1 << 1)
> +#define SII3132_PORT_CONTROL_INT                (1 << 2)
> +#define SII3132_PORT_CONTROL_32BITACTIVATION    (1 << 10)
> +
> +#define SII3132_PORT_STATUS_PORTREADY           0x80000000
> +
> +#define SII3132_PORT_INT_CMDCOMPL               (1 << 0)
> +#define SII3132_PORT_INT_CMDERR                 (1 << 1)
> +#define SII3132_PORT_INT_PORTRDY                (1 << 2)
> +
> +#define SATA_SII3132_MAXPORT    2
> +
> +#define PRB_CTRL_ATA            0x0
> +#define PRB_CTRL_PROT_OVERRIDE  0x1
> +#define PRB_CTRL_RESTRANSMIT    0x2
> +#define PRB_CTRL_EXT_CMD        0x4
> +#define PRB_CTRL_RCV            0x8
> +#define PRB_CTRL_PKT_READ       0x10
> +#define PRB_CTRL_PKT_WRITE      0x20
> +#define PRB_CTRL_INT_MASK       0x40
> +#define PRB_CTRL_SRST           0x80
> +
> +#define PRB_PROT_PACKET         0x01
> +#define PRB_PROT_LEGACY_QUEUE   0x02
> +#define PRB_PROT_NATIVE_QUEUE   0x04
> +#define PRB_PROT_READ           0x08
> +#define PRB_PROT_WRITE          0x10
> +#define PRB_PROT_TRANSPARENT    0x20
> +
> +#define SGE_XCF     (1 << 28)
> +#define SGE_DRD     (1 << 29)
> +#define SGE_LNK     (1 << 30)
> +#define SGE_TRM     0x80000000
> +
> +typedef struct _SATA_SI3132_SGE {
> +    UINT32      DataAddressLow;
> +    UINT32      DataAddressHigh;
> +    UINT32      DataCount;
> +    UINT32      Attributes;
> +} SATA_SI3132_SGE;
> +
> +typedef struct _SATA_SI3132_FIS {
> +    UINT8               FisType;
> +    UINT8               Control;
> +    UINT8               Command;
> +    UINT8               Features;
> +    UINT8               Fis[5 * 4];
> +} SATA_SI3132_FIS;
> +
> +typedef struct _SATA_SI3132_PRB {
> +    UINT16              Control;
> +    UINT16              ProtocolOverride;
> +    UINT32              RecTransCount;
> +    SATA_SI3132_FIS     Fis;
> +    SATA_SI3132_SGE     Sge[2];
> +} SATA_SI3132_PRB;
> +
> +typedef struct _SATA_SI3132_DEVICE {
> +    LIST_ENTRY                  Link; // This attribute must be the first entry of this structure (to avoid pointer computation)
> +    UINTN                       Index;
> +    struct _SATA_SI3132_PORT    *Port;  //Parent Port
> +    UINT32                      BlockSize;
> +} SATA_SI3132_DEVICE;
> +
> +typedef struct _SATA_SI3132_PORT {
> +    UINTN                           Index;
> +    UINTN                           RegBase;
> +    struct _SATA_SI3132_INSTANCE    *Instance;
> +
> +    //TODO: Support Port multiplier
> +    LIST_ENTRY                      Devices;
> +
> +    SATA_SI3132_PRB*                HostPRB;
> +    EFI_PHYSICAL_ADDRESS            PhysAddrHostPRB;
> +    VOID*                           PciAllocMappingPRB;
> +} SATA_SI3132_PORT;
> +
> +typedef struct _SATA_SI3132_INSTANCE {
> +    UINTN                       Signature;
> +
> +    SATA_SI3132_PORT            Ports[SATA_SII3132_MAXPORT];
> +
> +    EFI_ATA_PASS_THRU_PROTOCOL  AtaPassThruProtocol;
> +
> +    EFI_PCI_IO_PROTOCOL         *PciIo;
> +} SATA_SI3132_INSTANCE;
> +
> +#define SATA_SII3132_SIGNATURE              SIGNATURE_32('s', 'i', '3', '2')
> +#define INSTANCE_FROM_ATAPASSTHRU_THIS(a)   CR(a, SATA_SI3132_INSTANCE, AtaPassThruProtocol, SATA_SII3132_SIGNATURE)
> +
> +#define SATA_GLOBAL_READ32(Offset, Value)  PciIo->Mem.Read (PciIo, EfiPciIoWidthUint32, 0, Offset, 1, Value)
> +#define SATA_GLOBAL_WRITE32(Offset, Value) { UINT32 Value32 = Value; PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 0, Offset, 1, &Value32); }
> +
> +#define SATA_PORT_READ32(Offset, Value)  PciIo->Mem.Read (PciIo, EfiPciIoWidthUint32, 1, Offset, 1, Value)
> +#define SATA_PORT_WRITE32(Offset, Value) { UINT32 Value32 = Value; PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 1, Offset, 1, &Value32); }
> +
> +#define SATA_TRACE(txt)  DEBUG((EFI_D_VERBOSE, "ARM_SATA: " txt "\n"))
> +
> +extern EFI_COMPONENT_NAME_PROTOCOL  gSataSiI3132ComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL gSataSiI3132ComponentName2;
> +
> +/*
> + * Component Name Protocol Functions
> + */
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132ComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132ComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> +  IN  EFI_HANDLE                                      ControllerHandle,
> +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> +  IN  CHAR8                                           *Language,
> +  OUT CHAR16                                          **ControllerName
> +  );
> +
> +EFI_STATUS SiI3132HwResetPort (SATA_SI3132_PORT *Port);
> +
> +/*
> + * Driver Binding Protocol Functions
> + */
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132DriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132DriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SataSiI3132DriverBindingStop (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  Controller,
> +  IN UINTN                       NumberOfChildren,
> +  IN EFI_HANDLE                  *ChildHandleBuffer
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132AtaPassThruCommand (
> +  IN     SATA_SI3132_INSTANCE             *pSataSiI3132Instance,
> +  IN     SATA_SI3132_PORT                 *pSataPort,
> +  IN     UINT16                           PortMultiplierPort,
> +  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
> +  IN     EFI_EVENT                        Event OPTIONAL
> +  );
> +
> +/**
> + * EFI ATA Pass Thru Protocol
> + */
> +EFI_STATUS
> +EFIAPI
> +SiI3132AtaPassThru (
> +  IN     EFI_ATA_PASS_THRU_PROTOCOL       *This,
> +  IN     UINT16                           Port,
> +  IN     UINT16                           PortMultiplierPort,
> +  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
> +  IN     EFI_EVENT                        Event OPTIONAL
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132GetNextPort (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN OUT UINT16                 *Port
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132GetNextDevice (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN UINT16                     Port,
> +  IN OUT UINT16                 *PortMultiplierPort
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132BuildDevicePath (
> +  IN     EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN     UINT16                     Port,
> +  IN     UINT16                     PortMultiplierPort,
> +  IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132GetDevice (
> +  IN  EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN  EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
> +  OUT UINT16                     *Port,
> +  OUT UINT16                     *PortMultiplierPort
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132ResetPort (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN UINT16                     Port
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132ResetDevice (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN UINT16                     Port,
> +  IN UINT16                     PortMultiplierPort
> +  );
> +
> +#endif
> diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf
> new file mode 100644
> index 000000000000..a73b3bc168a8
> --- /dev/null
> +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf
> @@ -0,0 +1,38 @@
> +#/** @file
> +#  INF file for the Silicon Image I3132 SATA controller
> +#
> +#  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent

Comment only:
This file, unlike some other .infs in this series, does not include
the WARNING header. Feel free to fold one in before pushing.

/
    Leif

> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 1.27
> +  BASE_NAME                      = SataSiI3132Dxe
> +  FILE_GUID                      = 1df18da0-a18b-11df-8c3a-0002a5d5c51b
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = InitializeSataSiI3132
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  Platform/ARM/JunoPkg/ArmJuno.dec
> +
> +[LibraryClasses]
> +  MemoryAllocationLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +
> +[Sources]
> +  ComponentName.c
> +  SataSiI3132.c
> +  SiI3132AtaPassThru.c
> +
> +[Protocols]
> +  gEfiPciIoProtocolGuid                         # CONSUMED
> +  gEfiAtaPassThruProtocolGuid                   # PRODUCED
> +
> +[Pcd]
> +  gArmJunoTokenSpaceGuid.PcdSataSiI3132FeaturePMPSupport
> +  gArmJunoTokenSpaceGuid.PcdSataSiI3132FeatureDirectCommandIssuing
> diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c
> new file mode 100644
> index 000000000000..f15b59788310
> --- /dev/null
> +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c
> @@ -0,0 +1,834 @@
> +/** @file
> +
> +  WARNING:
> +  This driver fails to follow the UEFI driver model without a good
> +  reason, and only remains in the tree because it is still used by
> +  a small number of platforms. It will be removed when no longer used.
> +  New platforms should not use it, and no one should use this as
> +  reference code for developing new drivers.
> +
> +  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "SataSiI3132.h"
> +
> +#include <IndustryStandard/Atapi.h>
> +#include <Library/DevicePathLib.h>
> +
> +SATA_SI3132_DEVICE*
> +GetSataDevice (
> +  IN  SATA_SI3132_INSTANCE* SataInstance,
> +  IN  UINT16 Port,
> +  IN  UINT16 PortMultiplierPort
> +) {
> +  LIST_ENTRY              *List;
> +  SATA_SI3132_PORT        *SataPort;
> +  SATA_SI3132_DEVICE      *SataDevice;
> +
> +  if (Port >= SATA_SII3132_MAXPORT) {
> +    return NULL;
> +  }
> +
> +  SataPort = &(SataInstance->Ports[Port]);
> +  List = SataPort->Devices.ForwardLink;
> +
> +  while (List != &SataPort->Devices) {
> +    SataDevice = (SATA_SI3132_DEVICE*)List;
> +    if (SataDevice->Index == PortMultiplierPort) {
> +      return SataDevice;
> +    }
> +    List = List->ForwardLink;
> +  }
> +  return NULL;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +SiI3132AtaPassThruCommand (
> +  IN     SATA_SI3132_INSTANCE             *SataSiI3132Instance,
> +  IN     SATA_SI3132_PORT                 *SataPort,
> +  IN     UINT16                           PortMultiplierPort,
> +  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
> +  IN     EFI_EVENT                        Event OPTIONAL
> +  )
> +{
> +  SATA_SI3132_DEVICE      *SataDevice;
> +  EFI_PHYSICAL_ADDRESS    PhysInDataBuffer;
> +  UINTN                   InDataBufferLength = 0;
> +  EFI_PHYSICAL_ADDRESS    PhysOutDataBuffer;
> +  UINTN                   OutDataBufferLength;
> +  CONST UINTN             EmptySlot = 0;
> +  UINTN                   Control = PRB_CTRL_ATA;
> +  UINTN                   Protocol = 0;
> +  UINT32                  Value32, Error, Timeout = 0;
> +  CONST UINT32            IrqMask = (SII3132_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR) << 16;
> +  EFI_STATUS              Status;
> +  VOID*                   PciAllocMapping = NULL;
> +  EFI_PCI_IO_PROTOCOL     *PciIo;
> +
> +  PciIo = SataSiI3132Instance->PciIo;
> +  ZeroMem (SataPort->HostPRB, sizeof (SATA_SI3132_PRB));
> +
> +  // Construct Si3132 PRB
> +  switch (Packet->Protocol) {
> +  case EFI_ATA_PASS_THRU_PROTOCOL_ATA_HARDWARE_RESET:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET:
> +    SATA_TRACE ("SiI3132AtaPassThru() EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET");
> +    Control = PRB_CTRL_SRST;
> +
> +    if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
> +        SataPort->HostPRB->Fis.Control = 0x0F;
> +    }
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +
> +  // There is no difference for SiI3132 between PIO and DMA invokation
> +  case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:
> +  case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
> +    // Fixup the size for block transfer. Following UEFI Specification, 'InTransferLength' should
> +    // be in number of bytes. But for most data transfer commands, the value is in number of blocks
> +    if (Packet->Acb->AtaCommand == ATA_CMD_IDENTIFY_DRIVE) {
> +      InDataBufferLength = Packet->InTransferLength;
> +    } else {
> +      SataDevice = GetSataDevice (SataSiI3132Instance, SataPort->Index, PortMultiplierPort);
> +      if (!SataDevice || (SataDevice->BlockSize == 0)) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +
> +      InDataBufferLength = Packet->InTransferLength * SataDevice->BlockSize;
> +    }
> +
> +    Status = PciIo->Map (
> +               PciIo, EfiPciIoOperationBusMasterWrite,
> +               Packet->InDataBuffer, &InDataBufferLength, &PhysInDataBuffer, &PciAllocMapping
> +               );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    // Construct SGEs (32-bit system)
> +    SataPort->HostPRB->Sge[0].DataAddressLow = (UINT32)PhysInDataBuffer;
> +    SataPort->HostPRB->Sge[0].DataAddressHigh = (UINT32)(PhysInDataBuffer >> 32);
> +    SataPort->HostPRB->Sge[0].Attributes = SGE_TRM; // Only one SGE
> +    SataPort->HostPRB->Sge[0].DataCount = InDataBufferLength;
> +
> +    // Copy the Ata Command Block
> +    CopyMem (&SataPort->HostPRB->Fis, Packet->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
> +
> +    // Fixup the FIS
> +    SataPort->HostPRB->Fis.FisType = 0x27; // Register - Host to Device FIS
> +    SataPort->HostPRB->Fis.Control = 1 << 7; // Is a command
> +    if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
> +      SataPort->HostPRB->Fis.Control |= PortMultiplierPort & 0xFF;
> +    }
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:
> +  case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
> +    SataDevice = GetSataDevice (SataSiI3132Instance, SataPort->Index, PortMultiplierPort);
> +    if (!SataDevice || (SataDevice->BlockSize == 0)) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    // Fixup the size for block transfer. Following UEFI Specification, 'InTransferLength' should
> +    // be in number of bytes. But for most data transfer commands, the value is in number of blocks
> +    OutDataBufferLength = Packet->OutTransferLength * SataDevice->BlockSize;
> +
> +    Status = PciIo->Map (
> +               PciIo, EfiPciIoOperationBusMasterRead,
> +               Packet->OutDataBuffer, &OutDataBufferLength, &PhysOutDataBuffer, &PciAllocMapping
> +               );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    // Construct SGEs (32-bit system)
> +    SataPort->HostPRB->Sge[0].DataAddressLow  = (UINT32)PhysOutDataBuffer;
> +    SataPort->HostPRB->Sge[0].DataAddressHigh = (UINT32)(PhysOutDataBuffer >> 32);
> +    SataPort->HostPRB->Sge[0].Attributes      = SGE_TRM; // Only one SGE
> +    SataPort->HostPRB->Sge[0].DataCount       = OutDataBufferLength;
> +
> +    // Copy the Ata Command Block
> +    CopyMem (&SataPort->HostPRB->Fis, Packet->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
> +
> +    // Fixup the FIS
> +    SataPort->HostPRB->Fis.FisType = 0x27; // Register - Host to Device FIS
> +    SataPort->HostPRB->Fis.Control = 1 << 7; // Is a command
> +    if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
> +      SataPort->HostPRB->Fis.Control |= PortMultiplierPort & 0xFF;
> +    }
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_DMA:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_DMA_QUEUED:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_DIAGNOSTIC:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_RESET:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_FPDMA:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  case EFI_ATA_PASS_THRU_PROTOCOL_RETURN_RESPONSE:
> +    ASSERT (0); //TODO: Implement me!
> +    break;
> +  default:
> +    ASSERT (0);
> +    break;
> +  }
> +
> +  SataPort->HostPRB->Control = Control;
> +  SataPort->HostPRB->ProtocolOverride = Protocol;
> +
> +  // Clear IRQ
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, IrqMask);
> +
> +  if (!FeaturePcdGet (PcdSataSiI3132FeatureDirectCommandIssuing)) {
> +    // Indirect Command Issuance
> +
> +    //TODO: Find which slot is free (maybe use the Cmd FIFO)
> +    //SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, &EmptySlot);
> +
> +    SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDACTIV_REG + (EmptySlot * 8),
> +                     (UINT32)(SataPort->PhysAddrHostPRB & 0xFFFFFFFF));
> +    SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDACTIV_REG + (EmptySlot * 8) + 4,
> +                     (UINT32)((SataPort->PhysAddrHostPRB >> 32) & 0xFFFFFFFF));
> +  } else {
> +    // Direct Command Issuance
> +    Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 1, // Bar 1
> +        SataPort->RegBase + (EmptySlot * 0x80),
> +        sizeof (SATA_SI3132_PRB) / 4,
> +        SataPort->HostPRB);
> +    ASSERT_EFI_ERROR (Status);
> +
> +    SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, EmptySlot);
> +  }
> +
> +#if 0
> +  // Could need to be implemented if we run multiple command in parallel to know which slot has been completed
> +  SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_SLOTSTATUS_REG, &Value32);
> +  Timeout = Packet->Timeout;
> +  while (!Timeout && !Value32) {
> +    gBS->Stall (1);
> +    SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_SLOTSTATUS_REG, &Value32);
> +    Timeout--;
> +  }
> +#else
> +  SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
> +  if (!Packet->Timeout) {
> +    while (!(Value32 & IrqMask)) {
> +      gBS->Stall (1);
> +      SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
> +    }
> +  } else {
> +    Timeout = Packet->Timeout;
> +    while (Timeout && !(Value32 & IrqMask)) {
> +      gBS->Stall (1);
> +      SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
> +      Timeout--;
> +    }
> +  }
> +#endif
> +  // Fill Packet Ata Status Block
> +  Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint32, 1, // Bar 1
> +      SataPort->RegBase + 0x08,
> +      sizeof (EFI_ATA_STATUS_BLOCK) / 4,
> +      Packet->Asb);
> +  ASSERT_EFI_ERROR (Status);
> +
> +
> +  if ((Packet->Timeout != 0) && (Timeout == 0)) {
> +    DEBUG ((EFI_D_ERROR, "SiI3132AtaPassThru() Err:Timeout\n"));
> +    //ASSERT (0);
> +    return EFI_TIMEOUT;
> +  } else if (Value32 & (SII3132_PORT_INT_CMDERR << 16)) {
> +    SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDERROR_REG, &Error);
> +    DEBUG ((EFI_D_ERROR, "SiI3132AtaPassThru() CmdErr:0x%X (SiI3132 Err:0x%X)\n", Value32, Error));
> +    ASSERT (0);
> +    return EFI_DEVICE_ERROR;
> +  } else if (Value32 & (SII3132_PORT_INT_CMDCOMPL << 16)) {
> +    // Clear Command Complete
> +    SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, SII3132_PORT_INT_CMDCOMPL << 16);
> +
> +    if (PciAllocMapping) {
> +      Status = PciIo->Unmap (PciIo, PciAllocMapping);
> +      ASSERT (!EFI_ERROR (Status));
> +    }
> +
> +    // If the command was ATA_CMD_IDENTIFY_DRIVE then we need to update the BlockSize
> +    if (Packet->Acb->AtaCommand == ATA_CMD_IDENTIFY_DRIVE) {
> +      ATA_IDENTIFY_DATA *IdentifyData = (ATA_IDENTIFY_DATA*)Packet->InDataBuffer;
> +
> +      // Get the corresponding Block Device
> +      SataDevice = GetSataDevice (SataSiI3132Instance, SataPort->Index, PortMultiplierPort);
> +
> +      // Check logical block size
> +      if ((IdentifyData->phy_logic_sector_support & BIT12) != 0) {
> +        ASSERT (SataDevice != NULL);
> +        SataDevice->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) |
> +                                            IdentifyData->logic_sector_size_lo) * sizeof (UINT16));
> +      } else {
> +        SataDevice->BlockSize = 0x200;
> +      }
> +    }
> +    return EFI_SUCCESS;
> +  } else {
> +    ASSERT (0);
> +    return EFI_DEVICE_ERROR;
> +  }
> +}
> +
> +/**
> +  Sends an ATA command to an ATA device that is attached to the ATA controller. This function
> +  supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,
> +  and the non-blocking I/O functionality is optional.
> +
> +  @param[in]     This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in]     Port                The port number of the ATA device to send the command.
> +  @param[in]     PortMultiplierPort  The port multiplier port number of the ATA device to send the command.
> +                                     If there is no port multiplier, then specify 0.
> +  @param[in,out] Packet              A pointer to the ATA command to send to the ATA device specified by Port
> +                                     and PortMultiplierPort.
> +  @param[in]     Event               If non-blocking I/O is not supported then Event is ignored, and blocking
> +                                     I/O is performed. If Event is NULL, then blocking I/O is performed. If
> +                                     Event is not NULL and non blocking I/O is supported, then non-blocking
> +                                     I/O is performed, and Event will be signaled when the ATA command completes.
> +
> +  @retval EFI_SUCCESS                The ATA command was sent by the host. For bi-directional commands,
> +                                     InTransferLength bytes were transferred from InDataBuffer. For write and
> +                                     bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.
> +  @retval EFI_BAD_BUFFER_SIZE        The ATA command was not executed. The number of bytes that could be transferred
> +                                     is returned in InTransferLength. For write and bi-directional commands,
> +                                     OutTransferLength bytes were transferred by OutDataBuffer.
> +  @retval EFI_NOT_READY              The ATA command could not be sent because there are too many ATA commands
> +                                     already queued. The caller may retry again later.
> +  @retval EFI_DEVICE_ERROR           A device error occurred while attempting to send the ATA command.
> +  @retval EFI_INVALID_PARAMETER      Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA
> +                                     command was not sent, so no additional status information is available.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132AtaPassThru (
> +  IN     EFI_ATA_PASS_THRU_PROTOCOL       *This,
> +  IN     UINT16                           Port,
> +  IN     UINT16                           PortMultiplierPort,
> +  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
> +  IN     EFI_EVENT                        Event OPTIONAL
> +  )
> +{
> +  SATA_SI3132_INSTANCE    *SataSiI3132Instance;
> +  SATA_SI3132_DEVICE      *SataDevice;
> +  SATA_SI3132_PORT        *SataPort;
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SataDevice = GetSataDevice (SataSiI3132Instance, Port, PortMultiplierPort);
> +  if (!SataDevice) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  SataPort = SataDevice->Port;
> +
> +  DEBUG ((EFI_D_INFO, "SiI3132AtaPassThru(%d,%d) : AtaCmd:0x%X Prot:%d\n", Port, PortMultiplierPort,
> +         Packet->Acb->AtaCommand, Packet->Protocol));
> +
> +  return SiI3132AtaPassThruCommand (SataSiI3132Instance, SataPort, PortMultiplierPort, Packet, Event);
> +}
> +
> +/**
> +  Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
> +  These can either be the list of ports where ATA devices are actually present or the
> +  list of legal port numbers for the ATA controller. Regardless, the caller of this
> +  function must probe the port number returned to see if an ATA device is actually
> +  present at that location on the ATA controller.
> +
> +  The GetNextPort() function retrieves the port number on an ATA controller. If on input
> +  Port is 0xFFFF, then the port number of the first port on the ATA controller is returned
> +  in Port and EFI_SUCCESS is returned.
> +
> +  If Port is a port number that was returned on a previous call to GetNextPort(), then the
> +  port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS
> +  is returned. If Port is not 0xFFFF and Port was not returned on a previous call to
> +  GetNextPort(), then EFI_INVALID_PARAMETER is returned.
> +
> +  If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is
> +  returned.
> +
> +  @param[in]     This           A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in,out] Port           On input, a pointer to the port number on the ATA controller.
> +                                On output, a pointer to the next port number on the ATA
> +                                controller. An input value of 0xFFFF retrieves the first port
> +                                number on the ATA controller.
> +
> +  @retval EFI_SUCCESS           The next port number on the ATA controller was returned in Port.
> +  @retval EFI_NOT_FOUND         There are no more ports on this ATA controller.
> +  @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call
> +                                to GetNextPort().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132GetNextPort (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN OUT UINT16                 *Port
> +  )
> +{
> +  SATA_SI3132_INSTANCE    *SataSiI3132Instance;
> +  UINTN                   PrevPort;
> +  EFI_STATUS              Status = EFI_SUCCESS;
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PrevPort = *Port;
> +
> +  if (PrevPort == 0xFFFF) {
> +    *Port = 0;
> +  } else {
> +    if (PrevPort < SATA_SII3132_MAXPORT) {
> +        *Port = PrevPort + 1;
> +    } else {
> +        Status = EFI_NOT_FOUND;
> +    }
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA
> +  controller. These can either be the list of port multiplier ports where ATA devices are actually
> +  present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this
> +  function must probe the port number and port multiplier port number returned to see if an ATA
> +  device is actually present.
> +
> +  The GetNextDevice() function retrieves the port multiplier port number of an ATA device
> +  present on a port of an ATA controller.
> +
> +  If PortMultiplierPort points to a port multiplier port number value that was returned on a
> +  previous call to GetNextDevice(), then the port multiplier port number of the next ATA device
> +  on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
> +  returned.
> +
> +  If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first
> +  ATA device on port of the ATA controller is returned in PortMultiplierPort and
> +  EFI_SUCCESS is returned.
> +
> +  If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
> +  was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
> +  is returned.
> +
> +  If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of
> +  the ATA controller, then EFI_NOT_FOUND is returned.
> +
> +  @param[in]     This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in]     Port                The port number present on the ATA controller.
> +  @param[in,out] PortMultiplierPort  On input, a pointer to the port multiplier port number of an
> +                                     ATA device present on the ATA controller.
> +                                     If on input a PortMultiplierPort of 0xFFFF is specified,
> +                                     then the port multiplier port number of the first ATA device
> +                                     is returned. On output, a pointer to the port multiplier port
> +                                     number of the next ATA device present on an ATA controller.
> +
> +  @retval EFI_SUCCESS                The port multiplier port number of the next ATA device on the port
> +                                     of the ATA controller was returned in PortMultiplierPort.
> +  @retval EFI_NOT_FOUND              There are no more ATA devices on this port of the ATA controller.
> +  @retval EFI_INVALID_PARAMETER      PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not
> +                                     returned on a previous call to GetNextDevice().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132GetNextDevice (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN UINT16                     Port,
> +  IN OUT UINT16                 *PortMultiplierPort
> +  )
> +{
> +  SATA_SI3132_INSTANCE    *SataSiI3132Instance;
> +  SATA_SI3132_PORT        *SataPort;
> +  SATA_SI3132_DEVICE      *SataDevice;
> +  LIST_ENTRY              *List;
> +  EFI_STATUS              Status = EFI_SUCCESS;
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Port >= SATA_SII3132_MAXPORT) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SataPort = &(SataSiI3132Instance->Ports[Port]);
> +
> +  if (*PortMultiplierPort == 0xFFFF) {
> +    List = SataPort->Devices.ForwardLink;
> +    if (List != &SataPort->Devices) {
> +      // The list is not empty, return the first device
> +      *PortMultiplierPort = ((SATA_SI3132_DEVICE*)List)->Index;
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +  } else {
> +    SataDevice = GetSataDevice (SataSiI3132Instance, Port, *PortMultiplierPort);
> +    if (SataDevice != NULL) {
> +      // We have found the previous port multiplier, return the next one
> +      List = SataDevice->Link.ForwardLink;
> +      if (List != &SataPort->Devices) {
> +        *PortMultiplierPort = ((SATA_SI3132_DEVICE*)List)->Index;
> +      } else {
> +        Status = EFI_NOT_FOUND;
> +      }
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +  }
> +  return Status;
> +}
> +
> +/**
> +  Used to allocate and build a device path node for an ATA device on an ATA controller.
> +
> +  The BuildDevicePath() function allocates and builds a single device node for the ATA
> +  device specified by Port and PortMultiplierPort. If the ATA device specified by Port and
> +  PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.
> +  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough
> +  resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
> +
> +  Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
> +  DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,
> +  and EFI_SUCCESS is returned.
> +
> +  @param[in]     This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in]     Port                Port specifies the port number of the ATA device for which a
> +                                     device path node is to be allocated and built.
> +  @param[in]     PortMultiplierPort  The port multiplier port number of the ATA device for which a
> +                                     device path node is to be allocated and built. If there is no
> +                                     port multiplier, then specify 0.
> +  @param[in,out] DevicePath          A pointer to a single device path node that describes the ATA
> +                                     device specified by Port and PortMultiplierPort. This function
> +                                     is responsible for allocating the buffer DevicePath with the
> +                                     boot service AllocatePool(). It is the caller's responsibility
> +                                     to free DevicePath when the caller is finished with DevicePath.
> +  @retval EFI_SUCCESS                The device path node that describes the ATA device specified by
> +                                     Port and PortMultiplierPort was allocated and returned in DevicePath.
> +  @retval EFI_NOT_FOUND              The ATA device specified by Port and PortMultiplierPort does not
> +                                     exist on the ATA controller.
> +  @retval EFI_INVALID_PARAMETER      DevicePath is NULL.
> +  @retval EFI_OUT_OF_RESOURCES       There are not enough resources to allocate DevicePath.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132BuildDevicePath (
> +  IN     EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN     UINT16                     Port,
> +  IN     UINT16                     PortMultiplierPort,
> +  IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath
> +  )
> +{
> +  SATA_SI3132_INSTANCE        *SataSiI3132Instance;
> +  SATA_SI3132_DEVICE          *SataDevice;
> +  EFI_DEVICE_PATH_PROTOCOL    *SiI3132DevicePath;
> +
> +  SATA_TRACE ("SiI3132BuildDevicePath()");
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  SataDevice = GetSataDevice (SataSiI3132Instance, Port, PortMultiplierPort);
> +  if (SataDevice == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  SiI3132DevicePath = CreateDeviceNode (MESSAGING_DEVICE_PATH, MSG_SATA_DP, sizeof (SATA_DEVICE_PATH));
> +  if (SiI3132DevicePath == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  ((SATA_DEVICE_PATH*)SiI3132DevicePath)->HBAPortNumber = Port;
> +  if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
> +    ((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = PortMultiplierPort;
> +  } else {
> +    //Temp:((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = SATA_HBA_DIRECT_CONNECT_FLAG;
> +    ((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = 0;
> +  }
> +  ((SATA_DEVICE_PATH*)SiI3132DevicePath)->Lun = Port; //TODO: Search information how to define properly LUN (Logical Unit Number)
> +
> +  *DevicePath = SiI3132DevicePath;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Used to translate a device path node to a port number and port multiplier port number.
> +
> +  The GetDevice() function determines the port and port multiplier port number associated with
> +  the ATA device described by DevicePath. If DevicePath is a device path node type that the
> +  ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents
> +  DevicePath into a port number and port multiplier port number.
> +
> +  If this translation is successful, then that port number and port multiplier port number are returned
> +  in Port and PortMultiplierPort, and EFI_SUCCESS is returned.
> +
> +  If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.
> +
> +  If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then
> +  EFI_UNSUPPORTED is returned.
> +
> +  If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not
> +  a valid translation from DevicePath to a port number and port multiplier port number, then
> +  EFI_NOT_FOUND is returned.
> +
> +  @param[in]  This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in]  DevicePath          A pointer to the device path node that describes an ATA device on the
> +                                  ATA controller.
> +  @param[out] Port                On return, points to the port number of an ATA device on the ATA controller.
> +  @param[out] PortMultiplierPort  On return, points to the port multiplier port number of an ATA device
> +                                  on the ATA controller.
> +
> +  @retval EFI_SUCCESS             DevicePath was successfully translated to a port number and port multiplier
> +                                  port number, and they were returned in Port and PortMultiplierPort.
> +  @retval EFI_INVALID_PARAMETER   DevicePath is NULL.
> +  @retval EFI_INVALID_PARAMETER   Port is NULL.
> +  @retval EFI_INVALID_PARAMETER   PortMultiplierPort is NULL.
> +  @retval EFI_UNSUPPORTED         This driver does not support the device path node type in DevicePath.
> +  @retval EFI_NOT_FOUND           A valid translation from DevicePath to a port number and port multiplier
> +                                  port number does not exist.
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132GetDevice (
> +  IN  EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN  EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
> +  OUT UINT16                     *Port,
> +  OUT UINT16                     *PortMultiplierPort
> +  )
> +{
> +  SATA_SI3132_INSTANCE        *SataSiI3132Instance;
> +
> +  SATA_TRACE ("SiI3132GetDevice()");
> +
> +  if (!DevicePath || !Port || !PortMultiplierPort) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || (DevicePath->SubType != MSG_SATA_DP)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (((SATA_DEVICE_PATH*)DevicePath)->Lun >= SATA_SII3132_MAXPORT) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
> +    ASSERT (0); //TODO: Implement me!
> +    return EFI_UNSUPPORTED;
> +  } else {
> +    *Port = ((SATA_DEVICE_PATH*)DevicePath)->Lun;
> +    // Return the first Sata Device as there should be only one directly connected
> +    *PortMultiplierPort = ((SATA_SI3132_DEVICE*)SataSiI3132Instance->Ports[*Port].Devices.ForwardLink)->Index;
> +    return EFI_SUCCESS;
> +  }
> +}
> +
> +EFI_STATUS
> +SiI3132HwResetPort (
> +  IN SATA_SI3132_PORT *SataPort
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  UINT32              Value32;
> +  UINTN               Timeout;
> +
> +  SATA_TRACE ("SiI3132HwResetPort()");
> +
> +  PciIo = SataPort->Instance->PciIo;
> +
> +  // Clear Port Reset
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CONTROLCLEAR_REG, SII3132_PORT_CONTROL_RESET);
> +
> +  SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32);
> +  ASSERT (!(Value32 & SII3132_PORT_CONTROL_RESET));
> +
> +  // Initialize error counters
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTDECODE, 0);
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTCRC, 0);
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTHANDSHAKE, 0);
> +
> +  // Enable interrupts for command completion and command errors
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ENABLEINT_REG, SII3132_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR);
> +
> +  // Clear IRQ
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ENABLEINT_REG, SII3132_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR | SII3132_PORT_INT_PORTRDY | (1 << 3));
> +
> +  // Wait until Port Ready
> +  SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
> +  Timeout = 1000;
> +  while ((Timeout > 0) && ((Value32 & SII3132_PORT_INT_PORTRDY) == 0)) {
> +    gBS->Stall (1);
> +    Timeout--;
> +    SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
> +  }
> +  // Clear IRQ
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, SII3132_PORT_INT_PORTRDY);
> +
> +  if (Timeout == 0) {
> +    SATA_TRACE ("SiI3132HwResetPort(): Timeout");
> +    return EFI_TIMEOUT;
> +  } else if ((Value32 & SII3132_PORT_INT_PORTRDY) == 0) {
> +    SATA_TRACE ("SiI3132HwResetPort(): Port Not Ready");
> +    return EFI_DEVICE_ERROR;
> +  } else {
> +    return EFI_SUCCESS;
> +  }
> +}
> +
> +/**
> +  Resets a specific port on the ATA controller. This operation also resets all the ATA devices
> +  connected to the port.
> +
> +  The ResetChannel() function resets an a specific port on an ATA controller. This operation
> +  resets all the ATA devices connected to that port. If this ATA controller does not support
> +  a reset port operation, then EFI_UNSUPPORTED is returned.
> +
> +  If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is
> +  returned.
> +
> +  If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.
> +
> +  If the port reset operation is completed, then EFI_SUCCESS is returned.
> +
> +  @param[in]  This          A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in]  Port          The port number on the ATA controller.
> +
> +  @retval EFI_SUCCESS       The ATA controller port was reset.
> +  @retval EFI_UNSUPPORTED   The ATA controller does not support a port reset operation.
> +  @retval EFI_DEVICE_ERROR  A device error occurred while attempting to reset the ATA port.
> +  @retval EFI_TIMEOUT       A timeout occurred while attempting to reset the ATA port.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132ResetPort (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN UINT16                     Port
> +  )
> +{
> +  SATA_SI3132_INSTANCE    *SataSiI3132Instance;
> +  SATA_SI3132_PORT        *SataPort;
> +
> +  SATA_TRACE ("SiI3132ResetPort()");
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Port >= SATA_SII3132_MAXPORT) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  SataPort = &(SataSiI3132Instance->Ports[Port]);
> +  return SiI3132HwResetPort (SataPort);
> +}
> +
> +/**
> +  Resets an ATA device that is connected to an ATA controller.
> +
> +  The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.
> +  If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is
> +  returned.
> +
> +  If Port or PortMultiplierPort are not in a valid range for this ATA controller, then
> +  EFI_INVALID_PARAMETER is returned.
> +
> +  If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR
> +  is returned.
> +
> +  If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is
> +  returned.
> +
> +  If the device reset operation is completed, then EFI_SUCCESS is returned.
> +
> +  @param[in] This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
> +  @param[in] Port                Port represents the port number of the ATA device to be reset.
> +  @param[in] PortMultiplierPort  The port multiplier port number of the ATA device to reset.
> +                                 If there is no port multiplier, then specify 0.
> +  @retval EFI_SUCCESS            The ATA device specified by Port and PortMultiplierPort was reset.
> +  @retval EFI_UNSUPPORTED        The ATA controller does not support a device reset operation.
> +  @retval EFI_INVALID_PARAMETER  Port or PortMultiplierPort are invalid.
> +  @retval EFI_DEVICE_ERROR       A device error occurred while attempting to reset the ATA device
> +                                 specified by Port and PortMultiplierPort.
> +  @retval EFI_TIMEOUT            A timeout occurred while attempting to reset the ATA device
> +                                 specified by Port and PortMultiplierPort.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SiI3132ResetDevice (
> +  IN EFI_ATA_PASS_THRU_PROTOCOL *This,
> +  IN UINT16                     Port,
> +  IN UINT16                     PortMultiplierPort
> +  )
> +{
> +  EFI_PCI_IO_PROTOCOL     *PciIo;
> +  SATA_SI3132_INSTANCE    *SataSiI3132Instance;
> +  SATA_SI3132_PORT        *SataPort;
> +  SATA_SI3132_DEVICE      *SataDevice;
> +  UINTN                   Timeout;
> +  UINT32                  Value32;
> +
> +  SATA_TRACE ("SiI3132ResetDevice()");
> +
> +  SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
> +  if (!SataSiI3132Instance) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  PciIo = SataSiI3132Instance->PciIo;
> +
> +  SataDevice = GetSataDevice (SataSiI3132Instance, Port, PortMultiplierPort);
> +  if (!SataDevice) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  SataPort = SataDevice->Port;
> +
> +  SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CONTROLSET_REG, SII3132_PORT_DEVICE_RESET);
> +
> +  Timeout = 100;
> +  SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32);
> +  while ((Timeout > 0) && ((Value32 & SII3132_PORT_DEVICE_RESET) != 0)) {
> +    gBS->Stall (1);
> +    SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32);
> +    Timeout--;
> +  }
> +
> +  if (Timeout == 0) {
> +    SATA_TRACE ("SiI3132ResetDevice(): Timeout");
> +    return EFI_TIMEOUT;
> +  } else {
> +    return EFI_SUCCESS;
> +  }
> +}
> -- 
> 2.17.1
> 

  reply	other threads:[~2020-05-04 10:57 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-30 17:16 [PATCH edk2-platforms v3 0/8] move obsolete platform drivers out of core edk2 Ard Biesheuvel
2020-04-30 17:16 ` [PATCH edk2-platforms v3 1/8] Omap35xxPkg/LcdGraphicsOutputDxe: add missing protocol reference Ard Biesheuvel
2020-04-30 17:16 ` [PATCH edk2-platforms v3 2/8] Platform/ARM/VExpressPkg: incorporate PL180 driver Ard Biesheuvel
2020-04-30 17:16 ` [PATCH edk2-platforms v3 3/8] Platform/ARM/JunoPkg: incorporate SiI3132 SATA controller driver Ard Biesheuvel
2020-05-04 10:57   ` Leif Lindholm [this message]
2020-04-30 17:16 ` [PATCH edk2-platforms v3 4/8] Silicon/Synopsys/DesignWare: import eMMC DXE driver from EmbeddedPkg Ard Biesheuvel
2020-05-04 10:58   ` Leif Lindholm
2020-05-04 11:40     ` [edk2-devel] " Philippe Mathieu-Daudé
2020-05-04 11:44       ` Philippe Mathieu-Daudé
2020-04-30 17:16 ` [PATCH edk2-platforms v3 5/8] Platform/HiKey: switch to relocated version of eMMC driver Ard Biesheuvel
2020-04-30 17:16 ` [PATCH edk2-platforms v3 6/8] Platform/ARM/VExpressPkg: incorporate Lan91x driver Ard Biesheuvel
2020-05-04 11:41   ` [edk2-devel] " Philippe Mathieu-Daudé
2020-05-04 11:44     ` Philippe Mathieu-Daudé
2020-04-30 17:16 ` [PATCH edk2-platforms v3 7/8] Platform/ARM/VExpressPkg: incorporate Lan9118 driver Ard Biesheuvel
2020-05-04 11:42   ` [edk2-devel] " Philippe Mathieu-Daudé
2020-05-04 11:44     ` Philippe Mathieu-Daudé
2020-04-30 17:16 ` [PATCH edk2-platforms v3 8/8] Platform/ARM/VExpressPkg: incorporate ISP 1761 USB host driver Ard Biesheuvel
2020-05-04 11:00   ` Leif Lindholm
2020-05-04 11:00 ` [PATCH edk2-platforms v3 0/8] move obsolete platform drivers out of core edk2 Leif Lindholm
2020-05-04 13:19   ` Ard Biesheuvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200504105734.GC21486@vanye \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox