--- /dev/null
+/** @file\r
+\r
+CEATA specific functions implementation\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\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
+#include "SDMediaDevice.h"\r
+\r
+/**\r
+ Send RW_MULTIPLE_REGISTER command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param Address Register address.\r
+ @param ByteCount Buffer size.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer Buffer pointer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadWriteMultipleRegister (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 Address,\r
+ IN UINT8 ByteCount,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Argument;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ Argument = (Address << 16) | ByteCount;\r
+ if (Write) {\r
+ Argument |= BIT31;\r
+ }\r
+\r
+\r
+ if (Write) {\r
+ CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_REGISTER,\r
+ Argument,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ ByteCount,\r
+ ResponseR1b,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ } else {\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_REGISTER,\r
+ Argument,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ ByteCount,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);\r
+ }\r
+\r
+ }\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param DataUnitCount Buffer size in 512 bytes unit.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer Buffer pointer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadWriteMultipleBlock (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 DataUnitCount,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 TransferLength;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ TransferLength = DataUnitCount * DATA_UNIT_SIZE;\r
+ if (TransferLength > SDHostIo->HostCapability.BoundarySize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Write) {\r
+ CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_BLOCK,\r
+ (DataUnitCount | BIT31),\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ TransferLength,\r
+ ResponseR1b,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ } else {\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_BLOCK,\r
+ DataUnitCount,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send software reset\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+SoftwareReset (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Data;\r
+ UINT32 TimeOut;\r
+\r
+ Data = BIT2;\r
+\r
+ Status = FastIO (CardData, Reg_Control, &Data, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ TimeOut = 5 * 1000;\r
+\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Status = FastIO (CardData, Reg_Control, &Data, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ if ((Data & BIT2) == BIT2) {\r
+ break;\r
+ }\r
+\r
+ TimeOut--;\r
+ } while (TimeOut > 0);\r
+\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+ Data &= ~BIT2;\r
+ Status = FastIO (CardData, Reg_Control, &Data, TRUE);\r
+\r
+ TimeOut = 5 * 1000;\r
+\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Status = FastIO (CardData, Reg_Control, &Data, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ if ((Data & BIT2) != BIT2) {\r
+ break;\r
+ }\r
+\r
+ TimeOut--;\r
+ } while (TimeOut > 0);\r
+\r
+\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ SendATACommand specificed in Taskfile\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param TaskFile Pointer to TASK_FILE.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer If NULL, means no data transfer, neither read nor write.\r
+ @param SectorCount Buffer size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+SendATACommand (\r
+ IN CARD_DATA *CardData,\r
+ IN TASK_FILE *TaskFile,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT8 Data;\r
+ UINT32 TimeOut;\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ //\r
+ //Write register\r
+ //\r
+ Status = ReadWriteMultipleRegister (\r
+ CardData,\r
+ 0,\r
+ sizeof (TASK_FILE),\r
+ TRUE,\r
+ (UINT8*)TaskFile\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ TimeOut = 5000;\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Data = 0;\r
+ Status = FastIO (\r
+ CardData,\r
+ Reg_Command_Status,\r
+ &Data,\r
+ FALSE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {\r
+ break;\r
+ }\r
+\r
+ TimeOut --;\r
+ } while (TimeOut > 0);\r
+\r
+ if (TimeOut == 0) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ if (Buffer != NULL) {\r
+ Status = ReadWriteMultipleBlock (\r
+ CardData,\r
+ SectorCount,\r
+ Write,\r
+ (UINT8*)Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ TimeOut = 5 * 1000;\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+\r
+ Data = 0;\r
+ Status = FastIO (\r
+ CardData,\r
+ Reg_Command_Status,\r
+ &Data,\r
+ FALSE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {\r
+ break;\r
+ }\r
+\r
+ TimeOut --;\r
+ } while (TimeOut > 0);\r
+ if (TimeOut == 0) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ if (EFI_ERROR (Status)) {\r
+ SoftwareReset (CardData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ IDENTIFY_DEVICE command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+IndentifyDevice (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;\r
+\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ (UINT8*)&(CardData->IndentifyDeviceData),\r
+ 1\r
+ );\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ FLUSH_CACHE_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+FlushCache (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+\r
+ //\r
+ //Hitachi CE-ATA will always make the busy high after\r
+ //receving this command\r
+ //\r
+/*\r
+ EFI_STATUS Status;\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = FLUSH_CACHE_EXT;\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ NULL,\r
+ 0\r
+ );\r
+*/\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ STANDBY_IMMEDIATE command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+StandByImmediate (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;\r
+\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ NULL,\r
+ 0\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ READ_DMA_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+ @param SectorCount Size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadDMAExt (\r
+ IN CARD_DATA *CardData,\r
+ IN EFI_LBA LBA,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = READ_DMA_EXT;\r
+\r
+ CardData->TaskFile.SectorCount = (UINT8)SectorCount;\r
+ CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);\r
+\r
+ CardData->TaskFile.LBALow = (UINT8)LBA;\r
+ CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8);\r
+ CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16);\r
+\r
+ CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24);\r
+ CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32);\r
+ CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40);\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ Buffer,\r
+ SectorCount\r
+ );\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ WRITE_DMA_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+ @param SectorCount Size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+WriteDMAExt (\r
+ IN CARD_DATA *CardData,\r
+ IN EFI_LBA LBA,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = WRITE_DMA_EXT;\r
+\r
+ CardData->TaskFile.SectorCount = (UINT8)SectorCount;\r
+ CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);\r
+\r
+ CardData->TaskFile.LBALow = (UINT8)LBA;\r
+ CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8);\r
+ CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16);\r
+\r
+ CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24);\r
+ CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32);\r
+ CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40);\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ TRUE,\r
+ Buffer,\r
+ SectorCount\r
+ );\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Judge whether it is CE-ATA device or not.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval TRUE\r
+ @retval FALSE\r
+\r
+**/\r
+BOOLEAN\r
+IsCEATADevice (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = ReadWriteMultipleRegister (\r
+ CardData,\r
+ 0,\r
+ sizeof (TASK_FILE),\r
+ FALSE,\r
+ (UINT8*)&CardData->TaskFile\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ //To bring back the normal MMC card to work\r
+ //\r
+ CardData->SDHostIo->ResetSDHost (CardData->SDHostIo, Reset_DAT_CMD);\r
+ return FALSE;\r
+ }\r
+\r
+ if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&\r
+ CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA\r
+ ) {\r
+ //\r
+ //Disable Auto CMD for CE-ATA\r
+ //\r
+ CardData->SDHostIo->EnableAutoStopCmd (CardData->SDHostIo, FALSE);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+\r