**/
-#include <Uefi.h>
-
#include "MMCHS.h"
EFI_BLOCK_IO_MEDIA gMMCHSMedia = {
MaxDataTransferRate = gCardInfo.CSDData.TRAN_SPEED;
+ // For SD Cards we would need to send CMD6 to set
+ // speeds abouve 25MHz. High Speed mode 50 MHz and up
+
//Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
switch (MaxDataTransferRate & 0x7) {
case 0:
//Calculate total number of blocks and max. data transfer rate supported by the detected card.
GetCardConfigurationData();
- //Change MMCHS clock frequency to what detected card can support.
- UpdateMMCHSClkFrequency(gCardInfo.ClockFrequencySelect);
-
return Status;
}
return Status;
}
+ if ((gCardInfo.CardType != UNKNOWN_CARD) && (gCardInfo.CardType != MMC_CARD)) {
+ // We could read SCR register, but SD Card Phys spec stats any SD Card shall
+ // set SCR.SD_BUS_WIDTHS to support 4-bit mode, so why bother?
+
+ // Send ACMD6 (application specific commands must be prefixed with CMD55)
+ Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);
+ if (!EFI_ERROR (Status)) {
+ // set device into 4-bit data bus mode
+ Status = SendCmd (ACMD6, ACMD6_INT_EN, 0x2);
+ if (!EFI_ERROR (Status)) {
+ // Set host controler into 4-bit mode
+ MmioOr32 (MMCHS_HCTL, DTW_4_BIT);
+ DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n"));
+ }
+ }
+ }
+
//Send CMD16 to set the block length
CmdArgument = gCardInfo.BlockSize;
Status = SendCmd (CMD16, CMD16_INT_EN, CmdArgument);
return Status;
}
+ //Change MMCHS clock frequency to what detected card can support.
+ UpdateMMCHSClkFrequency(gCardInfo.ClockFrequencySelect);
+
return EFI_SUCCESS;
}
return EFI_SUCCESS;
}
+EFI_STATUS
+DmaBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Lba,
+ IN OUT VOID *Buffer,
+ IN UINTN BlockCount,
+ IN OPERATION_TYPE OperationType
+ )
+{
+ EFI_STATUS Status;
+ UINTN DmaSize = 0;
+ UINTN Cmd = 0;
+ UINTN CmdInterruptEnable;
+ UINTN CmdArgument;
+ VOID *BufferMap;
+ EFI_PHYSICAL_ADDRESS BufferAddress;
+ OMAP_DMA4 Dma4;
+ DMA_MAP_OPERATION DmaOperation;
+ EFI_STATUS MmcStatus;
+ UINTN RetryCount = 0;
+
+CpuDeadLoop ();
+ // Map passed in buffer for DMA xfer
+ DmaSize = BlockCount * This->Media->BlockSize;
+ Status = DmaMap (DmaOperation, Buffer, &DmaSize, &BufferAddress, &BufferMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&DmaOperation, sizeof (DMA_MAP_OPERATION));
+ \r
+ Dma4.DataType = 2; // DMA4_CSDPi[1:0] 32-bit elements from MMCHS_DATA\r
+ Dma4.SourceEndiansim = 0; // DMA4_CSDPi[21] \r
+ Dma4.DestinationEndianism = 0; // DMA4_CSDPi[19]\r
+ Dma4.SourcePacked = 0; // DMA4_CSDPi[6]\r
+ Dma4.DestinationPacked = 0; // DMA4_CSDPi[13]\r
+ Dma4.NumberOfElementPerFrame = This->Media->BlockSize/4; // DMA4_CENi (TRM 4K is optimum value) \r
+ Dma4.NumberOfFramePerTransferBlock = BlockCount; // DMA4_CFNi \r
+ Dma4.ReadPriority = 0; // DMA4_CCRi[6] Low priority read \r
+ Dma4.WritePriority = 0; // DMA4_CCRi[23] Prefetech disabled\r
+
+ //Populate the command information based on the operation type.
+ if (OperationType == READ) {
+ Cmd = CMD18; //Multiple block read
+ CmdInterruptEnable = CMD18_INT_EN;
+ DmaOperation = MapOperationBusMasterCommonBuffer;
+
+ Dma4.ReadPortAccessType =0 ; // DMA4_CSDPi[8:7] Can not burst MMCHS_DATA reg\r
+ Dma4.WritePortAccessType = 3; // DMA4_CSDPi[15:14] Memory burst 16x32\r
+ Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted\r
+ \r
+ Dma4.SourceStartAddress = MMCHS_DATA; // DMA4_CSSAi\r
+ Dma4.DestinationStartAddress = (UINT32)BufferAddress; // DMA4_CDSAi\r
+ Dma4.SourceElementIndex = 1; // DMA4_CSEi\r
+ Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi\r
+ Dma4.DestinationElementIndex = 1; // DMA4_CDEi\r
+ Dma4.DestinationFrameIndex = 0; // DMA4_CDFi\r
+\r
+ Dma4.ReadPortAccessMode = 0; // DMA4_CCRi[13:12] Always read MMCHS_DATA\r
+ Dma4.WritePortAccessMode = 1; // DMA4_CCRi[15:14] Post increment memory address\r
+ Dma4.ReadRequestNumber = 0x1e; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_RX (61) \r
+ Dma4.WriteRequestNumber = 1; // DMA4_CCRi[20:19] Syncro upper 0x3e == 62 (one based)
+
+ } else if (OperationType == WRITE) {
+ Cmd = CMD25; //Multiple block write
+ CmdInterruptEnable = CMD25_INT_EN;
+ DmaOperation = MapOperationBusMasterRead;
+
+ Dma4.ReadPortAccessType = 3; // DMA4_CSDPi[8:7] Memory burst 16x32\r
+ Dma4.WritePortAccessType = 0; // DMA4_CSDPi[15:14] Can not burst MMCHS_DATA reg\r
+ Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted ???\r
+ \r
+ Dma4.SourceStartAddress = (UINT32)BufferAddress; // DMA4_CSSAi\r
+ Dma4.DestinationStartAddress = MMCHS_DATA; // DMA4_CDSAi\r
+ Dma4.SourceElementIndex = 1; // DMA4_CSEi\r
+ Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi\r
+ Dma4.DestinationElementIndex = 1; // DMA4_CDEi\r
+ Dma4.DestinationFrameIndex = 0; // DMA4_CDFi\r
+\r
+ Dma4.ReadPortAccessMode = 1; // DMA4_CCRi[13:12] Post increment memory address\r
+ Dma4.WritePortAccessMode = 0; // DMA4_CCRi[15:14] Always write MMCHS_DATA\r
+ Dma4.ReadRequestNumber = 0x1d; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_TX (60) \r
+ Dma4.WriteRequestNumber = 1; // DMA4_CCRi[20:19] Syncro upper 0x3d == 61 (one based)
+
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ EnableDmaChannel (2, &Dma4);
+
+
+ //Set command argument based on the card access mode (Byte mode or Block mode)
+ if (gCardInfo.OCRData.AccessMode & BIT1) {
+ CmdArgument = Lba;
+ } else {
+ CmdArgument = Lba * This->Media->BlockSize;
+ }
+
+ //Send Command.
+ Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));
+ return Status;
+ }
+
+ //Check for the Transfer completion.
+ while (RetryCount < MAX_RETRY_COUNT) {
+ //Read Status
+ do {
+ MmcStatus = MmioRead32 (MMCHS_STAT);
+ } while (MmcStatus == 0);
+
+ //Check if Transfer complete (TC) bit is set?
+ if (MmcStatus & TC) {
+ break;
+ } else {
+ DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus));
+ //Check if DEB, DCRC or DTO interrupt occured.
+ if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) {
+ //There was an error during the data transfer.
+
+ //Set SRD bit to 1 and wait until it return to 0x0.
+ MmioOr32 (MMCHS_SYSCTL, SRD);
+ while((MmioRead32 (MMCHS_SYSCTL) & SRD) != 0x0);
+
+ DisableDmaChannel (2, DMA4_CSR_BLOCK, DMA4_CSR_ERR);
+ DmaUnmap (BufferMap);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ RetryCount++;
+ }
+
+ DisableDmaChannel (2, DMA4_CSR_BLOCK, DMA4_CSR_ERR);
+ Status = DmaUnmap (BufferMap);
+
+ if (RetryCount == MAX_RETRY_COUNT) {
+ DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));
+ return EFI_TIMEOUT;
+ }
+
+ return Status;
+}
+
EFI_STATUS
-TransferBlockData (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- OUT VOID *Buffer,
+TransferBlock (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINTN Lba,
+ IN OUT VOID *Buffer,
IN OPERATION_TYPE OperationType
)
{
EFI_STATUS Status;
UINTN MmcStatus;
UINTN RetryCount = 0;
+ UINTN Cmd = 0;
+ UINTN CmdInterruptEnable = 0;
+ UINTN CmdArgument = 0;
+
+
+ //Populate the command information based on the operation type.
+ if (OperationType == READ) {
+ Cmd = CMD17; //Single block read
+ CmdInterruptEnable = CMD18_INT_EN;
+ } else if (OperationType == WRITE) {
+ Cmd = CMD24; //Single block write
+ CmdInterruptEnable = CMD24_INT_EN;
+ }
+
+ //Set command argument based on the card access mode (Byte mode or Block mode)
+ if (gCardInfo.OCRData.AccessMode & BIT1) {
+ CmdArgument = Lba;
+ } else {
+ CmdArgument = Lba * This->Media->BlockSize;
+ }
+
+ //Send Command.
+ Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));
+ return Status;
+ }
//Read or Write data.
if (OperationType == READ) {
- Status = ReadBlockData(This, Buffer);
+ Status = ReadBlockData (This, Buffer);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n"));
return Status;
}
} else if (OperationType == WRITE) {
- Status = WriteBlockData(This, Buffer);
+ Status = WriteBlockData (This, Buffer);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n"));
return Status;
gMMCHSMedia.ReadOnly = (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
gMMCHSMedia.MediaPresent = TRUE;
gMMCHSMedia.MediaId++;
- gMediaChange = FALSE;
+
+ DEBUG ((EFI_D_INFO, "SD Card Media Change on Handle 0x%08x\n", gImageHandle));
return Status;
}
+#define MAX_MMCHS_TRANSFER_SIZE 0x4000
EFI_STATUS
SdReadWrite (
{
EFI_STATUS Status = EFI_SUCCESS;
UINTN RetryCount = 0;
- UINTN NumBlocks;
- UINTN Cmd = 0;
- UINTN CmdInterruptEnable = 0;
- UINTN CmdArgument = 0;
+ UINTN BlockCount;
+ UINTN BytesToBeTranferedThisPass = 0;
+ UINTN BytesRemainingToBeTransfered;
EFI_TPL OldTpl;\r
- BOOLEAN MediaPresentLastTime;\r
BOOLEAN Update;\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-
-
- if (Buffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
Update = FALSE;
- MediaPresentLastTime = gMMCHSMedia.MediaPresent;
if (gMediaChange) {
+ Update = TRUE;
Status = DetectCard ();
if (EFI_ERROR (Status)) {
// We detected a removal
gMMCHSMedia.LastBlock = 0;
gMMCHSMedia.BlockSize = 512; // Should be zero but there is a bug in DiskIo
gMMCHSMedia.ReadOnly = FALSE;
- } else {
- Update = TRUE;
}
gMediaChange = FALSE;
} else if (!gMMCHSMedia.MediaPresent) {
goto Done;
}
- if ((MediaPresentLastTime != gMMCHSMedia.MediaPresent) || Update) {
+ if (Update) {
+ DEBUG ((EFI_D_INFO, "SD Card ReinstallProtocolInterface ()\n"));
gBS->ReinstallProtocolInterface (\r
gImageHandle,\r
&gEfiBlockIoProtocolGuid,\r
goto Done;
}
- if (Lba > This->Media->LastBlock) {
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (Lba > This->Media->LastBlock) {
Status = EFI_INVALID_PARAMETER;
goto Done;
}
goto Done;
}
- //Populate the command information based on the operation type.
- if (OperationType == READ) {
- Cmd = CMD17; //Single block read
- CmdInterruptEnable = CMD17_INT_EN;
- } else if (OperationType == WRITE) {
- Cmd = CMD24; //Single block write
- CmdInterruptEnable = CMD24_INT_EN;
- }
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- //Calculate total number of blocks its going to read.
- NumBlocks = (BufferSize + (This->Media->BlockSize - 1))/This->Media->BlockSize;
+ BytesRemainingToBeTransfered = BufferSize;
+ while (BytesRemainingToBeTransfered > 0) {
- //Set command argument based on the card access mode (Byte mode or Block mode)
- if (gCardInfo.OCRData.AccessMode & BIT1) {
- CmdArgument = (UINTN)Lba;
- } else {
- CmdArgument = (UINTN)Lba * This->Media->BlockSize;
- }
+ if (gMediaChange) {
+ Status = EFI_NO_MEDIA;
+ DEBUG ((EFI_D_INFO, "SdReadWrite() EFI_NO_MEDIA due to gMediaChange\n"));
+ goto DoneRestoreTPL;
+ }
- while(NumBlocks) {
- //Send Command.
- Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));
- goto Done;
+ // Turn OFF DMA path until it is debugged
+ // BytesToBeTranferedThisPass = (BytesToBeTranferedThisPass >= MAX_MMCHS_TRANSFER_SIZE) ? MAX_MMCHS_TRANSFER_SIZE : BytesRemainingToBeTransfered;
+ BytesToBeTranferedThisPass = This->Media->BlockSize;
+
+ BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize;
+
+ if (BlockCount > 1) {
+ Status = DmaBlocks (This, Lba, Buffer, BlockCount, OperationType);
+ } else {
+ //Transfer a block worth of data.
+ Status = TransferBlock (This, Lba, Buffer, OperationType);
}
- //Transfer a block worth of data.
- Status = TransferBlockData(This, Buffer, OperationType);
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));
- goto Done;
- }
-
- //Adjust command argument.
- if (gCardInfo.OCRData.AccessMode & BIT1) {
- CmdArgument++; //Increase BlockIndex by one.
- } else {
- CmdArgument += This->Media->BlockSize; //Increase BlockIndex by BlockSize
+ goto DoneRestoreTPL;
}
- //Adjust Buffer.
+ BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass;
+ Lba += BlockCount;
Buffer = (UINT8 *)Buffer + This->Media->BlockSize;
- NumBlocks--;
}
-Done:\r
+DoneRestoreTPL:\r
gBS->RestoreTPL (OldTpl);\r
+Done:\r
return Status;\r
}
ASSERT_EFI_ERROR(Status);
ZeroMem (&gCardInfo, sizeof (CARD_INFO));
-
+
Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, TimerCallback, NULL, &gTimerEvent);
ASSERT_EFI_ERROR (Status);
- Status = gBS->SetTimer (gTimerEvent, TimerPeriodic, 1000000); // make me a PCD
+ Status = gBS->SetTimer (gTimerEvent, TimerPeriodic, FixedPcdGet32 (PcdMmchsTimerFreq100NanoSeconds));
ASSERT_EFI_ERROR (Status);
//Publish BlockIO.