+++ /dev/null
-/** @file\r
- This driver is used for Opal Password Feature support at AHCI mode.\r
-\r
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-\r
-#include "OpalPasswordPei.h"\r
-\r
-/**\r
- Start command for give slot on specific port.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
- @param CommandSlot The number of CommandSlot.\r
- @param Timeout The timeout Value of start.\r
-\r
- @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
- @retval EFI_TIMEOUT The operation is time out.\r
- @retval EFI_SUCCESS The command start successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciStartCommand (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port,\r
- IN UINT8 CommandSlot,\r
- IN UINT64 Timeout\r
- );\r
-\r
-/**\r
- Stop command running for giving port\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
- @param Timeout The timeout Value of stop.\r
-\r
- @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
- @retval EFI_TIMEOUT The operation is time out.\r
- @retval EFI_SUCCESS The command stop successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciStopCommand (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port,\r
- IN UINT64 Timeout\r
- );\r
-\r
-/**\r
- Read AHCI Operation register.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Offset The operation register offset.\r
-\r
- @return The register content read.\r
-\r
-**/\r
-UINT32\r
-EFIAPI\r
-AhciReadReg (\r
- IN UINT32 AhciBar,\r
- IN UINT32 Offset\r
- )\r
-{\r
- UINT32 Data;\r
-\r
- Data = 0;\r
-\r
- Data = MmioRead32 (AhciBar + Offset);\r
-\r
- return Data;\r
-}\r
-\r
-/**\r
- Write AHCI Operation register.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Offset The operation register offset.\r
- @param Data The Data used to write down.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciWriteReg (\r
- IN UINT32 AhciBar,\r
- IN UINT32 Offset,\r
- IN UINT32 Data\r
- )\r
-{\r
- MmioWrite32 (AhciBar + Offset, Data);\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- Do AND operation with the Value of AHCI Operation register.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Offset The operation register offset.\r
- @param AndData The Data used to do AND operation.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciAndReg (\r
- IN UINT32 AhciBar,\r
- IN UINT32 Offset,\r
- IN UINT32 AndData\r
- )\r
-{\r
- UINT32 Data;\r
-\r
- Data = AhciReadReg (AhciBar, Offset);\r
-\r
- Data &= AndData;\r
-\r
- AhciWriteReg (AhciBar, Offset, Data);\r
-}\r
-\r
-/**\r
- Do OR operation with the Value of AHCI Operation register.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Offset The operation register offset.\r
- @param OrData The Data used to do OR operation.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciOrReg (\r
- IN UINT32 AhciBar,\r
- IN UINT32 Offset,\r
- IN UINT32 OrData\r
- )\r
-{\r
- UINT32 Data;\r
-\r
- Data = AhciReadReg (AhciBar, Offset);\r
-\r
- Data |= OrData;\r
-\r
- AhciWriteReg (AhciBar, Offset, Data);\r
-}\r
-\r
-/**\r
- Wait for memory set to the test Value.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Offset The memory offset to test.\r
- @param MaskValue The mask Value of memory.\r
- @param TestValue The test Value of memory.\r
- @param Timeout The time out Value for wait memory set.\r
-\r
- @retval EFI_DEVICE_ERROR The memory is not set.\r
- @retval EFI_TIMEOUT The memory setting is time out.\r
- @retval EFI_SUCCESS The memory is correct set.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciWaitMmioSet (\r
- IN UINT32 AhciBar,\r
- IN UINT32 Offset,\r
- IN UINT32 MaskValue,\r
- IN UINT32 TestValue,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Value;\r
- UINT32 Delay;\r
-\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
-\r
- do {\r
- Value = AhciReadReg (AhciBar, Offset) & MaskValue;\r
-\r
- if (Value == TestValue) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay (100);\r
-\r
- Delay--;\r
-\r
- } while (Delay > 0);\r
-\r
- return EFI_TIMEOUT;\r
-}\r
-/**\r
- Wait for the Value of the specified system memory set to the test Value.\r
-\r
- @param Address The system memory address to test.\r
- @param MaskValue The mask Value of memory.\r
- @param TestValue The test Value of memory.\r
- @param Timeout The time out Value for wait memory set, uses 100ns as a unit.\r
-\r
- @retval EFI_TIMEOUT The system memory setting is time out.\r
- @retval EFI_SUCCESS The system memory is correct set.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciWaitMemSet (\r
- IN EFI_PHYSICAL_ADDRESS Address,\r
- IN UINT32 MaskValue,\r
- IN UINT32 TestValue,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Value;\r
- UINT32 Delay;\r
-\r
- Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
-\r
- do {\r
- //\r
- // Access sytem memory to see if the Value is the tested one.\r
- //\r
- // The system memory pointed by Address will be updated by the\r
- // SATA Host Controller, "volatile" is introduced to prevent\r
- // compiler from optimizing the access to the memory address\r
- // to only read once.\r
- //\r
- Value = *(volatile UINT32 *) (UINTN) Address;\r
- Value &= MaskValue;\r
-\r
- if (Value == TestValue) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay (100);\r
-\r
- Delay--;\r
-\r
- } while (Delay > 0);\r
-\r
- return EFI_TIMEOUT;\r
-}\r
-\r
-/**\r
- Check the memory status to the test Value.\r
-\r
- @param[in] Address The memory address to test.\r
- @param[in] MaskValue The mask Value of memory.\r
- @param[in] TestValue The test Value of memory.\r
- @param[in, out] RetryTimes The retry times Value for waitting memory set. If 0, then just try once.\r
-\r
- @retval EFI_NOTREADY The memory is not set.\r
- @retval EFI_TIMEOUT The memory setting retry times out.\r
- @retval EFI_SUCCESS The memory is correct set.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciCheckMemSet (\r
- IN UINTN Address,\r
- IN UINT32 MaskValue,\r
- IN UINT32 TestValue,\r
- IN OUT UINTN *RetryTimes OPTIONAL\r
- )\r
-{\r
- UINT32 Value;\r
-\r
- if (RetryTimes != NULL) {\r
- (*RetryTimes)--;\r
- }\r
-\r
- Value = *(volatile UINT32 *) Address;\r
- Value &= MaskValue;\r
-\r
- if (Value == TestValue) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\r
- return EFI_TIMEOUT;\r
- } else {\r
- return EFI_NOT_READY;\r
- }\r
-}\r
-\r
-/**\r
- Clear the port interrupt and error status. It will also clear\r
- HBA interrupt status.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciClearPortStatus (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port\r
- )\r
-{\r
- UINT32 Offset;\r
-\r
- //\r
- // Clear any error status\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
- AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));\r
-\r
- //\r
- // Clear any port interrupt status\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
- AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));\r
-\r
- //\r
- // Clear any HBA interrupt status\r
- //\r
- AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET));\r
-}\r
-\r
-/**\r
- Enable the FIS running for giving port.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
- @param Timeout The timeout Value of enabling FIS.\r
-\r
- @retval EFI_DEVICE_ERROR The FIS enable setting fails.\r
- @retval EFI_TIMEOUT The FIS enable setting is time out.\r
- @retval EFI_SUCCESS The FIS enable successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciEnableFisReceive (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Offset;\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);\r
-\r
- return AhciWaitMmioSet (\r
- AhciBar,\r
- Offset,\r
- EFI_AHCI_PORT_CMD_FR,\r
- EFI_AHCI_PORT_CMD_FR,\r
- Timeout\r
- );\r
-}\r
-\r
-/**\r
- Disable the FIS running for giving port.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
- @param Timeout The timeout Value of disabling FIS.\r
-\r
- @retval EFI_DEVICE_ERROR The FIS disable setting fails.\r
- @retval EFI_TIMEOUT The FIS disable setting is time out.\r
- @retval EFI_UNSUPPORTED The port is in running state.\r
- @retval EFI_SUCCESS The FIS disable successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciDisableFisReceive (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Offset;\r
- UINT32 Data;\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- Data = AhciReadReg (AhciBar, Offset);\r
-\r
- //\r
- // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
- //\r
- if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- //\r
- // Check if the Fis receive DMA engine for the port is running.\r
- //\r
- if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
-\r
- return AhciWaitMmioSet (\r
- AhciBar,\r
- Offset,\r
- EFI_AHCI_PORT_CMD_FR,\r
- 0,\r
- Timeout\r
- );\r
-}\r
-\r
-/**\r
- Build the command list, command table and prepare the fis receiver.\r
-\r
- @param AhciContext The pointer to the AHCI_CONTEXT.\r
- @param Port The number of port.\r
- @param PortMultiplier The timeout Value of stop.\r
- @param CommandFis The control fis will be used for the transfer.\r
- @param CommandList The command list will be used for the transfer.\r
- @param AtapiCommand The atapi command will be used for the transfer.\r
- @param AtapiCommandLength The Length of the atapi command.\r
- @param CommandSlotNumber The command slot will be used for the transfer.\r
- @param DataPhysicalAddr The pointer to the Data Buffer pci bus master address.\r
- @param DataLength The Data count to be transferred.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciBuildCommand (\r
- IN AHCI_CONTEXT *AhciContext,\r
- IN UINT8 Port,\r
- IN UINT8 PortMultiplier,\r
- IN EFI_AHCI_COMMAND_FIS *CommandFis,\r
- IN EFI_AHCI_COMMAND_LIST *CommandList,\r
- IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
- IN UINT8 AtapiCommandLength,\r
- IN UINT8 CommandSlotNumber,\r
- IN OUT VOID *DataPhysicalAddr,\r
- IN UINT64 DataLength\r
- )\r
-{\r
- EFI_AHCI_REGISTERS *AhciRegisters;\r
- UINT32 AhciBar;\r
- UINT64 BaseAddr;\r
- UINT64 PrdtNumber;\r
- UINTN RemainedData;\r
- UINTN MemAddr;\r
- DATA_64 Data64;\r
- UINT32 Offset;\r
-\r
- AhciRegisters = &AhciContext->AhciRegisters;\r
- AhciBar = AhciContext->AhciBar;\r
-\r
- //\r
- // Filling the PRDT\r
- //\r
- PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);\r
-\r
- //\r
- // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.\r
- // It also limits that the maximum amount of the PRDT entry in the command table\r
- // is 65535.\r
- //\r
- ASSERT (PrdtNumber <= 1);\r
-\r
- Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);\r
-\r
- BaseAddr = Data64.Uint64;\r
-\r
- ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
-\r
- ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
-\r
- CommandFis->AhciCFisPmNum = PortMultiplier;\r
-\r
- CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- if (AtapiCommand != NULL) {\r
- CopyMem (\r
- &AhciRegisters->AhciCommandTable->AtapiCmd,\r
- AtapiCommand,\r
- AtapiCommandLength\r
- );\r
-\r
- CommandList->AhciCmdA = 1;\r
- CommandList->AhciCmdP = 1;\r
-\r
- AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
- } else {\r
- AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
- }\r
-\r
- RemainedData = (UINTN) DataLength;\r
- MemAddr = (UINTN) DataPhysicalAddr;\r
- CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
-\r
- AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;\r
-\r
- Data64.Uint64 = (UINT64)MemAddr;\r
- AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba = Data64.Uint32.Lower32;\r
- AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;\r
-\r
- //\r
- // Set the last PRDT to Interrupt On Complete\r
- //\r
- AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;\r
-\r
- CopyMem (\r
- (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
- CommandList,\r
- sizeof (EFI_AHCI_COMMAND_LIST)\r
- );\r
-\r
- Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;\r
- AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
- AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
- AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;\r
-\r
-}\r
-\r
-/**\r
- Buid a command FIS.\r
-\r
- @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS Data structure.\r
- @param AtaCommandBlock A pointer to the AhciBuildCommandFis Data structure.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciBuildCommandFis (\r
- IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,\r
- IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock\r
- )\r
-{\r
- ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
-\r
- CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
- //\r
- // Indicator it's a command\r
- //\r
- CmdFis->AhciCFisCmdInd = 0x1;\r
- CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
-\r
- CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
- CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;\r
-\r
- CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;\r
- CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;\r
-\r
- CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;\r
- CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;\r
-\r
- CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;\r
- CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;\r
-\r
- CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;\r
- CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
-\r
- CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
-}\r
-\r
-/**\r
- Start a PIO Data transfer on specific port.\r
-\r
- @param AhciContext The pointer to the AHCI_CONTEXT.\r
- @param Port The number of port.\r
- @param PortMultiplier The timeout Value of stop.\r
- @param AtapiCommand The atapi command will be used for the transfer.\r
- @param AtapiCommandLength The Length of the atapi command.\r
- @param Read The transfer direction.\r
- @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.\r
- @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.\r
- @param MemoryAddr The pointer to the Data Buffer.\r
- @param DataCount The Data count to be transferred.\r
- @param Timeout The timeout Value of non Data transfer.\r
-\r
- @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.\r
- @retval EFI_TIMEOUT The operation is time out.\r
- @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
- @retval EFI_SUCCESS The PIO Data transfer executes successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciPioTransfer (\r
- IN AHCI_CONTEXT *AhciContext,\r
- IN UINT8 Port,\r
- IN UINT8 PortMultiplier,\r
- IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
- IN UINT8 AtapiCommandLength,\r
- IN BOOLEAN Read,\r
- IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
- IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
- IN OUT VOID *MemoryAddr,\r
- IN UINT32 DataCount,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_AHCI_REGISTERS *AhciRegisters;\r
- UINT32 AhciBar;\r
- UINT32 FisBaseAddr;\r
- UINT32 Offset;\r
- UINT32 Delay;\r
- EFI_AHCI_COMMAND_FIS CFis;\r
- EFI_AHCI_COMMAND_LIST CmdList;\r
- UINT32 PortTfd;\r
- UINT32 PrdCount;\r
- UINT32 OldRfisLo;\r
- UINT32 OldRfisHi;\r
- UINT32 OldCmdListLo;\r
- UINT32 OldCmdListHi;\r
-\r
- AhciRegisters = &AhciContext->AhciRegisters;\r
- AhciBar = AhciContext->AhciBar;\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
- OldRfisLo = AhciReadReg (AhciBar, Offset);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
- OldRfisHi = AhciReadReg (AhciBar, Offset);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
- AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
- AhciWriteReg (AhciBar, Offset, 0);\r
-\r
- //\r
- // Single task envrionment, we only use one command table for all port\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
- OldCmdListLo = AhciReadReg (AhciBar, Offset);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
- OldCmdListHi = AhciReadReg (AhciBar, Offset);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
- AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
- AhciWriteReg (AhciBar, Offset, 0);\r
-\r
- //\r
- // Package read needed\r
- //\r
- AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
-\r
- ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
-\r
- CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
- CmdList.AhciCmdW = Read ? 0 : 1;\r
-\r
- AhciBuildCommand (\r
- AhciContext,\r
- Port,\r
- PortMultiplier,\r
- &CFis,\r
- &CmdList,\r
- AtapiCommand,\r
- AtapiCommandLength,\r
- 0,\r
- MemoryAddr,\r
- DataCount\r
- );\r
-\r
- Status = AhciStartCommand (\r
- AhciBar,\r
- Port,\r
- 0,\r
- Timeout\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
- }\r
-\r
- //\r
- // Checking the status and wait the driver sending Data\r
- //\r
- FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;\r
- if (Read && (AtapiCommand == 0)) {\r
- //\r
- // Wait device sends the PIO setup fis before Data transfer\r
- //\r
- Status = EFI_TIMEOUT;\r
- Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
- do {\r
- Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
-\r
- Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
- if (!EFI_ERROR (Status)) {\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
- PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);\r
- //\r
- // PxTFD will be updated if there is a D2H or SetupFIS received.\r
- // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\r
- //\r
- if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
- Status = EFI_DEVICE_ERROR;\r
- break;\r
- }\r
-\r
- PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
- if (PrdCount == DataCount) {\r
- break;\r
- }\r
- }\r
-\r
- Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
- Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
- if (!EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- break;\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay(100);\r
-\r
- Delay--;\r
- } while (Delay > 0);\r
- } else {\r
- //\r
- // Wait for D2H Fis is received\r
- //\r
- Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
- Status = AhciWaitMemSet (\r
- Offset,\r
- EFI_AHCI_FIS_TYPE_MASK,\r
- EFI_AHCI_FIS_REGISTER_D2H,\r
- Timeout\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
- PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);\r
- if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
-Exit:\r
- AhciStopCommand (\r
- AhciBar,\r
- Port,\r
- Timeout\r
- );\r
-\r
- AhciDisableFisReceive (\r
- AhciBar,\r
- Port,\r
- Timeout\r
- );\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
- AhciWriteReg (AhciBar, Offset, OldRfisLo);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
- AhciWriteReg (AhciBar, Offset, OldRfisHi);\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
- AhciWriteReg (AhciBar, Offset, OldCmdListLo);\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
- AhciWriteReg (AhciBar, Offset, OldCmdListHi);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Stop command running for giving port\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
- @param Timeout The timeout Value of stop.\r
-\r
- @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
- @retval EFI_TIMEOUT The operation is time out.\r
- @retval EFI_SUCCESS The command stop successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciStopCommand (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Offset;\r
- UINT32 Data;\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- Data = AhciReadReg (AhciBar, Offset);\r
-\r
- if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
- AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
- }\r
-\r
- return AhciWaitMmioSet (\r
- AhciBar,\r
- Offset,\r
- EFI_AHCI_PORT_CMD_CR,\r
- 0,\r
- Timeout\r
- );\r
-}\r
-\r
-/**\r
- Start command for give slot on specific port.\r
-\r
- @param AhciBar AHCI bar address.\r
- @param Port The number of port.\r
- @param CommandSlot The number of CommandSlot.\r
- @param Timeout The timeout Value of start.\r
-\r
- @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
- @retval EFI_TIMEOUT The operation is time out.\r
- @retval EFI_SUCCESS The command start successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciStartCommand (\r
- IN UINT32 AhciBar,\r
- IN UINT8 Port,\r
- IN UINT8 CommandSlot,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 CmdSlotBit;\r
- EFI_STATUS Status;\r
- UINT32 PortStatus;\r
- UINT32 StartCmd;\r
- UINT32 PortTfd;\r
- UINT32 Offset;\r
- UINT32 Capability;\r
-\r
- //\r
- // Collect AHCI controller information\r
- //\r
- Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
-\r
- CmdSlotBit = (UINT32) (1 << CommandSlot);\r
-\r
- AhciClearPortStatus (\r
- AhciBar,\r
- Port\r
- );\r
-\r
- Status = AhciEnableFisReceive (\r
- AhciBar,\r
- Port,\r
- Timeout\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- PortStatus = AhciReadReg (AhciBar, Offset);\r
-\r
- StartCmd = 0;\r
- if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
- StartCmd = AhciReadReg (AhciBar, Offset);\r
- StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
- StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
- PortTfd = AhciReadReg (AhciBar, Offset);\r
-\r
- if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
- if ((Capability & BIT24) != 0) {\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);\r
-\r
- AhciWaitMmioSet (\r
- AhciBar,\r
- Offset,\r
- EFI_AHCI_PORT_CMD_COL,\r
- 0,\r
- Timeout\r
- );\r
- }\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
-\r
- //\r
- // Setting the command\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
- AhciAndReg (AhciBar, Offset, 0);\r
- AhciOrReg (AhciBar, Offset, CmdSlotBit);\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
- AhciAndReg (AhciBar, Offset, 0);\r
- AhciOrReg (AhciBar, Offset, CmdSlotBit);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Do AHCI HBA reset.\r
-\r
- @param[in] AhciBar AHCI bar address.\r
- @param[in] Timeout The timeout Value of reset.\r
-\r
- @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
- @retval EFI_TIMEOUT The reset operation is time out.\r
- @retval EFI_SUCCESS AHCI controller is reset successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciReset (\r
- IN UINT32 AhciBar,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Delay;\r
- UINT32 Value;\r
- UINT32 Capability;\r
-\r
- //\r
- // Collect AHCI controller information\r
- //\r
- Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
-\r
- //\r
- // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
- //\r
- if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
- AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
- }\r
-\r
- AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
-\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
-\r
- do {\r
- Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);\r
- if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay(100);\r
-\r
- Delay--;\r
- } while (Delay > 0);\r
-\r
- return EFI_TIMEOUT;\r
-\r
-\r
-}\r
-\r
-/**\r
- Allocate transfer-related data struct which is used at AHCI mode.\r
-\r
- @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.\r
-\r
- @retval EFI_OUT_OF_RESOURCE No enough resource.\r
- @retval EFI_SUCCESS Successful to allocate resource.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciAllocateResource (\r
- IN OUT AHCI_CONTEXT *AhciContext\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_AHCI_REGISTERS *AhciRegisters;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
- VOID *Base;\r
- VOID *Mapping;\r
-\r
- AhciRegisters = &AhciContext->AhciRegisters;\r
-\r
- //\r
- // Allocate resources required by AHCI host controller.\r
- //\r
- Status = IoMmuAllocateBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
- &Base,\r
- &DeviceAddress,\r
- &Mapping\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
- AhciRegisters->AhciRFisMapping = Mapping;\r
- AhciRegisters->AhciRFis = Base;\r
- ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));\r
-\r
- Status = IoMmuAllocateBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
- &Base,\r
- &DeviceAddress,\r
- &Mapping\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
- AhciRegisters->AhciRFis,\r
- AhciRegisters->AhciRFisMapping\r
- );\r
- AhciRegisters->AhciRFis = NULL;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
- AhciRegisters->AhciCmdListMapping = Mapping;\r
- AhciRegisters->AhciCmdList = Base;\r
- ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));\r
-\r
- Status = IoMmuAllocateBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),\r
- &Base,\r
- &DeviceAddress,\r
- &Mapping\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
- AhciRegisters->AhciCmdList,\r
- AhciRegisters->AhciCmdListMapping\r
- );\r
- AhciRegisters->AhciCmdList = NULL;\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
- AhciRegisters->AhciRFis,\r
- AhciRegisters->AhciRFisMapping\r
- );\r
- AhciRegisters->AhciRFis = NULL;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
- AhciRegisters->AhciCommandTableMapping = Mapping;\r
- AhciRegisters->AhciCommandTable = Base;\r
- ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));\r
-\r
- //\r
- // Allocate resources for data transfer.\r
- //\r
- Status = IoMmuAllocateBuffer (\r
- EFI_SIZE_TO_PAGES (HDD_PAYLOAD),\r
- &Base,\r
- &DeviceAddress,\r
- &Mapping\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
- AhciRegisters->AhciCommandTable,\r
- AhciRegisters->AhciCommandTableMapping\r
- );\r
- AhciRegisters->AhciCommandTable = NULL;\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
- AhciRegisters->AhciCmdList,\r
- AhciRegisters->AhciCmdListMapping\r
- );\r
- AhciRegisters->AhciCmdList = NULL;\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
- AhciRegisters->AhciRFis,\r
- AhciRegisters->AhciRFisMapping\r
- );\r
- AhciRegisters->AhciRFis = NULL;\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));\r
- AhciContext->BufferMapping = Mapping;\r
- AhciContext->Buffer = Base;\r
- ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD));\r
-\r
- DEBUG ((\r
- DEBUG_INFO,\r
- "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",\r
- __FUNCTION__,\r
- AhciContext->Buffer,\r
- AhciRegisters->AhciRFis,\r
- AhciRegisters->AhciCmdList,\r
- AhciRegisters->AhciCommandTable\r
- ));\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Free allocated transfer-related data struct which is used at AHCI mode.\r
-\r
- @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AhciFreeResource (\r
- IN OUT AHCI_CONTEXT *AhciContext\r
- )\r
-{\r
- EFI_AHCI_REGISTERS *AhciRegisters;\r
-\r
- AhciRegisters = &AhciContext->AhciRegisters;\r
-\r
- if (AhciContext->Buffer != NULL) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (HDD_PAYLOAD),\r
- AhciContext->Buffer,\r
- AhciContext->BufferMapping\r
- );\r
- AhciContext->Buffer = NULL;\r
- }\r
-\r
- if (AhciRegisters->AhciCommandTable != NULL) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),\r
- AhciRegisters->AhciCommandTable,\r
- AhciRegisters->AhciCommandTableMapping\r
- );\r
- AhciRegisters->AhciCommandTable = NULL;\r
- }\r
-\r
- if (AhciRegisters->AhciCmdList != NULL) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),\r
- AhciRegisters->AhciCmdList,\r
- AhciRegisters->AhciCmdListMapping\r
- );\r
- AhciRegisters->AhciCmdList = NULL;\r
- }\r
-\r
- if (AhciRegisters->AhciRFis != NULL) {\r
- IoMmuFreeBuffer (\r
- EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),\r
- AhciRegisters->AhciRFis,\r
- AhciRegisters->AhciRFisMapping\r
- );\r
- AhciRegisters->AhciRFis = NULL;\r
- }\r
-}\r
-\r
-/**\r
- Initialize ATA host controller at AHCI mode.\r
-\r
- The function is designed to initialize ATA host controller.\r
-\r
- @param[in] AhciContext The pointer to the AHCI_CONTEXT.\r
- @param[in] Port The port number to do initialization.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciModeInitialize (\r
- IN AHCI_CONTEXT *AhciContext,\r
- IN UINT8 Port\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_AHCI_REGISTERS *AhciRegisters;\r
- UINT32 AhciBar;\r
- UINT32 Capability;\r
- UINT32 Offset;\r
- UINT32 Data;\r
- UINT32 PhyDetectDelay;\r
-\r
- AhciRegisters = &AhciContext->AhciRegisters;\r
- AhciBar = AhciContext->AhciBar;\r
-\r
- Status = AhciReset (AhciBar, ATA_TIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Collect AHCI controller information\r
- //\r
- Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);\r
-\r
- //\r
- // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
- //\r
- if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
- AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
- AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);\r
-\r
- //\r
- // Single task envrionment, we only use one command table for all port\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
- AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
- Data = AhciReadReg (AhciBar, Offset);\r
- if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
- AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);\r
- }\r
-\r
- if ((Capability & BIT27) != 0) {\r
- AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);\r
- }\r
-\r
- //\r
- // Disable aggressive power management.\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
- AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
- //\r
- // Disable the reporting of the corresponding interrupt to system software.\r
- //\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
- AhciAndReg (AhciBar, Offset, 0);\r
-\r
- Status = AhciEnableFisReceive (\r
- AhciBar,\r
- Port,\r
- 5000000\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
- // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
- //\r
- PhyDetectDelay = 16 * 1000;\r
- do {\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
- if (AhciReadReg(AhciBar, Offset) != 0) {\r
- AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));\r
- }\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
-\r
- Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
- if (Data == 0) {\r
- break;\r
- }\r
-\r
- MicroSecondDelay (1000);\r
- PhyDetectDelay--;\r
- } while (PhyDetectDelay > 0);\r
-\r
- if (PhyDetectDelay == 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
- Status = AhciWaitMmioSet (\r
- AhciBar,\r
- Offset,\r
- 0x0000FFFF,\r
- 0x00000101,\r
- 160000000\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- return Status;\r
-}\r
-\r