SdMmc/DwMmcHcDxe: read FIFO for small block data
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
diff --git a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h
index a18cbc5..df68c67 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h
+++ b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHcDxe.h
@@ -70,11 +70,11 @@
#define DW_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
typedef struct {
- BOOLEAN Enable;
- EFI_SD_MMC_SLOT_TYPE SlotType;
- BOOLEAN MediaPresent;
- BOOLEAN Initialized;
- SD_MMC_CARD_TYPE CardType;
+ BOOLEAN Enable;
+ EFI_SD_MMC_SLOT_TYPE SlotType;
+ BOOLEAN MediaPresent;
+ BOOLEAN Initialized;
+ SD_MMC_CARD_TYPE CardType;
} DW_MMC_HC_SLOT;
typedef struct {
@@ -137,6 +137,7 @@
EFI_PHYSICAL_ADDRESS DmaDescPhy;
UINT32 DmaDescPages;
VOID *DmaMap;
+ BOOLEAN UseDma;
DW_MMC_HC_PRIVATE_DATA *Private;
} DW_MMC_HC_TRB;
diff --git a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c
index b4e5aac..5038889 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c
+++ b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.c
@@ -948,7 +948,6 @@
if (EFI_ERROR (Status)) {
return Status;
}
-
return Status;
}
@@ -1076,6 +1075,7 @@
UINT32 DmaDescPhy;
UINT32 Idsts;
UINT32 BytCnt;
+ UINT32 BlkSize;
Data = Trb->DataPhy;
DataLen = Trb->DataLen;
@@ -1151,13 +1151,25 @@
return EFI_DEVICE_ERROR;
}
- BytCnt = DW_MMC_BLOCK_SIZE * Blocks;
+ if (DataLen < DW_MMC_BLOCK_SIZE) {
+ BlkSize = DataLen;
+ BytCnt = DataLen;
+ Remaining = DataLen;
+ } else {
+ BlkSize = DW_MMC_BLOCK_SIZE;
+ BytCnt = DW_MMC_BLOCK_SIZE * Blocks;
+ Remaining = DW_MMC_BLOCK_SIZE * Blocks;
+ }
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BLKSIZ, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "BuildDmaDescTable: set block size fails: %r\n", Status));
+ return Status;
+ }
Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BYTCNT, FALSE, sizeof (BytCnt), &BytCnt);
if (EFI_ERROR (Status)) {
return Status;
}
DmaDesc = Trb->DmaDesc;
- Remaining = DW_MMC_BLOCK_SIZE * Blocks;
for (Index = 0; Index < Entries; Index++, DmaDesc++) {
DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_CH |
DW_MMC_IDMAC_DES0_DIC;
@@ -1171,7 +1183,8 @@
// First Descriptor
Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS;
// Last Descriptor
- Trb->DmaDesc[Entries - 1].Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_LD;
+ Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH | DW_MMC_IDMAC_DES0_DIC);
+ Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_LD;
Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1 (Remaining + DWMMC_DMA_BUF_SIZE);
// Set the next field of the Last Descriptor
Trb->DmaDesc[Entries - 1].Des3 = 0;
@@ -1188,6 +1201,63 @@
return Status;
}
+EFI_STATUS
+ReadFifo (
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 Data;
+ UINT32 Received;
+ UINT32 Count;
+ UINT32 Intsts;
+ UINT32 Sts;
+ UINT32 FifoCount;
+
+ PciIo = Trb->Private->PciIo;
+ Received = 0;
+ Count = (Trb->DataLen + 3) / 4;
+ while (1) {
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, TRUE, sizeof (Intsts), &Intsts);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadFifo: failed to read RINTSTS, Status:%r\n", Status));
+ return Status;
+ }
+ if (Intsts & DW_MMC_INT_DTO) {
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_STATUS, TRUE, sizeof (Sts), &Sts);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadFifo: failed to read STATUS, Status:%r\n", Status));
+ return Status;
+ }
+ // Convert to bytes
+ FifoCount = GET_STS_FIFO_COUNT (Sts) << 2;
+ Count = (MIN (FifoCount, Trb->DataLen) + 3) / 4;
+ Received = 0;
+ // Read FIFO
+ while (Count && (Received < Count)) {
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_FIFO_START, TRUE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadFifo: failed to read FIFO, Status:%r\n", Status));
+ return Status;
+ }
+ *(UINT32 *)((UINTN)Trb->Data + ((Count - Received - 1) << 2)) = SwapBytes32 (Data);
+ Received++;
+ }
+ }
+ if (Intsts & DW_MMC_INT_CMD_DONE) {
+ break;
+ }
+ }
+ Intsts = ~0;
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, FALSE, sizeof (Intsts), &Intsts);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadFifo: failed to write RINTSTS, Status:%r\n", Status));
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
+
/**
Create a new TRB for the SD/MMC cmd request.
@@ -1246,10 +1316,6 @@
goto Error;
}
- if (Trb->DataLen < Trb->BlockSize) {
- Trb->BlockSize = (UINT16)Trb->DataLen;
- }
-
if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
(Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
((Private->Slot[Trb->Slot].CardType == SdCardType) &&
@@ -1263,8 +1329,10 @@
}
PciIo = Private->PciIo;
- if (Trb->DataLen != 0) {
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) && (Trb->DataLen != 0)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) && (Trb->DataLen >= DWMMC_FIFO_THRESHOLD))) {
MapLength = Trb->DataLen;
+ Trb->UseDma = TRUE;
Status = PciIo->Map (
PciIo,
Flag,
@@ -1277,9 +1345,7 @@
Status = EFI_BAD_BUFFER_SIZE;
goto Error;
}
- }
- if (Trb->DataLen) {
Status = BuildDmaDescTable (Trb);
if (EFI_ERROR (Status)) {
PciIo->Unmap (PciIo, Trb->DataMap);
@@ -1290,8 +1356,10 @@
PciIo->Unmap (PciIo, Trb->DataMap);
goto Error;
}
- }
- }
+ } else {
+ Trb->UseDma = FALSE;
+ } // Dma
+ } // TuningBlock
if (Event != NULL) {
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
@@ -1582,6 +1650,8 @@
UINT32 ErrMask;
UINT32 Timeout;
UINT32 Idsts;
+ UINT32 BytCnt;
+ UINT32 BlkSize;
Packet = Trb->Packet;
PciIo = Trb->Private->PciIo;
@@ -1643,6 +1713,20 @@
}
Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
+ if (Trb->UseDma == FALSE) {
+ BytCnt = Packet->InTransferLength;
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BYTCNT, FALSE, sizeof (BytCnt), &BytCnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ BlkSize = Packet->InTransferLength;
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_BLKSIZ, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "DwMmcHcReset: set block size fails: %r\n", Status));
+ return Status;
+ }
+ }
+
Argument = Packet->SdMmcCmdBlk->CommandArgument;
Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_CMDARG, FALSE, sizeof (Argument), &Argument);
if (EFI_ERROR (Status)) {
@@ -1661,47 +1745,57 @@
}
ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
DW_MMC_INT_RCRC | DW_MMC_INT_RE;
- ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT | DW_MMC_INT_SBE;
- Timeout = 10000;
- do {
- Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, TRUE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (IntStatus & ErrMask) {
- return EFI_DEVICE_ERROR;
- }
- if (IntStatus & DW_MMC_INT_DTO) { // Transfer Done
- break;
- }
- if (--Timeout == 0) {
- break;
- }
- MicroSecondDelay (10);
- } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
- if (Packet->InTransferLength) {
- do {
- Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } while ((Idsts & DW_MMC_IDSTS_RI) == 0);
- Status = DwMmcHcStopDma (Private, Trb);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else if (Packet->OutTransferLength) {
- do {
- Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } while ((Idsts & DW_MMC_IDSTS_TI) == 0);
- Status = DwMmcHcStopDma (Private, Trb);
- if (EFI_ERROR (Status)) {
- return Status;
- }
+ ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE;
+ if (Packet->InTransferLength || Packet->OutTransferLength) {
+ ErrMask |= DW_MMC_INT_DCRC;
}
+ if (Trb->UseDma == FALSE) {
+ Status = ReadFifo (Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Timeout = 10000;
+ do {
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_RINTSTS, TRUE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (IntStatus & ErrMask) {
+ return EFI_DEVICE_ERROR;
+ }
+ if (IntStatus & DW_MMC_INT_DTO) { // Transfer Done
+ break;
+ }
+ if (--Timeout == 0) {
+ break;
+ }
+ MicroSecondDelay (10);
+ } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
+ if (Packet->InTransferLength) {
+ do {
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } while ((Idsts & DW_MMC_IDSTS_RI) == 0);
+ Status = DwMmcHcStopDma (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Packet->OutTransferLength) {
+ do {
+ Status = DwMmcHcRwMmio (PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } while ((Idsts & DW_MMC_IDSTS_TI) == 0);
+ Status = DwMmcHcStopDma (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } // Packet->InTransferLength
+ } // UseDma
switch (Packet->SdMmcCmdBlk->ResponseType) {
case SdMmcResponseTypeR1:
case SdMmcResponseTypeR1b:
@@ -1802,6 +1896,9 @@
UINT32 Idsts;
Packet = Trb->Packet;
+ if (Trb->UseDma == FALSE) {
+ return EFI_SUCCESS;
+ }
if (Packet->InTransferLength) {
do {
Status = DwMmcHcRwMmio (Private->PciIo, Trb->Slot, DW_MMC_IDSTS, TRUE, sizeof (Idsts), &Idsts);
diff --git a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h
index 84f16fc..9f0380c 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h
+++ b/Drivers/SdMmc/DwMmcHcDxe/DwMmcHci.h
@@ -52,9 +52,11 @@
#define DW_MMC_RINTSTS 0x044
#define DW_MMC_STATUS 0x048
#define DW_MMC_FIFOTH 0x04c
+#define DW_MMC_GPIO 0x058
#define DW_MMC_DEBNCE 0x064
#define DW_MMC_USRID 0x068
#define DW_MMC_VERID 0x06c
+#define DW_MMC_HCON 0x070
#define DW_MMC_UHSREG 0x074
#define DW_MMC_BMOD 0x080
#define DW_MMC_DBADDR 0x088
@@ -63,6 +65,8 @@
#define DW_MMC_DSCADDR 0x094
#define DW_MMC_BUFADDR 0x098
#define DW_MMC_CARDTHRCTL 0x100
+#define DW_MMC_UHSREG_EXT 0x108
+#define DW_MMC_ENABLE_SHIFT 0x110
#define DW_MMC_FIFO_START 0x200
#define GET_IDSTS_DMAC_FSM(x) (((x) >> 13) & 0xf)
@@ -149,6 +153,8 @@
#define DW_MMC_CTRL_RESET_ALL (DW_MMC_CTRL_RESET | DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET)
#define DW_MMC_STS_DATA_BUSY (1 << 9)
+#define DW_MMC_STS_FIFO_COUNT(x) (((x) & 0x1fff) << 17) /* Number of filled locations in FIFO */
+#define GET_STS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff)
#define DW_MMC_BMOD_SWR (1 << 0) /* Software Reset */
#define DW_MMC_BMOD_FB (1 << 1) /* Fix Burst */
@@ -157,15 +163,25 @@
#define DW_MMC_IDSTS_TI (1 << 0) /* Transmit Interrupt */
#define DW_MMC_IDSTS_RI (1 << 1) /* Receive Interrupt */
-#define DW_MMC_FIFO_TWMARK(x) (x & 0xfff)
-#define DW_MMC_FIFO_RWMARK(x) ((x & 0x1ff) << 16)
-#define DW_MMC_DMA_BURST_SIZE(x) ((x & 0x7) << 28)
+#define DW_MMC_FIFO_TWMARK(x) ((x) & 0xfff)
+#define DW_MMC_FIFO_RWMARK(x) (((x) & 0x1ff) << 16)
+#define DW_MMC_DMA_BURST_SIZE(x) (((x) & 0x7) << 28)
-#define DW_MMC_CARD_RD_THR(x) ((x & 0xfff) << 16)
+#define DW_MMC_CARD_RD_THR(x) (((x) & 0xfff) << 16)
#define DW_MMC_CARD_RD_THR_EN (1 << 0)
#define UHS_DDR_MODE (1 << 16)
+#define GENCLK_DIV 7
+
+#define DW_MMC_GPIO_CLK_DIV(x) (((x) & 0xf) << 8)
+#define DW_MMC_GPIO_USE_SAMPLE_DLY(x) (((x) & 1) << 13)
+#define DW_MMC_GPIO_CLK_ENABLE BIT16
+
+#define UHSEXT_SAMPLE_PHASE(x) (((x) & 0x1f) << 16)
+#define UHSEXT_SAMPLE_DRVPHASE(x) (((x) & 0x1f) << 21)
+#define UHSEXT_SAMPLE_DLY(x) (((x) & 0x1f) << 26)
+
#define DWMMC_DMA_BUF_SIZE (512 * 8)
#define DWMMC_FIFO_THRESHOLD 16
diff --git a/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c b/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c
index 48f2b67..1bccdee 100644
--- a/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c
+++ b/Drivers/SdMmc/DwMmcHcDxe/SdDevice.c
@@ -918,6 +918,8 @@
BOOLEAN Xpc;
BOOLEAN S18r;
UINT64 MaxCurrent;
+ SD_SCR Scr;
+ SD_CSD Csd;
PciIo = Private->PciIo;
PassThru = &Private->PassThru;
@@ -941,7 +943,7 @@
// 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.
//
Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);
- if (!EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));
return EFI_DEVICE_ERROR;
}
@@ -1013,6 +1015,24 @@
DEBUG ((DEBUG_ERROR, "SdCardIdentification: Selecting card fails with %r\n", Status));
return Status;
}
+
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, 1);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSwitchBusWidth fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdCardGetScr (PassThru, Slot, Rca, &Scr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardGetScr fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdCardGetCsd (PassThru, Slot, Rca, &Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardGetCsd fails with %r\n", Status));
+ return Status;
+ }
//
// Enter Data Tranfer Mode.
//