--- /dev/null
+/** @file\r
+\r
+Block I/O protocol for MMC/SD device\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
+ Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive.\r
+ verification operation of the device during reset.\r
+ (This parameter is ingored in this driver.)\r
+\r
+ @retval EFI_SUCCESS Success\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);\r
+ }\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ The caller is responsible for writing to only legitimate locations.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the\r
+ intrinsic block size of 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
+\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
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Address;\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 RemainingLength;\r
+ UINT32 TransferLength;\r
+ UINT8 *BufferPointer;\r
+ BOOLEAN SectorAddressing;\r
+ UINTN TotalBlock;\r
+\r
+ DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));\r
+ Status = EFI_SUCCESS;\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+ if (MediaId != CardData->BlockIoMedia.MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+ if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {\r
+ SectorAddressing = TRUE;\r
+ } else {\r
+ SectorAddressing = FALSE;\r
+ }\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);\r
+ }\r
+ TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);\r
+ if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+\r
+ if (!Buffer) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+\r
+\r
+\r
+ BufferPointer = Buffer;\r
+ RemainingLength = (UINT32)BufferSize;\r
+\r
+ while (RemainingLength > 0) {\r
+ if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {\r
+ if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {\r
+ TransferLength = SDHostIo->HostCapability.BoundarySize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCKLEN,\r
+ CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCK_COUNT,\r
+ TransferLength / CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Status = SendCommand (\r
+ CardData,\r
+ READ_MULTIPLE_BLOCK,\r
+ Address,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));\r
+ break;\r
+ }\r
+ } else {\r
+ if (RemainingLength > CardData->BlockIoMedia.BlockSize) {\r
+ TransferLength = CardData->BlockIoMedia.BlockSize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ READ_SINGLE_BLOCK,\r
+ Address,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ (UINT32)TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));\r
+ break;\r
+ }\r
+ }\r
+ CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);\r
+\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address += TransferLength / 512;\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address += TransferLength;\r
+ }\r
+ BufferPointer += TransferLength;\r
+ RemainingLength -= TransferLength;\r
+ }\r
+\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if ((CardData->CardType == SDMemoryCard) ||\r
+ (CardData->CardType == SDMemoryCard2)||\r
+ (CardData->CardType == SDMemoryCard2High)) {\r
+ SendCommand (\r
+ CardData,\r
+ STOP_TRANSMISSION,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ } else {\r
+ SendCommand (\r
+ CardData,\r
+ STOP_TRANSMISSION,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ }\r
+\r
+ }\r
+\r
+\r
+Done:\r
+ DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ The caller is responsible for writing to only legitimate locations.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the\r
+ intrinsic block size of 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
+\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
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Address;\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 RemainingLength;\r
+ UINT32 TransferLength;\r
+ UINT8 *BufferPointer;\r
+ BOOLEAN SectorAddressing;\r
+\r
+ DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));\r
+ Status = EFI_SUCCESS;\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+ if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {\r
+ SectorAddressing = TRUE;\r
+ } else {\r
+ SectorAddressing = FALSE;\r
+ }\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);\r
+ }\r
+\r
+ if (!Buffer) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (This->Media->ReadOnly == TRUE) {\r
+ Status = EFI_WRITE_PROTECTED;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+\r
+\r
+ BufferPointer = Buffer;\r
+ RemainingLength = (UINT32)BufferSize;\r
+\r
+ while (RemainingLength > 0) {\r
+ if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {\r
+ if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {\r
+ TransferLength = SDHostIo->HostCapability.BoundarySize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+\r
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCKLEN,\r
+ CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCK_COUNT,\r
+ TransferLength / CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ WRITE_MULTIPLE_BLOCK,\r
+ Address,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ (UINT32)TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));\r
+ break;\r
+ }\r
+ } else {\r
+ if (RemainingLength > CardData->BlockIoMedia.BlockSize) {\r
+ TransferLength = CardData->BlockIoMedia.BlockSize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ WRITE_BLOCK,\r
+ Address,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ (UINT32)TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ }\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address += TransferLength / 512;\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address += TransferLength;\r
+ }\r
+ BufferPointer += TransferLength;\r
+ RemainingLength -= TransferLength;\r
+\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ SendCommand (\r
+ CardData,\r
+ STOP_TRANSMISSION,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+\r
+ }\r
+\r
+\r
+Done:\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.\r
+ (In this driver, this function just returns EFI_SUCCESS.)\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ MMC/SD card BlockIo init function.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+MMCSDBlockIoInit (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ //\r
+ //BlockIO protocol\r
+ //\r
+ CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+ CardData->BlockIo.Media = &(CardData->BlockIoMedia);\r
+ CardData->BlockIo.Reset = MMCSDBlockReset;\r
+ CardData->BlockIo.ReadBlocks = MMCSDBlockReadBlocks ;\r
+ CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;\r
+ CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;\r
+\r
+ CardData->BlockIoMedia.MediaId = 0;\r
+ CardData->BlockIoMedia.RemovableMedia = FALSE;\r
+ CardData->BlockIoMedia.MediaPresent = TRUE;\r
+ CardData->BlockIoMedia.LogicalPartition = FALSE;\r
+\r
+ if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {\r
+ CardData->BlockIoMedia.ReadOnly = TRUE;\r
+ } else {\r
+ CardData->BlockIoMedia.ReadOnly = FALSE;\r
+ }\r
+\r
+\r
+ CardData->BlockIoMedia.WriteCaching = FALSE;\r
+ CardData->BlockIoMedia.BlockSize = CardData->BlockLen;\r
+ CardData->BlockIoMedia.IoAlign = 1;\r
+ CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);\r
+\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+\r