Create a new Styx platform driver StyxSataPlatformDxe which contains the existing platform specific SATA initialization code, but uses the new platform PCI I/O driver to register the platform AHCI devices.
This has two advantages: - we can use generic drivers for the platform PCI I/O emulation, and for the AHCI support built on top of it, - we can register both SATA devices, allowing us to use all 14 ports on Overdrive B1
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel ard.biesheuvel@linaro.org --- Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/InitController.c | 181 ++++++++++++++++++++ Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/SataRegisters.h | 180 +++++++++++++++++++ Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/StyxSataPlatformDxe.inf | 61 +++++++ 3 files changed, 422 insertions(+)
diff --git a/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/InitController.c b/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/InitController.c new file mode 100644 index 000000000000..e9cc1f9d52c7 --- /dev/null +++ b/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/InitController.c @@ -0,0 +1,181 @@ +/** @file + Initialize SATA Phy, Serdes, and Controller. + + Copyright (c) 2014 - 2016, AMD Inc. All rights reserved.<BR> + Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR> + + 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 "SataRegisters.h" + +#include <Library/AmdSataInitLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PlatformPciIoDeviceRegistrationLib.h> + +STATIC +VOID +ResetSataController ( + EFI_PHYSICAL_ADDRESS AhciBaseAddr + ) +{ + // Make a minimal global reset for HBA regiser + MmioOr32 (AhciBaseAddr + EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET); + + // Clear all interrupts + MmioWrite32 (AhciBaseAddr + EFI_AHCI_PORT_IS, EFI_AHCI_PORT_IS_CLEAR); + + // Turn on interrupts and ensure that the HBA is working in AHCI mode + MmioOr32 (AhciBaseAddr + EFI_AHCI_GHC_OFFSET, + EFI_AHCI_GHC_IE | EFI_AHCI_GHC_ENABLE); +} + +STATIC +VOID +SetSataCapabilities ( + EFI_PHYSICAL_ADDRESS AhciBaseAddr + ) +{ + UINT32 Capability; + + Capability = 0; + if (FixedPcdGetBool (PcdSataSssSupport)) // Staggered Spin-Up Support bit + Capability |= EFI_AHCI_CAP_SSS; + if (FixedPcdGetBool (PcdSataSmpsSupport)) // Mechanical Presence Support bit + Capability |= EFI_AHCI_CAP_SMPS; + + MmioOr32 (AhciBaseAddr + EFI_AHCI_CAPABILITY_OFFSET, Capability); +} + +STATIC +VOID +InitializeSataPorts ( + EFI_PHYSICAL_ADDRESS AhciBaseAddr, + UINTN PortCount + ) +{ + INTN PortNum; + BOOLEAN IsCpd; + BOOLEAN IsMpsp; + UINT32 PortRegAddr; + UINT32 RegVal; + + // Set Ports Implemented (PI) + MmioWrite32 (AhciBaseAddr + EFI_AHCI_PI_OFFSET, (1 << PortCount) - 1); + + IsCpd = FixedPcdGetBool (PcdSataPortCpd); + IsMpsp = FixedPcdGetBool (PcdSataPortMpsp); + if (!IsCpd && !IsMpsp) { + return; + } + + for (PortNum = 0; PortNum < PortCount; PortNum++) { + PortRegAddr = EFI_AHCI_PORT_OFFSET (PortNum) + EFI_AHCI_PORT_CMD; + RegVal = MmioRead32(AhciBaseAddr + PortRegAddr); + if (IsCpd) + RegVal |= EFI_AHCI_PORT_CMD_CPD; + else + RegVal &= ~EFI_AHCI_PORT_CMD_CPD; + if (IsMpsp) + RegVal |= EFI_AHCI_PORT_CMD_MPSP; + else + RegVal &= ~EFI_AHCI_PORT_CMD_MPSP; + RegVal |= EFI_AHCI_PORT_CMD_HPCP; + MmioWrite32(AhciBaseAddr + PortRegAddr, RegVal); + } +} + +STATIC +EFI_STATUS +InitializeSataController ( + EFI_PHYSICAL_ADDRESS AhciBaseAddr, + UINTN SataPortCount, + UINTN StartPort + ) +{ + UINT8 SataChPerSerdes; + UINT32 PortNum; + UINT32 EvenPort; + UINT32 OddPort; + + SataChPerSerdes = FixedPcdGet8 (PcdSataNumChPerSerdes); + + for (PortNum = 0; PortNum < SataPortCount; PortNum += SataChPerSerdes) { + EvenPort = (UINT32)(FixedPcdGet16 (PcdSataPortMode) >> (PortNum * 2)) & 3; + OddPort = (UINT32)(FixedPcdGet16 (PcdSataPortMode) >> ((PortNum+1) * 2)) & 3; + SataPhyInit ((StartPort + PortNum) / SataChPerSerdes, EvenPort, OddPort); + } + + // + // Reset SATA controller + // + ResetSataController (AhciBaseAddr); + + // + // Set SATA capabilities + // + SetSataCapabilities (AhciBaseAddr); + + // + // Set and intialize the Sata ports + // + InitializeSataPorts (AhciBaseAddr, SataPortCount); + + return PlatformPciIoRegisterDevice (AhciBaseAddr, PlatformPciIoDeviceAhci, + PlatformPciIoDmaCoherent, NULL, NULL); +} + +EFI_STATUS +EFIAPI +StyxSataPlatformDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT32 PortNum; + EFI_STATUS Status; + + // + // Perform SATA workarounds + // + for (PortNum = 0; PortNum < FixedPcdGet8(PcdSataPortCount); PortNum++) { + SetCwMinSata0 (PortNum); + } + + Status = InitializeSataController (FixedPcdGet32(PcdSataCtrlAxiSlvPort), + FixedPcdGet8(PcdSataPortCount), 0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: failed to initialize primary SATA controller!\n", + __FUNCTION__)); + return Status; + } + + for (PortNum = 0; PortNum < FixedPcdGet8(PcdSataPortCount); PortNum++) { + SetPrdSingleSata0 (PortNum); + } + + if (FixedPcdGet8(PcdSata1PortCount) > 0) { + for (PortNum = 0; PortNum < FixedPcdGet8(PcdSata1PortCount); PortNum++) { + SetCwMinSata1 (PortNum); + } + + Status = InitializeSataController (FixedPcdGet32(PcdSata1CtrlAxiSlvPort), + FixedPcdGet8(PcdSata1PortCount), FixedPcdGet8(PcdSataPortCount)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: failed to initialize secondary SATA controller!\n", + __FUNCTION__)); + } else { + for (PortNum = 0; PortNum < FixedPcdGet8(PcdSata1PortCount); PortNum++) { + SetPrdSingleSata1 (PortNum); + } + } + } + return EFI_SUCCESS; +} diff --git a/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/SataRegisters.h b/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/SataRegisters.h new file mode 100644 index 000000000000..ff78f4ac3c67 --- /dev/null +++ b/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/SataRegisters.h @@ -0,0 +1,180 @@ +/** @file + Header file for AHCI mode of ATA host controller. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2014 - 2016, AMD Inc. All rights reserved.<BR> + + 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. + +**/ +#ifndef __SATA_REGISTERS_H__ +#define __SATA_REGISTERS_H__ + +#define EFI_AHCI_BAR_INDEX 0x05 + +#define EFI_AHCI_CAPABILITY_OFFSET 0x0000 +#define EFI_AHCI_CAP_SSS BIT27 +#define EFI_AHCI_CAP_SMPS BIT28 +#define EFI_AHCI_CAP_S64A BIT31 +#define EFI_AHCI_GHC_OFFSET 0x0004 +#define EFI_AHCI_GHC_RESET BIT0 +#define EFI_AHCI_GHC_IE BIT1 +#define EFI_AHCI_GHC_ENABLE BIT31 +#define EFI_AHCI_IS_OFFSET 0x0008 +#define EFI_AHCI_PI_OFFSET 0x000C + +#define EFI_AHCI_MAX_PORTS 32 + +// +// Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms. +// +#define EFI_AHCI_BUS_PHY_DETECT_TIMEOUT 10 +// +// Refer SATA1.0a spec, the FIS enable time should be less than 500ms. +// +#define EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT EFI_TIMER_PERIOD_MILLISECONDS(500) +// +// Refer SATA1.0a spec, the bus reset time should be less than 1s. +// +#define EFI_AHCI_BUS_RESET_TIMEOUT EFI_TIMER_PERIOD_SECONDS(1) + +#define EFI_AHCI_ATAPI_DEVICE_SIG 0xEB140000 +#define EFI_AHCI_ATA_DEVICE_SIG 0x00000000 +#define EFI_AHCI_PORT_MULTIPLIER_SIG 0x96690000 +#define EFI_AHCI_ATAPI_SIG_MASK 0xFFFF0000 + +// +// Each PRDT entry can point to a memory block up to 4M byte +// +#define EFI_AHCI_MAX_DATA_PER_PRDT 0x400000 + +#define EFI_AHCI_FIS_REGISTER_H2D 0x27 //Register FIS - Host to Device +#define EFI_AHCI_FIS_REGISTER_H2D_LENGTH 20 +#define EFI_AHCI_FIS_REGISTER_D2H 0x34 //Register FIS - Device to Host +#define EFI_AHCI_FIS_REGISTER_D2H_LENGTH 20 +#define EFI_AHCI_FIS_DMA_ACTIVATE 0x39 //DMA Activate FIS - Device to Host +#define EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH 4 +#define EFI_AHCI_FIS_DMA_SETUP 0x41 //DMA Setup FIS - Bi-directional +#define EFI_AHCI_FIS_DMA_SETUP_LENGTH 28 +#define EFI_AHCI_FIS_DATA 0x46 //Data FIS - Bi-directional +#define EFI_AHCI_FIS_BIST 0x58 //BIST Activate FIS - Bi-directional +#define EFI_AHCI_FIS_BIST_LENGTH 12 +#define EFI_AHCI_FIS_PIO_SETUP 0x5F //PIO Setup FIS - Device to Host +#define EFI_AHCI_FIS_PIO_SETUP_LENGTH 20 +#define EFI_AHCI_FIS_SET_DEVICE 0xA1 //Set Device Bits FIS - Device to Host +#define EFI_AHCI_FIS_SET_DEVICE_LENGTH 8 + +#define EFI_AHCI_D2H_FIS_OFFSET 0x40 +#define EFI_AHCI_DMA_FIS_OFFSET 0x00 +#define EFI_AHCI_PIO_FIS_OFFSET 0x20 +#define EFI_AHCI_SDB_FIS_OFFSET 0x58 +#define EFI_AHCI_FIS_TYPE_MASK 0xFF +#define EFI_AHCI_U_FIS_OFFSET 0x60 + +// +// Port register +// +#define EFI_AHCI_PORT_START 0x0100 +#define EFI_AHCI_PORT_REG_WIDTH 0x0080 +#define EFI_AHCI_PORT_CLB 0x0000 +#define EFI_AHCI_PORT_CLBU 0x0004 +#define EFI_AHCI_PORT_FB 0x0008 +#define EFI_AHCI_PORT_FBU 0x000C +#define EFI_AHCI_PORT_IS 0x0010 +#define EFI_AHCI_PORT_IS_DHRS BIT0 +#define EFI_AHCI_PORT_IS_PSS BIT1 +#define EFI_AHCI_PORT_IS_SSS BIT2 +#define EFI_AHCI_PORT_IS_SDBS BIT3 +#define EFI_AHCI_PORT_IS_UFS BIT4 +#define EFI_AHCI_PORT_IS_DPS BIT5 +#define EFI_AHCI_PORT_IS_PCS BIT6 +#define EFI_AHCI_PORT_IS_DIS BIT7 +#define EFI_AHCI_PORT_IS_PRCS BIT22 +#define EFI_AHCI_PORT_IS_IPMS BIT23 +#define EFI_AHCI_PORT_IS_OFS BIT24 +#define EFI_AHCI_PORT_IS_INFS BIT26 +#define EFI_AHCI_PORT_IS_IFS BIT27 +#define EFI_AHCI_PORT_IS_HBDS BIT28 +#define EFI_AHCI_PORT_IS_HBFS BIT29 +#define EFI_AHCI_PORT_IS_TFES BIT30 +#define EFI_AHCI_PORT_IS_CPDS BIT31 +#define EFI_AHCI_PORT_IS_CLEAR 0xFFFFFFFF +#define EFI_AHCI_PORT_IS_FIS_CLEAR 0x0000000F + +#define EFI_AHCI_PORT_OFFSET(PortNum) \ + (EFI_AHCI_PORT_START + ((PortNum) * EFI_AHCI_PORT_REG_WIDTH)) + +#define EFI_AHCI_PORT_IE 0x0014 +#define EFI_AHCI_PORT_CMD 0x0018 +#define EFI_AHCI_PORT_CMD_ST_MASK 0xFFFFFFFE +#define EFI_AHCI_PORT_CMD_ST BIT0 +#define EFI_AHCI_PORT_CMD_SUD BIT1 +#define EFI_AHCI_PORT_CMD_POD BIT2 +#define EFI_AHCI_PORT_CMD_CLO BIT3 +#define EFI_AHCI_PORT_CMD_CR BIT15 +#define EFI_AHCI_PORT_CMD_FRE BIT4 +#define EFI_AHCI_PORT_CMD_FR BIT14 +#define EFI_AHCI_PORT_CMD_MASK ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL) +#define EFI_AHCI_PORT_CMD_PMA BIT17 +#define EFI_AHCI_PORT_CMD_HPCP BIT18 +#define EFI_AHCI_PORT_CMD_MPSP BIT19 +#define EFI_AHCI_PORT_CMD_CPD BIT20 +#define EFI_AHCI_PORT_CMD_ESP BIT21 +#define EFI_AHCI_PORT_CMD_ATAPI BIT24 +#define EFI_AHCI_PORT_CMD_DLAE BIT25 +#define EFI_AHCI_PORT_CMD_ALPE BIT26 +#define EFI_AHCI_PORT_CMD_ASP BIT27 +#define EFI_AHCI_PORT_CMD_ICC_MASK (BIT28 | BIT29 | BIT30 | BIT31) +#define EFI_AHCI_PORT_CMD_ACTIVE (1 << 28 ) +#define EFI_AHCI_PORT_TFD 0x0020 +#define EFI_AHCI_PORT_TFD_MASK (BIT7 | BIT3 | BIT0) +#define EFI_AHCI_PORT_TFD_BSY BIT7 +#define EFI_AHCI_PORT_TFD_DRQ BIT3 +#define EFI_AHCI_PORT_TFD_ERR BIT0 +#define EFI_AHCI_PORT_TFD_ERR_MASK 0x00FF00 +#define EFI_AHCI_PORT_SIG 0x0024 +#define EFI_AHCI_PORT_SSTS 0x0028 +#define EFI_AHCI_PORT_SSTS_DET_MASK 0x000F +#define EFI_AHCI_PORT_SSTS_DET 0x0001 +#define EFI_AHCI_PORT_SSTS_DET_PCE 0x0003 +#define EFI_AHCI_PORT_SSTS_SPD_MASK 0x00F0 +#define EFI_AHCI_PORT_SCTL 0x002C +#define EFI_AHCI_PORT_SCTL_DET_MASK 0x000F +#define EFI_AHCI_PORT_SCTL_MASK (~EFI_AHCI_PORT_SCTL_DET_MASK) +#define EFI_AHCI_PORT_SCTL_DET_INIT 0x0001 +#define EFI_AHCI_PORT_SCTL_DET_PHYCOMM 0x0003 +#define EFI_AHCI_PORT_SCTL_SPD_MASK 0x00F0 +#define EFI_AHCI_PORT_SCTL_IPM_MASK 0x0F00 +#define EFI_AHCI_PORT_SCTL_IPM_INIT 0x0300 +#define EFI_AHCI_PORT_SCTL_IPM_PSD 0x0100 +#define EFI_AHCI_PORT_SCTL_IPM_SSD 0x0200 +#define EFI_AHCI_PORT_SERR 0x0030 +#define EFI_AHCI_PORT_SERR_RDIE BIT0 +#define EFI_AHCI_PORT_SERR_RCE BIT1 +#define EFI_AHCI_PORT_SERR_TDIE BIT8 +#define EFI_AHCI_PORT_SERR_PCDIE BIT9 +#define EFI_AHCI_PORT_SERR_PE BIT10 +#define EFI_AHCI_PORT_SERR_IE BIT11 +#define EFI_AHCI_PORT_SERR_PRC BIT16 +#define EFI_AHCI_PORT_SERR_PIE BIT17 +#define EFI_AHCI_PORT_SERR_CW BIT18 +#define EFI_AHCI_PORT_SERR_BDE BIT19 +#define EFI_AHCI_PORT_SERR_DE BIT20 +#define EFI_AHCI_PORT_SERR_CRCE BIT21 +#define EFI_AHCI_PORT_SERR_HE BIT22 +#define EFI_AHCI_PORT_SERR_LSE BIT23 +#define EFI_AHCI_PORT_SERR_TSTE BIT24 +#define EFI_AHCI_PORT_SERR_UFT BIT25 +#define EFI_AHCI_PORT_SERR_EX BIT26 +#define EFI_AHCI_PORT_ERR_CLEAR 0xFFFFFFFF +#define EFI_AHCI_PORT_SACT 0x0034 +#define EFI_AHCI_PORT_CI 0x0038 +#define EFI_AHCI_PORT_SNTF 0x003C + +#endif diff --git a/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/StyxSataPlatformDxe.inf b/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/StyxSataPlatformDxe.inf new file mode 100644 index 000000000000..da9e667da1ab --- /dev/null +++ b/Platforms/AMD/Styx/Drivers/StyxSataPlatformDxe/StyxSataPlatformDxe.inf @@ -0,0 +1,61 @@ +## @file +# +# Component description file for the Styx SATA platform driver. +# +# Copyright (c) 2014 - 2016, AMD Inc. All rights reserved.<BR> +# Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR> +# +# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = StyxSataPlatformDxe + FILE_GUID = 4703fac4-9de9-4010-87d1-11402894296a + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = StyxSataPlatformDxeEntryPoint + +[Sources] + InitController.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + AmdModulePkg/AmdModulePkg.dec + OpenPlatformPkg/Platforms/AMD/Styx/AmdStyx.dec + +[LibraryClasses] + AmdSataInit + UefiDriverEntryPoint + DebugLib + BaseLib + PlatformPciIoDeviceRegistrationLib + UefiBootServicesTableLib + +[FixedPcd] + gAmdModulePkgTokenSpaceGuid.PcdSataSerdesBase + gAmdModulePkgTokenSpaceGuid.PcdSataSerdesOffset + gAmdModulePkgTokenSpaceGuid.PcdSataNumChPerSerdes + + gAmdStyxTokenSpaceGuid.PcdSataCtrlAxiSlvPort + gAmdStyxTokenSpaceGuid.PcdSataPortCount + gAmdStyxTokenSpaceGuid.PcdSataPortMode + gAmdStyxTokenSpaceGuid.PcdSataSmpsSupport + gAmdStyxTokenSpaceGuid.PcdSataSssSupport + gAmdStyxTokenSpaceGuid.PcdSataPortCpd + gAmdStyxTokenSpaceGuid.PcdSataPortMpsp + gAmdStyxTokenSpaceGuid.PcdSata1CtrlAxiSlvPort + gAmdStyxTokenSpaceGuid.PcdSata1PortCount + +[Depex] + TRUE +