-/** @file
- MMC/SD Card driver for OMAP 35xx (SDIO not supported)
-
- This driver always produces a BlockIo protocol but it starts off with no Media
- present. A TimerCallBack detects when media is inserted or removed and after
- a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the
- media to be detected (or removed) and the BlockIo Media structure will get
- updated. No MMC/SD Card harward registers are updated until the first BlockIo
- ReadBlocks/WriteBlocks after media has been insterted (booting with a card
- plugged in counts as an insertion event).
-
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
-
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "MMCHS.h"
-
-EFI_BLOCK_IO_MEDIA gMMCHSMedia = {
- SIGNATURE_32('s','d','i','o'), // MediaId
- TRUE, // RemovableMedia
- FALSE, // MediaPresent
- FALSE, // LogicalPartition
- FALSE, // ReadOnly
- FALSE, // WriteCaching
- 512, // BlockSize
- 4, // IoAlign
- 0, // Pad
- 0 // LastBlock
-};
-
-typedef struct {
- VENDOR_DEVICE_PATH Mmc;
- EFI_DEVICE_PATH End;
-} MMCHS_DEVICE_PATH;
-
-MMCHS_DEVICE_PATH gMmcHsDevicePath = {
- {
- HARDWARE_DEVICE_PATH,
- HW_VENDOR_DP,
- (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
- (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
- 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- sizeof (EFI_DEVICE_PATH_PROTOCOL),
- 0
- }
-};
-
-CARD_INFO gCardInfo;
-EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
-EFI_EVENT gTimerEvent;
-BOOLEAN gMediaChange = FALSE;
-
-//
-// Internal Functions
-//
-
-
-VOID
-ParseCardCIDData (
- UINT32 Response0,
- UINT32 Response1,
- UINT32 Response2,
- UINT32 Response3
- )
-{
- gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF);
- gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8));
- gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF);
- gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF);
- gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF);
- gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF);
- gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF);
- gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF);
- gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF);
- gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF);
-}
-
-
-VOID
-UpdateMMCHSClkFrequency (
- UINTN NewCLKD
- )
-{
- //Set Clock enable to 0x0 to not provide the clock to the card
- MmioAnd32 (MMCHS_SYSCTL, ~CEN);
-
- //Set new clock frequency.
- MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);
-
- //Poll till Internal Clock Stable
- while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);
-
- //Set Clock enable to 0x1 to provide the clock to the card
- MmioOr32 (MMCHS_SYSCTL, CEN);
-}
-
-
-EFI_STATUS
-SendCmd (
- UINTN Cmd,
- UINTN CmdInterruptEnableVal,
- UINTN CmdArgument
- )
-{
- UINTN MmcStatus;
- UINTN RetryCount = 0;
-
- //Check if command line is in use or not. Poll till command line is available.
- while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);
-
- //Provide the block size.
- MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);
-
- //Setting Data timeout counter value to max value.
- MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);
-
- //Clear Status register.
- MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);
-
- //Set command argument register
- MmioWrite32 (MMCHS_ARG, CmdArgument);
-
- //Enable interrupt enable events to occur
- MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);
-
- //Send a command
- MmioWrite32 (MMCHS_CMD, Cmd);
-
- //Check for the command status.
- while (RetryCount < MAX_RETRY_COUNT) {
- do {
- MmcStatus = MmioRead32 (MMCHS_STAT);
- } while (MmcStatus == 0);
-
- //Read status of command response
- if ((MmcStatus & ERRI) != 0) {
-
- //Perform soft-reset for mmci_cmd line.
- MmioOr32 (MMCHS_SYSCTL, SRC);
- while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
-
- DEBUG ((EFI_D_INFO, "MmcStatus: %x\n", MmcStatus));
- return EFI_DEVICE_ERROR;
- }
-
- //Check if command is completed.
- if ((MmcStatus & CC) == CC) {
- MmioWrite32 (MMCHS_STAT, CC);
- break;
- }
-
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- return EFI_TIMEOUT;
- }
-
- return EFI_SUCCESS;
-}
-
-
-VOID
-GetBlockInformation (
- UINTN *BlockSize,
- UINTN *NumBlocks
- )
-{
- CSD_SDV2 *CsdSDV2Data;
- UINTN CardSize;
-
- if (gCardInfo.CardType == SD_CARD_2_HIGH) {
- CsdSDV2Data = (CSD_SDV2 *)&gCardInfo.CSDData;
-
- //Populate BlockSize.
- *BlockSize = (0x1UL << CsdSDV2Data->READ_BL_LEN);
-
- //Calculate Total number of blocks.
- CardSize = CsdSDV2Data->C_SIZELow16 | (CsdSDV2Data->C_SIZEHigh6 << 2);
- *NumBlocks = ((CardSize + 1) * 1024);
- } else {
- //Populate BlockSize.
- *BlockSize = (0x1UL << gCardInfo.CSDData.READ_BL_LEN);
-
- //Calculate Total number of blocks.
- CardSize = gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2);
- *NumBlocks = (CardSize + 1) * (1 << (gCardInfo.CSDData.C_SIZE_MULT + 2));
- }
-
- //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
- if (*BlockSize > 512) {
- *NumBlocks = MultU64x32(*NumBlocks, *BlockSize/2);
- *BlockSize = 512;
- }
-
- DEBUG ((EFI_D_INFO, "Card type: %x, BlockSize: %x, NumBlocks: %x\n", gCardInfo.CardType, *BlockSize, *NumBlocks));
-}
-
-
-VOID
-CalculateCardCLKD (
- UINTN *ClockFrequencySelect
- )
-{
- UINT8 MaxDataTransferRate;
- UINTN TransferRateValue = 0;
- UINTN TimeValue = 0 ;
- UINTN Frequency = 0;
-
- 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:
- TransferRateValue = 100 * 1000;
- break;
-
- case 1:
- TransferRateValue = 1 * 1000 * 1000;
- break;
-
- case 2:
- TransferRateValue = 10 * 1000 * 1000;
- break;
-
- case 3:
- TransferRateValue = 100 * 1000 * 1000;
- break;
-
- default:
- DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
- ASSERT(FALSE);
- }
-
- //Calculate Time value (Bits 6:3 of TRAN_SPEED)
- switch ((MaxDataTransferRate >> 3) & 0xF) {
- case 1:
- TimeValue = 10;
- break;
-
- case 2:
- TimeValue = 12;
- break;
-
- case 3:
- TimeValue = 13;
- break;
-
- case 4:
- TimeValue = 15;
- break;
-
- case 5:
- TimeValue = 20;
- break;
-
- case 6:
- TimeValue = 25;
- break;
-
- case 7:
- TimeValue = 30;
- break;
-
- case 8:
- TimeValue = 35;
- break;
-
- case 9:
- TimeValue = 40;
- break;
-
- case 10:
- TimeValue = 45;
- break;
-
- case 11:
- TimeValue = 50;
- break;
-
- case 12:
- TimeValue = 55;
- break;
-
- case 13:
- TimeValue = 60;
- break;
-
- case 14:
- TimeValue = 70;
- break;
-
- case 15:
- TimeValue = 80;
- break;
-
- default:
- DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
- ASSERT(FALSE);
- }
-
- Frequency = TransferRateValue * TimeValue/10;
-
- //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.
- *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);
-
- DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));
-}
-
-
-VOID
-GetCardConfigurationData (
- VOID
- )
-{
- UINTN BlockSize;
- UINTN NumBlocks;
- UINTN ClockFrequencySelect;
-
- //Calculate BlockSize and Total number of blocks in the detected card.
- GetBlockInformation(&BlockSize, &NumBlocks);
- gCardInfo.BlockSize = BlockSize;
- gCardInfo.NumBlocks = NumBlocks;
-
- //Calculate Card clock divider value.
- CalculateCardCLKD(&ClockFrequencySelect);
- gCardInfo.ClockFrequencySelect = ClockFrequencySelect;
-}
-
-
-EFI_STATUS
-InitializeMMCHS (
- VOID
- )
-{
- UINT8 Data = 0;
- EFI_STATUS Status;
-
- //Select Device group to belong to P1 device group in Power IC.
- Data = DEV_GRP_P1;
- Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);
- ASSERT_EFI_ERROR(Status);
-
- //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.
- Data = VSEL_3_00V;
- Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);
- ASSERT_EFI_ERROR(Status);
-
- //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.
- MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));
-
- // Enable WP GPIO
- MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);
-
- // Enable Card Detect
- Data = CARD_DETECT_ENABLE;
- gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);
-
-
- return Status;
-}
-
-
-EFI_STATUS
-PerformCardIdenfication (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN CmdArgument = 0;
- UINTN Response = 0;
- UINTN RetryCount = 0;
- BOOLEAN SDCmd8Supported = FALSE;
-
- //Enable interrupts.
- MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |
- CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));
-
- //Controller INIT procedure start.
- MmioOr32 (MMCHS_CON, INIT);
- MmioWrite32 (MMCHS_CMD, 0x00000000);
- while (!(MmioRead32 (MMCHS_STAT) & CC));
-
- //Wait for 1 ms
- gBS->Stall(1000);
-
- //Set CC bit to 0x1 to clear the flag
- MmioOr32 (MMCHS_STAT, CC);
-
- //Retry INIT procedure.
- MmioWrite32 (MMCHS_CMD, 0x00000000);
- while (!(MmioRead32 (MMCHS_STAT) & CC));
-
- //End initialization sequence
- MmioAnd32 (MMCHS_CON, ~INIT);
-
- MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));
-
- //Change clock frequency to 400KHz to fit protocol
- UpdateMMCHSClkFrequency(CLKD_400KHZ);
-
- MmioOr32 (MMCHS_CON, OD);
-
- //Send CMD0 command.
- Status = SendCmd (CMD0, CMD0_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "Cmd0 fails.\n"));
- return Status;
- }
-
- DEBUG ((EFI_D_INFO, "CMD0 response: %x\n", MmioRead32 (MMCHS_RSP10)));
-
- //Send CMD5 command.
- Status = SendCmd (CMD5, CMD5_INT_EN, CmdArgument);
- if (Status == EFI_SUCCESS) {
- DEBUG ((EFI_D_ERROR, "CMD5 Success. SDIO card. Follow SDIO card specification.\n"));
- DEBUG ((EFI_D_INFO, "CMD5 response: %x\n", MmioRead32 (MMCHS_RSP10)));
- //NOTE: Returning unsupported error for now. Need to implement SDIO specification.
- return EFI_UNSUPPORTED;
- } else {
- DEBUG ((EFI_D_INFO, "CMD5 fails. Not an SDIO card.\n"));
- }
-
- MmioOr32 (MMCHS_SYSCTL, SRC);
- gBS->Stall(1000);
- while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
-
- //Send CMD8 command. (New v2.00 command for Voltage check)
- //Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass.
- //MMC & SD1.1 card will fail this command.
- CmdArgument = CMD8_ARG;
- Status = SendCmd (CMD8, CMD8_INT_EN, CmdArgument);
- if (Status == EFI_SUCCESS) {
- Response = MmioRead32 (MMCHS_RSP10);
- DEBUG ((EFI_D_INFO, "CMD8 success. CMD8 response: %x\n", Response));
- if (Response != CmdArgument) {
- return EFI_DEVICE_ERROR;
- }
- DEBUG ((EFI_D_INFO, "Card is SD2.0\n"));
- SDCmd8Supported = TRUE; //Supports high capacity.
- } else {
- DEBUG ((EFI_D_INFO, "CMD8 fails. Not an SD2.0 card.\n"));
- }
-
- MmioOr32 (MMCHS_SYSCTL, SRC);
- gBS->Stall(1000);
- while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
-
- //Poll till card is busy
- while (RetryCount < MAX_RETRY_COUNT) {
- //Send CMD55 command.
- CmdArgument = 0;
- Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);
- if (Status == EFI_SUCCESS) {
- DEBUG ((EFI_D_INFO, "CMD55 success. CMD55 response: %x\n", MmioRead32 (MMCHS_RSP10)));
- gCardInfo.CardType = SD_CARD;
- } else {
- DEBUG ((EFI_D_INFO, "CMD55 fails.\n"));
- gCardInfo.CardType = MMC_CARD;
- }
-
- //Send appropriate command for the card type which got detected.
- if (gCardInfo.CardType == SD_CARD) {
- CmdArgument = ((UINTN *) &(gCardInfo.OCRData))[0];
-
- //Set HCS bit.
- if (SDCmd8Supported) {
- CmdArgument |= HCS;
- }
-
- Status = SendCmd (ACMD41, ACMD41_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_INFO, "ACMD41 fails.\n"));
- return Status;
- }
- ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 (MMCHS_RSP10);
- DEBUG ((EFI_D_INFO, "SD card detected. ACMD41 OCR: %x\n", ((UINT32 *) &(gCardInfo.OCRData))[0]));
- } else if (gCardInfo.CardType == MMC_CARD) {
- CmdArgument = 0;
- Status = SendCmd (CMD1, CMD1_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_INFO, "CMD1 fails.\n"));
- return Status;
- }
- Response = MmioRead32 (MMCHS_RSP10);
- DEBUG ((EFI_D_INFO, "MMC card detected.. CMD1 response: %x\n", Response));
-
- //NOTE: For now, I am skipping this since I only have an SD card.
- //Compare card OCR and host OCR (Section 22.6.1.3.2.4)
- return EFI_UNSUPPORTED; //For now, MMC is not supported.
- }
-
- //Poll the card until it is out of its power-up sequence.
- if (gCardInfo.OCRData.Busy == 1) {
-
- if (SDCmd8Supported) {
- gCardInfo.CardType = SD_CARD_2;
- }
-
- //Card is ready. Check CCS (Card capacity status) bit (bit#30).
- //SD 2.0 standard card will response with CCS 0, SD high capacity card will respond with CCS 1.
- if (gCardInfo.OCRData.AccessMode & BIT1) {
- gCardInfo.CardType = SD_CARD_2_HIGH;
- DEBUG ((EFI_D_INFO, "High capacity card.\n"));
- } else {
- DEBUG ((EFI_D_INFO, "Standard capacity card.\n"));
- }
-
- break;
- }
-
- gBS->Stall(1000);
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- DEBUG ((EFI_D_ERROR, "Timeout error. RetryCount: %d\n", RetryCount));
- return EFI_TIMEOUT;
- }
-
- //Read CID data.
- CmdArgument = 0;
- Status = SendCmd (CMD2, CMD2_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status));
- return Status;
- }
-
- DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));
-
- //Parse CID register data.
- ParseCardCIDData(MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76));
-
- //Read RCA
- CmdArgument = 0;
- Status = SendCmd (CMD3, CMD3_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status));
- return Status;
- }
-
- //Set RCA for the detected card. RCA is CMD3 response.
- gCardInfo.RCA = (MmioRead32 (MMCHS_RSP10) >> 16);
- DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA));
-
- //MMC Bus setting change after card identification.
- MmioAnd32 (MMCHS_CON, ~OD);
- MmioOr32 (MMCHS_HCTL, SDVS_3_0_V);
- UpdateMMCHSClkFrequency(CLKD_400KHZ); //Set the clock frequency to 400KHz.
-
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS
-GetCardSpecificData (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN CmdArgument;
-
- //Send CMD9 to retrieve CSD.
- CmdArgument = gCardInfo.RCA << 16;
- Status = SendCmd (CMD9, CMD9_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status));
- return Status;
- }
-
- //Populate 128-bit CSD register data.
- ((UINT32 *)&(gCardInfo.CSDData))[0] = MmioRead32 (MMCHS_RSP10);
- ((UINT32 *)&(gCardInfo.CSDData))[1] = MmioRead32 (MMCHS_RSP32);
- ((UINT32 *)&(gCardInfo.CSDData))[2] = MmioRead32 (MMCHS_RSP54);
- ((UINT32 *)&(gCardInfo.CSDData))[3] = MmioRead32 (MMCHS_RSP76);
-
- DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));
-
- //Calculate total number of blocks and max. data transfer rate supported by the detected card.
- GetCardConfigurationData();
-
- return Status;
-}
-
-
-EFI_STATUS
-PerformCardConfiguration (
- VOID
- )
-{
- UINTN CmdArgument = 0;
- EFI_STATUS Status;
-
- //Send CMD7
- CmdArgument = gCardInfo.RCA << 16;
- Status = SendCmd (CMD7, CMD7_INT_EN, CmdArgument);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", 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);
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status));
- return Status;
- }
-
- //Change MMCHS clock frequency to what detected card can support.
- UpdateMMCHSClkFrequency(gCardInfo.ClockFrequencySelect);
-
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS
-ReadBlockData (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- OUT VOID *Buffer
- )
-{
- UINTN MmcStatus;
- UINTN *DataBuffer = Buffer;
- UINTN DataSize = This->Media->BlockSize/4;
- UINTN Count;
- UINTN RetryCount = 0;
-
- //Check controller status to make sure there is no error.
- while (RetryCount < MAX_RETRY_COUNT) {
- do {
- //Read Status.
- MmcStatus = MmioRead32 (MMCHS_STAT);
- } while(MmcStatus == 0);
-
- //Check if Buffer read ready (BRR) bit is set?
- if (MmcStatus & BRR) {
-
- //Clear BRR bit
- MmioOr32 (MMCHS_STAT, BRR);
-
- //Read block worth of data.
- for (Count = 0; Count < DataSize; Count++) {
- *DataBuffer++ = MmioRead32 (MMCHS_DATA);
- }
- break;
- }
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- return EFI_TIMEOUT;
- }
-
- return EFI_SUCCESS;
-}
-
-
-EFI_STATUS
-WriteBlockData (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- OUT VOID *Buffer
- )
-{
- UINTN MmcStatus;
- UINTN *DataBuffer = Buffer;
- UINTN DataSize = This->Media->BlockSize/4;
- UINTN Count;
- UINTN RetryCount = 0;
-
- //Check controller status to make sure there is no error.
- while (RetryCount < MAX_RETRY_COUNT) {
- do {
- //Read Status.
- MmcStatus = MmioRead32 (MMCHS_STAT);
- } while(MmcStatus == 0);
-
- //Check if Buffer write ready (BWR) bit is set?
- if (MmcStatus & BWR) {
-
- //Clear BWR bit
- MmioOr32 (MMCHS_STAT, BWR);
-
- //Write block worth of data.
- for (Count = 0; Count < DataSize; Count++) {
- MmioWrite32 (MMCHS_DATA, *DataBuffer++);
- }
-
- break;
- }
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- return EFI_TIMEOUT;
- }
-
- 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));
-
-
- Dma4.DataType = 2; // DMA4_CSDPi[1:0] 32-bit elements from MMCHS_DATA
-
- Dma4.SourceEndiansim = 0; // DMA4_CSDPi[21]
-
- Dma4.DestinationEndianism = 0; // DMA4_CSDPi[19]
-
- Dma4.SourcePacked = 0; // DMA4_CSDPi[6]
-
- Dma4.DestinationPacked = 0; // DMA4_CSDPi[13]
-
- Dma4.NumberOfElementPerFrame = This->Media->BlockSize/4; // DMA4_CENi (TRM 4K is optimum value)
-
- Dma4.NumberOfFramePerTransferBlock = BlockCount; // DMA4_CFNi
-
- Dma4.ReadPriority = 0; // DMA4_CCRi[6] Low priority read
-
- Dma4.WritePriority = 0; // DMA4_CCRi[23] Prefetech disabled
-
-
- //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
-
- Dma4.WritePortAccessType = 3; // DMA4_CSDPi[15:14] Memory burst 16x32
-
- Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted
-
-
-
- Dma4.SourceStartAddress = MMCHS_DATA; // DMA4_CSSAi
-
- Dma4.DestinationStartAddress = (UINT32)BufferAddress; // DMA4_CDSAi
-
- Dma4.SourceElementIndex = 1; // DMA4_CSEi
-
- Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi
-
- Dma4.DestinationElementIndex = 1; // DMA4_CDEi
-
- Dma4.DestinationFrameIndex = 0; // DMA4_CDFi
-
-
-
- Dma4.ReadPortAccessMode = 0; // DMA4_CCRi[13:12] Always read MMCHS_DATA
-
- Dma4.WritePortAccessMode = 1; // DMA4_CCRi[15:14] Post increment memory address
-
- Dma4.ReadRequestNumber = 0x1e; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_RX (61)
-
- 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
-
- Dma4.WritePortAccessType = 0; // DMA4_CSDPi[15:14] Can not burst MMCHS_DATA reg
-
- Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted ???
-
-
-
- Dma4.SourceStartAddress = (UINT32)BufferAddress; // DMA4_CSSAi
-
- Dma4.DestinationStartAddress = MMCHS_DATA; // DMA4_CDSAi
-
- Dma4.SourceElementIndex = 1; // DMA4_CSEi
-
- Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi
-
- Dma4.DestinationElementIndex = 1; // DMA4_CDEi
-
- Dma4.DestinationFrameIndex = 0; // DMA4_CDFi
-
-
-
- Dma4.ReadPortAccessMode = 1; // DMA4_CCRi[13:12] Post increment memory address
-
- Dma4.WritePortAccessMode = 0; // DMA4_CCRi[15:14] Always write MMCHS_DATA
-
- Dma4.ReadRequestNumber = 0x1d; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_TX (60)
-
- 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
-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);
- if (EFI_ERROR(Status)) {
- DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n"));
- return Status;
- }
- } else if (OperationType == WRITE) {
- Status = WriteBlockData (This, Buffer);
- if (EFI_ERROR(Status)) {
- DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n"));
- 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);
-
- return EFI_DEVICE_ERROR;
- }
- }
- RetryCount++;
- }
-
- if (RetryCount == MAX_RETRY_COUNT) {
- DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));
- return EFI_TIMEOUT;
- }
-
- return EFI_SUCCESS;
-}
-
-BOOLEAN
-CardPresent (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT8 Data;
-
- //
- // Card detect is a GPIO0 on the TPS65950
- //
- Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);
- if (EFI_ERROR (Status)) {
- return FALSE;
- }
-
- if ((Data & CARD_DETECT_BIT) == CARD_DETECT_BIT) {
- // No Card present
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-EFI_STATUS
-DetectCard (
- VOID
- )
-{
- EFI_STATUS Status;
-
- if (!CardPresent ()) {
- return EFI_NO_MEDIA;
- }
-
- //Initialize MMC host controller clocks.
- Status = InitializeMMCHS ();
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));
- return Status;
- }
-
- //Software reset of the MMCHS host controller.
- MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);
- gBS->Stall(1000);
- while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);
-
- //Soft reset for all.
- MmioWrite32 (MMCHS_SYSCTL, SRA);
- gBS->Stall(1000);
- while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);
-
- //Voltage capabilities initialization. Activate VS18 and VS30.
- MmioOr32 (MMCHS_CAPA, (VS30 | VS18));
-
- //Wakeup configuration
- MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);
- MmioOr32 (MMCHS_HCTL, IWE);
-
- //MMCHS Controller default initialization
- MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));
-
- MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));
-
- //Enable internal clock
- MmioOr32 (MMCHS_SYSCTL, ICE);
-
- //Set the clock frequency to 80KHz.
- UpdateMMCHSClkFrequency (CLKD_80KHZ);
-
- //Enable SD bus power.
- MmioOr32 (MMCHS_HCTL, (SDBP_ON));
-
- //Poll till SD bus power bit is set.
- while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);
-
- //Card idenfication
- Status = PerformCardIdenfication ();
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n"));
- return Status;
- }
-
- //Get CSD (Card specific data) for the detected card.
- Status = GetCardSpecificData();
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- //Configure the card in data transfer mode.
- Status = PerformCardConfiguration();
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- //Patch the Media structure.
- gMMCHSMedia.LastBlock = (gCardInfo.NumBlocks - 1);
- gMMCHSMedia.BlockSize = gCardInfo.BlockSize;
- gMMCHSMedia.ReadOnly = (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
- gMMCHSMedia.MediaPresent = TRUE;
- gMMCHSMedia.MediaId++;
-
- 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 (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINTN Lba,
- OUT VOID *Buffer,
- IN UINTN BufferSize,
- IN OPERATION_TYPE OperationType
- )
-{
- EFI_STATUS Status = EFI_SUCCESS;
- UINTN RetryCount = 0;
- UINTN BlockCount;
- UINTN BytesToBeTranferedThisPass = 0;
- UINTN BytesRemainingToBeTransfered;
- EFI_TPL OldTpl;
-
- BOOLEAN Update;
-
-
-
- Update = FALSE;
-
- if (gMediaChange) {
- Update = TRUE;
- Status = DetectCard ();
- if (EFI_ERROR (Status)) {
- // We detected a removal
- gMMCHSMedia.MediaPresent = FALSE;
- gMMCHSMedia.LastBlock = 0;
- gMMCHSMedia.BlockSize = 512; // Should be zero but there is a bug in DiskIo
- gMMCHSMedia.ReadOnly = FALSE;
- }
- gMediaChange = FALSE;
- } else if (!gMMCHSMedia.MediaPresent) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
-
- if (Update) {
- DEBUG ((EFI_D_INFO, "SD Card ReinstallProtocolInterface ()\n"));
- gBS->ReinstallProtocolInterface (
- gImageHandle,
- &gEfiBlockIoProtocolGuid,
- &gBlockIo,
- &gBlockIo
- );
- return EFI_MEDIA_CHANGED;
- }
-
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if (Buffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if (Lba > This->Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if ((BufferSize % This->Media->BlockSize) != 0) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto Done;
- }
-
- //Check if the data lines are not in use.
- while ((RetryCount++ < MAX_RETRY_COUNT) && ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) != DATI_ALLOWED));
- if (RetryCount == MAX_RETRY_COUNT) {
- Status = EFI_TIMEOUT;
- goto Done;
- }
-
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
-
- BytesRemainingToBeTransfered = BufferSize;
- while (BytesRemainingToBeTransfered > 0) {
-
- if (gMediaChange) {
- Status = EFI_NO_MEDIA;
- DEBUG ((EFI_D_INFO, "SdReadWrite() EFI_NO_MEDIA due to gMediaChange\n"));
- goto DoneRestoreTPL;
- }
-
- // 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);
- }
-
- if (EFI_ERROR(Status)) {
- DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));
- goto DoneRestoreTPL;
- }
-
- BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass;
- Lba += BlockCount;
- Buffer = (UINT8 *)Buffer + This->Media->BlockSize;
- }
-
-DoneRestoreTPL:
-
- gBS->RestoreTPL (OldTpl);
-
-Done:
-
- return Status;
-
-}
-
-
-/**
-
- Reset the Block Device.
-
-
-
- @param This Indicates a pointer to the calling context.
-
- @param ExtendedVerification Driver may perform diagnostics on reset.
-
-
-
- @retval EFI_SUCCESS The device was reset.
-
- @retval EFI_DEVICE_ERROR The device is not functioning properly and could
-
- not be reset.
-
-
-
-**/
-EFI_STATUS
-EFIAPI
-MMCHSReset (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
-{
- return EFI_SUCCESS;
-}
-
-
-/**
-
- Read BufferSize bytes from Lba into Buffer.
-
-
-
- @param This Indicates a pointer to the calling context.
-
- @param MediaId Id of the media, changes every time the media is replaced.
-
- @param Lba The starting Logical Block Address to read from
-
- @param BufferSize Size of Buffer, must be a multiple of device block size.
-
- @param Buffer A pointer to the destination buffer for the data. The caller is
-
- responsible for either having implicit or explicit ownership of the buffer.
-
-
-
- @retval EFI_SUCCESS The data was read correctly from the device.
-
- @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
-
- @retval EFI_NO_MEDIA There is no media in the device.
-
- @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
-
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
-
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
-
- or the buffer is not on proper alignment.
-
-EFI_STATUS
-
-**/
-EFI_STATUS
-EFIAPI
-MMCHSReadBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
-
- //Perform Read operation.
- Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ);
-
- return Status;
-
-}
-
-
-/**
-
- Write BufferSize bytes from Lba into Buffer.
-
-
-
- @param This Indicates a pointer to the calling context.
-
- @param MediaId The media ID that the write request is for.
-
- @param Lba The starting logical block address to be written. The caller is
-
- responsible for writing to only legitimate locations.
-
- @param BufferSize Size of Buffer, must be a multiple of device block size.
-
- @param Buffer A pointer to the source buffer for the data.
-
-
-
- @retval EFI_SUCCESS The data was written correctly to the device.
-
- @retval EFI_WRITE_PROTECTED The device can not be written to.
-
- @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
-
- @retval EFI_NO_MEDIA There is no media in the device.
-
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
-
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
-
- @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
-
- or the buffer is not on proper alignment.
-
-
-
-**/
-EFI_STATUS
-EFIAPI
-MMCHSWriteBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
-{
- EFI_STATUS Status;
-
- //Perform write operation.
- Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE);
-
-
- return Status;
-
-}
-
-
-/**
-
- Flush the Block Device.
-
-
-
- @param This Indicates a pointer to the calling context.
-
-
-
- @retval EFI_SUCCESS All outstanding data was written to the device
-
- @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
-
- @retval EFI_NO_MEDIA There is no media in the device.
-
-
-
-**/
-EFI_STATUS
-EFIAPI
-MMCHSFlushBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This
- )
-{
- return EFI_SUCCESS;
-}
-
-
-EFI_BLOCK_IO_PROTOCOL gBlockIo = {
- EFI_BLOCK_IO_INTERFACE_REVISION, // Revision
- &gMMCHSMedia, // *Media
- MMCHSReset, // Reset
- MMCHSReadBlocks, // ReadBlocks
- MMCHSWriteBlocks, // WriteBlocks
- MMCHSFlushBlocks // FlushBlocks
-};
-
-
-/**
-
- Timer callback to convert card present hardware into a boolean that indicates
-
- a media change event has happened. If you just check the GPIO you could see
-
- card 1 and then check again after card 1 was removed and card 2 was inserted
-
- and you would still see media present. Thus you need the timer tick to catch
-
- the toggle event.
-
-
-
- @param Event Event whose notification function is being invoked.
-
- @param Context The pointer to the notification function's context,
-
- which is implementation-dependent. Not used.
-
-
-
-**/
-VOID
-EFIAPI
-TimerCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- BOOLEAN Present;
-
- Present = CardPresent ();
- if (gMMCHSMedia.MediaPresent) {
- if (!Present && !gMediaChange) {
- gMediaChange = TRUE;
- }
- } else {
- if (Present && !gMediaChange) {
- gMediaChange = TRUE;
- }
- }
-}
-
-
-EFI_STATUS
-EFIAPI
-MMCHSInitialize (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
- 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, FixedPcdGet32 (PcdMmchsTimerFreq100NanoSeconds));
- ASSERT_EFI_ERROR (Status);
-
- //Publish BlockIO.
- Status = gBS->InstallMultipleProtocolInterfaces (
- &ImageHandle,
- &gEfiBlockIoProtocolGuid, &gBlockIo,
- &gEfiDevicePathProtocolGuid, &gMmcHsDevicePath,
- NULL
- );
- return Status;
-}
+/** @file\r
+ MMC/SD Card driver for OMAP 35xx (SDIO not supported)\r
+\r
+ This driver always produces a BlockIo protocol but it starts off with no Media\r
+ present. A TimerCallBack detects when media is inserted or removed and after \r
+ a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the \r
+ media to be detected (or removed) and the BlockIo Media structure will get\r
+ updated. No MMC/SD Card harward registers are updated until the first BlockIo\r
+ ReadBlocks/WriteBlocks after media has been insterted (booting with a card \r
+ plugged in counts as an insertion event). \r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\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 "MMCHS.h"\r
+\r
+EFI_BLOCK_IO_MEDIA gMMCHSMedia = {\r
+ SIGNATURE_32('s','d','i','o'), // MediaId\r
+ TRUE, // RemovableMedia\r
+ FALSE, // MediaPresent\r
+ FALSE, // LogicalPartition\r
+ FALSE, // ReadOnly\r
+ FALSE, // WriteCaching\r
+ 512, // BlockSize\r
+ 4, // IoAlign\r
+ 0, // Pad\r
+ 0 // LastBlock\r
+};\r
+\r
+typedef struct {\r
+ VENDOR_DEVICE_PATH Mmc;\r
+ EFI_DEVICE_PATH End;\r
+} MMCHS_DEVICE_PATH;\r
+\r
+MMCHS_DEVICE_PATH gMmcHsDevicePath = {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ (UINT8)(sizeof(VENDOR_DEVICE_PATH)),\r
+ (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),\r
+ 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 \r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
+ 0\r
+ }\r
+};\r
+\r
+CARD_INFO gCardInfo;\r
+EMBEDDED_EXTERNAL_DEVICE *gTPS65950;\r
+EFI_EVENT gTimerEvent;\r
+BOOLEAN gMediaChange = FALSE;\r
+\r
+//\r
+// Internal Functions\r
+//\r
+\r
+\r
+VOID\r
+ParseCardCIDData (\r
+ UINT32 Response0, \r
+ UINT32 Response1, \r
+ UINT32 Response2,\r
+ UINT32 Response3\r
+ )\r
+{\r
+ gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF);\r
+ gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8));\r
+ gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF);\r
+ gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF);\r
+ gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF);\r
+ gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF);\r
+ gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF);\r
+ gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF);\r
+ gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF);\r
+ gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF);\r
+}\r
+\r
+\r
+VOID\r
+UpdateMMCHSClkFrequency (\r
+ UINTN NewCLKD\r
+ )\r
+{\r
+ //Set Clock enable to 0x0 to not provide the clock to the card\r
+ MmioAnd32 (MMCHS_SYSCTL, ~CEN);\r
+\r
+ //Set new clock frequency.\r
+ MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6); \r
+\r
+ //Poll till Internal Clock Stable\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);\r
+\r
+ //Set Clock enable to 0x1 to provide the clock to the card\r
+ MmioOr32 (MMCHS_SYSCTL, CEN);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+SendCmd (\r
+ UINTN Cmd,\r
+ UINTN CmdInterruptEnableVal,\r
+ UINTN CmdArgument\r
+ )\r
+{\r
+ UINTN MmcStatus;\r
+ UINTN RetryCount = 0;\r
+\r
+ //Check if command line is in use or not. Poll till command line is available.\r
+ while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);\r
+\r
+ //Provide the block size.\r
+ MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);\r
+\r
+ //Setting Data timeout counter value to max value.\r
+ MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);\r
+\r
+ //Clear Status register.\r
+ MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);\r
+\r
+ //Set command argument register\r
+ MmioWrite32 (MMCHS_ARG, CmdArgument);\r
+\r
+ //Enable interrupt enable events to occur\r
+ MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);\r
+\r
+ //Send a command\r
+ MmioWrite32 (MMCHS_CMD, Cmd);\r
+\r
+ //Check for the command status.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ do {\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while (MmcStatus == 0);\r
+\r
+ //Read status of command response\r
+ if ((MmcStatus & ERRI) != 0) {\r
+\r
+ //Perform soft-reset for mmci_cmd line.\r
+ MmioOr32 (MMCHS_SYSCTL, SRC);\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
+\r
+ DEBUG ((EFI_D_INFO, "MmcStatus: %x\n", MmcStatus));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //Check if command is completed.\r
+ if ((MmcStatus & CC) == CC) {\r
+ MmioWrite32 (MMCHS_STAT, CC);\r
+ break;\r
+ }\r
+\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+VOID\r
+GetBlockInformation (\r
+ UINTN *BlockSize,\r
+ UINTN *NumBlocks\r
+ )\r
+{\r
+ CSD_SDV2 *CsdSDV2Data;\r
+ UINTN CardSize;\r
+\r
+ if (gCardInfo.CardType == SD_CARD_2_HIGH) {\r
+ CsdSDV2Data = (CSD_SDV2 *)&gCardInfo.CSDData;\r
+\r
+ //Populate BlockSize.\r
+ *BlockSize = (0x1UL << CsdSDV2Data->READ_BL_LEN);\r
+\r
+ //Calculate Total number of blocks.\r
+ CardSize = CsdSDV2Data->C_SIZELow16 | (CsdSDV2Data->C_SIZEHigh6 << 2);\r
+ *NumBlocks = ((CardSize + 1) * 1024);\r
+ } else {\r
+ //Populate BlockSize.\r
+ *BlockSize = (0x1UL << gCardInfo.CSDData.READ_BL_LEN);\r
+\r
+ //Calculate Total number of blocks.\r
+ CardSize = gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2);\r
+ *NumBlocks = (CardSize + 1) * (1 << (gCardInfo.CSDData.C_SIZE_MULT + 2));\r
+ }\r
+\r
+ //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
+ if (*BlockSize > 512) {\r
+ *NumBlocks = MultU64x32(*NumBlocks, *BlockSize/2);\r
+ *BlockSize = 512;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Card type: %x, BlockSize: %x, NumBlocks: %x\n", gCardInfo.CardType, *BlockSize, *NumBlocks));\r
+}\r
+\r
+\r
+VOID\r
+CalculateCardCLKD (\r
+ UINTN *ClockFrequencySelect\r
+ )\r
+{\r
+ UINT8 MaxDataTransferRate;\r
+ UINTN TransferRateValue = 0;\r
+ UINTN TimeValue = 0 ;\r
+ UINTN Frequency = 0;\r
+\r
+ MaxDataTransferRate = gCardInfo.CSDData.TRAN_SPEED;\r
+\r
+ // For SD Cards we would need to send CMD6 to set\r
+ // speeds abouve 25MHz. High Speed mode 50 MHz and up\r
+\r
+ //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)\r
+ switch (MaxDataTransferRate & 0x7) {\r
+ case 0:\r
+ TransferRateValue = 100 * 1000;\r
+ break;\r
+\r
+ case 1:\r
+ TransferRateValue = 1 * 1000 * 1000;\r
+ break;\r
+\r
+ case 2:\r
+ TransferRateValue = 10 * 1000 * 1000;\r
+ break;\r
+\r
+ case 3:\r
+ TransferRateValue = 100 * 1000 * 1000;\r
+ break;\r
+\r
+ default:\r
+ DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //Calculate Time value (Bits 6:3 of TRAN_SPEED)\r
+ switch ((MaxDataTransferRate >> 3) & 0xF) {\r
+ case 1:\r
+ TimeValue = 10;\r
+ break;\r
+\r
+ case 2:\r
+ TimeValue = 12;\r
+ break;\r
+\r
+ case 3:\r
+ TimeValue = 13;\r
+ break;\r
+\r
+ case 4:\r
+ TimeValue = 15;\r
+ break;\r
+\r
+ case 5:\r
+ TimeValue = 20;\r
+ break;\r
+\r
+ case 6:\r
+ TimeValue = 25;\r
+ break;\r
+\r
+ case 7:\r
+ TimeValue = 30;\r
+ break;\r
+\r
+ case 8:\r
+ TimeValue = 35;\r
+ break;\r
+\r
+ case 9:\r
+ TimeValue = 40;\r
+ break;\r
+\r
+ case 10:\r
+ TimeValue = 45;\r
+ break;\r
+\r
+ case 11:\r
+ TimeValue = 50;\r
+ break;\r
+\r
+ case 12:\r
+ TimeValue = 55;\r
+ break;\r
+\r
+ case 13:\r
+ TimeValue = 60;\r
+ break;\r
+\r
+ case 14:\r
+ TimeValue = 70;\r
+ break;\r
+\r
+ case 15:\r
+ TimeValue = 80;\r
+ break;\r
+\r
+ default:\r
+ DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ Frequency = TransferRateValue * TimeValue/10;\r
+\r
+ //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.\r
+ *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);\r
+\r
+ DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));\r
+}\r
+\r
+\r
+VOID\r
+GetCardConfigurationData (\r
+ VOID\r
+ )\r
+{\r
+ UINTN BlockSize;\r
+ UINTN NumBlocks;\r
+ UINTN ClockFrequencySelect;\r
+\r
+ //Calculate BlockSize and Total number of blocks in the detected card.\r
+ GetBlockInformation(&BlockSize, &NumBlocks);\r
+ gCardInfo.BlockSize = BlockSize;\r
+ gCardInfo.NumBlocks = NumBlocks;\r
+\r
+ //Calculate Card clock divider value.\r
+ CalculateCardCLKD(&ClockFrequencySelect);\r
+ gCardInfo.ClockFrequencySelect = ClockFrequencySelect;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+InitializeMMCHS (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 Data = 0;\r
+ EFI_STATUS Status;\r
+\r
+ //Select Device group to belong to P1 device group in Power IC.\r
+ Data = DEV_GRP_P1;\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.\r
+ Data = VSEL_3_00V;\r
+ Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);\r
+ ASSERT_EFI_ERROR(Status);\r
+ \r
+ //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.\r
+ MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));\r
+\r
+ // Enable WP GPIO\r
+ MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);\r
+\r
+ // Enable Card Detect\r
+ Data = CARD_DETECT_ENABLE;\r
+ gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+PerformCardIdenfication (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN CmdArgument = 0;\r
+ UINTN Response = 0;\r
+ UINTN RetryCount = 0;\r
+ BOOLEAN SDCmd8Supported = FALSE;\r
+\r
+ //Enable interrupts.\r
+ MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |\r
+ CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));\r
+\r
+ //Controller INIT procedure start.\r
+ MmioOr32 (MMCHS_CON, INIT);\r
+ MmioWrite32 (MMCHS_CMD, 0x00000000);\r
+ while (!(MmioRead32 (MMCHS_STAT) & CC));\r
+\r
+ //Wait for 1 ms\r
+ gBS->Stall(1000);\r
+\r
+ //Set CC bit to 0x1 to clear the flag\r
+ MmioOr32 (MMCHS_STAT, CC);\r
+\r
+ //Retry INIT procedure.\r
+ MmioWrite32 (MMCHS_CMD, 0x00000000);\r
+ while (!(MmioRead32 (MMCHS_STAT) & CC));\r
+\r
+ //End initialization sequence\r
+ MmioAnd32 (MMCHS_CON, ~INIT);\r
+\r
+ MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));\r
+\r
+ //Change clock frequency to 400KHz to fit protocol\r
+ UpdateMMCHSClkFrequency(CLKD_400KHZ);\r
+\r
+ MmioOr32 (MMCHS_CON, OD);\r
+\r
+ //Send CMD0 command.\r
+ Status = SendCmd (CMD0, CMD0_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Cmd0 fails.\n"));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "CMD0 response: %x\n", MmioRead32 (MMCHS_RSP10)));\r
+\r
+ //Send CMD5 command. \r
+ Status = SendCmd (CMD5, CMD5_INT_EN, CmdArgument);\r
+ if (Status == EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_ERROR, "CMD5 Success. SDIO card. Follow SDIO card specification.\n"));\r
+ DEBUG ((EFI_D_INFO, "CMD5 response: %x\n", MmioRead32 (MMCHS_RSP10)));\r
+ //NOTE: Returning unsupported error for now. Need to implement SDIO specification.\r
+ return EFI_UNSUPPORTED; \r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "CMD5 fails. Not an SDIO card.\n"));\r
+ }\r
+\r
+ MmioOr32 (MMCHS_SYSCTL, SRC);\r
+ gBS->Stall(1000);\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
+\r
+ //Send CMD8 command. (New v2.00 command for Voltage check)\r
+ //Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass.\r
+ //MMC & SD1.1 card will fail this command.\r
+ CmdArgument = CMD8_ARG;\r
+ Status = SendCmd (CMD8, CMD8_INT_EN, CmdArgument);\r
+ if (Status == EFI_SUCCESS) {\r
+ Response = MmioRead32 (MMCHS_RSP10);\r
+ DEBUG ((EFI_D_INFO, "CMD8 success. CMD8 response: %x\n", Response));\r
+ if (Response != CmdArgument) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Card is SD2.0\n"));\r
+ SDCmd8Supported = TRUE; //Supports high capacity.\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "CMD8 fails. Not an SD2.0 card.\n"));\r
+ }\r
+\r
+ MmioOr32 (MMCHS_SYSCTL, SRC);\r
+ gBS->Stall(1000);\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
+\r
+ //Poll till card is busy\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ //Send CMD55 command. \r
+ CmdArgument = 0;\r
+ Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);\r
+ if (Status == EFI_SUCCESS) {\r
+ DEBUG ((EFI_D_INFO, "CMD55 success. CMD55 response: %x\n", MmioRead32 (MMCHS_RSP10)));\r
+ gCardInfo.CardType = SD_CARD;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "CMD55 fails.\n"));\r
+ gCardInfo.CardType = MMC_CARD;\r
+ }\r
+\r
+ //Send appropriate command for the card type which got detected.\r
+ if (gCardInfo.CardType == SD_CARD) {\r
+ CmdArgument = ((UINTN *) &(gCardInfo.OCRData))[0];\r
+\r
+ //Set HCS bit.\r
+ if (SDCmd8Supported) {\r
+ CmdArgument |= HCS;\r
+ }\r
+\r
+ Status = SendCmd (ACMD41, ACMD41_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "ACMD41 fails.\n"));\r
+ return Status;\r
+ }\r
+ ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 (MMCHS_RSP10);\r
+ DEBUG ((EFI_D_INFO, "SD card detected. ACMD41 OCR: %x\n", ((UINT32 *) &(gCardInfo.OCRData))[0]));\r
+ } else if (gCardInfo.CardType == MMC_CARD) {\r
+ CmdArgument = 0;\r
+ Status = SendCmd (CMD1, CMD1_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "CMD1 fails.\n"));\r
+ return Status;\r
+ }\r
+ Response = MmioRead32 (MMCHS_RSP10);\r
+ DEBUG ((EFI_D_INFO, "MMC card detected.. CMD1 response: %x\n", Response));\r
+\r
+ //NOTE: For now, I am skipping this since I only have an SD card.\r
+ //Compare card OCR and host OCR (Section 22.6.1.3.2.4)\r
+ return EFI_UNSUPPORTED; //For now, MMC is not supported.\r
+ }\r
+\r
+ //Poll the card until it is out of its power-up sequence.\r
+ if (gCardInfo.OCRData.Busy == 1) {\r
+\r
+ if (SDCmd8Supported) {\r
+ gCardInfo.CardType = SD_CARD_2;\r
+ }\r
+\r
+ //Card is ready. Check CCS (Card capacity status) bit (bit#30).\r
+ //SD 2.0 standard card will response with CCS 0, SD high capacity card will respond with CCS 1.\r
+ if (gCardInfo.OCRData.AccessMode & BIT1) {\r
+ gCardInfo.CardType = SD_CARD_2_HIGH;\r
+ DEBUG ((EFI_D_INFO, "High capacity card.\n"));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Standard capacity card.\n"));\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ gBS->Stall(1000);\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ DEBUG ((EFI_D_ERROR, "Timeout error. RetryCount: %d\n", RetryCount));\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ //Read CID data.\r
+ CmdArgument = 0;\r
+ Status = SendCmd (CMD2, CMD2_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));\r
+\r
+ //Parse CID register data.\r
+ ParseCardCIDData(MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76));\r
+\r
+ //Read RCA\r
+ CmdArgument = 0;\r
+ Status = SendCmd (CMD3, CMD3_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //Set RCA for the detected card. RCA is CMD3 response.\r
+ gCardInfo.RCA = (MmioRead32 (MMCHS_RSP10) >> 16);\r
+ DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA));\r
+\r
+ //MMC Bus setting change after card identification.\r
+ MmioAnd32 (MMCHS_CON, ~OD);\r
+ MmioOr32 (MMCHS_HCTL, SDVS_3_0_V);\r
+ UpdateMMCHSClkFrequency(CLKD_400KHZ); //Set the clock frequency to 400KHz.\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+GetCardSpecificData (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN CmdArgument;\r
+\r
+ //Send CMD9 to retrieve CSD.\r
+ CmdArgument = gCardInfo.RCA << 16;\r
+ Status = SendCmd (CMD9, CMD9_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //Populate 128-bit CSD register data.\r
+ ((UINT32 *)&(gCardInfo.CSDData))[0] = MmioRead32 (MMCHS_RSP10);\r
+ ((UINT32 *)&(gCardInfo.CSDData))[1] = MmioRead32 (MMCHS_RSP32);\r
+ ((UINT32 *)&(gCardInfo.CSDData))[2] = MmioRead32 (MMCHS_RSP54);\r
+ ((UINT32 *)&(gCardInfo.CSDData))[3] = MmioRead32 (MMCHS_RSP76);\r
+\r
+ DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));\r
+\r
+ //Calculate total number of blocks and max. data transfer rate supported by the detected card.\r
+ GetCardConfigurationData();\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+PerformCardConfiguration (\r
+ VOID\r
+ )\r
+{\r
+ UINTN CmdArgument = 0;\r
+ EFI_STATUS Status;\r
+\r
+ //Send CMD7\r
+ CmdArgument = gCardInfo.RCA << 16;\r
+ Status = SendCmd (CMD7, CMD7_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if ((gCardInfo.CardType != UNKNOWN_CARD) && (gCardInfo.CardType != MMC_CARD)) {\r
+ // We could read SCR register, but SD Card Phys spec stats any SD Card shall\r
+ // set SCR.SD_BUS_WIDTHS to support 4-bit mode, so why bother?\r
+ \r
+ // Send ACMD6 (application specific commands must be prefixed with CMD55)\r
+ Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);\r
+ if (!EFI_ERROR (Status)) {\r
+ // set device into 4-bit data bus mode\r
+ Status = SendCmd (ACMD6, ACMD6_INT_EN, 0x2);\r
+ if (!EFI_ERROR (Status)) {\r
+ // Set host controler into 4-bit mode\r
+ MmioOr32 (MMCHS_HCTL, DTW_4_BIT);\r
+ DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n"));\r
+ }\r
+ }\r
+ }\r
+\r
+ //Send CMD16 to set the block length\r
+ CmdArgument = gCardInfo.BlockSize;\r
+ Status = SendCmd (CMD16, CMD16_INT_EN, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //Change MMCHS clock frequency to what detected card can support.\r
+ UpdateMMCHSClkFrequency(gCardInfo.ClockFrequencySelect);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+ReadBlockData (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ UINTN MmcStatus;\r
+ UINTN *DataBuffer = Buffer;\r
+ UINTN DataSize = This->Media->BlockSize/4;\r
+ UINTN Count;\r
+ UINTN RetryCount = 0;\r
+\r
+ //Check controller status to make sure there is no error.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ do {\r
+ //Read Status.\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while(MmcStatus == 0);\r
+\r
+ //Check if Buffer read ready (BRR) bit is set?\r
+ if (MmcStatus & BRR) {\r
+\r
+ //Clear BRR bit\r
+ MmioOr32 (MMCHS_STAT, BRR);\r
+\r
+ //Read block worth of data.\r
+ for (Count = 0; Count < DataSize; Count++) {\r
+ *DataBuffer++ = MmioRead32 (MMCHS_DATA);\r
+ }\r
+ break;\r
+ }\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+WriteBlockData (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ UINTN MmcStatus;\r
+ UINTN *DataBuffer = Buffer;\r
+ UINTN DataSize = This->Media->BlockSize/4;\r
+ UINTN Count;\r
+ UINTN RetryCount = 0;\r
+\r
+ //Check controller status to make sure there is no error.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ do {\r
+ //Read Status.\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while(MmcStatus == 0);\r
+\r
+ //Check if Buffer write ready (BWR) bit is set?\r
+ if (MmcStatus & BWR) {\r
+\r
+ //Clear BWR bit\r
+ MmioOr32 (MMCHS_STAT, BWR);\r
+\r
+ //Write block worth of data.\r
+ for (Count = 0; Count < DataSize; Count++) {\r
+ MmioWrite32 (MMCHS_DATA, *DataBuffer++);\r
+ }\r
+\r
+ break;\r
+ }\r
+ RetryCount++;\r
+ }\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DmaBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINTN Lba,\r
+ IN OUT VOID *Buffer,\r
+ IN UINTN BlockCount,\r
+ IN OPERATION_TYPE OperationType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN DmaSize = 0;\r
+ UINTN Cmd = 0;\r
+ UINTN CmdInterruptEnable;\r
+ UINTN CmdArgument;\r
+ VOID *BufferMap;\r
+ EFI_PHYSICAL_ADDRESS BufferAddress;\r
+ OMAP_DMA4 Dma4;\r
+ DMA_MAP_OPERATION DmaOperation;\r
+ EFI_STATUS MmcStatus;\r
+ UINTN RetryCount = 0;\r
+\r
+CpuDeadLoop ();\r
+ // Map passed in buffer for DMA xfer\r
+ DmaSize = BlockCount * This->Media->BlockSize;\r
+ Status = DmaMap (DmaOperation, Buffer, &DmaSize, &BufferAddress, &BufferMap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ZeroMem (&DmaOperation, sizeof (DMA_MAP_OPERATION));\r
+ \r
+\r
+ Dma4.DataType = 2; // DMA4_CSDPi[1:0] 32-bit elements from MMCHS_DATA\r
+\r
+ Dma4.SourceEndiansim = 0; // DMA4_CSDPi[21] \r
+\r
+ Dma4.DestinationEndianism = 0; // DMA4_CSDPi[19]\r
+\r
+ Dma4.SourcePacked = 0; // DMA4_CSDPi[6]\r
+\r
+ Dma4.DestinationPacked = 0; // DMA4_CSDPi[13]\r
+\r
+ Dma4.NumberOfElementPerFrame = This->Media->BlockSize/4; // DMA4_CENi (TRM 4K is optimum value) \r
+\r
+ Dma4.NumberOfFramePerTransferBlock = BlockCount; // DMA4_CFNi \r
+\r
+ Dma4.ReadPriority = 0; // DMA4_CCRi[6] Low priority read \r
+\r
+ Dma4.WritePriority = 0; // DMA4_CCRi[23] Prefetech disabled\r
+\r
+\r
+ //Populate the command information based on the operation type.\r
+ if (OperationType == READ) {\r
+ Cmd = CMD18; //Multiple block read\r
+ CmdInterruptEnable = CMD18_INT_EN;\r
+ DmaOperation = MapOperationBusMasterCommonBuffer;\r
+\r
+ Dma4.ReadPortAccessType =0 ; // DMA4_CSDPi[8:7] Can not burst MMCHS_DATA reg\r
+\r
+ Dma4.WritePortAccessType = 3; // DMA4_CSDPi[15:14] Memory burst 16x32\r
+\r
+ Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted\r
+\r
+ \r
+\r
+ Dma4.SourceStartAddress = MMCHS_DATA; // DMA4_CSSAi\r
+\r
+ Dma4.DestinationStartAddress = (UINT32)BufferAddress; // DMA4_CDSAi\r
+\r
+ Dma4.SourceElementIndex = 1; // DMA4_CSEi\r
+\r
+ Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi\r
+\r
+ Dma4.DestinationElementIndex = 1; // DMA4_CDEi\r
+\r
+ Dma4.DestinationFrameIndex = 0; // DMA4_CDFi\r
+\r
+\r
+\r
+ Dma4.ReadPortAccessMode = 0; // DMA4_CCRi[13:12] Always read MMCHS_DATA\r
+\r
+ Dma4.WritePortAccessMode = 1; // DMA4_CCRi[15:14] Post increment memory address\r
+\r
+ Dma4.ReadRequestNumber = 0x1e; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_RX (61) \r
+\r
+ Dma4.WriteRequestNumber = 1; // DMA4_CCRi[20:19] Syncro upper 0x3e == 62 (one based)\r
+\r
+ } else if (OperationType == WRITE) { \r
+ Cmd = CMD25; //Multiple block write\r
+ CmdInterruptEnable = CMD25_INT_EN;\r
+ DmaOperation = MapOperationBusMasterRead;\r
+\r
+ Dma4.ReadPortAccessType = 3; // DMA4_CSDPi[8:7] Memory burst 16x32\r
+\r
+ Dma4.WritePortAccessType = 0; // DMA4_CSDPi[15:14] Can not burst MMCHS_DATA reg\r
+\r
+ Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted ???\r
+\r
+ \r
+\r
+ Dma4.SourceStartAddress = (UINT32)BufferAddress; // DMA4_CSSAi\r
+\r
+ Dma4.DestinationStartAddress = MMCHS_DATA; // DMA4_CDSAi\r
+\r
+ Dma4.SourceElementIndex = 1; // DMA4_CSEi\r
+\r
+ Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi\r
+\r
+ Dma4.DestinationElementIndex = 1; // DMA4_CDEi\r
+\r
+ Dma4.DestinationFrameIndex = 0; // DMA4_CDFi\r
+\r
+\r
+\r
+ Dma4.ReadPortAccessMode = 1; // DMA4_CCRi[13:12] Post increment memory address\r
+\r
+ Dma4.WritePortAccessMode = 0; // DMA4_CCRi[15:14] Always write MMCHS_DATA\r
+\r
+ Dma4.ReadRequestNumber = 0x1d; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_TX (60) \r
+\r
+ Dma4.WriteRequestNumber = 1; // DMA4_CCRi[20:19] Syncro upper 0x3d == 61 (one based)\r
+\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+\r
+ EnableDmaChannel (2, &Dma4);\r
+ \r
+\r
+ //Set command argument based on the card access mode (Byte mode or Block mode)\r
+ if (gCardInfo.OCRData.AccessMode & BIT1) {\r
+ CmdArgument = Lba;\r
+ } else {\r
+ CmdArgument = Lba * This->Media->BlockSize;\r
+ }\r
+\r
+ //Send Command.\r
+ Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //Check for the Transfer completion.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ //Read Status\r
+ do {\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while (MmcStatus == 0);\r
+\r
+ //Check if Transfer complete (TC) bit is set?\r
+ if (MmcStatus & TC) {\r
+ break;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus));\r
+ //Check if DEB, DCRC or DTO interrupt occured.\r
+ if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) {\r
+ //There was an error during the data transfer.\r
+\r
+ //Set SRD bit to 1 and wait until it return to 0x0.\r
+ MmioOr32 (MMCHS_SYSCTL, SRD);\r
+ while((MmioRead32 (MMCHS_SYSCTL) & SRD) != 0x0);\r
+\r
+ DisableDmaChannel (2, DMA4_CSR_BLOCK, DMA4_CSR_ERR);\r
+ DmaUnmap (BufferMap);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ RetryCount++;\r
+ } \r
+\r
+ DisableDmaChannel (2, DMA4_CSR_BLOCK, DMA4_CSR_ERR);\r
+ Status = DmaUnmap (BufferMap);\r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+TransferBlock (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINTN Lba,\r
+ IN OUT VOID *Buffer,\r
+ IN OPERATION_TYPE OperationType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN MmcStatus;\r
+ UINTN RetryCount = 0;\r
+ UINTN Cmd = 0;\r
+ UINTN CmdInterruptEnable = 0;\r
+ UINTN CmdArgument = 0;\r
+\r
+\r
+ //Populate the command information based on the operation type.\r
+ if (OperationType == READ) {\r
+ Cmd = CMD17; //Single block read\r
+ CmdInterruptEnable = CMD18_INT_EN;\r
+ } else if (OperationType == WRITE) { \r
+ Cmd = CMD24; //Single block write\r
+ CmdInterruptEnable = CMD24_INT_EN;\r
+ }\r
+\r
+ //Set command argument based on the card access mode (Byte mode or Block mode)\r
+ if (gCardInfo.OCRData.AccessMode & BIT1) {\r
+ CmdArgument = Lba;\r
+ } else {\r
+ CmdArgument = Lba * This->Media->BlockSize;\r
+ }\r
+\r
+ //Send Command.\r
+ Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //Read or Write data.\r
+ if (OperationType == READ) {\r
+ Status = ReadBlockData (This, Buffer);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n"));\r
+ return Status;\r
+ }\r
+ } else if (OperationType == WRITE) {\r
+ Status = WriteBlockData (This, Buffer);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n"));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //Check for the Transfer completion.\r
+ while (RetryCount < MAX_RETRY_COUNT) {\r
+ //Read Status\r
+ do {\r
+ MmcStatus = MmioRead32 (MMCHS_STAT);\r
+ } while (MmcStatus == 0);\r
+\r
+ //Check if Transfer complete (TC) bit is set?\r
+ if (MmcStatus & TC) {\r
+ break;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus));\r
+ //Check if DEB, DCRC or DTO interrupt occured.\r
+ if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) {\r
+ //There was an error during the data transfer.\r
+\r
+ //Set SRD bit to 1 and wait until it return to 0x0.\r
+ MmioOr32 (MMCHS_SYSCTL, SRD);\r
+ while((MmioRead32 (MMCHS_SYSCTL) & SRD) != 0x0);\r
+\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ RetryCount++;\r
+ } \r
+\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+CardPresent (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Data;\r
+\r
+ //\r
+ // Card detect is a GPIO0 on the TPS65950\r
+ //\r
+ Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((Data & CARD_DETECT_BIT) == CARD_DETECT_BIT) {\r
+ // No Card present\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+DetectCard (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (!CardPresent ()) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ //Initialize MMC host controller clocks.\r
+ Status = InitializeMMCHS ();\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //Software reset of the MMCHS host controller.\r
+ MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);\r
+ gBS->Stall(1000);\r
+ while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);\r
+\r
+ //Soft reset for all.\r
+ MmioWrite32 (MMCHS_SYSCTL, SRA);\r
+ gBS->Stall(1000);\r
+ while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);\r
+\r
+ //Voltage capabilities initialization. Activate VS18 and VS30.\r
+ MmioOr32 (MMCHS_CAPA, (VS30 | VS18));\r
+\r
+ //Wakeup configuration\r
+ MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);\r
+ MmioOr32 (MMCHS_HCTL, IWE);\r
+\r
+ //MMCHS Controller default initialization\r
+ MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));\r
+\r
+ MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));\r
+\r
+ //Enable internal clock\r
+ MmioOr32 (MMCHS_SYSCTL, ICE);\r
+\r
+ //Set the clock frequency to 80KHz.\r
+ UpdateMMCHSClkFrequency (CLKD_80KHZ);\r
+\r
+ //Enable SD bus power.\r
+ MmioOr32 (MMCHS_HCTL, (SDBP_ON));\r
+\r
+ //Poll till SD bus power bit is set.\r
+ while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);\r
+\r
+ //Card idenfication\r
+ Status = PerformCardIdenfication ();\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n"));\r
+ return Status;\r
+ }\r
+ \r
+ //Get CSD (Card specific data) for the detected card.\r
+ Status = GetCardSpecificData();\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //Configure the card in data transfer mode.\r
+ Status = PerformCardConfiguration();\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //Patch the Media structure.\r
+ gMMCHSMedia.LastBlock = (gCardInfo.NumBlocks - 1);\r
+ gMMCHSMedia.BlockSize = gCardInfo.BlockSize;\r
+ gMMCHSMedia.ReadOnly = (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;\r
+ gMMCHSMedia.MediaPresent = TRUE; \r
+ gMMCHSMedia.MediaId++; \r
+\r
+ DEBUG ((EFI_D_INFO, "SD Card Media Change on Handle 0x%08x\n", gImageHandle));\r
+\r
+ return Status;\r
+}\r
+\r
+#define MAX_MMCHS_TRANSFER_SIZE 0x4000\r
+\r
+EFI_STATUS\r
+SdReadWrite (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINTN Lba, \r
+ OUT VOID *Buffer, \r
+ IN UINTN BufferSize,\r
+ IN OPERATION_TYPE OperationType\r
+ )\r
+{\r
+ EFI_STATUS Status = EFI_SUCCESS;\r
+ UINTN RetryCount = 0;\r
+ UINTN BlockCount;\r
+ UINTN BytesToBeTranferedThisPass = 0;\r
+ UINTN BytesRemainingToBeTransfered;\r
+ EFI_TPL OldTpl;\r
+\r
+ BOOLEAN Update;\r
+\r
+\r
+ \r
+ Update = FALSE;\r
+\r
+ if (gMediaChange) {\r
+ Update = TRUE;\r
+ Status = DetectCard ();\r
+ if (EFI_ERROR (Status)) {\r
+ // We detected a removal\r
+ gMMCHSMedia.MediaPresent = FALSE;\r
+ gMMCHSMedia.LastBlock = 0;\r
+ gMMCHSMedia.BlockSize = 512; // Should be zero but there is a bug in DiskIo\r
+ gMMCHSMedia.ReadOnly = FALSE; \r
+ }\r
+ gMediaChange = FALSE;\r
+ } else if (!gMMCHSMedia.MediaPresent) {\r
+ Status = EFI_NO_MEDIA;\r
+ goto Done;\r
+ }\r
+\r
+ if (Update) {\r
+ DEBUG ((EFI_D_INFO, "SD Card ReinstallProtocolInterface ()\n"));\r
+ gBS->ReinstallProtocolInterface (\r
+ gImageHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &gBlockIo,\r
+ &gBlockIo\r
+ );\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if (Lba > This->Media->LastBlock) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ \r
+ if ((BufferSize % This->Media->BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ //Check if the data lines are not in use.\r
+ while ((RetryCount++ < MAX_RETRY_COUNT) && ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) != DATI_ALLOWED));\r
+ if (RetryCount == MAX_RETRY_COUNT) {\r
+ Status = EFI_TIMEOUT;\r
+ goto Done;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ BytesRemainingToBeTransfered = BufferSize;\r
+ while (BytesRemainingToBeTransfered > 0) {\r
+\r
+ if (gMediaChange) {\r
+ Status = EFI_NO_MEDIA;\r
+ DEBUG ((EFI_D_INFO, "SdReadWrite() EFI_NO_MEDIA due to gMediaChange\n"));\r
+ goto DoneRestoreTPL;\r
+ }\r
+\r
+ // Turn OFF DMA path until it is debugged\r
+ // BytesToBeTranferedThisPass = (BytesToBeTranferedThisPass >= MAX_MMCHS_TRANSFER_SIZE) ? MAX_MMCHS_TRANSFER_SIZE : BytesRemainingToBeTransfered;\r
+ BytesToBeTranferedThisPass = This->Media->BlockSize;\r
+\r
+ BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize;\r
+\r
+ if (BlockCount > 1) {\r
+ Status = DmaBlocks (This, Lba, Buffer, BlockCount, OperationType);\r
+ } else {\r
+ //Transfer a block worth of data.\r
+ Status = TransferBlock (This, Lba, Buffer, OperationType);\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));\r
+ goto DoneRestoreTPL;\r
+ }\r
+\r
+ BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass;\r
+ Lba += BlockCount;\r
+ Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
+ }\r
+\r
+DoneRestoreTPL:\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+Done:\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+\r
+ Reset the Block Device.\r
+\r
+\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+\r
+ not be reset.\r
+\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCHSReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ return EFI_SUCCESS; \r
+}\r
+\r
+\r
+/**\r
+\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+\r
+ @param Lba The starting Logical Block Address to read from\r
+\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+\r
+ or the buffer is not on proper alignment.\r
+\r
+EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCHSReadBlocks (\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
+\r
+ //Perform Read operation.\r
+ Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ);\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @param MediaId The media ID that the write request is for.\r
+\r
+ @param Lba The starting logical block address to be written. The caller is\r
+\r
+ responsible for writing to only legitimate locations.\r
+\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+\r
+ or the buffer is not on proper alignment.\r
+\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCHSWriteBlocks (\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
+\r
+ //Perform write operation.\r
+ Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE);\r
+\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+\r
+ Flush the Block Device.\r
+\r
+\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
+\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCHSFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_BLOCK_IO_PROTOCOL gBlockIo = {\r
+ EFI_BLOCK_IO_INTERFACE_REVISION, // Revision\r
+ &gMMCHSMedia, // *Media\r
+ MMCHSReset, // Reset\r
+ MMCHSReadBlocks, // ReadBlocks\r
+ MMCHSWriteBlocks, // WriteBlocks\r
+ MMCHSFlushBlocks // FlushBlocks\r
+};\r
+\r
+\r
+/**\r
+\r
+ Timer callback to convert card present hardware into a boolean that indicates\r
+\r
+ a media change event has happened. If you just check the GPIO you could see \r
+\r
+ card 1 and then check again after card 1 was removed and card 2 was inserted\r
+\r
+ and you would still see media present. Thus you need the timer tick to catch\r
+\r
+ the toggle event.\r
+\r
+\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+\r
+ @param Context The pointer to the notification function's context,\r
+\r
+ which is implementation-dependent. Not used.\r
+\r
+\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TimerCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ BOOLEAN Present;\r
+\r
+ Present = CardPresent ();\r
+ if (gMMCHSMedia.MediaPresent) {\r
+ if (!Present && !gMediaChange) {\r
+ gMediaChange = TRUE;\r
+ }\r
+ } else {\r
+ if (Present && !gMediaChange) {\r
+ gMediaChange = TRUE; \r
+ }\r
+ }\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MMCHSInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ ZeroMem (&gCardInfo, sizeof (CARD_INFO));\r
+\r
+ Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, TimerCallback, NULL, &gTimerEvent);\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ Status = gBS->SetTimer (gTimerEvent, TimerPeriodic, FixedPcdGet32 (PcdMmchsTimerFreq100NanoSeconds)); \r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //Publish BlockIO.\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ImageHandle, \r
+ &gEfiBlockIoProtocolGuid, &gBlockIo, \r
+ &gEfiDevicePathProtocolGuid, &gMmcHsDevicePath,\r
+ NULL\r
+ );\r
+ return Status;\r
+}\r