/** @file * * Copyright (c) 2017, Andrei Warkentin * Copyright (c) Microsoft Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include "SdhciHostDxe.h" #include #include #include #include #include #define CONFIG_MMC_SDHCI_SDMA #define word32 *(volatile unsigned int *)(long) //#define SDHCI_MAX_RETRY_COUNT (1000 * 20) // MMC/SD/SDIO1 register definitions. #define MMCHS1_OFFSET 0x00300000 #define MMCHS2_OFFSET 0x00340000 #define MMCHS1_BASE (BCM2836_SOC_REGISTERS + MMCHS1_OFFSET) #define MMCHS2_BASE (BCM2836_SOC_REGISTERS + MMCHS2_OFFSET) #define MMCHS1_LENGTH 0x00000100 #define MMCHS2_LENGTH 0x00000100 #define MMCHS_DMA_ADDRESS (mMmcHsBase + 0x0) #define MMCHS_BLK_SIZE (mMmcHsBase + 0x4) #define MMCHS_BLK_COUNT (mMmcHsBase + 0x6) #define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) /* * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. */ #define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) #define SDHCI_DEFAULT_BOUNDARY_ARG (7) #define MMCHS_TRANS_MODE (mMmcHsBase + 0xC) #define SDHCI_TRNS_DMA BIT0 #define SDHCI_TRNS_BLK_CNT_EN BIT1 #define SDHCI_TRNS_ACMD12 BIT2 #define SDHCI_TRNS_READ BIT4 #define SDHCI_TRNS_MULTI BIT5 #define BLEN_512BYTES (0x200UL << 0) #define MMCHS_ARG (mMmcHsBase + 0x8) #define MMCHS_CMD (mMmcHsBase + 0xC) #define MMCHS_CMD16 (mMmcHsBase + 0xE) #define BCE_ENABLE BIT1 #define DDIR_READ BIT4 #define DDIR_WRITE (0x0UL << 4) #define MSBS_SGLEBLK (0x0UL << 5) #define MSBS_MULTBLK BIT5 #define RSP_TYPE_MASK (0x3UL << 16) #define RSP_TYPE_136BITS BIT16 #define RSP_TYPE_48BITS (0x2UL << 16) #define RSP_TYPE_48BUSY (0x3UL << 16) #define CCCE_ENABLE BIT19 #define CICE_ENABLE BIT20 #define DP_ENABLE BIT21 #define CMD_TYPE_NORMAL 0 #define CMD_TYPE_ABORT 3 #define TYPE(CMD_TYPE) (((CMD_TYPE) & 0x3) << 22) #define _INDX(CMD_INDX) ((CMD_INDX & 0x3F) << 24) #define MMC_CMD_NUM(CMD) (((CMD) >> 24) & 0x3F) #define INDX(CMD_INDX) (TYPE(CMD_TYPE_NORMAL) | _INDX(CMD_INDX)) #define INDX_ABORT(CMD_INDX) (TYPE(CMD_TYPE_ABORT) | _INDX(CMD_INDX)) #define MMCHS_RSP10 (mMmcHsBase + 0x10) #define MMCHS_RSP32 (mMmcHsBase + 0x14) #define MMCHS_RSP54 (mMmcHsBase + 0x18) #define MMCHS_RSP76 (mMmcHsBase + 0x1C) #define MMCHS_DATA (mMmcHsBase + 0x20) #define MMCHS_PRES_STATE (mMmcHsBase + 0x24) #define CMDI_MASK BIT0 #define CMDI_ALLOWED (0x0UL << 0) #define CMDI_NOT_ALLOWED BIT0 #define DATI_MASK BIT1 #define DATI_ALLOWED (0x0UL << 1) #define DATI_NOT_ALLOWED BIT1 #define WRITE_PROTECT_OFF BIT19 #define SDHCI_CMD_INHIBIT BIT0 #define SDHCI_DATA_INHIBIT BIT1 #define SDHCI_DOING_WRITE BIT8 #define SDHCI_DOING_READ BIT9) #define SDHCI_SPACE_AVAILABLE BIT10 #define SDHCI_DATA_AVAILABLE BIT11 #define SDHCI_CARD_PRESENT BIT16 #define SDHCI_CARD_STATE_STABLE BIT17 #define SDHCI_CARD_DETECT_PIN_LEVEL BIT18 #define SDHCI_WRITE_PROTECT BIT19 #define SDHCI_DATA_0_LVL BIT20 #define MMCHS_HCTL (mMmcHsBase + 0x28) #define DTW_1_BIT (0x0UL << 1) #define DTW_4_BIT BIT1 #define HIGH_SPEED_EN BIT2 #define DTW_8_BIT BIT5 #define SDBP_MASK BIT8 #define SDBP_OFF (0x0UL << 8) #define SDBP_ON BIT8 #define SDVS_MASK (0x7UL << 9) #define SDVS_1_8_V (0x5UL << 9) #define SDVS_3_0_V (0x6UL << 9) #define SDVS_3_3_V (0x7UL << 9) #define IWE BIT24 #define SDHCI_CTRL_LED BIT0 #define SDHCI_CTRL_4BITBUS BIT1 #define SDHCI_CTRL_HISPD BIT2 #define SDHCI_CTRL_DMA_MASK 0x18 #define SDHCI_CTRL_SDMA 0x00 #define MMCHS_SYSCTL (mMmcHsBase + 0x2C) #define ICE BIT0 #define ICS_MASK BIT1 #define ICS BIT1 #define CEN BIT2 #define CLKD_MASK (0x3FFUL << 6) #define CLKD_80KHZ (0x258UL) //(96*1000/80)/2 #define CLKD_400KHZ (0xF0UL) #define CLKD_12500KHZ (0x200UL) #define DTO_MASK (0xFUL << 16) #define DTO_VAL (0xEUL << 16) #define SRA BIT24 #define SRC_MASK BIT25 #define SRC BIT25 #define SRD BIT26 #define MMCHS_RESET (mMmcHsBase + 0x2F) #define RST_ALL 0x01 #define RST_CMD 0x02 #define RST_DATA 0x04 #define MMCHS_INT_STAT (mMmcHsBase + 0x30) #define CC BIT0 #define TC BIT1 #define BWR BIT4 #define BRR BIT5 #define CARD_INS BIT6 #define ERRI BIT15 #define CTO BIT16 #define DTO BIT20 #define DCRC BIT21 #define DEB BIT22 #define SDHCI_INT_RESPONSE BIT0 #define SDHCI_INT_DATA_END BIT1 #define SDHCI_INT_DMA_END BIT3 #define SDHCI_INT_SPACE_AVAIL BIT4 #define SDHCI_INT_DATA_AVAIL BIT5 #define SDHCI_INT_CARD_INSERT BIT6 #define SDHCI_INT_CARD_REMOVE BIT7 #define SDHCI_INT_CARD_INT BIT8 #define SDHCI_INT_ERROR BIT15 #define SDHCI_INT_TIMEOUT BIT16 #define SDHCI_INT_CRC BIT17 #define SDHCI_INT_END_BIT BIT18 #define SDHCI_INT_INDEX BIT19 #define SDHCI_INT_DATA_TIMEOUT BIT20 #define SDHCI_INT_DATA_CRC BIT21 #define SDHCI_INT_DATA_END_BIT BIT22 #define SDHCI_INT_BUS_POWER BIT23 #define SDHCI_INT_ACMD12ERR BIT24 #define SDHCI_INT_ADMA_ERROR BIT25 #define MMCHS_IE (mMmcHsBase + 0x34) #define CC_EN BIT0 #define TC_EN BIT1 #define BWR_EN BIT4 #define BRR_EN BIT5 #define CTO_EN BIT16 #define CCRC_EN BIT17 #define CEB_EN BIT18 #define CIE_EN BIT19 #define DTO_EN BIT20 #define DCRC_EN BIT21 #define DEB_EN BIT22 #define CERR_EN BIT28 #define BADA_EN BIT29 #define ALL_EN 0x27f003b //0xFFFFFFFF #define ALL_MASK 0xFFFFFFFF #define MMCHS_ISE (mMmcHsBase + 0x38) #define CC_SIGEN BIT0 #define TC_SIGEN BIT1 #define BWR_SIGEN BIT4 #define BRR_SIGEN BIT5 #define CTO_SIGEN BIT16 #define CCRC_SIGEN BIT17 #define CEB_SIGEN BIT18 #define CIE_SIGEN BIT19 #define DTO_SIGEN BIT20 #define DCRC_SIGEN BIT21 #define DEB_SIGEN BIT22 #define CERR_SIGEN BIT28 #define BADA_SIGEN BIT29 #define MMCHS_AC12 (mMmcHsBase + 0x3C) #define MMCHS_HCTL2 (mMmcHsBase + 0x3E) #define SDHCI_CTRL_UHS_MASK 0x0007 #define SDHCI_CTRL_UHS_SDR12 0x0000 #define SDHCI_CTRL_UHS_SDR25 0x0001 #define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 #define SDHCI_CTRL_EMMC_SDR50 0x0001 #define SDHCI_CTRL_EMMC_HS200 0x0003 #define SDHCI_CTRL_EMMC_HS400 0x0007 #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 #define SDHCI_CTRL_DRV_TYPE_A 0x0010 #define SDHCI_CTRL_DRV_TYPE_C 0x0020 #define SDHCI_CTRL_DRV_TYPE_D 0x0030 #define SDHCI_CTRL_EXEC_TUNING 0x0040 #define SDHCI_CTRL_TUNED_CLK 0x0080 #define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 #define MMCHS_CAPA (mMmcHsBase + 0x40) #define VS30 BIT25 #define VS18 BIT26 #define MMCHS_CUR_CAPA (mMmcHsBase + 0x48) #define MMCHS_REV (mMmcHsBase + 0xFC) #define BLOCK_COUNT_SHIFT 16 #define RCA_SHIFT 16 #define CMD_R1 (RSP_TYPE_48BITS | CCCE_ENABLE | CICE_ENABLE) #define CMD_R1B (RSP_TYPE_48BUSY | CCCE_ENABLE | CICE_ENABLE) #define CMD_R2 (RSP_TYPE_136BITS | CCCE_ENABLE) #define CMD_R3 (RSP_TYPE_48BITS) #define CMD_R6 (RSP_TYPE_48BITS | CCCE_ENABLE | CICE_ENABLE) #define CMD_R7 (RSP_TYPE_48BITS | CCCE_ENABLE | CICE_ENABLE) #define CMD_R1_ADTC (CMD_R1 | DP_ENABLE) #define CMD_R1_ADTC_READ (CMD_R1_ADTC | DDIR_READ) #define CMD_R1_ADTC_WRITE (CMD_R1_ADTC | DDIR_WRITE) #define CMD0 (INDX(0)) // Go idle #define CMD1 (INDX(1) | CMD_R3) // MMC: Send Op Cond #define CMD2 (INDX(2) | CMD_R2) // Send CID #define CMD3 (INDX(3) | CMD_R6) // Set Relative Addr #define CMD4 (INDX(4)) // Set DSR #define CMD5 (INDX(5) | CMD_R1B) // SDIO: Sleep/Awake //#define CMD6 (INDX(6) | CMD_R1_ADTC_READ) // Switch #define CMD6 (INDX(6) | CMD_R1B) // Switch #define CMD7 (INDX(7) | CMD_R1) // Select/Deselect #define CMD8_SD (INDX(8) | CMD_R7) // Send If Cond #define CMD8_SD_ARG (0x0UL << 12 | BIT8 | 0xCEUL << 0) #define CMD8_MMC (INDX(8) | CMD_R1_ADTC_READ) // Send Ext Csd #define CMD8_MMC_ARG (0) #define CMD9 (INDX(9) | CMD_R2) // Send CSD #define CMD10 (INDX(10) | CMD_R2) // Send CID #define CMD11 (INDX(11) | CMD_R1) // Voltage Switch #define CMD12 (INDX_ABORT(12) | CMD_R1B) // Stop Transmission #define CMD13 (INDX(13) | CMD_R1) // Send Status #define CMD15 (INDX(15)) // Go inactive state #define CMD16 (INDX(16) | CMD_R1) // Set Blocklen #define CMD17 (INDX(17) | CMD_R1_ADTC_READ) // Read Single Block #define CMD18 (INDX(18) | CMD_R1_ADTC_READ | MSBS_MULTBLK) // Read Multiple Blocks #define CMD19 (INDX(19) | CMD_R1_ADTC_READ) // SD: Send Tuning Block (64 bytes) #define CMD20 (INDX(20) | CMD_R1B) // SD: Speed Class Control #define CMD23 (INDX(23) | CMD_R1) // Set Block Count for CMD18 and CMD25 #define CMD24 (INDX(24) | CMD_R1_ADTC_WRITE) // Write Block #define CMD25 (INDX(25) | CMD_R1_ADTC_WRITE | MSBS_MULTBLK) // Write Multiple Blocks #define CMD55 (INDX(55) | CMD_R1) // App Cmd #define ACMD6 (INDX(6) | CMD_R1) // Set Bus Width #define ACMD22 (INDX(22) | CMD_R1_ADTC_READ) // SEND_NUM_WR_BLOCKS #define ACMD41 (INDX(41) | CMD_R3) // Send Op Cond #define ACMD51 (INDX(51) | CMD_R1_ADTC_READ) // Send SCR #define MMC_ACMD22 (MMC_INDX(22) | MMC_CMD_WAIT_RESPONSE) // User-friendly command names #define CMD_IO_SEND_OP_COND CMD5 #define CMD_SEND_CSD CMD9 // CSD: Card-Specific Data #define CMD_STOP_TRANSMISSION CMD12 #define CMD_SEND_STATUS CMD13 #define CMD_READ_SINGLE_BLOCK CMD17 #define CMD_READ_MULTIPLE_BLOCK CMD18 #define CMD_SET_BLOCK_COUNT CMD23 #define CMD_WRITE_SINGLE_BLOCK CMD24 #define CMD_WRITE_MULTIPLE_BLOCK CMD25 #define DEBUG_MMCHOST_SD DEBUG_INFO #define MMC_DATA_READ 1 #define MMC_DATA_WRITE 2 typedef struct { UINT8 *buffer; UINT32 flags; UINT32 blocks; UINT32 blocksize; } SDHCI_DATA; //STATIC BOOLEAN mCardIsPresent = FALSE; //STATIC CARD_DETECT_STATE mCardDetectState = CardDetectRequired; UINT32 LastExecutedCommand = (UINT32) -1; STATIC UINTN mMmcHsBase; STATIC UINT32 mMmcDataCommand; STATIC UINT32 mMmcDataArgument; STATIC SDHCI_DATA gSdhciData; STATIC UINT32 EFIAPI SdMmioWrite32 ( IN UINTN Address, IN UINT32 Value ) { UINT32 ret; ret = (UINT32)MmioWrite32 (Address, Value); // There is a bug about clock domain crossing on writes, delay to avoid it //gBS->Stall (STALL_AFTER_REG_WRITE_US); return ret; } STATIC UINT32 EFIAPI SdMmioOr32 ( IN UINTN Address, IN UINT32 OrData ) { return SdMmioWrite32 (Address, MmioRead32 (Address) | OrData); } STATIC UINT32 EFIAPI SdMmioAnd32 ( IN UINTN Address, IN UINT32 AndData ) { return SdMmioWrite32 (Address, MmioRead32 (Address) & AndData); } STATIC UINT32 EFIAPI SdMmioAndThenOr32 ( IN UINTN Address, IN UINT32 AndData, IN UINT32 OrData ) { return SdMmioWrite32 (Address, (MmioRead32 (Address) & AndData) | OrData); } void IomemShow(const char *label, unsigned long base, unsigned int start, unsigned int end) { unsigned int val, offset = start, nr = 0; if (label) DEBUG ((DEBUG_ERROR, "%a:\n", label)); DEBUG ((DEBUG_ERROR, "%08lx: ", base + offset)); for (offset = start; offset <= end; offset += 0x04) { if (nr >= 4) { DEBUG ((DEBUG_ERROR, "\n%08lx: ", base + offset)); nr = 0; } val = MmioRead32(base + offset); DEBUG ((DEBUG_ERROR, "%08lx ", val)); nr++; } DEBUG ((DEBUG_ERROR, "\n")); } /** These SD commands are optional, according to the SD Spec **/ BOOLEAN IgnoreCommand ( UINT32 Command ) { switch (Command) { case MMC_CMD20: return TRUE; default: return FALSE; } } /** Translates a generic SD command into the format used by the Arasan SD Host Controller **/ UINT32 TranslateCommand ( UINT32 Command, UINT32 Argument ) { UINT32 Translation = 0xffffffff; if (LastExecutedCommand == CMD55) { switch (Command) { case MMC_CMD6: Translation = ACMD6; DEBUG ((DEBUG_MMCHOST_SD, "ACMD6\n")); break; case MMC_ACMD22: Translation = ACMD22; DEBUG ((DEBUG_MMCHOST_SD, "ACMD22\n")); break; case MMC_ACMD41: Translation = ACMD41; DEBUG ((DEBUG_MMCHOST_SD, "ACMD41\n")); break; case MMC_ACMD51: Translation = ACMD51; DEBUG ((DEBUG_MMCHOST_SD, "ACMD51\n")); break; default: DEBUG ((DEBUG_ERROR, "MMCHost: TranslateCommand(): Unrecognized App command: %d\n", Command)); } } else { switch (Command) { case MMC_CMD0: Translation = CMD0; break; case MMC_CMD1: Translation = CMD1; break; case MMC_CMD2: Translation = CMD2; break; case MMC_CMD3: Translation = CMD3; break; case MMC_CMD5: Translation = CMD5; break; case MMC_CMD6: Translation = CMD6; break; case MMC_CMD7: Translation = CMD7; break; case MMC_CMD8: { if (Argument == CMD8_SD_ARG) { Translation = CMD8_SD; DEBUG ((DEBUG_MMCHOST_SD, "Sending SD CMD8 variant\n")); } else { ASSERT (Argument == CMD8_MMC_ARG); Translation = CMD8_MMC; DEBUG ((DEBUG_MMCHOST_SD, "Sending MMC CMD8 variant\n")); } break; } case MMC_CMD9: Translation = CMD9; break; case MMC_CMD11: Translation = CMD11; break; case MMC_CMD12: Translation = CMD12; break; case MMC_CMD13: Translation = CMD13; break; case MMC_CMD16: Translation = CMD16; break; case MMC_CMD17: Translation = CMD17; break; case MMC_CMD18: Translation = CMD18; break; case MMC_CMD23: Translation = CMD23; break; case MMC_CMD24: Translation = CMD24; break; case MMC_CMD25: Translation = CMD25; break; case MMC_CMD55: Translation = CMD55; break; default: DEBUG ((DEBUG_ERROR, "MMCHost: TranslateCommand(): Unrecognized Command: %d\n", Command)); } } return Translation; } /** Repeatedly polls a register until its value becomes correct, or until MAX_RETRY_COUNT polls is reached **/ EFI_STATUS PollRegisterWithMask ( IN UINTN Register, IN UINTN Mask, IN UINTN ExpectedValue ) { UINTN RetryCount = 0; while (RetryCount < MAX_RETRY_COUNT) { if ((MmioRead32 (Register) & Mask) != ExpectedValue) { RetryCount++; MicroSecondDelay(2); } else { break; } } if (RetryCount == MAX_RETRY_COUNT) { return EFI_TIMEOUT; } return EFI_SUCCESS; } /** Calculate the clock divisor **/ EFI_STATUS CalculateClockFrequencyDivisor ( IN UINTN TargetFrequency, OUT UINT32 *DivisorValue, OUT UINTN *ActualFrequency ) { EFI_STATUS Status; UINT32 Divisor; UINTN BaseFrequency = 0; Status = SdhciGetClockRate(TargetFrequency, &BaseFrequency); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Couldn't get RPI_MBOX_CLOCK_RATE_EMMC\n")); return Status; } ASSERT (BaseFrequency != 0); Divisor = BaseFrequency / TargetFrequency; // Arasan controller is based on 3.0 spec so the div is multiple of 2 // Actual Frequency = BaseFequency/(Div*2) Divisor /= 2; if ((TargetFrequency < BaseFrequency) && (TargetFrequency * 2 * Divisor != BaseFrequency)) { Divisor += 1; } if (Divisor > MAX_DIVISOR_VALUE) { Divisor = MAX_DIVISOR_VALUE; } DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: BaseFrequency 0x%x Divisor 0x%x\n", BaseFrequency, Divisor)); *DivisorValue = (Divisor & 0xFF) << 8; Divisor >>= 8; *DivisorValue |= (Divisor & 0x03) << 6; if (ActualFrequency) { if (Divisor == 0) { *ActualFrequency = BaseFrequency; } else { *ActualFrequency = BaseFrequency / Divisor; *ActualFrequency >>= 1; } DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: *ActualFrequency 0x%x\n", *ActualFrequency)); } DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: *DivisorValue 0x%x\n", *DivisorValue)); return EFI_SUCCESS; } STATIC EFI_STATUS SdhciSoftReset ( IN UINT32 Mask ) { DEBUG ((DEBUG_INFO, "SoftReset with mask 0x%x\n", Mask)); SdMmioOr32 (MMCHS_SYSCTL, Mask); if (PollRegisterWithMask (MMCHS_SYSCTL, Mask, 0) == EFI_TIMEOUT) { DEBUG ((DEBUG_ERROR, "Failed to SoftReset with mask 0x%x\n", Mask)); return EFI_TIMEOUT; } return EFI_SUCCESS; } STATIC void SdhciTransferPio( IN EFI_MMC_HOST_PROTOCOL *This, IN SDHCI_DATA *data ) { UINT32 *buf = (UINT32 *)data->buffer; UINT32 len = data->blocksize>>2; if (data->flags == MMC_DATA_READ) { while(len--) *buf++ = MmioRead32 (MMCHS_DATA); } else { while(len--) MmioWrite32 (MMCHS_DATA, *buf++); } } STATIC EFI_STATUS SdhciTransferData( IN EFI_MMC_HOST_PROTOCOL *This, IN SDHCI_DATA *data, IN UINTN StartAddr ) { unsigned int stat, rdy, mask, timeout, block = 0; BOOLEAN transfer_done = FALSE; #ifdef CONFIG_MMC_SDHCI_SDMA unsigned char ctrl; ctrl = MmioRead8(MMCHS_HCTL); ctrl &= ~SDHCI_CTRL_DMA_MASK; MmioWrite8(MMCHS_HCTL, ctrl); #endif timeout = 1000000; rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE; do { stat = MmioRead32(MMCHS_INT_STAT); if (stat & SDHCI_INT_ERROR) { //UINT32 i, *Buffer; DEBUG ((DEBUG_ERROR, "+++++%a Error detected in status(0x%X)!\n", __FUNCTION__, stat)); #if 0 IomemShow("emmc regs", (unsigned long)mMmcHsBase, 0, 0x3E); IomemShow("PHY regs", (unsigned long)(mMmcHsBase+0x800), 0, 0x13); Buffer = (UINT32*)data->buffer; for (i = 0; i < 128*data->blocks; i++) { if (0xCCCCCCCC == Buffer[i]) { break; } } DEBUG ((DEBUG_ERROR, "Buffer[%u]:0x%x, 0x%x\n", i-2, Buffer[i-2], Buffer[i-1])); DEBUG ((DEBUG_ERROR, "blocks:%u Trans size:%u, blks:%u\n", data->blocks, i*4, i/128)); IomemShow("last buf", (unsigned long)&Buffer[i], 0, 0x1FF); #endif return EFI_DEVICE_ERROR; } if (!transfer_done && (stat & rdy)) { if (!(MmioRead32(MMCHS_PRES_STATE) & mask)) continue; MmioWrite32(MMCHS_INT_STAT, rdy); SdhciTransferPio(This, data); data->buffer += data->blocksize; if (++block >= data->blocks) { /* Keep looping until the SDHCI_INT_DATA_END is * cleared, even if we finished sending all the * blocks. */ transfer_done = TRUE; continue; } } #ifdef CONFIG_MMC_SDHCI_SDMA if (!transfer_done && (stat & SDHCI_INT_DMA_END)) { MmioWrite32(MMCHS_INT_STAT, SDHCI_INT_DMA_END); StartAddr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1); StartAddr += SDHCI_DEFAULT_BOUNDARY_SIZE; MmioWrite32 (MMCHS_DMA_ADDRESS, (UINT32)StartAddr); } #endif if (timeout-- > 0) MicroSecondDelay(5); else { DEBUG ((DEBUG_ERROR, "%a Transfer data timeout\n", __FUNCTION__)); return EFI_TIMEOUT; } } while (!(stat & SDHCI_INT_DATA_END)); return EFI_SUCCESS; } EFI_STATUS SdhciSendCommand ( IN EFI_MMC_HOST_PROTOCOL *This, IN MMC_CMD MmcCmd, IN UINT32 Argument, IN UINT32 CmdSendOKMask ) { UINTN MmcStatus; UINTN RetryCount = 0; EFI_STATUS Status = EFI_SUCCESS; DEBUG ((DEBUG_MMCHOST_SD, "DATA_CMD REG:0x%x 0x%x 0x%x\n", MmcCmd, Argument, LastExecutedCommand)); DEBUG ((DEBUG_MMCHOST_SD, "BLK SIZE:0x%x 0x%x\n", MmioRead16(MMCHS_BLK_SIZE), MmioRead16(MMCHS_BLK_COUNT))); DEBUG ((DEBUG_MMCHOST_SD, "PSTATE:0x%x 0x%x\n", MmioRead32(MMCHS_PRES_STATE), MmioRead32(MMCHS_INT_STAT))); //IomemShow("SDHCI", mMmcHsBase, 0, 0xFF); MmioWrite16 (MMCHS_TRANS_MODE, (MmcCmd&0xffff)); // Set command argument register MmioWrite32 (MMCHS_ARG, Argument); //DEBUG ((DEBUG_ERROR, "MmcCmd:0x%x\n", (MmcCmd>>16))); // Send the command MmioWrite16 (MMCHS_CMD16, (MmcCmd>>16)); // Check for the command status. while (RetryCount < MAX_RETRY_COUNT) { MmcStatus = MmioRead32(MMCHS_INT_STAT); // Read status of command response if ((MmcStatus & ERRI) != 0) { // CMD5 (CMD_IO_SEND_OP_COND) is only valid for SDIO // cards and thus expected to fail. DEBUG ((DEBUG_ERROR, "%a(%u): MMC_CMD%u completion TIMEOUT PresState 0x%x MmcStatus 0x%x,0x%x\n", __FUNCTION__, __LINE__, MMC_CMD_NUM (MmcCmd), MmioRead32 (MMCHS_PRES_STATE), MmcStatus, CmdSendOKMask)); SdhciSoftReset(SRC); Status = EFI_DEVICE_ERROR; goto Exit; } // Check if command is completed. if ((MmcStatus & CmdSendOKMask) == CmdSendOKMask) { SdMmioWrite32 (MMCHS_INT_STAT, CmdSendOKMask); break; } RetryCount++; MicroSecondDelay(1); } if (RetryCount == MAX_RETRY_COUNT) { DEBUG ((DEBUG_ERROR, "%a(%u): MMC_CMD%u completion TIMEOUT PresState 0x%x MmcStatus 0x%x,0x%x\n", __FUNCTION__, __LINE__, MMC_CMD_NUM (MmcCmd), MmioRead32 (MMCHS_PRES_STATE), MmcStatus, CmdSendOKMask)); Status = EFI_TIMEOUT; goto Exit; } Exit: if (EFI_ERROR (Status)) { LastExecutedCommand = (UINT32) -1; } else { LastExecutedCommand = MmcCmd; } return Status; } EFI_STATUS MMCSetClock ( IN UINTN ClockFrequency ) { EFI_STATUS Status; UINT32 Divisor; // First turn off the clock SdMmioAnd32 (MMCHS_SYSCTL, ~CEN); Status = CalculateClockFrequencyDivisor (ClockFrequency, &Divisor, NULL); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "MMCHost: MmcStandByState(): Fail to initialize SD clock to %u Hz\n", ClockFrequency)); return Status; } // Setup new divisor SdMmioAndThenOr32 (MMCHS_SYSCTL, (UINT32) ~CLKD_MASK, Divisor); // Wait for the clock to stabilise while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS); // Set Data Timeout Counter value, set clock frequency, enable internal clock SdMmioOr32 (MMCHS_SYSCTL, CEN); return EFI_SUCCESS; } BOOLEAN MMCIsReadOnly ( IN EFI_MMC_HOST_PROTOCOL *This ) { BOOLEAN IsReadOnly = !((MmioRead32 (MMCHS_PRES_STATE) & WRITE_PROTECT_OFF) == WRITE_PROTECT_OFF); DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: MMCIsReadOnly(): %d\n", IsReadOnly)); return IsReadOnly; } EFI_STATUS MMCBuildDevicePath ( IN EFI_MMC_HOST_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL **DevicePath ) { EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; EFI_GUID DevicePathGuid = EFI_CALLER_ID_GUID; DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: MMCBuildDevicePath()\n")); NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH)); CopyGuid (&((VENDOR_DEVICE_PATH*) NewDevicePathNode)->Guid, &DevicePathGuid); *DevicePath = NewDevicePathNode; return EFI_SUCCESS; } EFI_STATUS MMCSendCommand ( IN EFI_MMC_HOST_PROTOCOL *This, IN MMC_CMD MmcCmd, IN UINT32 Argument ) { UINTN MmcStatus; UINTN RetryCount = 0; UINTN CmdSendOKMask; EFI_STATUS Status = EFI_SUCCESS; BOOLEAN IsAppCmd = (LastExecutedCommand == CMD55); BOOLEAN IsDATCmd = FALSE; //BOOLEAN IsADTCCmd = FALSE; SDHCI_DATA *data = &gSdhciData; DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: MMCSendCommand(MmcCmd: %08x, Argument: %08x)\n", MmcCmd, Argument)); if (IgnoreCommand (MmcCmd)) { return EFI_SUCCESS; } MmcCmd = TranslateCommand (MmcCmd, Argument); if (MmcCmd == 0xffffffff) { return EFI_UNSUPPORTED; } if ((MmcCmd & CMD_R1_ADTC) == CMD_R1_ADTC) { IsDATCmd = TRUE; } #if 0 if (((MmcCmd & CMD_R1B) == CMD_R1B && /* * Abort commands don't get inhibited by DAT. */ (MmcCmd & TYPE (CMD_TYPE_ABORT)) != TYPE (CMD_TYPE_ABORT)) || IsADTCCmd || /* * We want to detect BRR/BWR change. */ MmcCmd == CMD_SEND_STATUS) { IsDATCmd = TRUE; } #endif CmdSendOKMask = CMDI_MASK; if (IsDATCmd) { CmdSendOKMask |= DATI_MASK; } if (PollRegisterWithMask (MMCHS_PRES_STATE, CmdSendOKMask, 0) == EFI_TIMEOUT) { DEBUG ((DEBUG_ERROR, "%a(%u): not ready for MMC_CMD%u PresState 0x%x MmcStatus 0x%x\n", __FUNCTION__, __LINE__, MMC_CMD_NUM (MmcCmd), MmioRead32 (MMCHS_PRES_STATE), MmioRead32 (MMCHS_INT_STAT))); Status = EFI_TIMEOUT; goto Exit; } if (IsAppCmd && MmcCmd == ACMD22) { SdMmioWrite32 (MMCHS_BLK_SIZE, 4); data->blocksize = 4; } else if (IsAppCmd && MmcCmd == ACMD51) { SdMmioWrite32 (MMCHS_BLK_SIZE, 8); data->blocksize = 8; } else if (!IsAppCmd && MmcCmd == CMD6) { SdMmioWrite32 (MMCHS_BLK_SIZE, 64); data->blocksize = 64; } else if (IsDATCmd) { SdMmioWrite32 (MMCHS_BLK_SIZE, BLEN_512BYTES); data->blocksize = 512; } // Set Data timeout counter value to max value. SdMmioAndThenOr32 (MMCHS_SYSCTL, (UINT32) ~DTO_MASK, DTO_VAL); // Clear Interrupt Status Register, but not the Card Inserted bit // to avoid messing with card detection logic. SdMmioWrite32 (MMCHS_INT_STAT, ALL_MASK); //DEBUG ((DEBUG_ERROR, "MMC_CMD%u REG:0x%x 0x%x\n", MMC_CMD_NUM(MmcCmd), MmcCmd, Argument)); if (IsDATCmd) { //DEBUG ((DEBUG_ERROR, "MMC_CMD%u Data Cmd\n", MMC_CMD_NUM(MmcCmd))); mMmcDataCommand = MmcCmd; mMmcDataArgument = Argument; LastExecutedCommand = MmcCmd; return EFI_SUCCESS; } // Set command argument register SdMmioWrite32 (MMCHS_ARG, Argument); // Send the command SdMmioWrite32 (MMCHS_CMD, MmcCmd); //DEBUG ((DEBUG_ERROR, "MmcCmd:0x%x, 0x%x\n", (MmcCmd>>16), Argument)); // Check for the command status. while (RetryCount < MAX_RETRY_COUNT) { MmcStatus = MmioRead32 (MMCHS_INT_STAT); // Read status of command response if ((MmcStatus & ERRI) != 0) { // // CMD5 (CMD_IO_SEND_OP_COND) is only valid for SDIO // cards and thus expected to fail. // if (MmcCmd != CMD_IO_SEND_OP_COND) { DEBUG ((DEBUG_ERROR, "%a(%u): MMC_CMD%u ERRI MmcStatus 0x%x,0x%x\n", __FUNCTION__, __LINE__, MMC_CMD_NUM (MmcCmd), MmcStatus, CmdSendOKMask)); DEBUG ((DEBUG_ERROR, "MMC_CMD REG:0x%x 0x%x\n", MmioRead32(MMCHS_CMD), MmioRead32(MMCHS_ARG))); } SdhciSoftReset(SRC); Status = EFI_DEVICE_ERROR; goto Exit; } // Check if command is completed. if ((MmcStatus & CmdSendOKMask) == CmdSendOKMask) { SdMmioWrite32 (MMCHS_INT_STAT, CmdSendOKMask); break; } RetryCount++; MicroSecondDelay(1); } MicroSecondDelay(1); if (RetryCount == MAX_RETRY_COUNT) { DEBUG ((DEBUG_ERROR, "%a(%u): MMC_CMD%u completion TIMEOUT PresState 0x%x MmcStatus 0x%x,0x%x\n", __FUNCTION__, __LINE__, MMC_CMD_NUM (MmcCmd), MmioRead32 (MMCHS_PRES_STATE), MmcStatus, CmdSendOKMask)); Status = EFI_TIMEOUT; goto Exit; } Exit: SdhciSoftReset(SRC | SRD); if (EFI_ERROR (Status)) { LastExecutedCommand = (UINT32) -1; } else { LastExecutedCommand = MmcCmd; } return Status; } EFI_STATUS MMCNotifyState ( IN EFI_MMC_HOST_PROTOCOL *This, IN MMC_STATE State ) { EFI_STATUS Status; UINTN ClockFrequency; UINT32 Divisor; DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: MMCNotifyState(State: %d)\n", State)); switch (State) { case MmcHwInitializationState: { DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: current divisor %x\n", MmioRead32(MMCHS_SYSCTL))); DEBUG ((DEBUG_MMCHOST_SD, "MMCHost Release: %a, %a\n", __DATE__, __TIME__)); Status = SdhciSoftReset(SRA); if (EFI_ERROR (Status)) { return Status; } DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: CAP %X CAPH %X\n", MmioRead32(MMCHS_CAPA),MmioRead32(MMCHS_CUR_CAPA))); // Lets switch to card detect test mode. //SdMmioOr32 (MMCHS_HCTL, BIT7|BIT6); // set card voltage SdMmioAnd32 (MMCHS_HCTL, ~SDBP_ON); SdMmioAndThenOr32 (MMCHS_HCTL, (UINT32) ~SDBP_MASK, SDVS_1_8_V); SdMmioOr32 (MMCHS_HCTL, SDBP_ON); DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: AC12 %X HCTL %X\n", MmioRead32(MMCHS_AC12),MmioRead32(MMCHS_HCTL))); // First turn off the clock SdMmioAnd32 (MMCHS_SYSCTL, ~CEN); // Attempt to set the clock to 400Khz which is the expected initialization speed Status = CalculateClockFrequencyDivisor (400000, &Divisor, NULL); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "MMCHost: MMCNotifyState(): Fail to initialize SD clock\n")); return Status; } // Set Data Timeout Counter value, set clock frequency, enable internal clock SdMmioOr32 (MMCHS_SYSCTL, DTO_VAL | Divisor | CEN | ICS | ICE); SdMmioOr32 (MMCHS_HCTL, SDBP_ON); // wait for ICS while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS); DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: AC12 %X HCTL %X\n", MmioRead32(MMCHS_AC12),MmioRead32(MMCHS_HCTL))); // Enable interrupts SdMmioWrite32 (MMCHS_IE, ALL_EN); } break; case MmcIdleState: break; case MmcReadyState: break; case MmcIdentificationState: break; case MmcStandByState: ClockFrequency = 25000000; Status = MMCSetClock(ClockFrequency); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "MMCHost: MmcStandByState(): Fail to initialize SD clock to %u Hz\n", ClockFrequency)); return Status; } break; case MmcTransferState: break; case MmcSendingDataState: break; case MmcReceiveDataState: break; case MmcProgrammingState: break; case MmcDisconnectState: case MmcInvalidState: default: DEBUG ((DEBUG_ERROR, "MMCHost: MMCNotifyState(): Invalid State: %d\n", State)); ASSERT (0); } return EFI_SUCCESS; } BOOLEAN MMCIsCardPresent ( IN EFI_MMC_HOST_PROTOCOL *This ) { return TRUE; } EFI_STATUS MMCReceiveResponse ( IN EFI_MMC_HOST_PROTOCOL *This, IN MMC_RESPONSE_TYPE Type, IN UINT32* Buffer ) { ASSERT (Buffer != NULL); if (Type == MMC_RESPONSE_TYPE_R2) { // 16-byte response Buffer[0] = MmioRead32 (MMCHS_RSP10); Buffer[1] = MmioRead32 (MMCHS_RSP32); Buffer[2] = MmioRead32 (MMCHS_RSP54); Buffer[3] = MmioRead32 (MMCHS_RSP76); Buffer[3] <<= 8; Buffer[3] |= (Buffer[2] >> 24) & 0xFF; Buffer[2] <<= 8; Buffer[2] |= (Buffer[1] >> 24) & 0xFF; Buffer[1] <<= 8; Buffer[1] |= (Buffer[0] >> 24) & 0xFF; Buffer[0] <<= 8; DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: MMCReceiveResponse(Type: %x), Buffer[0-3]: %08x, %08x, %08x, %08x\n", Type, Buffer[0], Buffer[1], Buffer[2], Buffer[3])); } else { // 4-byte response Buffer[0] = MmioRead32 (MMCHS_RSP10); DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: MMCReceiveResponse(Type: %08x), Buffer[0]: %08x\n", Type, Buffer[0])); } gBS->Stall (STALL_AFTER_REC_RESP_US); if (LastExecutedCommand == CMD_STOP_TRANSMISSION) { DEBUG ((DEBUG_MMCHOST_SD, "MMCHost: soft-resetting after CMD12\n")); return SdhciSoftReset(SRC | SRD); } return EFI_SUCCESS; } EFI_STATUS MMCReadBlockData ( IN EFI_MMC_HOST_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Length, IN UINT32* Buffer ) { UINT16 Mode; EFI_STATUS Status = EFI_SUCCESS; SDHCI_DATA *data = &gSdhciData; UINT32 cmd = 0; UINTN StartAddr = (UINTN)Buffer; DEBUG ((DEBUG_MMCHOST_SD, "%a(%u): LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n", __FUNCTION__, __LINE__, Lba, Length, Buffer)); if (Buffer == NULL) { DEBUG ((DEBUG_ERROR, "%a(%u): NULL Buffer\n", __FUNCTION__, __LINE__)); return EFI_INVALID_PARAMETER; } if ((StartAddr & 0x7) != 0x0) { DEBUG ((DEBUG_ERROR, "%a(%u): Buffer need 8 Byte align\n", __FUNCTION__, __LINE__)); return EFI_INVALID_PARAMETER; } if (Length % sizeof (UINT32) != 0) { DEBUG ((DEBUG_ERROR, "%a(%u): bad Length %u\n", __FUNCTION__, __LINE__, Length)); return EFI_INVALID_PARAMETER; } if (data->blocksize == 0 || data->blocksize > 512) { DEBUG ((DEBUG_ERROR, "%a(%u): blocksize %u\n", __FUNCTION__, __LINE__, data->blocksize)); return EFI_INVALID_PARAMETER; } data->flags = MMC_DATA_READ; data->blocks = (UINT32)((Length) / data->blocksize); data->buffer = (UINT8 *)Buffer; //memset(Buffer, 0xCC, Length); MmioWrite16 (MMCHS_BLK_SIZE, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize)); MmioWrite16 (MMCHS_BLK_COUNT, (UINT16)data->blocks); Mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_READ; if (data->blocks > 1) Mode |= (SDHCI_TRNS_MULTI /*| SDHCI_TRNS_ACMD12*/); #ifdef CONFIG_MMC_SDHCI_SDMA MmioWrite32 (MMCHS_DMA_ADDRESS, (UINT32)StartAddr); Mode |= SDHCI_TRNS_DMA; InvalidateDataCacheRange (Buffer, Length); #endif //MmioWrite16 (MMCHS_TRANS_MODE, Mode); cmd = (mMmcDataCommand & 0xFFFF0000) | Mode; Status = SdhciSendCommand(This, cmd, mMmcDataArgument, CMDI_MASK /*| DATI_MASK*/); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a(%u): bad cmd %x\n", __FUNCTION__, __LINE__, mMmcDataCommand)); goto Exit; } Status = SdhciTransferData(This, data, StartAddr); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a(%u): SdhciTransferData fail!\n", __FUNCTION__, __LINE__)); goto Exit; } MicroSecondDelay(1); Exit: //stat = MmioRead32(MMCHS_INT_STAT); MmioWrite32 (MMCHS_INT_STAT, ALL_MASK); SdhciSoftReset(SRC | SRD); return Status; } EFI_STATUS MMCWriteBlockData ( IN EFI_MMC_HOST_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Length, IN UINT32* Buffer ) { UINT16 Mode; EFI_STATUS Status = EFI_SUCCESS; SDHCI_DATA *data = &gSdhciData; UINT32 cmd = 0; UINTN StartAddr = (UINTN)Buffer; DEBUG ((DEBUG_MMCHOST_SD, "%a(%u): LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n", __FUNCTION__, __LINE__, Lba, Length, Buffer)); if (Buffer == NULL) { DEBUG ((DEBUG_ERROR, "%a(%u): NULL Buffer\n", __FUNCTION__, __LINE__)); return EFI_INVALID_PARAMETER; } if ((StartAddr & 0x7) != 0x0) { DEBUG ((DEBUG_ERROR, "%a(%u): Buffer need 8 Byte align\n", __FUNCTION__, __LINE__)); return EFI_INVALID_PARAMETER; } if (Length % sizeof (UINT32) != 0) { DEBUG ((DEBUG_ERROR, "%a(%u): bad Length %u\n", __FUNCTION__, __LINE__, Length)); return EFI_INVALID_PARAMETER; } data->flags = MMC_DATA_WRITE; data->blocks = (UINT32)((Length + data->blocksize - 1) / data->blocksize); data->buffer = (UINT8 *)Buffer; MmioWrite16 (MMCHS_BLK_SIZE, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, data->blocksize)); MmioWrite16 (MMCHS_BLK_COUNT, (UINT16)data->blocks); Mode = SDHCI_TRNS_BLK_CNT_EN; if (data->blocks > 1) Mode |= SDHCI_TRNS_MULTI; #ifdef CONFIG_MMC_SDHCI_SDMA MmioWrite32 (MMCHS_DMA_ADDRESS, (UINT32)StartAddr); Mode |= SDHCI_TRNS_DMA; WriteBackDataCacheRange (Buffer, Length); #endif cmd = (mMmcDataCommand & 0xFFFF0000) | Mode; Status = SdhciSendCommand(This, cmd, mMmcDataArgument, CMDI_MASK /*| DATI_MASK*/); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a(%u): bad cmd %x\n", __FUNCTION__, __LINE__, mMmcDataCommand)); goto Exit; } Status = SdhciTransferData(This, data, StartAddr); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a(%u): SdhciTransferData fail!\n", __FUNCTION__, __LINE__)); goto Exit; } MicroSecondDelay(1); Exit: //stat = MmioRead32(MMCHS_INT_STAT); MmioWrite32 (MMCHS_INT_STAT, ALL_MASK); SdhciSoftReset(SRC | SRD); return Status; } EFI_STATUS MMCSetIos ( IN EFI_MMC_HOST_PROTOCOL *This, IN UINT32 BusClockFreq, IN UINT32 BusWidth, IN UINT32 TimingMode ) { EFI_STATUS Status = EFI_SUCCESS; UINT32 Ctrl, Ctrl2; if (BusClockFreq > 200*1000*1000) { return EFI_UNSUPPORTED; } Ctrl = MmioRead8(MMCHS_HCTL); if (TimingMode != EMMCBACKWARD) { Ctrl2 = MmioRead16(MMCHS_HCTL2); /* Select Bus Speed Mode for host */ Ctrl2 &= ~SDHCI_CTRL_UHS_MASK; switch (TimingMode) { case EMMCHS52DDR1V2: case EMMCHS52DDR1V8: case EMMCHS52: //Ctrl |= HIGH_SPEED_EN; Ctrl &= ~HIGH_SPEED_EN; Ctrl2 |= (SDHCI_CTRL_VDD_180 | SDHCI_CTRL_DRV_TYPE_A | SDHCI_CTRL_EMMC_SDR50); break; case EMMCBACKWARD: case EMMCHS26: Ctrl &= ~HIGH_SPEED_EN; break; case EMMCHS400DDR1V8: case EMMCHS400DDR1V2: Ctrl |= HIGH_SPEED_EN; Ctrl2 |= (SDHCI_CTRL_VDD_180 | SDHCI_CTRL_DRV_TYPE_A | SDHCI_CTRL_EMMC_HS400); break; default: return EFI_UNSUPPORTED; } MmioWrite16(MMCHS_HCTL2, Ctrl2); } switch (BusWidth) { case 1: Ctrl &= ~DTW_4_BIT; break; case 4: Ctrl |= DTW_4_BIT;; break; case 8: Ctrl &= ~DTW_4_BIT; Ctrl |= DTW_8_BIT; break; default: return EFI_UNSUPPORTED; } MmioWrite8(MMCHS_HCTL, Ctrl); if (BusClockFreq) { Status = MMCSetClock (BusClockFreq); } return Status; } BOOLEAN MMCIsMultiBlock ( IN EFI_MMC_HOST_PROTOCOL *This ) { return TRUE; } EFI_MMC_HOST_PROTOCOL gSdhciHost = { MMC_HOST_PROTOCOL_REVISION, MMCIsCardPresent, MMCIsReadOnly, MMCBuildDevicePath, MMCNotifyState, MMCSendCommand, MMCReceiveResponse, MMCReadBlockData, MMCWriteBlockData, MMCSetIos, MMCIsMultiBlock }; EFI_STATUS MMCInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_HANDLE Handle = NULL; DEBUG ((DEBUG_MMCHOST_SD, "RkSdhciHost: MMCInitialize()\n")); mMmcHsBase = PcdGet32 (PcdSdhciDxeBaseAddress); SdhciEmmcDxeIoMux(); #if 0 word32(mMmcHsBase + 0x800) = (0x1 << 1); MicroSecondDelay(10); word32(mMmcHsBase + 0x800) = 0; word32(0xFD7C0000 + 0x0A7C) = ((0x1FUL << 4) << 16) | (0x1F << 4); MicroSecondDelay(10); word32(0xFD7C0000 + 0x0A7C) = ((0x1FUL << 4) << 16) | (0 << 4); word32(0xFD5FD000 + 0x40) = 0xFFFF6666; word32(0xFD5FD000 + 0x58) = 0xFFFF6666; word32(0xFD5FD000 + 0x5C) = 0xFFFF6666; #endif Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEmbeddedMmcHostProtocolGuid, &gSdhciHost, NULL ); ASSERT_EFI_ERROR (Status); return Status; }