From f63424474e8b022c0b7675d282c9b4c255a95ff4 Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Mon, 11 May 2015 17:50:27 +0000 Subject: EmbeddedPkg: Added SATA Silicon Image driver Note: This is the same SATA controller present on Juno R1. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin Reviewed-by: Ronald Cron git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17413 6f19259b-4bc3-4df7-8a09-765794883524 --- EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c | 545 +++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c (limited to 'EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c') diff --git a/EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c b/EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c new file mode 100644 index 0000000000..5a5526c0df --- /dev/null +++ b/EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c @@ -0,0 +1,545 @@ +/** @file +* PCIe Sata support for the Silicon Image I3132 +* +* Copyright (c) 2011-2015, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#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; + 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 stoping 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 + ); +} -- cgit v1.2.3