summaryrefslogtreecommitdiff
path: root/EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c
diff options
context:
space:
mode:
Diffstat (limited to 'EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c')
-rw-r--r--EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c545
1 files changed, 545 insertions, 0 deletions
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 <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;
+ 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
+ );
+}