MdeModulePkg/SdMmcPciHcDxe: Fix PIO transfer mode

Current driver does not support PIO transfer mode for
commands other then tuning. This change adds the code
to transfer PIO data.

Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Marcin Wojtas <mw@semihalf.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>
Cc: Liming Gao <liming.gao@intel.com>

Signed-off-by: Mateusz Albecki <mateusz.albecki@intel.com>
Tested-by: Hao A Wu <hao.a.wu@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
This commit is contained in:
Albecki, Mateusz 2020-02-28 01:25:26 +08:00 committed by mergify[bot]
parent 63fd7f3898
commit 9bfaa3da1e
2 changed files with 114 additions and 21 deletions

View File

@ -158,6 +158,9 @@ typedef struct {
UINT64 Timeout;
UINT32 Retries;
BOOLEAN PioModeTransferCompleted;
UINT32 PioBlockIndex;
SD_MMC_HC_ADMA_32_DESC_LINE *Adma32Desc;
SD_MMC_HC_ADMA_64_V3_DESC_LINE *Adma64V3Desc;
SD_MMC_HC_ADMA_64_V4_DESC_LINE *Adma64V4Desc;

View File

@ -1715,6 +1715,8 @@ SdMmcPrintTrb (
DEBUG ((DebugLevel, "CommandComplete: %d\n", Trb->CommandComplete));
DEBUG ((DebugLevel, "Timeout: %ld\n", Trb->Timeout));
DEBUG ((DebugLevel, "Retries: %d\n", Trb->Retries));
DEBUG ((DebugLevel, "PioModeTransferCompleted: %d\n", Trb->PioModeTransferCompleted));
DEBUG ((DebugLevel, "PioBlockIndex: %d\n", Trb->PioBlockIndex));
DEBUG ((DebugLevel, "Adma32Desc: %p\n", Trb->Adma32Desc));
DEBUG ((DebugLevel, "Adma64V3Desc: %p\n", Trb->Adma64V3Desc));
DEBUG ((DebugLevel, "Adma64V4Desc: %p\n", Trb->Adma64V4Desc));
@ -1819,6 +1821,8 @@ SdMmcCreateTrb (
Trb->CommandComplete = FALSE;
Trb->Timeout = Packet->Timeout;
Trb->Retries = SD_MMC_TRB_RETRIES;
Trb->PioModeTransferCompleted = FALSE;
Trb->PioBlockIndex = 0;
Trb->Private = Private;
if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
@ -2481,6 +2485,104 @@ SdMmcCheckCommandComplete (
return EFI_NOT_READY;
}
/**
Transfers data from card using PIO method.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
@param[in] IntStatus Snapshot of the normal interrupt status register.
@retval EFI_SUCCESS PIO transfer completed successfully.
@retval EFI_NOT_READY PIO transfer completion still pending.
@retval Others PIO transfer failed to complete.
**/
EFI_STATUS
SdMmcTransferDataWithPio (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN SD_MMC_HC_TRB *Trb,
IN UINT16 IntStatus
)
{
EFI_STATUS Status;
UINT16 Data16;
UINT32 BlockCount;
EFI_PCI_IO_PROTOCOL_WIDTH Width;
UINTN Count;
BlockCount = (Trb->DataLen / Trb->BlockSize);
if (Trb->DataLen % Trb->BlockSize != 0) {
BlockCount += 1;
}
if (Trb->PioBlockIndex >= BlockCount) {
return EFI_SUCCESS;
}
switch (Trb->BlockSize % sizeof (UINT32)) {
case 0:
Width = EfiPciIoWidthFifoUint32;
Count = Trb->BlockSize / sizeof (UINT32);
break;
case 2:
Width = EfiPciIoWidthFifoUint16;
Count = Trb->BlockSize / sizeof (UINT16);
break;
case 1:
case 3:
default:
Width = EfiPciIoWidthFifoUint8;
Count = Trb->BlockSize;
break;
}
if (Trb->Read) {
if ((IntStatus & BIT5) == 0) {
return EFI_NOT_READY;
}
Data16 = BIT5;
SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data16), &Data16);
Status = Private->PciIo->Mem.Read (
Private->PciIo,
Width,
Trb->Slot,
SD_MMC_HC_BUF_DAT_PORT,
Count,
(VOID*)((UINT8*)Trb->Data + (Trb->BlockSize * Trb->PioBlockIndex))
);
if (EFI_ERROR (Status)) {
return Status;
}
Trb->PioBlockIndex++;
} else {
if ((IntStatus & BIT4) == 0) {
return EFI_NOT_READY;
}
Data16 = BIT4;
SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data16), &Data16);
Status = Private->PciIo->Mem.Write (
Private->PciIo,
Width,
Trb->Slot,
SD_MMC_HC_BUF_DAT_PORT,
Count,
(VOID*)((UINT8*)Trb->Data + (Trb->BlockSize * Trb->PioBlockIndex))
);
if (EFI_ERROR (Status)) {
return Status;
}
Trb->PioBlockIndex++;
}
if (Trb->PioBlockIndex >= BlockCount) {
Trb->PioModeTransferCompleted = TRUE;
return EFI_SUCCESS;
} else {
return EFI_NOT_READY;
}
}
/**
Update the SDMA address on the SDMA buffer boundary interrupt.
@ -2565,6 +2667,13 @@ SdMmcCheckDataTransfer (
return Status;
}
if (Trb->Mode == SdMmcPioMode && !Trb->PioModeTransferCompleted) {
Status = SdMmcTransferDataWithPio (Private, Trb, IntStatus);
if (EFI_ERROR (Status)) {
return Status;
}
}
if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) != 0)) {
Data16 = BIT3;
Status = SdMmcHcRwMmio (
@ -2607,7 +2716,6 @@ SdMmcCheckTrbResult (
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
UINT16 IntStatus;
UINT32 PioLength;
Packet = Trb->Packet;
//
@ -2643,26 +2751,8 @@ SdMmcCheckTrbResult (
(Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
((Private->Slot[Trb->Slot].CardType == SdCardType) &&
(Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
//
// When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
// wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
// Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
//
if ((IntStatus & BIT5) == BIT5) {
//
// Clear Buffer Read Ready interrupt at first.
//
IntStatus = BIT5;
SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
//
// Read data out from Buffer Port register
//
for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);
}
Status = EFI_SUCCESS;
goto Done;
}
Status = SdMmcTransferDataWithPio (Private, Trb, IntStatus);
goto Done;
}
if (!Trb->CommandComplete) {