From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) by mx.groups.io with SMTP id smtpd.web10.3740.1588589859007985952 for ; Mon, 04 May 2020 03:57:39 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@nuviainc-com.20150623.gappssmtp.com header.s=20150623 header.b=ZR8lTKPe; spf=pass (domain: nuviainc.com, ip: 209.85.128.66, mailfrom: leif@nuviainc.com) Received: by mail-wm1-f66.google.com with SMTP id 188so7907813wmc.2 for ; Mon, 04 May 2020 03:57:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nuviainc-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=VtmOXK/HQdduXcdW9RBNTMD74/MUx0LU0jbMKRuYVr8=; b=ZR8lTKPeeH0wDcDxILJdFBk+x6c7pEe/r0QbMIyZ0w3yPSx7a4uxnfohSpWBGN8X8b +gn+SxJC0z+j9G3uLSVNETFAxH+5ktlHkb3+PUiVoRbznJszCSMepB7KNzrhPZ5a88O3 zwLbX6buvML1zbFq4vfKLnlTDH3gwdcSRTw3EPSnI7RatBleIo5P82fu7DrextK2FZ6d eF840QhgSi5TE4XBck77J5jsu8lLZCLU3n/OVu+v+mnT8aikQ9Xk5zBwTknyIkjplkOc eoJOevdfzIoq2+QjZoPTRm6/KwhGmjPpDw4dx9Nwl2wzH7FBbCHH+6MPMx2pZYHNHPXC rgKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=VtmOXK/HQdduXcdW9RBNTMD74/MUx0LU0jbMKRuYVr8=; b=dPzAD9FpCUIPyC3+DBy7nL1J3vDkCGVd3GduZvLc7uvG3YYBI/dfpYpzPxmUsJXpe0 HsiXkGDex70q+4MPvnJ4iH+v0gbriXlEE0B3WqjitrRDaE+7YFxid4KTUHxqOBktw1IE NH4PDcJBSDOsYrrTSWeukmB98ohyzLwhaawPMZj4AEXhzsIDEhRKiL8mvSHbRtjiP5zU yOGuGj1u74gNTLDPbcFoe4qAKqu8nBECdsK8kFwbLv7aOagb0HJOUztgnJsWanPXOozy DmyxEfiJJnBTO9qXSCNP+OtUfzGGTYM59i/QoTNO+y+lY94kOtERgr5tfue4D8lOMhcm lPEA== X-Gm-Message-State: AGi0Pub2rOeYp/9ZxYjXuhMk+4Nw1deIp8uIiDrLhAxu8gcNBMjYpN+R sWHbmzFplb6Y3Z3vcxrx32Vj0A== X-Google-Smtp-Source: APiQypIjAPSSXkWAwZCPjnvqVknFPCIg+2jwisX8t2VeDvjKHqBauxp0iTPdLsxT9TmDR2eUu8puEA== X-Received: by 2002:a7b:c118:: with SMTP id w24mr13519493wmi.173.1588589856706; Mon, 04 May 2020 03:57:36 -0700 (PDT) Return-Path: Received: from vanye ([2001:470:1f09:12f0:b26e:bfff:fea9:f1b8]) by smtp.gmail.com with ESMTPSA id g69sm13695143wmg.17.2020.05.04.03.57.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 May 2020 03:57:36 -0700 (PDT) Date: Mon, 4 May 2020 11:57:34 +0100 From: "Leif Lindholm" To: Ard Biesheuvel Cc: devel@edk2.groups.io Subject: Re: [PATCH edk2-platforms v3 3/8] Platform/ARM/JunoPkg: incorporate SiI3132 SATA controller driver Message-ID: <20200504105734.GC21486@vanye> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> <20200430171650.24139-4-ard.biesheuvel@arm.com> MIME-Version: 1.0 In-Reply-To: <20200430171650.24139-4-ard.biesheuvel@arm.com> User-Agent: Mutt/1.10.1 (2018-07-13) Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 > Reviewed-by: Leif Lindholm > --- > 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 > + > +#include > +#include > +#include > +#include > + > +#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 > + > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#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 > +#include > + > +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 >