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
>
next prev parent 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