ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.c b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.c
new file mode 100644
index 0000000..236ac95
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.c
@@ -0,0 +1,2004 @@
+/******************************************************************************
+ *
+ * (C)Copyright 2005 - 2011 Marvell. All Rights Reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
+ * The copyright notice above does not evidence any actual or intended
+ * publication of such source code.
+ * This Module contains Proprietary Information of Marvell and should be
+ * treated as Confidential.
+ * The information in this file is provided for the exclusive use of the
+ * licensees of Marvell.
+ * Such users have the right to use, modify, and incorporate this code into
+ * products for purposes authorized by the license agreement provided they
+ * include this notice and the associated copyright notice with any such
+ * product.
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "predefines.h"
+#include "sdmmc_api.h"
+#include "sdhc2.h"
+#include "Errors.h"
+#include "PlatformConfig.h"
+#include "xllp_dfc_defs.h"
+#include "loadoffsets.h"
+
+static MM4_SDMMC_CONTEXT_T MM4_Context; // Only need one
+extern ADMA_DESCRIPTOR *admaDesc;
+
+UINT_T MM4_MMCDecodeCID(void)
+{
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ UINT_T ManufactureID; // Manufactor ID
+ UINT_T OID; // OEM/Application ID
+ UINT_T SerialNumber;
+ UINT_T ProductName; // last 32bits
+ UINT_T ProductRevision;
+
+ ManufactureID = UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 120, 8);
+ OID = UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 104, 8);
+ ProductName = UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 56, 32);
+ SerialNumber = UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 16, 32);
+ ProductRevision = UNSTUFF_BITS(pSDMMCP->CardReg.CID.CID_VALUE, 48, 8);
+
+ switch (ManufactureID)
+ {
+ case 0x45:
+ case 0x02:
+ obm_printf("Manufacturer: SanDisK\n\r");
+ break;
+
+ case 0xfe:
+ case 0x13:
+ obm_printf("Manufacturer: Micron\n\r");
+ break;
+
+ case 0x70:
+ obm_printf("Manufacturer: Kingston\n\r");
+ break;
+
+ case 0x11:
+ obm_printf("Manufacturer: Toshiba\n\r");
+ break;
+
+ case 0x90:
+ obm_printf("Manufacturer: Hynix\n\r");
+ break;
+
+ case 0x15:
+ obm_printf("Manufacturer: Samsung\n\r");
+ break;
+
+ default:
+ obm_printf("New Manufacturer: 0x%08x\n\r", ManufactureID);
+ break;
+ }
+
+}
+
+UINT_T MM4_MMCDecodeEXTCSD(void)
+{
+ UINT8_T pBuffer[512];
+ UINT_T ret = NoError;
+ UINT_T sectors;
+ UINT64 capacity;
+ UINT8_T erase_group_define, card_type;
+ UINT_T boot_partition_size;
+ UINT8_T spec_version; // system specification version number
+
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ ret = MM4_MMCReadEXTCSD((UINT_T *)pBuffer);
+ if (ret != NoError)
+ return ret;
+
+ if (pBuffer[212] || pBuffer[213] || pBuffer[214] || pBuffer[215]) // SEC_COUNT
+ {
+ sectors = pBuffer[212] | (pBuffer[213] << 8) | (pBuffer[214] << 16) | (pBuffer[215] << 24);
+ capacity = sectors;
+ capacity *= 512; // capacity equals to sectors multiply by 512B
+ #if USE_SERIAL_DEBUG
+ obm_printf("sectors: 0x%08x\n\r", sectors);
+ obm_printf("capacity MB: %d\n\r", sectors/2/1024);
+ #endif
+
+ if (pSDMMCP->AccessMode == SECTOR_ACCESS)
+ {
+ pSDMMCP->CardCapacity = sectors;
+ }
+ else
+ {
+ pSDMMCP->CardCapacity = capacity;
+ }
+ }
+
+ erase_group_define = pBuffer[175]; // ERASE_GROUP_DEF
+ if (erase_group_define)
+ {
+ pSDMMCP->EraseSize = pBuffer[224] * 512 * 1024; // overwrite it, and erase unit size = 512KB * HC_ERASE_GRP_SIZE
+ }
+
+ boot_partition_size = pBuffer[226] * 128 *1024; // BOOT_SIZE_MULT * 128KB
+ if (pSDMMCP->AccessMode == SECTOR_ACCESS)
+ {
+ pSDMMCP->BootPartitionSize = boot_partition_size / HARD512BLOCKLENGTH;
+ }
+ else
+ {
+ pSDMMCP->BootPartitionSize = boot_partition_size;
+ }
+
+ #if USE_SERIAL_DEBUG
+ obm_printf("Boot Partition Size: %dMB\n\r", boot_partition_size/1024/1024);
+ obm_printf("pSDMMCP->BootPartitionSize: 0x%08x\n\r", pSDMMCP->BootPartitionSize);
+ #endif
+
+ card_type = pBuffer[196] & 0xf; // CARD_TYPE
+ pSDMMCP->DeviceType = card_type;
+
+ obm_printf("pSDMMCP->DeviceType: 0x%x\n\r", pSDMMCP->DeviceType);
+
+ spec_version = pBuffer[192];
+ switch (spec_version)
+ {
+ case 0:
+ obm_printf("MMC Version 4.0\n\r");
+ break;
+ case 1:
+ obm_printf("MMC Version 4.1\n\r");
+ break;
+ case 2:
+ obm_printf("MMC Version 4.2\n\r");
+ break;
+ case 3:
+ obm_printf("MMC Version 4.3\n\r");
+ break;
+ case 5:
+ obm_printf("MMC Version 4.41\n\r");
+ break;
+ case 6:
+ obm_printf("MMC Version 4.5\n\r");
+ break;
+
+ case 4:
+ default:
+ obm_printf("Reserved Version: %d\n\r", spec_version);
+ break;
+ }
+
+ return ret;
+}
+
+/**********************************************************
+* MM4_CardInit
+* Initializes the inserted card
+* Input:
+* none
+* Output:
+* none
+* Returns:
+* WTP recoginized Success/Fail return code
+***********************************************************/
+UINT_T MM4_CardInit(UINT_T BaseAddress, UINT_T InterruptMask)
+{
+ UINT_T argument,Retval;
+ UINT_T controllervoltage;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // Assign pContext and clock values
+ MM4_PrepareMMCContext (pSDMMCP, BaseAddress);
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ // enable ints moved out of ConfigureMMC to here
+ // because pending interrupts (left over from bootrom
+ // mmc activity) were kicking off before the context
+ // had enough info for the isr to service the request.
+ // now pads have been set up, and the context has
+ // enough information to service interrupts (specifically,
+ // it has the mm4 base regs address). ok to enable ints.
+ EnablePeripheralIRQInterrupt(InterruptMask);
+
+ // Issue a full reset.
+ MMC4FullSWReset(pContext);
+
+ // Enable and start clocks
+ MMC4SetBusRate(pContext, MM4CLOCK200KHZRATE);
+
+ // Set Read Response Timeout
+ MMC4SetDataTimeout(pContext, CLOCK_27_MULT);
+
+ // Unmask and Enable interrupts
+ MMC4EnableDisableIntSources(pContext, ENABLE_INTS);
+
+ //MMC4Gen74Clocks(pContext);
+
+ Retval = MM4_IDCard(pSDMMCP, &controllervoltage);
+ if (Retval != NoError)
+ //return Retval;
+ return SDMMCNotFound;
+
+ // Set up State
+ pSDMMCP->State = INITIALIZE;
+
+ // SD and MMC joint functionality again
+ // At this point we should have our OCR contents. See if they match the voltage range we choose for the controller
+ Retval = MM4_CheckVoltageCompatibility(pSDMMCP, controllervoltage);
+ if (Retval != NoError)
+ return SDMMCInitializationError; // We couldn't find any cards
+
+ //send CMD2 to get the CID numbers
+ argument = NO_ARGUMENT;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD2, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R2 | MM4_136_RES);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R2, 0x10);
+
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ #if USE_SERIAL_DEBUG
+ MM4_MMCDecodeCID();
+ #endif
+
+ // Next its CMD3 to assign an RCA to the cards
+ if (pSDMMCP->SD == XLLP_SD)
+ {
+ argument = NO_ARGUMENT;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD3, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R6 | MM4_48_RES);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R6, 0x10);
+ }
+ else
+ {
+ pSDMMCP->CardReg.RCA = (pSDMMCP->CardReg.CID.SerialNum) << 16;
+ argument = pSDMMCP->CardReg.RCA;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD3, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x10);
+ }
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ //send CMD13 to check the status of the card
+ Retval = MM4_CheckCardStatus(pSDMMCP, 0x700, R1_LOCKEDCARDMASK); // Make sure card is stdby mode
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ // now we are beyond the point where some cards have subtle non-compliance issues with the spec.
+ // for example, some cards leave the error bits from unrecognized commands (like 55 & 41) set
+ // until this point - which is correct (since CMD3 was the first R1 type command).
+ // other cards clear them earlier, which is incorrect - but presents fewer initialization failures.
+ // at this point it is safe, and necessary, to begin rigorously examining all error status bits.
+ pSDMMCP->StrictErrorCheck = 1;
+
+ // Send CMD 9 to retrieve the CSD
+ argument = pSDMMCP->CardReg.RCA;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD9, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R2 | MM4_136_RES);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R2, 0x100);
+
+ // Save off some information from the CSD
+ // There is no page size for SDMMC. However save some information so slot type functionality will work
+ pSDMMCP->pFlashP->BlockSize = pSDMMCP->pFlashP->PageSize = pSDMMCP->ReadBlockSize;
+
+ //send CMD7 to get card into transfer state
+ argument = pSDMMCP->CardReg.RCA;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD7, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES); // fixme: from standby to transfer state should be an r1, not r1b
+ Retval |= MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+
+ //send CMD13 to check the status of the card
+ Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK); // Make sure card is transfer mode
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ // CMD 16 Set Block Length
+ argument = pSDMMCP->ReadBlockSize;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD16, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+
+ // Set the block length for the controller
+ pContext->pMMC4Reg->mm4_blk_cntl = argument;
+
+ // Check if High Speed is enabled in the fuses
+ if(MMCHighSpeedTimingEnabled())
+ Retval = MM4HighSpeedTiming();
+ else
+ MMC4SetBusRate(pContext, MM4CLOCK12_5MHZRATE);
+
+ //send CMD13 to check the status of the card
+ Retval = MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK); // Make sure card is transfer mode
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ Retval = MM4_MMCDecodeEXTCSD(); // MMC decodes extension CSD register
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ if (pSDMMCP->DeviceType & EXT_CSD_CARD_TYPE_DDR_52)
+ {
+ obm_printf("DDR mode\n\r");
+
+ // eMMC DDR mode, set bit31, clear bit30
+ //MMC4SetTXIntCLKSet(pContext, 0, 1);
+ MMC4SetTXConfig(pContext);
+ MMC4SetRXConfig(pContext);
+
+ MMC4SelectUHSMode(pContext, SDH_BUS_SPEED_DDR_CLK_50M); // host to DDR mode
+
+ Retval = MM4SetBusWidth(DDR_8); //set the bus width to 8, eMMC to DDR mode
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+ }
+ else
+ {
+ obm_printf("SDR mode\n\r");
+
+ //#if HELN
+ // Helan eMMC DDR mode, set bit30, clear bit31
+ MMC4SetTXIntCLKSet(pContext, 1, 0);
+ //#endif
+
+ Retval = MM4SetBusWidth(SDR_8); //set the bus width to 8, eMMC to SDR mode
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+ }
+
+ //send CMD13 to check the status of the card
+ Retval = MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK); // Make sure card is transfer mode
+ if (Retval != NoError)
+ return SDMMCInitializationError;
+
+ // Enable SDMA/ADMA Mode based on support
+#if MMC_SDMA_MODE
+ obm_printf("SDMA mode\n\r");
+ pSDMMCP->SDMMC_DMA_Mode = SDMA;
+#elif MMC_ADMA_MODE
+ obm_printf("ADMA2 mode\n\r");
+ pSDMMCP->SDMMC_DMA_Mode = ADMA2;
+#else
+ obm_printf("NODMA mode\n\r");
+ pSDMMCP->SDMMC_DMA_Mode = NODMA;
+#endif
+
+ // Set up State, Ready for Data transfers
+ pSDMMCP->State = READY;
+
+ return NoError;
+}
+
+/**********************************************************
+* MM4_IDCard
+* Identifies which type of card was inserted
+* Input:
+* none
+* Output:
+* none
+* Returns:
+* WTP recoginized Success/Fail return code
+***********************************************************/
+UINT MM4_IDCard(P_SDMMC_Properties_T pSDMMCP, UINT_T *pControllerVoltage)
+{
+ // Local Variables
+ P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext; // Assign our context value
+ P_MM4_CTRL_REG pP_MM4_CTRL_REG;
+ UINT_T AnyError = 0;
+ UINT_T argument = 0;
+ UINT_T Retval = 0;
+ UINT_T HighCapacity = 0;
+ UINT_T attempts = 0;
+ UINT_T Ncr = 0x100; // command response timeout.
+
+ // Assign some context
+ pP_MM4_CTRL_REG = (P_MM4_CTRL_REG)&pContext->pMMC4Reg->mm4_mmc_ctrl_reg;
+
+ // Enable power
+ *pControllerVoltage = MM4_SetControllerVoltage(pContext);
+ pContext->pMMC4Reg->mm4_blk_cntl = 0;
+
+ // Send CMD0 (GO_IDLE_STATE) to get card into idle state
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD0, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_NONE | MM4_NO_RES);
+ AnyError += MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_NONE, Ncr);
+
+ // Check for High Capacity Cards First
+ do
+ {
+ // Start with SD
+ pP_MM4_CTRL_REG->mmc_card = 0;
+
+ // Try High Voltage range first:
+ // Note: this is a valid command for SD cards in the idle state.
+ // for mmc cards in the idle state, this is not valid, so no reponse is generated.
+ // however, even some SD cards may miss this command, so that's why it is
+ // sent out twice. See SD spec, step 4 of figure 9 in card init and id section.
+ argument = (SDVHS_2_7_TO_3_6 << SDVHSARGSHIFT) | SDVHSCHECKPATTERN; // 2.7-3.6V Range
+ MM4_SendSetupCommand(pSDMMCP, XLLP_SD_CMD8, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R7 | MM4_48_RES);
+
+ // get the response (if any) to XLLP_SD_CMD8.
+ MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R7, Ncr);
+
+ // Check for High Capacity Cards
+ HighCapacity = (pSDMMCP->SD_VHS == argument);
+ } while (!HighCapacity && ++attempts < 2);
+
+ pSDMMCP->SD = XLLP_SD;
+
+ // First time, pass NULL argument to get back values card is compatible with
+ // Send appropriate CMD Sequence to Identify the type of card inserted
+ argument = 0;
+ attempts = 0;
+ pSDMMCP->CardReg.OCR = 0; // Make sure to clear out OCR.
+
+ do
+ {
+ switch (pSDMMCP->SD)
+ {
+ case XLLP_SD: // Assume SD
+ MM4_SendSetupCommand(pSDMMCP, XLLP_SD_CMD55, MM4_CMD_TYPE_NORMAL, 0, MM4_RT_R1 | MM4_48_RES);
+ MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, Ncr);
+
+
+ MM4_SendSetupCommand(pSDMMCP, XLLP_SD_ACMD41, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R3 | MM4_48_RES);
+ MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R3, Ncr);
+
+ if (pSDMMCP->CardReg.OCR == 0)
+ {
+ pSDMMCP->SD = XLLP_MMC;
+ }
+ else
+ {
+ Retval = NoError;
+ }
+ break;
+ case XLLP_MMC: // Assume MMC
+ pP_MM4_CTRL_REG->mmc_card = 1;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD1, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R3 | MM4_48_RES);
+ AnyError += MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R3, Ncr);
+
+ if (pSDMMCP->CardReg.OCR == 0)
+ {
+ Retval = NotFoundError;
+ }
+ else
+ {
+ Retval = NoError;
+ }
+ break;
+ }
+
+ argument = pSDMMCP->CardReg.OCR | 0x40000000;
+ attempts++;
+ Delay(100);
+ } while (((pSDMMCP->CardReg.OCR & 0x80000000) != 0x80000000) && (AnyError == 0) && (attempts < 10000));
+ if ((pSDMMCP->CardReg.OCR & 0x80000000) != 0x80000000)
+ return NotFoundError;
+
+ // Assign Access Mode.
+ if (pSDMMCP->CardReg.OCR & OCR_ACCESS_MODE_MASK)
+ pSDMMCP->AccessMode = SECTOR_ACCESS;
+ else
+ pSDMMCP->AccessMode = BYTE_ACCESS;
+
+ return Retval;
+}
+
+/***************************************************************
+* MM4SetBusWidth()
+* Sets the Bus width highest bus width supported.
+* Input: UINT_T Width
+* Output:
+* Returns: NoError, ReadError or NotSupportedError
+*
+*****************************************************************/
+UINT_T MM4SetBusWidth(UINT8_T value)
+{
+ UINT8_T SDBusWidth = 0;
+ MMC_CMD6_OVERLAY Cmd6;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ P_MM4_CNTL1 pMM4_CNTL1;
+ UINT_T Retval = NoError;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+ pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+ // Check supported configurations first
+ if (pSDMMCP->SD == XLLP_SD)
+ {
+ // Assume 1 bit Mode.
+ SDBusWidth = SCRSD1BITMODE;
+ }
+ else
+ {
+ // Issue CMD 6 to set BUS WIDTH bits in EXT_CSD register byte 183
+ Cmd6.MMC_CMD6_Layout.Access = EXT_CSD_ACCESS_WRITE_BYTE; //Write Byte
+ Cmd6.MMC_CMD6_Layout.CmdSet = 0; // Don't Care
+ Cmd6.MMC_CMD6_Layout.Index = BUS_WIDTH_MMC_EXT_CSD_OFFSET; // Choose Bus Width
+ Cmd6.MMC_CMD6_Layout.Reserved0 = 0;
+ Cmd6.MMC_CMD6_Layout.Reserved1 = 0;
+ Cmd6.MMC_CMD6_Layout.Value = value; // Choose 8 bit mode.
+
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+ // Wait for the Read to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY)); // TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+ if (Retval != NoError)
+ return Retval;
+ }
+
+ //send CMD13 to check the status of the card
+ Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK); // Make sure card is transfer mode
+ if (Retval != NoError)
+ {
+ pSDMMCP->State = READY;
+ return Retval;
+ }
+
+ // Now change the controller to boost bus width
+ //if (pSDMMCP->SD == XLLP_SD)
+ //{
+ // if (SDBusWidth == SCRSD4BITMODE)
+ // {
+ // pMM4_CNTL1->datawidth = 1; // Move to 4-bit mode
+ // return NoError;
+ // }
+ //}
+ //else
+ if (pSDMMCP->SD == XLLP_MMC)
+ pMM4_CNTL1->ex_data_width = 1; // Move to 8-bit mode.
+
+ return NoError;
+}
+
+/***************************************************************
+* MM4HighSpeedTiming()
+* Sets the Bus speed to high speed timing
+* Input:
+* Output:
+* Returns: NoError, ReadError or NotSupportedError
+*
+*****************************************************************/
+UINT_T MM4HighSpeedTiming(void)
+{
+ MMC_CMD6_OVERLAY Cmd6;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ P_MM4_CNTL1 pMM4_CNTL1;
+ UINT_T Retval = NoError;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+ pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+ // Check supported configurations first
+ if (pSDMMCP->SD == XLLP_SD)
+ {
+ MMC4SetBusRate(pContext, MM4CLOCK12_5MHZRATE);
+ return NoError;
+ }
+ else
+ {
+ // Issue CMD 6 to set BUS WIDTH bits in EXT_CSD register byte 183
+ Cmd6.MMC_CMD6_Layout.Access = EXT_CSD_ACCESS_WRITE_BYTE; //Write Byte
+ Cmd6.MMC_CMD6_Layout.CmdSet = 0; // Don't Care
+ Cmd6.MMC_CMD6_Layout.Index = HS_TIMING_MMC_EXT_CSD_OFFSET; // Choose Bus Width
+ Cmd6.MMC_CMD6_Layout.Reserved0 = 0;
+ Cmd6.MMC_CMD6_Layout.Reserved1 = 0;
+ Cmd6.MMC_CMD6_Layout.Value = (UINT8_T) 1; // Choose High Speed Timing.
+
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+ // Wait for the Read to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+ if (Retval != NoError)
+ return Retval;
+ }
+
+ //send CMD13 to check the status of the card
+ Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK); // Make sure card is transfer mode
+ if (Retval != NoError)
+ {
+ pSDMMCP->State = READY;
+ MMC4SetBusRate(pContext, MM4CLOCK12_5MHZRATE); // Failed, stick with lower speed
+ return NoError;
+ }
+ else
+ pMM4_CNTL1->hispeed = 1;
+
+ // Now change the speed to max through the controller
+ MMC4SetBusRate(pContext, MM4CLOCK50MHZRATE);
+
+ return NoError;
+}
+
+/***************************************************************
+* MM4SwitchPartition
+* If the Card supports partitioning (eSD) this routine will switch to the appropriate
+* partition by using extended partition command set CMD37.
+* Input:
+* PartitionNumber - Contains the partition Number to switch to and enable bits for the boot partitions.
+* Output:
+* Returns: NoError, ReadError or NotSupportedError
+*
+*****************************************************************/
+UINT_T MM4SwitchPartition(UINT_T PartitionNumber)
+{
+ UINT_T argument, Cmd;
+ UINT_T Retval = NoError;
+ MMC_CMD6_OVERLAY Cmd6;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // Must set partition
+ if (pSDMMCP->SD == XLLP_SD)
+ {
+ // CMD 43 Select Partition
+ Cmd = XLLP_eSD_CMD43;
+ argument = PartitionNumber << 24;//partition number goes in bits [31:24], rest are 0's
+ MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+ }
+ else
+ {
+ // Issue CMD 6 to clear PARTITION_ACCESS bits in EXT_CSD register byte 179
+ Cmd6.MMC_CMD6_Layout.Access = EXT_CSD_ACCESS_CLEAR_BITS; // Clear bits
+ Cmd6.MMC_CMD6_Layout.CmdSet = 0; // Don't Care
+ Cmd6.MMC_CMD6_Layout.Index = PARTITION_CONFIG_MMC_EXT_CSD_OFFSET; // Choose Boot Config
+ Cmd6.MMC_CMD6_Layout.Reserved0 = 0;
+ Cmd6.MMC_CMD6_Layout.Reserved1 = 0;
+ Cmd6.MMC_CMD6_Layout.Value = PARTITION_ACCESS_BITS; // Clear out Partition Access bits
+
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+ // Wait for the Read to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, 0x500);
+ if (Retval != NoError)
+ return Retval;
+
+ // Now issue CMD 6 again to set the right bits.
+ Cmd6.MMC_CMD6_Layout.Access = EXT_CSD_ACCESS_SET_BITS; // Clear bits
+ Cmd6.MMC_CMD6_Layout.CmdSet = 0; // Don't Care
+ Cmd6.MMC_CMD6_Layout.Index = PARTITION_CONFIG_MMC_EXT_CSD_OFFSET; // Choose Boot Config
+ Cmd6.MMC_CMD6_Layout.Reserved0 = 0;
+ Cmd6.MMC_CMD6_Layout.Reserved1 = 0;
+ Cmd6.MMC_CMD6_Layout.Value = PartitionNumber; // Set the correct partition
+
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD6, MM4_CMD_TYPE_NORMAL, Cmd6.MMC_CMD6_Bits, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+ // Wait for the Read to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+ Retval |= MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, 0x500);
+ if (Retval != NoError)
+ return Retval;
+ }
+
+ Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK);
+ if (Retval != NoError)
+ {
+ pSDMMCP->State = READY;
+ return SDMMC_SWITCH_ERROR;
+ }
+ return NoError;
+}
+
+/**********************************************************
+* MM4_CardShutdown
+* Shuts down the MM4 hardware
+* Input:
+* Output:
+* none
+* Returns:
+* WTP recoginized Success/Fail return code
+***********************************************************/
+UINT_T MM4_CardShutdown(void)
+{
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ P_MM4_CNTL1 pMM4_CNTL1;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+ pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+
+ // send a CMD0, go idle here so the card gets into the idle state.
+ // even though that forces any subsequent software, like the os,
+ // to rediscover and reinit the card, this is worth doing. by
+ // putting the card into the idle state, it will be able to handle
+ // any bootrom flash probe operation if a platform reset occurs
+ // before the OS has completely initialized the device.
+ //
+ // Send CMD0 (GO_IDLE_STATE) to get card into idle state
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD0, MM4_CMD_TYPE_NORMAL, 0, MM4_RT_NONE | MM4_NO_RES);
+ MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_NONE, 1);
+
+ // Disable Bus Power
+ pMM4_CNTL1->buspwr = 1;
+
+ // Stop Bus Clock
+ MMC4StopBusClock (pSDMMCP->pContext);
+
+ // Mask all interrupts
+ MMC4EnableDisableIntSources(pSDMMCP->pContext, DISABLE_INTS);
+
+ // Disable internal clocks.
+ MMC4StopInternalBusClock(pSDMMCP->pContext);
+
+ return NoError;
+}
+
+/****************************************************************
+* MM4PrepareMMCContext
+* Sets certain Peripheral register address
+* Input:
+* P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+* Output:
+* none
+* Returns:
+* none
+*****************************************************************/
+void MM4_PrepareMMCContext (P_SDMMC_Properties_T pSDMMCP, UINT_T BaseAddress)
+{
+ pSDMMCP->pContext = &MM4_Context;
+
+ // First fill out pContext
+ ((P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext)->pMMC4Reg = (P_MM4_SDMMC_T) BaseAddress;
+}
+
+/****************************************************************
+* MM4_SetControllerVoltage
+* Inspects the Capabilities Register for supported voltage types by the
+* controller. Then programs the CNTL1 register with the desired range.
+* Enables bus power
+* Input:
+* P_MM4_SDMMC_CONTEXT_T pContext
+* Output:
+* none
+* Returns:
+* none
+*****************************************************************/
+UINT_T MM4_SetControllerVoltage (P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ UINT_T controllervoltage;
+ P_MM4_CNTL1 pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+ MM4_CNTL1_UNION MM4_cntl1;
+
+ // Capture the Value
+ MM4_cntl1.mm4_cntl1_value = *(VUINT_T*) pMM4_CNTL1;
+
+ // Note that this really doesn't control voltage, it just needs to match one of the supported values in the capabilities 2 register.
+ controllervoltage = MM4_VLTGSEL_3_3;
+
+ // Set the voltage to controller
+ MM4_cntl1.mm4_cntl1_bits.vltgsel = controllervoltage;
+
+ // Enable Bus Power
+ MM4_cntl1.mm4_cntl1_bits.buspwr = 1;
+
+ // Write back out.
+ *(VUINT_T*) pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_value;
+
+ return controllervoltage;
+}
+
+/****************************************************************
+* MM4_CheckVoltageCompatibility
+* Checks to make sure that the OCR register of the device supports the
+* voltage range that was selected for the controller
+* Input:
+* P_MM4_SDMMC_CONTEXT_T pContext, UINT_T ControllerVoltage
+* Output:
+* none
+* Returns:
+* none
+*****************************************************************/
+UINT_T MM4_CheckVoltageCompatibility(P_SDMMC_Properties_T pSDMMCP, UINT_T ControllerVoltage)
+{
+ // Check SD vs MMC
+ if (pSDMMCP->SD == XLLP_SD)
+ {
+ switch (ControllerVoltage)
+ {
+ case MM4_VLTGSEL_3_3:
+ if (pSDMMCP->CardReg.OCR & SD_OCR_VOLTAGE_3_3_TO_3_6)
+ return NoError;
+
+ case MM4_VLTGSEL_3_0:
+ if (pSDMMCP->CardReg.OCR & SD_OCR_VOLTAGE_1_8_TO_3_3)
+ return NoError;
+
+ case MM4_VLTGSEL_1_8:
+ if (pSDMMCP->CardReg.OCR & SD_OCR_VOLTAGE_1_8)
+ return NoError;
+ }
+ }
+ else
+ {
+ if ((pSDMMCP->CardReg.OCR & MMC_OCR_VOLTAGE_ALL) == MMC_OCR_VOLTAGE_ALL)
+ return NoError;
+ }
+ return SDMMCDeviceVoltageNotSupported;
+}
+
+
+/******************************************************************************
+ Description:
+ Set up the registers of the controller to start the transaction to
+ communicate to the card for data related command. The commands are clearly defined in the MMC
+ specification.
+ Input Parameters:
+ P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+ Cmd
+ Command Index - See MMC or SD specification
+ argument
+ the argument of the command. MSW is for ARGH and LSW is for ARGL
+ BlockType
+ Multiple or Single Block Type
+ ResType
+ Expected response type
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+
+void MM4_SendDataCommand (P_SDMMC_Properties_T pSDMMCP,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType)
+{
+ // Assign our context value
+ P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ // no need to clear out any fault state that may be left over from a previously failed transaction.
+ // that's because the caller has set State to read or write before calling here.
+
+ // No Response to the command yet
+ pSDMMCP->CardReponse.CommandComplete = 0;
+ pSDMMCP->CardReponse.TransferComplete = 0;
+
+ // save the info for use by the isr:
+ pSDMMCP->Trans.RespType = (ResType >> 8) & 0x000000ff;
+ pSDMMCP->Trans.Cmd = Cmd; // Fixme: how to know when to set the ACMD flag?
+
+ MMC4SendDataCommand(pContext,
+ Cmd,
+ Argument,
+ BlockType,
+ DataDirection,
+ ResType & 0x000000ff, // clear out any bits not for the SD_CMD.RES_TYPE field
+ ((pSDMMCP->SDMMC_DMA_Mode == NODMA) ? 0 : 1),
+ ((pSDMMCP->SDMMC_DMA_Mode == ADMA2) ? 1 : 0));
+}
+
+/******************************************************************************
+ Description:
+ Set up the registers of the controller to start the transaction to
+ communicate to the card for data related command. The commands are clearly defined in the MMC
+ specification.
+ Input Parameters:
+ P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+ Cmd
+ Command Index - See MMC or SD specification
+ argument
+ the argument of the command. MSW is for ARGH and LSW is for ARGL
+ BlockType
+ Multiple or Single Block Type
+ ResType
+ Expected response type
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MM4_SendDataCommandNoAuto12 (P_SDMMC_Properties_T pSDMMCP,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType)
+{
+ // Assign our context value
+ P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ // no need to clear out any fault state that may be left over from a previously failed transaction.
+ // that's because the caller has set State to read or write before calling here.
+
+ // No Response to the command yet
+ pSDMMCP->CardReponse.CommandComplete = 0;
+ pSDMMCP->CardReponse.TransferComplete = 0;
+
+ // save the info for use by the isr:
+ pSDMMCP->Trans.RespType = (ResType >> 8) & 0x000000ff;
+ pSDMMCP->Trans.Cmd = Cmd; // Fixme: how to know when to set the ACMD flag?
+
+ MMC4SendDataCommandNoAuto12(pContext,
+ Cmd,
+ Argument,
+ BlockType,
+ DataDirection,
+ ResType & 0x000000ff, // clear out any bits not for the SD_CMD.RES_TYPE field
+ ((pSDMMCP->SDMMC_DMA_Mode == NODMA) ? 0 : 1),
+ ((pSDMMCP->SDMMC_DMA_Mode == ADMA2) ? 0 : 1)); //Block count is disabled for ADMA2
+}
+
+/******************************************************************************
+ Description:
+ Set up the registers of the controller to start the transaction to
+ communicate to the card for setup related commands.
+ The commands are clearly defined in the MMC specification.
+ Input Parameters:
+ P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+ Cmd
+ Command Index - See MMC or SD specification
+ argument
+ the argument of the command. MSW is for ARGH and LSW is for ARGL
+ ResType
+ Expected response type
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MM4_SendSetupCommand(P_SDMMC_Properties_T pSDMMCP,
+ UINT_T Cmd,
+ UINT_T CmdType,
+ UINT_T Argument,
+ UINT_T ResType)
+{
+ // Assign our context value
+ P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ // clear out any fault status that may be left over from a previously failed transaction.
+ pSDMMCP->State = READY;
+
+ // No Response to the command yet
+ pSDMMCP->CardReponse.CommandComplete = 0;
+ pSDMMCP->CardReponse.TransferComplete = 0;
+
+ // save the info for use by the isr:
+ pSDMMCP->Trans.RespType = (ResType >> 8) & 0x000000ff;
+ pSDMMCP->Trans.Cmd = Cmd; // Fixme: how to know when to set the ACMD flag?
+
+ MMC4SendSetupCommand(pContext,
+ Cmd,
+ CmdType,
+ Argument,
+ ResType & 0x000000ff); // clear out any bits not for the SD_CMD.RES_TYPE field
+}
+
+/****************************************************************
+* MM4_Read_Response
+* Reads the response from the Controller Buffer Registers to the Local Buffer.
+* According to the last command and response type it does the correct interpretation.
+* There is also a timeout as the routine waits for the ISR to signal last command completion.
+* Input:
+* P_SDMMC_Properties_T pSDMMCP - Generic SD/MMC driver properties structure
+* ResponseType - See SD/MMC specifications
+* ResponseTimeOut - A time out value in millisec's
+* Output:
+* none
+* Returns:
+* MM4InterpretTimeOutError or NoError
+*****************************************************************/
+UINT_T MM4_Interpret_Response(P_SDMMC_Properties_T pSDMMCP, UINT_T ResponseType, UINT_T ResponseTimeOut)
+{
+ UINT_T i, temp, temp2, temp3, startTime, endTime;
+ UINT_T Retval = NoError;
+ P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext; // Assign our context value
+ P_MM4_CMD_XFRMD_UNION pMM4_XFRMD;
+
+ startTime = GetOSCR0(); // get the start time
+ endTime = startTime;
+
+ // Overlap XFRMD register contents using uniun
+ pMM4_XFRMD = (P_MM4_CMD_XFRMD_UNION) &pContext->pMMC4Reg->mm4_cmd_xfrmd;
+
+ // Wait for the Response based on the CommandComplete interrupt signal
+ while (1)
+ {
+ // if the command had an error, the command may have aborted
+ // without setting the command complete bit. for example,
+ // if no response is received, then the command is aborted,
+ // the MM4_ISR sets the state to FAULT, and command complete
+ // will not assert. check for such a scenario here.
+ if( pSDMMCP->State == FAULT )
+ {
+ Retval = SDMMC_GENERAL_ERROR;
+ break; // continue to capture command response to return a more specific error
+ }
+
+ if (pSDMMCP->CardReponse.CommandComplete)
+ {
+ if(ResponseType != MMC_RESPONSE_R1B)
+ break; // Done no issue.
+ else if (pSDMMCP->CardReponse.TransferComplete)
+ break; // R1B type commands now require MMC xfer_complete bit to be set
+ }
+
+ // check if too much time has elapsed. if so, timeout.
+ endTime = GetOSCR0();
+
+ if (OSCR0IntervalInMilli(startTime, endTime) > ResponseTimeOut)
+ {
+ Retval = MM4InterpretTimeOutError;
+ return Retval;
+ }
+ }
+
+ // Read in the Buffers
+ switch (ResponseType)
+ {
+ case MMC_RESPONSE_NONE:
+ break;
+ case MMC_RESPONSE_R1:
+ case MMC_RESPONSE_R1B:
+ pSDMMCP->CardReponse.R1_RESP = pSDMMCP->CardReponse.pBuffer[0];
+ break;
+ case MMC_RESPONSE_R2: // This is for CID or CSD register
+ {
+ if (pMM4_XFRMD->mm4_cmd_xfrmd_bits.cmd_idx == XLLP_MMC_CMD9) //CSD
+ {
+ // Copy the CSD values from the buffer
+ for (i=0; i<4; i++)
+ pSDMMCP->CardReg.CSD.CSD_VALUE[i] = pSDMMCP->CardReponse.pBuffer[i];
+
+ UINT16_T MMC_RESPONSE[8]; // for shift CSD register
+
+ MMC_RESPONSE[7] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[3] >> 16) & 0xffff);
+ MMC_RESPONSE[6] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[3] & 0xffff);
+ MMC_RESPONSE[5] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 16) & 0xffff);
+ MMC_RESPONSE[4] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[2] & 0xffff);
+ MMC_RESPONSE[3] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 16) & 0xffff);
+ MMC_RESPONSE[2] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[1] & 0xffff);
+ MMC_RESPONSE[1] = (UINT16_T)((pSDMMCP->CardReg.CSD.CSD_VALUE[0] >> 16) & 0xffff);
+ MMC_RESPONSE[0] = (UINT16_T)(pSDMMCP->CardReg.CSD.CSD_VALUE[0] & 0xffff);
+
+
+ pSDMMCP->CardReg.CSD.CSD_VALUE[0] = (UINT32_T)(MMC_RESPONSE[5] >> 8 | MMC_RESPONSE[6] << 8 | MMC_RESPONSE[7] << 24);
+ pSDMMCP->CardReg.CSD.CSD_VALUE[1] = (UINT32_T)(MMC_RESPONSE[3] >> 8 | MMC_RESPONSE[4] << 8 | MMC_RESPONSE[5] << 24);
+ pSDMMCP->CardReg.CSD.CSD_VALUE[2] = (UINT32_T)(MMC_RESPONSE[1] >> 8 | MMC_RESPONSE[2] << 8 | MMC_RESPONSE[3] << 24);
+ pSDMMCP->CardReg.CSD.CSD_VALUE[3] = (UINT32_T)(MMC_RESPONSE[0] << 8 | MMC_RESPONSE[1] << 24);
+
+ // Optionally we could record maximum block lengths from the CSD.
+ // But some devices cheat and put incorrect values in this field.
+ // Save off read Block Size, play it safe, for now hard code to 512 Bytes
+ pSDMMCP->ReadBlockSize = HARD512BLOCKLENGTH;
+ // Save off Write Block Size
+ pSDMMCP->WriteBlockSize = HARD512BLOCKLENGTH;
+
+ // Capture Erase Granularity.
+ if (pSDMMCP->SD == XLLP_SD)
+ {
+ // Check Erase Single Block Enable - Bit 46
+ if ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 14) & 1)
+ pSDMMCP->EraseSize = pSDMMCP->WriteBlockSize;
+ else
+ {
+ pSDMMCP->EraseSize = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 7) & 0x7F) + 1;
+ pSDMMCP->EraseSize *= pSDMMCP->WriteBlockSize;
+ }
+ }
+ else // MMC Card
+ {
+ // if the card use high capacity erase unit size, pSDMMCP->EraseSize will be overwritten
+
+ //pSDMMCP->EraseSize = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 5) & 0x1F) + 1; // Get ERASE_GRP_MULT
+ //pSDMMCP->EraseSize *= (((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 10) & 0x1F) + 1); // Get ERASE_GRP_SIZE
+ pSDMMCP->EraseSize = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 5) & 0x1F) + 1; // Get ERASE_GRP_MULT
+ pSDMMCP->EraseSize *= (((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 10) & 0x1F) + 1); // Get ERASE_GRP_SIZE
+ pSDMMCP->EraseSize *= pSDMMCP->WriteBlockSize;
+ }
+
+ // Now calculate the capacity of this card
+ // the execution of CMD9 is before CMD8
+ // if the card is larger than 2GB, pSDMMCP->CardCapacity will be overwritten
+
+ //temp = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 16) & 0xF); // Get READ_BL_LEN
+ temp = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 16) & 0xF); // Get READ_BL_LEN
+ temp = 1 << temp;
+
+ // Now we have Max Block Length
+ //temp2 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 15) & 0x7) + 2; // Get C_SIZE_MULT
+ temp2 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 15) & 0x7) + 2; // Get C_SIZE_MULT
+ temp2 = 1 << temp2;
+
+ //temp3 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] >> 30) & 0x3); // Get C_SIZE
+ temp3 = ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] >> 30) & 0x3); // Get C_SIZE
+ //temp3 |= ((pSDMMCP->CardReg.CSD.CSD_VALUE[2] & 0x3FF) << 2); // Get C_SIZE
+ temp3 |= ((pSDMMCP->CardReg.CSD.CSD_VALUE[1] & 0x3FF) << 2); // Get C_SIZE
+ temp3++;
+
+ pSDMMCP->CardCapacity = temp3 * temp2 * temp; // Total Size of the card in Bytes
+ }
+ else // Assume CID
+ {
+ // Copy the CSD values from the buffer
+ for (i=0; i<4; i++)
+ pSDMMCP->CardReg.CID.CID_VALUE[i] = pSDMMCP->CardReponse.pBuffer[i];
+
+ UINT16_T MMC_RESPONSE1[8]; // for shift CID register
+
+ MMC_RESPONSE1[7] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[3] >> 16) & 0xffff);
+ MMC_RESPONSE1[6] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[3] & 0xffff);
+ MMC_RESPONSE1[5] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[2] >> 16) & 0xffff);
+ MMC_RESPONSE1[4] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[2] & 0xffff);
+ MMC_RESPONSE1[3] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[1] >> 16) & 0xffff);
+ MMC_RESPONSE1[2] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[1] & 0xffff);
+ MMC_RESPONSE1[1] = (UINT16_T)((pSDMMCP->CardReg.CID.CID_VALUE[0] >> 16) & 0xffff);
+ MMC_RESPONSE1[0] = (UINT16_T)(pSDMMCP->CardReg.CID.CID_VALUE[0] & 0xffff);
+
+
+ pSDMMCP->CardReg.CID.CID_VALUE[0] = (UINT32_T)(MMC_RESPONSE1[5] >> 8 | MMC_RESPONSE1[6] << 8 | MMC_RESPONSE1[7] << 24);
+ pSDMMCP->CardReg.CID.CID_VALUE[1] = (UINT32_T)(MMC_RESPONSE1[3] >> 8 | MMC_RESPONSE1[4] << 8 | MMC_RESPONSE1[5] << 24);
+ pSDMMCP->CardReg.CID.CID_VALUE[2] = (UINT32_T)(MMC_RESPONSE1[1] >> 8 | MMC_RESPONSE1[2] << 8 | MMC_RESPONSE1[3] << 24);
+ pSDMMCP->CardReg.CID.CID_VALUE[3] = (UINT32_T)(MMC_RESPONSE1[0] << 8 | MMC_RESPONSE1[1] << 24);
+
+ // Now capture the serial number from the CID - 32 bit number
+ if (pSDMMCP->SD == XLLP_MMC)
+ {
+ //pSDMMCP->CardReg.CID.SerialNum = (pSDMMCP->CardReg.CID.CID_VALUE[0] >> 16) & (0xFF);
+ pSDMMCP->CardReg.CID.SerialNum = (pSDMMCP->CardReg.CID.CID_VALUE[3] >> 16) & (0xFFFF);
+ //pSDMMCP->CardReg.CID.SerialNum |= (pSDMMCP->CardReg.CID.CID_VALUE[1] << 16);
+ pSDMMCP->CardReg.CID.SerialNum |= (pSDMMCP->CardReg.CID.CID_VALUE[2] << 16);
+ }
+ else
+ {
+ pSDMMCP->CardReg.CID.SerialNum = (pSDMMCP->CardReg.CID.CID_VALUE[0] >> 24) & (0xFF);
+ pSDMMCP->CardReg.CID.SerialNum |= (pSDMMCP->CardReg.CID.CID_VALUE[1] << 8);
+ }
+ }
+ break;
+ }
+ case MMC_RESPONSE_R3:
+ {
+ pSDMMCP->CardReg.OCR = pSDMMCP->CardReponse.pBuffer[0];
+ break;
+ }
+ case MMC_RESPONSE_R4: // These modes are not supported by the driver
+ case MMC_RESPONSE_R5:
+ case MMC_RESPONSE_R5B:
+ break;
+ case MMC_RESPONSE_R6: // Publishes RCA for SD cards
+ {
+ pSDMMCP->CardReg.RCA = pSDMMCP->CardReponse.pBuffer[0];
+ break;
+ }
+ case MMC_RESPONSE_R7:
+ {
+ pSDMMCP->SD_VHS = pSDMMCP->CardReponse.pBuffer[0];
+ break;
+ }
+ }
+ return Retval;
+}
+
+/****************************************************************
+* SDMMCGetMatchWaitCardStatus
+* Gets the status of the card by issuing CMD 13. The rerturn from the routine is based
+* on a check against the expected value which is passed in
+* Input:
+* pSDMMCP - pointer to the current context
+* MaxWaitMSec - Maximum wait time in millisec
+* R1_Resp_Match - Desired Value to be matched
+* Output:
+* none
+* Returns:
+* none
+*****************************************************************/
+UINT_T MM4_CheckCardStatus(P_SDMMC_Properties_T pSDMMCP, UINT_T R1_Resp_Match, UINT_T Mask)
+{
+ UINT_T argument, cardStatus, retval;
+
+ //send CMD13 to check the status of the card
+ argument = pSDMMCP->CardReg.RCA;
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD13, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+ retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+
+ // Mask out undesired check bits
+ cardStatus = (pSDMMCP->CardReponse.R1_RESP) & Mask;
+
+ if ((cardStatus == R1_Resp_Match) && (retval == NoError))
+ return NoError;
+ else
+ return MM4CheckCardStatusTimeOutError;
+}
+
+/***********************************************************
+* MM4_ReadBlocks()
+* Reads the given block off of the SD/MMC card and
+* into LocalAddr or empty buffer
+* input:
+* none
+* output:
+* LocalAddr will contain the contents of the block
+* returns:
+* none
+************************************************************/
+UINT_T MM4_ReadBlocks(void)
+{
+ UINT_T argument;
+ UINT_T Retval = NoError;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ P_MM4_BLK_CNTL pMM4_BLK_CNTL;
+ P_MM4_CNTL1 pMM4_CNTL1;
+ UINT_T total_blks,loadaddr,blks_to_txfr;
+ UINT_T i=0;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ // Must set MMC NUMBLK
+ pMM4_BLK_CNTL = (P_MM4_BLK_CNTL) &pContext->pMMC4Reg->mm4_blk_cntl;
+ //blk_cnt is used in PIO/SDMA mode
+ pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+ pMM4_CNTL1 = (P_MM4_CNTL1)&pContext->pMMC4Reg->mm4_cntl1;
+
+ total_blks = pSDMMCP->Trans.NumBlocks;
+ loadaddr = pSDMMCP->Trans.LocalAddr;
+
+ if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+ {
+ pMM4_BLK_CNTL->dma_bufsz = MM4_512_HOST_DMA_BDRY;
+ pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.LocalAddr;
+ }
+ else if (pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+ {
+ memset(admaDesc, 0, sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+ while(total_blks)
+ {
+ blks_to_txfr = (total_blks > MAX_TRANS_BLKS_ADMA_DESC)? MAX_TRANS_BLKS_ADMA_DESC: total_blks,
+ MM4_SetupADMADesc(
+ &admaDesc[i],
+ VALID_DESC,
+ (total_blks > MAX_TRANS_BLKS_ADMA_DESC)? NOT_LAST_DESC: LAST_DESC,
+ NO_DMA_INT,
+ TRANSFER,
+ blks_to_txfr,
+ loadaddr);
+ total_blks -= blks_to_txfr;
+ loadaddr += blks_to_txfr * pSDMMCP->ReadBlockSize;
+ i++;
+ }
+ pMM4_CNTL1->dma_sel = 2; //ADMA2
+
+ //Set the ADMA register to the address of descriptor table
+ pContext->pMMC4Reg->mm4_adma_system_address1 = (UINT_T)&admaDesc[0];
+
+ // Set the block count register to the total number of blocks for transterring
+ // and the max limmit is 65535
+ pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+
+ //AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA is used and BLK_CNT is disabled
+ //mm4_sysaddr holds the argument field for Auto CMD23 that is the number of blocks
+ pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.NumBlocks;
+
+ #if ENABLE_MMU
+ dcache_clean_range(&admaDesc[0], sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+ #endif
+ }
+
+ #if ENABLE_MMU && (MMC_ADMA_MODE || MMC_SDMA_MODE)
+ // if MMU is enabled, for DMA operations need to invalidate data cache for data consistency
+ dcache_invalidate_range(pSDMMCP->Trans.LocalAddr, pSDMMCP->Trans.NumBlocks * 512);
+ #endif
+
+ // Set up State
+ pSDMMCP->State = READ;
+
+ // Do a CMD 18 Read Multiple Block
+ // In byte mode addressing; all addresses need to be specified as byte offsets.
+ argument = pSDMMCP->Trans.CardAddress;
+ if (pSDMMCP->AccessMode == BYTE_ACCESS)
+ argument *= HARD512BLOCKLENGTH;
+
+ // Kick off the Read
+ MM4_SendDataCommand(pSDMMCP, XLLP_MMC_CMD18, argument, MM4_MULTI_BLOCK_TRAN, MM4_CARD_TO_HOST_DATA, MM4_RT_R1 | MM4_48_RES);
+
+ // Wait for the Read to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+ // Get the Card Response
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+ if ((Retval != NoError) || ((pSDMMCP->CardReponse.R1_RESP & R1_LOCKEDCARDMASK) != 0x900) || (pSDMMCP->State == FAULT))
+ {
+ Retval = SDMMCReadError;
+ pSDMMCP->State = FAULT;
+ }
+ else
+ {
+ pSDMMCP->State = READY;
+ }
+
+ return Retval;
+}
+
+// fixme: change this to use an r1b type...
+UINT_T MM4_WaitReady(UINT_T TimeOutMilliSec)
+{
+ UINT_T startTime, endTime;
+ UINT_T writecomplete = 0;
+ UINT_T Retval = NoError;
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+ UINT_T argument = pSDMMCP->CardReg.RCA;
+
+ // issue a series of get status commands until the (new) status indicates ready.
+ // limit the amount of time to wait to the input parameter TimeOutMilliSec
+ startTime = GetOSCR0();
+ startTime = GetOSCR0();
+ do
+ {
+ //send CMD13 to check the status of the card
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD13, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100); // FIXME: this timeout value should be dependent on CSD and operating configuration
+ if (Retval != NoError) break; // failed to complete transaction
+
+ // examine the new status, which was just extracted from the response field of the get stauts command.
+ if( ( pSDMMCP->CardReponse.R1_RESP & 0x00000100 ) == 0x00000100 ) // card_status:READY_FOR_DATA asserted. write is complete.
+ {
+ writecomplete = 1;
+ break;
+ }
+
+ endTime = GetOSCR0(); // check for end of wait interval
+ }
+ while( OSCR0IntervalInMilli(startTime, endTime) < TimeOutMilliSec );
+
+ return writecomplete;
+}
+
+/***********************************************************
+* MM4_WriteBlocks()
+* Writes the required number of blocks to CardAddress
+* input:
+* none
+* output:
+* Address starting with CardAddress will contain content from LocalAddress
+* returns:
+* none
+************************************************************/
+UINT_T MM4_WriteBlocks(void)
+{
+ UINT_T argument;
+ UINT_T Retval = NoError;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ P_MM4_BLK_CNTL pMM4_BLK_CNTL;
+ P_MM4_CNTL1 pMM4_CNTL1;
+ UINT_T total_blks,loadaddr,blks_to_txfr;
+ UINT_T i=0;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ // Must set MMC NUMBLK
+ pMM4_BLK_CNTL = (P_MM4_BLK_CNTL) &pContext->pMMC4Reg->mm4_blk_cntl;
+ //Required for PIO and SDMA mode
+ pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+ pMM4_CNTL1 = (P_MM4_CNTL1)&pContext->pMMC4Reg->mm4_cntl1;
+
+ total_blks = pSDMMCP->Trans.NumBlocks;
+ loadaddr = pSDMMCP->Trans.LocalAddr;
+ if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+ {
+ pMM4_BLK_CNTL->dma_bufsz = MM4_512_HOST_DMA_BDRY;
+ pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.LocalAddr;
+ }
+ else if(pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+ {
+ memset(admaDesc, 0, sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+ while(total_blks)
+ {
+ blks_to_txfr = (total_blks > MAX_TRANS_BLKS_ADMA_DESC)? MAX_TRANS_BLKS_ADMA_DESC: total_blks,
+ MM4_SetupADMADesc(&admaDesc[i],
+ VALID_DESC,
+ (total_blks > MAX_TRANS_BLKS_ADMA_DESC)? NOT_LAST_DESC: LAST_DESC,
+ NO_DMA_INT,
+ TRANSFER,
+ blks_to_txfr,
+ loadaddr);
+ total_blks -= blks_to_txfr;
+ loadaddr += blks_to_txfr * pSDMMCP->ReadBlockSize;
+ i++;
+ }
+ pMM4_CNTL1->dma_sel = 2; //ADMA2
+
+ //Set the ADMA register to the address of descriptor table
+ pContext->pMMC4Reg->mm4_adma_system_address1 = (UINT_T)&admaDesc[0];
+
+ // Set the block count register to the total number of blocks for transterring
+ // and the max limmit is 65535
+ pMM4_BLK_CNTL->blk_cnt = pSDMMCP->Trans.NumBlocks;
+
+ //AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA is used and BLK_CNT is disabled
+ //mm4_sysaddr holds the argument field for Auto CMD23 that is the number of blocks
+ pContext->pMMC4Reg->mm4_sysaddr = pSDMMCP->Trans.NumBlocks;
+
+ #if ENABLE_MMU
+ dcache_clean_range(&admaDesc[0], sizeof(ADMA_DESCRIPTOR)*NO_ADMA_TX_DESCS);
+ #endif
+ }
+
+ #if ENABLE_MMU && (MMC_ADMA_MODE || MMC_SDMA_MODE)
+ // if MMU is enabled, for DMA operations need to clean data cache for data consistency
+ dcache_clean_range(pSDMMCP->Trans.LocalAddr, pSDMMCP->Trans.NumBlocks * 512);
+ #endif
+
+ // Set up State
+ pSDMMCP->State = WRITE;
+
+ // Do a CMD 25 Write Multiple Blocks
+ // In byte mode addressing; all addresses need to be specified as byte offsets.
+ argument = pSDMMCP->Trans.CardAddress;
+ if (pSDMMCP->AccessMode == BYTE_ACCESS)
+ argument *= HARD512BLOCKLENGTH;
+
+ MM4_SendDataCommand(pSDMMCP, XLLP_MMC_CMD25, argument, MM4_MULTI_BLOCK_TRAN, MM4_HOST_TO_CARD_DATA, MM4_RT_R1 | MM4_48_RES);
+
+ // Wait for the Write to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY)); // TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+ // Get the Card Response
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+ if ((Retval != NoError) || (pSDMMCP->State == FAULT) || ((pSDMMCP->CardReponse.R1_RESP & R1_NOMASK) != 0x900))
+ {
+ Retval = WriteError;
+ pSDMMCP->State = FAULT;
+ return Retval;
+ }
+
+ // the write data transfer completed...now must wait for the card to assert the ready line.
+ // (the ready status from the last data transfer is meaningless here because it was left
+ // over from the write command that initiated the data transfer.)
+ //
+ // section 7.7.2 of the mmc 4.3 spec defines a formula for the timeout value.
+ // for now, just use a constant. Samsung KLMxGxxExM defines max write timeout as 600 ms
+ // FIXME: implement the formula, which is based on info from the CSD...
+
+ if( !MM4_WaitReady(600) )
+ {
+ Retval = WriteError;
+ pSDMMCP->State = FAULT;
+ return Retval;
+ }
+
+ pSDMMCP->State = READY;
+ return NoError;
+}
+
+/***********************************************************
+* MM4_EraseBlocks()
+* Erases required number of blocks at CardAddress
+* input:
+* none
+* output:
+* Blocks erased on erase group alignment
+* returns:
+* none
+************************************************************/
+UINT_T MM4_EraseBlocks(void)
+{
+ UINT_T argument, Cmd;
+ UINT_T Retval = NoError;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ // CMD 32/35 Define Erase Group Start Address
+ if (pSDMMCP->SD == XLLP_SD)
+ Cmd = XLLP_SD_CMD32;
+ else
+ Cmd = XLLP_MMC_CMD35;
+
+ // In byte mode addressing; all addresses need to be specified as byte offsets.
+ argument = pSDMMCP->Trans.CardAddress;
+ if (pSDMMCP->AccessMode == BYTE_ACCESS)
+ argument *= HARD512BLOCKLENGTH;
+
+ MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+
+ // Wait for the command to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY)); // TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+ if( pSDMMCP->State == FAULT ) // This state entered if ISR detected an error.
+ {
+ return SDMMC_ERASE_PARAM_ERROR;
+ }
+
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+ if (Retval != NoError)
+ {
+ pSDMMCP->State = FAULT;
+ return EraseError;
+ }
+
+ // CMD 33/36 Define Erase Group End Address
+ if (pSDMMCP->SD == XLLP_SD)
+ Cmd = XLLP_SD_CMD33;
+ else
+ Cmd = XLLP_MMC_CMD36;
+
+ // In byte mode addressing; all addresses need to be specified as byte offsets.
+ argument = pSDMMCP->Trans.CardAddress + pSDMMCP->Trans.TransWordSize*4;
+ if (pSDMMCP->AccessMode == BYTE_ACCESS)
+ argument *= HARD512BLOCKLENGTH;
+
+ MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_48_RES);
+
+ // Wait for the command to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY)); // TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+ if( pSDMMCP->State == FAULT ) // This state entered if ISR detected an error.
+ {
+ return SDMMC_ERASE_PARAM_ERROR;
+ }
+
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+ if (Retval != NoError)
+ {
+ pSDMMCP->State = FAULT;
+ return EraseError;
+ }
+
+ // CMD 38
+ Cmd = XLLP_MMC_CMD38;
+ if (pSDMMCP->Trans.CardAddress % pSDMMCP->EraseSize ||
+ (pSDMMCP->Trans.TransWordSize*4) % pSDMMCP->EraseSize)
+ argument = 0x1; /* trim */
+ else
+ argument = 0x0; /* erase */
+ MM4_SendSetupCommand(pSDMMCP, Cmd, MM4_CMD_TYPE_NORMAL, argument, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY);
+
+ // Wait for the command to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY)); // TBD add timeout Let the ISR run, we'll either get a fault or finish
+
+ if( pSDMMCP->State == FAULT ) // This state entered if ISR detected an error.
+ {
+ return SDMMC_ERASE_PARAM_ERROR;
+ }
+
+ Retval = MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, 0x8000);
+ if (Retval != NoError)
+ {
+ Retval = EraseError;
+ pSDMMCP->State = FAULT;
+ }
+ else
+ {
+ pSDMMCP->State = READY;
+ }
+ return Retval;
+}
+
+/***********************************************************
+* SDMMCWriteFifo
+* Writes 2048 bytes (512 words) to the FIFO
+* Input:
+* P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+* Output:
+* none
+* Returns:
+* none
+*************************************************************/
+void MM4_WriteFifo(P_SDMMC_Properties_T pSDMMCP)
+{
+ int i, t = 0;
+ UINT_T Buffer =0x0;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ volatile UINT_T *pMMC_TX_Fifo;
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ pMMC_TX_Fifo = (volatile UINT_T *)&(pContext->pMMC4Reg->mm4_dp);
+ t = pSDMMCP->Trans.WordIndex;
+
+ // Ignore Pre Bytes
+ for (i=0; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.StartDiscardWords); i++, t++)
+ *pMMC_TX_Fifo = Buffer;
+
+ // Write Requested Data
+ for (; ((i < MM4FIFOWORDSIZE) && (t < (pSDMMCP->Trans.TransWordSize-pSDMMCP->Trans.EndDiscardWords))); i++, t++)
+ *pMMC_TX_Fifo = ((UINT_T*) pSDMMCP->Trans.LocalAddr)[t];
+
+ // Ignore Trailing Bytes
+ for (; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.TransWordSize); i++, t++)
+ *pMMC_TX_Fifo = Buffer;
+
+ pSDMMCP->Trans.WordIndex = t;
+
+}
+
+/***********************************************************
+* MM4_ReadFifo
+* Reads the contents of the read fifo (512 words)
+* Input:
+* P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+* Output:
+* buffer will contain the contents of the read fifo
+* Returns:
+* none
+*************************************************************/
+void MM4_ReadFifo(P_SDMMC_Properties_T pSDMMCP)
+{
+ int i, t = 0;
+ UINT_T Buffer =0x0;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ volatile UINT_T *pMMC_RX_Fifo;
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+
+ pMMC_RX_Fifo = (volatile UINT_T *)&(pContext->pMMC4Reg->mm4_dp);
+ t = pSDMMCP->Trans.WordIndex;
+
+ // Ignore Pre Bytes
+ for (i=0; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.StartDiscardWords); i++, t++)
+ Buffer = *pMMC_RX_Fifo;
+
+ // Read Requested Data
+ for (; ((i < MM4FIFOWORDSIZE) && (t < (pSDMMCP->Trans.TransWordSize-pSDMMCP->Trans.EndDiscardWords))); i++, t++)
+ ((UINT_T*) pSDMMCP->Trans.LocalAddr)[t] = *pMMC_RX_Fifo;
+
+ // Ignore Trailing Bytes
+ for (; (i < MM4FIFOWORDSIZE) && (t < pSDMMCP->Trans.TransWordSize); i++, t++)
+ Buffer = *pMMC_RX_Fifo;
+
+ pSDMMCP->Trans.WordIndex = t;
+}
+
+/****************************************************************
+* MM4_SendStopCommand
+* Issues a stop command for open ended read and write block operations
+*
+* Input:
+* P_SDMMC_Properties_T pSDMMCP - pointer to the SDMMC context structure
+* Output:
+* none
+* Returns:
+* none
+*****************************************************************/
+void MM4_SendStopCommand(P_SDMMC_Properties_T pSDMMCP)
+{
+ if(pSDMMCP->State == READ)
+ {
+ // Send a CMD 12 to stop transmissions.
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD12, MM4_CMD_TYPE_NORMAL, NULL, MM4_RT_R1 | MM4_48_RES); // fixme: r1 for read, r1b for write.
+ MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1, 0x100);
+ }
+ if(pSDMMCP->State == WRITE)
+ {
+ // Send a CMD 12 to stop transmissions.
+ MM4_SendSetupCommand(pSDMMCP, XLLP_MMC_CMD12, MM4_CMD_TYPE_NORMAL, NULL, MM4_RT_R1 | MM4_RT_BUSY | MM4_48_RES_WITH_BUSY); // fixme: r1 for read, r1b for write.
+ MM4_Interpret_Response(pSDMMCP, MMC_RESPONSE_R1B, MMC_RESPONSE_R1B_TIMEOUT);
+ }
+}
+
+/****************************************************************
+* MM4_ISR
+* Interrupt Service Routine for SDMMC controller
+* Controls flow and catches faults asynchronously
+* Input:
+* P_SDMMC_Properties_T pSDMMCP
+* Output:
+* none
+* Returns:
+* none
+*****************************************************************/
+void MM4_ISR(P_SDMMC_Properties_T pSDMMCP)
+{
+ UINT_T i;
+ UINT_T i_stat_copy; // Keep a copy of i stat register
+ UINT_T i_err_stat; // contains only error status bits.
+ UINT_T i_acmd12_err_stat;
+ P_MM4_I_STAT p_i_stat_copy; // Pointer to the copy.
+ UINT_T cmderror = 0;
+ UINT_T resptype;
+ P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext; // Assign our context value
+ UINT_T r1_resp_error_bits = 0xfdffc080; // that strange mask is all possible error bits in the card stat field.
+
+ // Assign required pointers to registers
+ VUINT_T *pmm4_resp0 = (VUINT_T *)(&pContext->pMMC4Reg->mm4_resp0);
+ VUINT_T *pmm4_acmd12_er = (VUINT_T *)(&pContext->pMMC4Reg->mm4_acmd12_er);
+ VUINT_T *pmm4_istat = (VUINT_T *)(&pContext->pMMC4Reg->mm4_i_stat);
+ VUINT_T *pmm4_sysaddr = (VUINT_T *)(&pContext->pMMC4Reg->mm4_sysaddr);
+
+ // Grab snapshot copies of i_stat
+ i_stat_copy = *(UINT_T *) (&pContext->pMMC4Reg->mm4_i_stat); // Grab a single copy.
+ p_i_stat_copy = (P_MM4_I_STAT)&i_stat_copy;
+
+ // command response will send out anyway, no matter command completed or not
+ for (i = 0; i < 4; i++)
+ pSDMMCP->CardReponse.pBuffer[i] = pmm4_resp0[i];
+
+ // Check for any error
+ if( p_i_stat_copy->cmdcomp )
+ {
+ // if we're in strict error checking mode, and
+ // if the completing command has an R1 or R1B status,
+ // look for any error bits in the card status field
+ if( pSDMMCP->StrictErrorCheck )
+ {
+ resptype = (pSDMMCP->Trans.RespType << 8) & MM4_RT_MASK; // convert to a value more convenient for comparisons...
+ if( resptype == MM4_RT_R1 )
+ {
+ cmderror = (*pmm4_resp0 & r1_resp_error_bits ); // that strange mask is all possible error bits.
+ }
+ }
+ else cmderror = 0; // don't examine error because not strict error checking mode or this is not an R1 type of command.
+ }
+
+ if (p_i_stat_copy->errint || cmderror )
+ {
+ // each error condition has its own handling/recovery requirements....
+
+ // move the error bits down to a low halfword so the defines in sd.h
+ // can be used. (they were based on 16 bit io access)
+ i_err_stat = i_stat_copy >> 16;
+ pSDMMCP->DeviceStatus = i_stat_copy;
+
+ // check & handle each error condition
+
+ // the following errors require an sd host controller reset:
+ if( ( i_err_stat & SD_ERROR_INT_STATUS_AXI_RESP_ERR ) ||
+ ( i_err_stat & SD_ERROR_INT_STATUS_DATA_TIMEOUT_ERR ) ||
+ ( i_err_stat & SD_ERROR_INT_STATUS_CMD_TIMEOUT_ERR ) ||
+ cmderror )
+ {
+ MMC4CMDSWReset(pContext); // this cleas the command inhibit flag in sd_present_state_1.
+ MMC4DataSWReset(pContext); // this clears the data inhibit flag and stops mclk.
+ }
+
+ // acmd 12 error requires examining a separate error status register:
+ else if( i_err_stat & SD_ERROR_INT_STATUS_AUTO_CMD12_ERR )
+ {
+ i_acmd12_err_stat = *pmm4_acmd12_er;
+
+ // any acmd12 error requires an sd host controller reset
+ // because there's no way to know if the command was processed.
+ MMC4CMDSWReset(pContext); // this cleas the command inhibit flag in sd_present_state_1.
+ MMC4DataSWReset(pContext); // this clears the data inhibit flag and stops mclk.
+
+ // clear the acmd12 error bits.
+ *pmm4_acmd12_er = i_acmd12_err_stat;
+ }
+
+ // clear the general error status bits
+ *pmm4_istat = i_stat_copy;
+ i = *pmm4_istat; // Must make a dummy read to allow interrupts to clear.
+
+ // set a flag so the caller knows this request failed.
+ pSDMMCP->State = FAULT;
+
+ // done with handling an error condition.
+ // nothing more to do.
+ return;
+ }
+
+ // is this an sdma interrupt event?
+ if(*pmm4_istat & (1u<<3)) // bit 3 is dmaint
+ {
+ // the transfer halted because the boundary specified in ... was reached.
+ // rewriting the sysaddr with the next address allows the transfer to resume.
+ // fortunately the sysaddr register itself contains the next address.
+ // so, just re-write the sysaddr register with its own current contents.
+ //Coverity - 10008: Self Assignment error - No Effect.
+ //This is OK. That's the way the hardware works!
+ if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+ {
+ i = *pmm4_sysaddr;
+ *pmm4_sysaddr = i; // sysaddr points to next addr to write.
+ }
+
+ // for ADMA2, no ISR for per DMA transfer, when all data transfer complete, it will generate XFER_COMP ISR
+ if (pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+ pSDMMCP->State = READY;
+
+ *pmm4_istat = (1u<<3); // bit 3 is dmaint
+ i = *pmm4_istat; // read-back to ensure write completes
+
+ }
+ // fall through the rest of the isr.
+ // end of dmaint handling.
+
+ // Has the Command completed? If so read the response register
+ if (p_i_stat_copy->cmdcomp)
+ {
+ // Indicate that the response has been read
+ pSDMMCP->CardReponse.CommandComplete = 1;
+ }
+
+ if (p_i_stat_copy->xfrcomp)
+ {
+ // Indicate that the response has been read
+ pSDMMCP->CardReponse.TransferComplete = 1;
+ }
+
+ // Are we DMA enabled?
+ if((pSDMMCP->SDMMC_DMA_Mode))
+ {
+ if (p_i_stat_copy->xfrcomp)
+ pSDMMCP->State = READY;
+ }
+
+ // Clear the interrupts
+ *pmm4_istat = i_stat_copy; // Clear the interrupt source.
+ i = *pmm4_istat; // Must make a dummy read to allow interrupts to clear.
+
+ if(pSDMMCP->SDMMC_DMA_Mode == NODMA)
+ {
+ // Handle State based interrupts XFRCOMP, BUFRDRDY, BUFWRRDY
+ switch (pSDMMCP->State)
+ {
+ case WRITE:
+ {
+ if (p_i_stat_copy->bufwrrdy)
+ MM4_WriteFifo(pSDMMCP);
+
+ // Are we done sending all of data?
+ if (pSDMMCP->Trans.TransWordSize == pSDMMCP->Trans.WordIndex)
+ pSDMMCP->State = DATATRAN;
+
+ break;
+ }
+ case READ:
+ {
+ if (p_i_stat_copy->bufrdrdy)
+ MM4_ReadFifo(pSDMMCP);
+
+ // Are we done sending all of data?
+ if (pSDMMCP->Trans.TransWordSize == pSDMMCP->Trans.WordIndex)
+ pSDMMCP->State = DATATRAN;
+
+ break;
+ }
+ case DATATRAN:
+ {
+ // Wait for Transfer Complete Signal
+ if (p_i_stat_copy->xfrcomp)
+ pSDMMCP->State = READY;
+
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return;
+}
+
+/***************************************************************
+* MM4_MMCReadEXTCSD
+* Reads in 512 bytes of Extended CSD
+* Input: Pointer to 512 byte buffer
+* Output:
+* Returns: NoError, ReadError or NotSupportedError
+*
+*****************************************************************/
+UINT_T MM4_MMCReadEXTCSD (UINT_T *pBuffer)
+{
+ UINT_T Retval;
+ P_MM4_SDMMC_CONTEXT_T pContext;
+ P_MM4_CNTL1 pMM4_CNTL1;
+ P_MM4_BLK_CNTL pMM4_BLK_CNTL;
+ ADMA_DESCRIPTOR admaDesc;
+
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ if (pSDMMCP->SD == XLLP_SD)
+ return NoError; // This is an MMC command only!
+
+ // Assign our context value
+ pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
+ pMM4_CNTL1 = (P_MM4_CNTL1) &pContext->pMMC4Reg->mm4_cntl1;
+
+ // Set up State
+ pSDMMCP->State = READ;
+
+ // This requires a transfer over the data lines.
+ pMM4_BLK_CNTL = (P_MM4_BLK_CNTL) &pContext->pMMC4Reg->mm4_blk_cntl;
+ pMM4_BLK_CNTL->blk_cnt = 0;
+ if (pSDMMCP->SDMMC_DMA_Mode == SDMA)
+ {
+ pMM4_BLK_CNTL->dma_bufsz = MM4_512_HOST_DMA_BDRY;
+ pContext->pMMC4Reg->mm4_sysaddr = (UINT_T) pBuffer;
+ } //MMC_SDMA_MODE
+ else if(pSDMMCP->SDMMC_DMA_Mode == ADMA2)
+ {
+ MM4_SetupADMADesc(&admaDesc,
+ VALID_DESC,
+ LAST_DESC,
+ NO_DMA_INT,
+ TRANSFER,
+ 1,//EXT_CSD is sent as a block of data
+ (UINT_T)pBuffer);
+ pMM4_CNTL1->dma_sel = 2; //ADMA2
+ //Set the ADMA register to the address of descriptor table
+ pContext->pMMC4Reg->mm4_adma_system_address1 = (UINT_T)&admaDesc;
+ }
+ pSDMMCP->Trans.StartDiscardWords = 0;
+ pSDMMCP->Trans.EndDiscardWords = 0; // We'll take all 512 bytes
+ pSDMMCP->Trans.TransWordSize = pSDMMCP->ReadBlockSize / 4; // Total Transfer Size including pre and post bytes
+ pSDMMCP->Trans.LocalAddr = (UINT_T) pBuffer;
+ pSDMMCP->Trans.WordIndex = 0; // Stores Index of Current write position
+
+ MM4_SendDataCommandNoAuto12(pSDMMCP, XLLP_MMC_CMD8, NO_ARGUMENT, MM4_SINGLE_BLOCK_TRAN, MM4_CARD_TO_HOST_DATA, MM4_RT_R1 | MM4_48_RES);
+
+ // Wait for the Write to Complete
+ while ((pSDMMCP->State != FAULT) && (pSDMMCP->State != READY));
+
+ if( pSDMMCP->State == FAULT ) // This state entered if ISR detected an error.
+ {
+ return SDMMCReadError;
+ }
+
+ //send CMD13 to check the status of the card
+ Retval |= MM4_CheckCardStatus(pSDMMCP, 0x900, R1_LOCKEDCARDMASK); // Make sure card is transfer mode
+
+ pSDMMCP->State = READY;
+
+ if (Retval != NoError)
+ return SDMMC_SWITCH_ERROR;
+
+ return NoError;
+}
+
+/***********************************************************
+* MM4_SetupADMADesc()
+* Function to setup ADMA descriptor i.e; fills the descriptor contents
+* input:
+* P_ADMA_DESCRIPTOR -> Address of the ADMA descriptor
+* DESC_VAL_INVAL -> Indicates whether the descriptor is valid or not
+* END_DESC -> Indicates if the current descriptor is the last of the chain
+* ATTRIBUTES -> Indicates the type of descriptor whether it is transfer type or link type
+* NumBlocks -> Number of blocks that are transferred by this descriptor
+* Address -> Destination address if the descriptor is of type transfer or the descriptor
+* it is linked to if it is of type link
+* output:
+* Fills the input descriptor
+* returns:
+* none
+************************************************************/
+void MM4_SetupADMADesc(P_ADMA_DESCRIPTOR pAdmaDesc,
+ DESC_VAL_INVAL ValidDesc,
+ END_DESC EndDesc,
+ DMA_INT_EN DmaInterrupt,
+ ATTRIBUTES Attributes,
+ UINT_T NumBlocks,
+ UINT_T Address)
+{
+ // Initialize Flash Properties
+ P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
+
+ memset(pAdmaDesc,0, sizeof(ADMA_DESCRIPTOR));
+ pAdmaDesc->Address = Address;
+ pAdmaDesc->Length = NumBlocks * pSDMMCP->ReadBlockSize;
+ pAdmaDesc->Rsvd = 0;
+ pAdmaDesc->attr = Attributes;
+ pAdmaDesc->Rsvd0 = 0;
+ pAdmaDesc->dma_int_en = DmaInterrupt;
+ pAdmaDesc->end_desc = EndDesc;
+ pAdmaDesc->desc_val_inval = ValidDesc;
+ return;
+}