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;
+}
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.h b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.h
new file mode 100644
index 0000000..44eeffe
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2.h
@@ -0,0 +1,103 @@
+/******************************************************************************
+ *
+ * (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.
+ *
+******************************************************************************/
+
+#ifndef __SDHC2_H__
+#define __SDHC2_H__
+
+#include "misc.h"
+#include "sdhc2_controller.h"
+#include "SD.h"
+
+#define UNSTUFF_BITS(resp,start,size) \
+ ({ \
+ const int __size = size; \
+ const unsigned int __mask = (__size < 32 ? 1 << __size : 0) - 1; \
+ const int __off = 3 - ((start) / 32); \
+ const int __shft = (start) & 31; \
+ unsigned int __res; \
+ \
+ __res = resp[__off] >> __shft; \
+ if (__size + __shft > 32) \
+ __res |= resp[__off-1] << ((32 - __shft) % 32); \
+ __res & __mask; \
+ })
+
+// Prototypes
+UINT_T MM4_CardInit(UINT_T BaseAddress, UINT_T InterruptMask);
+
+// Helper / Internal
+UINT MM4_IDCard(P_SDMMC_Properties_T pSDMMCP, UINT_T *pControllerVoltage);
+UINT_T MM4SetBusWidth(UINT8_T value);
+UINT_T MM4HighSpeedTiming(void);
+UINT_T MM4_MMCReadEXTCSD (UINT_T *pBuffer);
+UINT_T MM4_CheckVoltageCompatibility(P_SDMMC_Properties_T pSDMMCP, UINT_T ControllerVoltage);
+UINT_T MM4_SetControllerVoltage (P_MM4_SDMMC_CONTEXT_T pContext);
+UINT_T MM4_CheckCardStatus(P_SDMMC_Properties_T pSDMMCP, UINT_T R1_Resp_Match, UINT_T Mask);
+UINT_T MM4_Interpret_Response(P_SDMMC_Properties_T pSDMMCP, UINT_T ResponseType, UINT_T ResponseTimeOut);
+void MM4_PrepareMMCContext (P_SDMMC_Properties_T pSDMMCP, UINT_T BaseAddress);
+UINT_T MM4_SelectSlot(UINT_T slot);
+void MM4_ISR(P_SDMMC_Properties_T pSDMMCP);
+void MM4_SendDataCommand (P_SDMMC_Properties_T pSDMMCP,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType);
+
+void MM4_SendDataCommandNoAuto12 (P_SDMMC_Properties_T pSDMMCP,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType);
+
+void MM4_SendSetupCommand(P_SDMMC_Properties_T pSDMMCP,
+ UINT_T Cmd,
+ UINT_T CmdType,
+ UINT_T Argument,
+ UINT_T ResType);
+
+UINT_T MM4_MMCAlternateBootMode(UINT_T BaseAddress, UINT_T InterruptMask);
+UINT_T MM4_MMCAlternateBootModeReadTIM(void);
+UINT_T MM4_MMCAlternateBootModeReadResume(void);
+UINT_T MM4_MMCAlternateBootFinalize(void);
+
+void MM4_SetupADMADesc(P_ADMA_DESCRIPTOR pAdmaDesc,
+ DESC_VAL_INVAL ValidDesc,
+ END_DESC EndDesc,
+ DMA_INT_EN DmaInterrupt,
+ ATTRIBUTES Attributes,
+ UINT_T Length,
+ UINT_T Address);
+
+UINT_T MM4_ReadBlocks(void);
+UINT_T MM4_WriteBlocks(void);
+UINT_T MM4_EraseBlocks(void);
+UINT_T MM4_CardShutdown(void);
+void MM4_WriteFifo(P_SDMMC_Properties_T pSDMMCP);
+void MM4_ReadFifo(P_SDMMC_Properties_T pSDMMCP);
+void MM4_SendStopCommand(P_SDMMC_Properties_T pSDMMCP);
+UINT_T MM4SwitchPartition(UINT_T PartitionNumber);
+UINT_T MM4_WaitForOperationComplete(UINT_T TimeOutMillisec );
+void MMCClocks( int Clks, unsigned int nCmdState_period, GPIO_CFG_T *pMMCClkCfg, GPIO_CFG_T *pMMCCmdCfg );
+UINT_T MM4_TestBus_SetBusWidth(void);
+UINT_T MM4_SendReceive_TestPattern(UINT_T *pOutput, UINT_T Length);
+
+#endif
+
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.c b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.c
new file mode 100644
index 0000000..860a42e
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.c
@@ -0,0 +1,685 @@
+/******************************************************************************
+ *
+ * (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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+**
+** FILENAME: sdhc_controller.c
+**
+** PURPOSE: MMC and SD specific low level controller routines for the MM4 controller
+**
+**
+**
+**
+******************************************************************************/
+#include "sdhc2_controller.h"
+#include "misc.h"
+#include "Errors.h"
+#include "timer.h"
+
+void MMC4Gen74Clocks(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_SD_LEGACY_CTRL_REG pMM4_SD_LEGACY_CTRL_REG;
+ P_MM4_CTRL_REG pP_MM4_CTRL_REG;
+ UINT_T startTime, endTime;
+ UINT_T retval = NoError;
+
+ pMM4_SD_LEGACY_CTRL_REG = (P_MM4_SD_LEGACY_CTRL_REG)&pContext->pMMC4Reg->mm4_legacy_ctrl_reg;
+ pP_MM4_CTRL_REG = (P_MM4_CTRL_REG)&pContext->pMMC4Reg->mm4_mmc_ctrl_reg;
+
+ // Enable capturing status for sending out 74 clock cycles.
+ pP_MM4_CTRL_REG->misc_int_en = 1;
+ pP_MM4_CTRL_REG->misc_int = 1;
+
+ // Enable and start 74 clock cycles
+ pMM4_SD_LEGACY_CTRL_REG->gen_pad_clk_cnt = 74; // 74 clock cycles.
+ pMM4_SD_LEGACY_CTRL_REG->gen_pad_clk_on = 1; // Start generating the clocks.
+
+ // Wait for the 74 clock cycles to be generated.
+ startTime = GetOSCR0();
+ startTime = GetOSCR0();
+ do
+ {
+ if (pP_MM4_CTRL_REG->misc_int)
+ break; // 74 clock cycles have been generated.
+
+ endTime = GetOSCR0();
+
+ if (OSCR0IntervalInMilli(startTime, endTime) >= 10)
+ return SDMMCInitializationError;
+ }while(1);
+
+ return retval;
+}
+
+/******************************************************************************
+ Description:
+ Start MMC/SD Internal bus clock. MUST be done to start MM4CLK!
+ Only after starting bus clock, communication between
+ controller and card is possible
+ Input Parameters:
+ pContext--Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4StartInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 1;
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+ // Wait for clock to become stable. * TBD * Add timeout
+ do
+ {
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ } while (!(MM4_cntl2.mm4_cntl2_bits.inter_clk_stable));
+
+ return;
+}
+
+/******************************************************************************
+ Description:
+ Stops the MMC/SD Internal bus clock.
+ Input Parameters:
+ pContext--Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4StopInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 0;
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+ // Wait for clock to become stable. * TBD * Add timeout
+ do
+ {
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ } while (MM4_cntl2.mm4_cntl2_bits.inter_clk_stable);
+
+ return;
+}
+
+
+/******************************************************************************
+ Description:
+ Start MMC bus clock. Only after starting bus clock, communication between
+ controller and card is possible
+ Input Parameters:
+ pContext--Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4StartBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.mm4clken = 1;
+
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+ Description:
+ Stops MMC bus clock.
+ Input Parameters:
+ pContext--Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4StopBusClock (P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Request bus clock stop
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.mm4clken = 0;
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+ return;
+}
+
+/******************************************************************************
+ Description:
+ Set a new MMC bus clock rate. This function stops and resumes bus clock.
+ Input Parameters:
+ pContext
+ Pointer to MMC context structure
+ rate
+ bus clock speed
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4SetBusRate(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T rate)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Request bus clock stop, set rate, start clock.
+ MMC4StopBusClock (pContext);
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+
+ // Update the rate and start the clock.
+ MM4_cntl2.mm4_cntl2_bits.sd_freq_sel_lo = (rate & 0xFF);
+ MM4_cntl2.mm4_cntl2_bits.sd_freq_sel_hi = ((rate >> 8) & 3);
+ MM4_cntl2.mm4_cntl2_bits.mm4clken = 1;
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+
+ // Make sure internal bus clock also enabled.
+ MMC4StartInternalBusClock(pContext);
+
+ return;
+}
+
+void MMC4SelectUHSMode(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T mode)
+{
+ UINT8_T ctrl = 0;
+ P_MM4_HOST_CNTL2_UNION pMM4_host_CNTL2;
+ MM4_HOST_CNTL2_UNION MM4_host_cntl2;
+
+ MMC4StopBusClock (pContext);
+
+ pMM4_host_CNTL2 = (P_MM4_HOST_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_acmd12_er);
+ MM4_host_cntl2.mm4_host_cntl2_value = *(VUINT_T *)pMM4_host_CNTL2;
+
+ if (mode & SDH_BUS_SPEED_SDR_CLK_208M) {
+ ctrl |= 0x03;
+ } else if (mode & SDH_BUS_SPEED_SDR_CLK_100M) {
+ ctrl |= 0x02;
+ } else if (mode & SDH_BUS_SPEED_DDR_CLK_50M) {
+ ctrl |= 0x04;
+ } else if (mode & SDH_BUS_SPEED_SDR_CLK_50M) {
+ ctrl |= 0x01;
+ } else if (mode & SDH_BUS_SPEED_DEFAULT) {
+ ctrl |= 0x00;
+ }
+
+ MM4_host_cntl2.mm4_host_cntl2_bits.uhs_mode_sel = ctrl;
+ *(VUINT_T *)pMM4_host_CNTL2 = MM4_host_cntl2.mm4_host_cntl2_value;
+
+ MMC4StartBusClock(pContext);
+
+ return;
+}
+
+void MMC4SetTXIntCLKSet(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T mode1, UINT_T mode2)
+{
+ P_MM4_TX_CFG pMM4_TX_CFG;
+
+ pMM4_TX_CFG = (P_MM4_TX_CFG)&pContext->pMMC4Reg->mm4_sd_tx_cfg_reg;
+
+ //set the tx_int_clk_sel that makes the Tih dependant on bus clock rather than base clock
+ pMM4_TX_CFG->tx_int_clk = mode1;
+ pMM4_TX_CFG->tx_mux_sel = mode2;
+}
+
+void MMC4SetRXConfig(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ UINT_T value = 0;
+ P_MM4_RX_CFG_UNION pMM4_RX_CFG_UNION;
+ P_MM4_SD_DLINE_CTRL p_MM4_SD_DLINE_CTRL;
+ P_MM4_SD_DLINE_CFG p_MM4_SD_DLINE_CFG;
+
+ pMM4_RX_CFG_UNION = (P_MM4_RX_CFG)&pContext->pMMC4Reg->mm4_sd_rx_cfg_reg;
+ p_MM4_SD_DLINE_CTRL = (P_MM4_SD_DLINE_CTRL)&pContext->pMMC4Reg->mm4_sd_dline_ctrl_reg;
+ p_MM4_SD_DLINE_CFG = (P_MM4_SD_DLINE_CFG)&pContext->pMMC4Reg->mm4_sd_dline_cfg_reg;
+
+ value = pMM4_RX_CFG_UNION->MM4_RX_CFG_value;
+ value &= ~(RX_SDCLK_SEL1_MASK << RX_SDCLK_SEL1_SHIFT);
+ /* clock by SDCLK_SEL0, so it is default setting */
+ value |= 0x1 << RX_SDCLK_SEL1_SHIFT;
+ *(VUINT_T *)pMM4_RX_CFG_UNION = value;
+
+ p_MM4_SD_DLINE_CFG->rx_dline_reg = 0x0;
+ p_MM4_SD_DLINE_CTRL->rx_dline_code = DDR_RX_DELAY;
+ p_MM4_SD_DLINE_CTRL->dline_pu = 1;
+}
+
+void MMC4SetTXConfig(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ UINT_T value = 0;
+ UINT_T tx_delay = DDR_TX_DELAY;
+ P_MM4_TX_CFG_UNION pMM4_TX_CFG_UNION;
+ P_MM4_SD_DLINE_CTRL p_MM4_SD_DLINE_CTRL;
+ P_MM4_SD_DLINE_CFG p_MM4_SD_DLINE_CFG;
+
+ pMM4_TX_CFG_UNION = (P_MM4_TX_CFG)&pContext->pMMC4Reg->mm4_sd_tx_cfg_reg;
+ p_MM4_SD_DLINE_CTRL = (P_MM4_SD_DLINE_CTRL)&pContext->pMMC4Reg->mm4_sd_dline_ctrl_reg;
+ p_MM4_SD_DLINE_CFG = (P_MM4_SD_DLINE_CFG)&pContext->pMMC4Reg->mm4_sd_dline_cfg_reg;
+
+ value = pMM4_TX_CFG_UNION->MM4_TX_CFG_value;
+ if (tx_delay)
+ {
+ value &= ~TX_SEL_BUS_CLK; //clr bit 30
+ value |= TX_MUX_SEL; //set bit 31 select DDLL
+ }
+
+ *(VUINT_T *)pMM4_TX_CFG_UNION = value;
+ p_MM4_SD_DLINE_CFG->tx_dline_reg = 0x0;
+ p_MM4_SD_DLINE_CTRL->tx_dline_code = tx_delay & TX_DELAY_MASK;
+ p_MM4_SD_DLINE_CTRL->dline_pu = 1;
+}
+
+/******************************************************************************
+ Description:
+ This routine unmasks and enables or masks and disables required interrupts
+ needed by the driver
+ Input Parameters:
+ pContext
+ Pointer to MMC context structure
+ Desire - Enable or Disable the interrupts
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4EnableDisableIntSources(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T Desire)
+{
+ P_MM4_I_STAT pMM4_I_STAT;
+ MM4_I_STAT_UNION MM4_i_stat;
+
+ // Capture existing Value
+ pMM4_I_STAT = (P_MM4_I_STAT)((VUINT32_T) &pContext->pMMC4Reg->mm4_i_sig_en);
+
+ MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT;
+ // Route the interrupt signal enable register
+ MM4_i_stat.mm4_i_stat_bits.cmdcomp = Desire;
+ MM4_i_stat.mm4_i_stat_bits.xfrcomp = Desire;
+ MM4_i_stat.mm4_i_stat_bits.dmaint = Desire;
+ MM4_i_stat.mm4_i_stat_bits.bufwrrdy = Desire;
+ MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire;
+ MM4_i_stat.mm4_i_stat_bits.errint = Desire;
+ MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.cenderr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.dtoerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.dcrcerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.denderr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.admaerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.crc_stat_err = Desire;
+
+ // Write it out
+ *(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value;
+
+ // Now remove the masks
+ pMM4_I_STAT = (P_MM4_I_STAT)((VUINT32_T) &pContext->pMMC4Reg->mm4_i_stat_en);
+ MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT;
+ MM4_i_stat.mm4_i_stat_bits.cmdcomp = Desire;
+ MM4_i_stat.mm4_i_stat_bits.xfrcomp = Desire;
+ MM4_i_stat.mm4_i_stat_bits.dmaint = Desire;
+ MM4_i_stat.mm4_i_stat_bits.bufwrrdy = Desire;
+ MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire;
+ MM4_i_stat.mm4_i_stat_bits.errint = Desire;
+ MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.cenderr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.dtoerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.dcrcerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.denderr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.admaerr = Desire;
+ MM4_i_stat.mm4_i_stat_bits.crc_stat_err = Desire;
+
+ // Write it out
+ *(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value;
+
+ return;
+}
+
+/******************************************************************************
+ Description:
+ Set the data response timeout value.
+ Input Parameters:
+ pContext
+ Pointer to MMC context structure
+ CounterValue
+ the value which will be written into DTOCNTR
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4SetDataTimeout(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T CounterValue)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.dtocntr = CounterValue;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+ Description:
+ This function will induce a software reset of all MMC4 data lines
+ Input Parameters:
+ pContext
+ Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4CMDSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.cmdswrst = 1;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+ Description:
+ This function will induce a software reset of all MMC4 data lines
+ Input Parameters:
+ pContext
+ Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4DataSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.datswrst = 1;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+ Description:
+ This function will induce a full software reset of all MMC4 components except
+ MM4_CAPX
+ Input Parameters:
+ pContext
+ Pointer to MMC context structure
+ Output Parameters:
+ None
+ Returns:
+ None
+*******************************************************************************/
+void MMC4FullSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
+{
+ P_MM4_CNTL2 pMM4_CNTL2;
+ MM4_CNTL2_UNION MM4_cntl2;
+
+ // Set the register
+ pMM4_CNTL2 = (P_MM4_CNTL2)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl2);
+ MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
+ MM4_cntl2.mm4_cntl2_bits.mswrst = 1;
+
+ // Write Back
+ *(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
+ return;
+}
+
+/******************************************************************************
+ 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:
+ pContext
+ Pointer to MMC context 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 MMC4SendDataCommand(P_MM4_SDMMC_CONTEXT_T pContext,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType,
+ UINT_T DMAMode,
+ UINT_T AutoCmd23En)
+{
+ MM4_CMD_XFRMD_UNION xfrmd;
+ P_MM4_STATE pMM4_STATE;
+ MM4_STATE_UNION MM4_state;
+
+ // Make sure the controller is ready to accept the next command
+ pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+
+ do
+ {
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+ } while (MM4_state.mm4_state_bits.dcmdinhbt);
+
+ // Set the Argument Field
+ pContext->pMMC4Reg->mm4_arg = Argument;
+
+ // Set the Data Transfer Command fields.
+ xfrmd.mm4_cmd_xfrmd_value = 0;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_type = MM4_CMD_TYPE_NORMAL;
+ xfrmd.mm4_cmd_xfrmd_bits.dpsel = MM4_CMD_DATA;
+// xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
+// xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
+ xfrmd.mm4_cmd_xfrmd_bits.ms_blksel = BlockType;
+ xfrmd.mm4_cmd_xfrmd_bits.dxfrdir = DataDirection;
+
+ //if SDMA/ADMA2
+ if (DMAMode)
+ xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE;
+ //CMD23 -> Lets the card know about number of blocks to transfer for the upcoming read/write transaction
+ //AutoCMD23 should be sent prior to CMD18 or CMD25 if ADMA2 is used and BLK_CNT is disabled for ADMA2
+ //Since AutoCMD23 is sent, AutoCMD12 is not required
+ if(AutoCmd23En)
+ {
+ xfrmd.mm4_cmd_xfrmd_bits.autocmd23 = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE; // block counter is a better choice than send stop command
+ }
+ else
+ {
+ //For PIO and SDMA mode
+ xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE;
+ }
+
+ // Kick off the command
+ pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
+
+ return;
+}
+
+
+/******************************************************************************
+ 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:
+ pContext
+ Pointer to MMC context 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 MMC4SendDataCommandNoAuto12(P_MM4_SDMMC_CONTEXT_T pContext,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType,
+ UINT_T DMAMode,
+ UINT_T Blk_Cnt_Enable)
+{
+ MM4_CMD_XFRMD_UNION xfrmd;
+ P_MM4_STATE pMM4_STATE;
+ MM4_STATE_UNION MM4_state;
+
+ // Make sure the controller is ready to accept the next command
+ pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+
+ do
+ {
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+ } while (MM4_state.mm4_state_bits.dcmdinhbt);
+ // Set the Argument Field
+ pContext->pMMC4Reg->mm4_arg = Argument;
+
+ // Set the Data Transfer Command fields.
+ xfrmd.mm4_cmd_xfrmd_value = 0;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_type = MM4_CMD_TYPE_NORMAL;
+ xfrmd.mm4_cmd_xfrmd_bits.dpsel = MM4_CMD_DATA;
+// xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
+// xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
+ xfrmd.mm4_cmd_xfrmd_bits.ms_blksel = BlockType;
+ xfrmd.mm4_cmd_xfrmd_bits.dxfrdir = DataDirection;
+ xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = FALSE;
+
+ if (DMAMode)
+ xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE;
+
+ if(Blk_Cnt_Enable) //Blk_Cnt is not enabled for ADMA2
+ xfrmd.mm4_cmd_xfrmd_bits.blkcnten = TRUE;
+
+ // Kick off the command
+ pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
+ return;
+}
+
+/******************************************************************************
+ 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:
+ pContext
+ Pointer to MMC context 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 MMC4SendSetupCommand(P_MM4_SDMMC_CONTEXT_T pContext,
+ UINT_T Cmd,
+ UINT_T CmdType,
+ UINT_T Argument,
+ UINT_T ResType)
+{
+ MM4_CMD_XFRMD_UNION xfrmd;
+ P_MM4_STATE pMM4_STATE;
+ MM4_STATE_UNION MM4_state;
+ UINT_T startTime, endTime;
+
+ startTime = GetOSCR0(); // get the start time
+ startTime = GetOSCR0(); // get the start time
+ endTime = startTime;
+
+ // Make sure the controller is ready to accept the next command
+ pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+
+ do
+ {
+ endTime = GetOSCR0();
+
+ if (OSCR0IntervalInMilli(startTime, endTime) > 200)
+ return; // Let the getresponse routine catch the error
+
+ MM4_state.mm4_state_value = *(VUINT_T *)pMM4_STATE;
+ } while (MM4_state.mm4_state_bits.ccmdinhbt);
+
+ // Set the Argument Field
+ pContext->pMMC4Reg->mm4_arg = Argument;
+
+ // Set the Data Transfer Command fields.
+ xfrmd.mm4_cmd_xfrmd_value = 0;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_idx = Cmd;
+ xfrmd.mm4_cmd_xfrmd_bits.cmd_type = CmdType;
+// xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
+ xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
+
+ // Kick off the command
+ pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
+ return;
+}
diff --git a/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.h b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.h
new file mode 100644
index 0000000..7a40eac
--- /dev/null
+++ b/marvell/obm/Common/Flash/SDMMC/SDHC2/sdhc2_controller.h
@@ -0,0 +1,661 @@
+/******************************************************************************
+ *
+ * (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.
+ *
+ ******************************************************************************/
+
+
+#ifndef __SDHC2_CONTROLLER_H
+#define __SDHC2_CONTROLLER_H
+
+#include "Typedef.h"
+
+// MMC controller registers definition
+typedef struct
+{
+ VUINT32_T mm4_sysaddr; // DMA system address 0x0
+ VUINT32_T mm4_blk_cntl; // Block size control register 0x4
+ VUINT32_T mm4_arg; // Command argument 0x8
+ VUINT32_T mm4_cmd_xfrmd; // Command and transfer mode 0xC
+ VUINT32_T mm4_resp0; // cmd response 0 0x10
+ VUINT32_T mm4_resp1; // cmd response 1 0x14
+ VUINT32_T mm4_resp2; // cmd response 2 0x18
+ VUINT32_T mm4_resp3; // cmd response 3 0x1C
+ VUINT32_T mm4_dp; // buffer data port 0x20
+ VUINT32_T mm4_state; // mm4 state 0x24
+ VUINT32_T mm4_cntl1; // host control 1 0x28
+ VUINT32_T mm4_cntl2; // host control 2 0x2C
+ VUINT32_T mm4_i_stat; // status of current command 0x30
+ VUINT32_T mm4_i_stat_en; // interrupt status enable 0x34
+ VUINT32_T mm4_i_sig_en; // interrupt signal enable 0x38
+ VUINT32_T mm4_acmd12_er; // auto cmd12 error status 0x3C
+ VUINT32_T mm4_cap1_2; // capabilities 1,2 0x40
+ VUINT32_T mm4_cap3_4; // capabilities 3,4 0x44
+ VUINT32_T mm4_sd_max_current1_2; // max current capabilities 0x48
+ VUINT32_T mm4_sd_max_current3_4; // max current capabilities 0x4C
+ VUINT32_T mm4_force_event; // force event for AutoCMD12 Error Status 0x50
+ VUINT32_T mm4_adma_err_stat; // ADMA Error Status 0x54
+ VUINT32_T mm4_adma_system_address1; // ADMA Address 63:32 0x58
+ VUINT32_T mm4_adma_system_address2; // ADMA Address 32:0
+ VUINT32_T mm4_preset_value_for_init_ds; // 0x60
+ VUINT32_T mm4_preset_value_for_hs_sdr12; // 0x64
+ VUINT32_T mm4_preset_value_for_hs_sdr25_50; // 0x68
+ VUINT32_T mm4_preset_value_for_hs_sdr104_50; // 0x6C
+ VUINT32_T reserved_X1[28]; // reserved fields 0x70
+ VUINT32_T mm4_shared_bus_control; // Shared Bus Control Register 0xE0
+ VUINT32_T reserved_X2[6]; // reserved 0xE4
+ VUINT32_T mm4_sd_slot_int_stat_ctrl_ver; // SD Interrupt Line and Version Support 0xFC
+ VUINT32_T mm4_vid_pid; // SD HOST CTRL Vendor ID/Project ID/version ID Register 0x100
+ VUINT32_T mm4_op_ctrl; // SDHC Opeartion Control register 0x104
+ VUINT32_T mm4_op_ext_reg; // SDHC Operation extend CTRL Register 0x108
+ VUINT32_T mm4_legacy_ctrl_reg; // SDHC LEGACY CTRL Parameters Register 0x10C
+ VUINT32_T mm4_legacy_ceata_reg; // SDHC LEGACY CTRL for CEATA Device Register 0x110
+ VUINT32_T mm4_mmc_ctrl_reg; // SDHC MMC DEVICE CTRL Registers 0x114
+ VUINT32_T mm4_sd_rx_cfg_reg; // Receive Timing Config 0x118
+ VUINT32_T mm4_sd_tx_cfg_reg; // Transmit Timing Config 0x11C
+ VUINT32_T mm4_sd_hwtune_cfg_reg; // SDHC HW TUNING Configuration Register 0x120
+ VUINT32_T mm4_sd_hwtune_cfg2_reg; // SDHC HW TUNING Configuration2 Register 0x124
+ VUINT32_T mm4_sd_roundtrip_timing_reg; // SDHC ROUND TRIP(TRANSIMIT TO RECEIVE) TIMING PARAM Regsiter 0x128
+ VUINT32_T mm4_sd_gpio_cfg_reg; // SDHC GPIO CFG Register 0x12C
+ VUINT32_T mm4_sd_dline_ctrl_reg; // SDHC DELAYLINE Control Register 0x130
+ VUINT32_T mm4_sd_dline_cfg_reg; // SDHC DELAYLINE CFG Register 0x134
+} MM4_SDMMC_T, *P_MM4_SDMMC_T;
+
+/*************************** Register Masks ********************************/
+/**************************************************************************/
+// ******************** MM4_BLK_CNTL **********************************
+typedef struct
+{
+ unsigned int xfr_blksz : 12; // Transfer Block Size
+ unsigned int dma_bufsz : 4; // Host DMA buffer size
+ unsigned int blk_cnt : 16; // Block Count for Current Transfer
+} MM4_BLK_CNTL, *P_MM4_BLK_CNTL;
+
+#define MM4_512_HOST_DMA_BDRY 0x7
+
+// ********************* MM4_CMD_XFRMD ********************************
+typedef struct
+{
+ unsigned int dma_en : 1; // DMA enable 0
+ unsigned int blkcnten : 1; // Block Count Enable 1
+ unsigned int autocmd12 : 1; // AutoCMD12 2
+ unsigned int autocmd23 : 1; // AutoCMD23 3
+ unsigned int dxfrdir : 1; // Data Transfer Direction Select 4
+ unsigned int ms_blksel : 1; // Multi Block Select 5
+ unsigned int reserved2 : 10; // 6
+ unsigned int res_type : 2; // Response Type 16
+ unsigned int reserved3 : 1; // 18
+ unsigned int crcchken : 1; // CRC check enable 19
+ unsigned int idxchken : 1; // Command Index Check Enable 20
+ unsigned int dpsel : 1; // Data present select 21
+ unsigned int cmd_type : 2; // Cmd Type 22
+ unsigned int cmd_idx : 6; // Cmd Index 24
+ unsigned int reserved4 : 2; // 30
+} MM4_CMD_XFRMD, *P_MM4_CMD_XFRMD;
+
+typedef union
+{
+ MM4_CMD_XFRMD mm4_cmd_xfrmd_bits;
+ UINT_T mm4_cmd_xfrmd_value;
+} MM4_CMD_XFRMD_UNION, *P_MM4_CMD_XFRMD_UNION;
+
+#define NO_ARGUMENT 0x0
+#define MM4_CMD_TYPE_NORMAL 0
+#define MM4_CMD_TYPE_SUSPEND 1
+#define MM4_CMD_TYPE_RESUME 2
+#define MM4_CMD_TYPE_ABORT 3
+#define MM4_CMD_DATA 1
+#define MM4_CMD_NODATA 0
+#define MM4_NO_RES 0
+#define MM4_136_RES 1
+#define MM4_48_RES 2
+#define MM4_48_RES_WITH_BUSY 3
+
+// this information will be included in the response type argument of relevant apis.
+// it will occupy bits 15:8 of the RespType parameter.
+#define MM4_RT_MASK 0x7f00
+#define MM4_RT_NONE 0x0000
+#define MM4_RT_R1 0x0100
+#define MM4_RT_R2 0x0200
+#define MM4_RT_R3 0x0300
+#define MM4_RT_R4 0x0400
+#define MM4_RT_R5 0x0500
+#define MM4_RT_R6 0x0600
+#define MM4_RT_R7 0x0700 // sd card interface condition
+
+#define MM4_RT_BUSYMASK 0x8000
+#define MM4_RT_BUSY 0x8000
+
+
+#define MM4_MULTI_BLOCK_TRAN 1
+#define MM4_SINGLE_BLOCK_TRAN 0
+#define MM4_HOST_TO_CARD_DATA 0
+#define MM4_CARD_TO_HOST_DATA 1
+
+// ********************* MM4_STATE ********************************
+typedef struct
+{
+ unsigned int ccmdinhbt : 1;
+ unsigned int dcmdinhbt : 1;
+ unsigned int datactv : 1;
+ unsigned int retuning_req : 1;
+ unsigned int reserved0 : 4;
+ unsigned int wractv : 1;
+ unsigned int rdactv : 1;
+ unsigned int bufwren : 1;
+ unsigned int bufrden : 1;
+ unsigned int reserved1 : 4;
+ unsigned int cdinstd : 1;
+ unsigned int cdstbl : 1;
+ unsigned int cddetlvl : 1;
+ unsigned int wpswlvl : 1;
+ unsigned int lwrdatlvl : 4;
+ unsigned int cmdlvl : 1;
+ unsigned int uprdatlvl : 4;
+ unsigned int reserved2 : 3;
+} MM4_STATE, *P_MM4_STATE;
+
+typedef union
+{
+ MM4_STATE mm4_state_bits;
+ UINT_T mm4_state_value;
+} MM4_STATE_UNION, *P_MM4_STATE_UNION;
+
+// ********************* MM4_CNTL1 ********************************
+typedef struct
+{
+ unsigned int ledcntl : 1; // 0
+ unsigned int datawidth : 1; // 1
+ unsigned int hispeed : 1; // 2
+ unsigned int dma_sel : 2; // 3
+ unsigned int ex_data_width : 1; // 5
+ unsigned int card_det_l : 1; // 6
+ unsigned int card_det_s : 1; // 7
+ unsigned int buspwr : 1; // 8
+ unsigned int vltgsel : 3; // 9
+ unsigned int reserved2 : 4; // 12
+ unsigned int bgreqstp : 1; // 16
+ unsigned int contreq : 1;
+ unsigned int rdwcntl : 1;
+ unsigned int bgirqen : 1;
+ unsigned int reserved3 : 12;
+} MM4_CNTL1, *P_MM4_CNTL1;
+
+typedef union
+{
+ MM4_CNTL1 mm4_cntl1_bits;
+ UINT_T mm4_cntl1_value;
+} MM4_CNTL1_UNION, *P_MM4_CNTL1_UNION;
+
+#define MM4_VLTGSEL_1_8 0x5
+#define MM4_VLTGSEL_3_0 0x6
+#define MM4_VLTGSEL_3_3 0x7
+
+// ********************* MM4_CNTL2 ********************************
+typedef struct
+{
+ unsigned int inter_clk_en : 1; // Internal Clock Enable
+ unsigned int inter_clk_stable : 1; // Internal Clock Stable
+ unsigned int mm4clken : 1; // Clock Enable
+ unsigned int reserved1 : 2; // bits 3,4
+ unsigned int clk_gen_sel : 1; // bit 5
+ unsigned int sd_freq_sel_hi : 2; // 6
+ unsigned int sd_freq_sel_lo : 8; // 8
+ unsigned int dtocntr : 4; // bit 0 Data Timeout Counter Value
+ unsigned int reserved2 : 4; //
+ unsigned int mswrst : 1; // bit 8 Software Reset for All
+ unsigned int cmdswrst : 1; // bit 9 Software Reset for MM4CMD Line
+ unsigned int datswrst : 1; // bit 10 Software Reset for MM4DATx Lines
+ unsigned int reserved3 : 5; // bits 11-15
+} MM4_CNTL2, *P_MM4_CNTL2;
+
+// ********************* MM4_HOST_CNTL2 ********************************
+typedef struct
+{
+ unsigned int reserved : 16; // bit 0~15
+ unsigned int uhs_mode_sel : 3; // bit 16-18: UHS Mode Select
+ unsigned int v1_8_sig_en : 1; // 1.8V Signaling Enable
+ unsigned int dri_strength_sel : 2; // Driver Strength Select
+ unsigned int execute_tunning : 1; // Execute Tuning
+ unsigned int samp_clk_sel : 1; // Sampling Clock Select
+ unsigned int reserved1 : 6; // bits 8~13
+ unsigned int async_int_en : 1; // Asynchronous Interrupt Enable
+ unsigned int preset_val_en : 1; // Preset Value Enable
+} MM4_HOST_CNTL2, *P_MM4_HOST_CNTL2;
+
+#define SDH_BUS_SPEED_DEFAULT (1<<0)
+#define SDH_BUS_SPEED_SDR_CLK_50M (1<<1)
+#define SDH_BUS_SPEED_SDR_CLK_100M (1<<2)
+#define SDH_BUS_SPEED_SDR_CLK_208M (1<<3)
+#define SDH_BUS_SPEED_DDR_CLK_50M (1<<4)
+
+#define CLOCK_27_MULT 0xE
+
+#if BASE_CLOCK_208MHZ
+//Clock divider settings for 208Mhz bus clock
+#define MM4CLOCK200KHZRATE 0x1FF // Set also additional SD_FREQ_HI bit. So SD_FREQ_SEL = 0x1FF = 511 * 2 = 1022 (clock divider)
+#define MM4CLOCK50MHZRATE 2
+#define MM4CLOCK25MHZRATE 4
+#define MM4CLOCK12_5MHZRATE 8
+#define MM4CLOCK6MHZRATE 16
+#else
+//Clock divider settings for 104Mhz bus clock
+#define MM4CLOCK200KHZRATE 0xFF // Set also additional SD_FREQ_HI bit. So SD_FREQ_SEL = 0x1FF = 511 * 2 = 1022 (clock divider)
+#define MM4CLOCK50MHZRATE 1
+#define MM4CLOCK25MHZRATE 2
+#define MM4CLOCK12_5MHZRATE 4
+#define MM4CLOCK6MHZRATE 8
+#endif
+
+typedef union
+{
+ //Coverity - declare struct volatile to eliminate infinite loop defect
+ volatile MM4_CNTL2 mm4_cntl2_bits;
+ VUINT_T mm4_cntl2_value;
+} MM4_CNTL2_UNION, *P_MM4_CNTL2_UNION;
+
+typedef union
+{
+ //Coverity - declare struct volatile to eliminate infinite loop defect
+ volatile MM4_HOST_CNTL2 mm4_host_cntl2_bits;
+ VUINT_T mm4_host_cntl2_value;
+} MM4_HOST_CNTL2_UNION, *P_MM4_HOST_CNTL2_UNION;
+
+// ********************* MM4_I_STAT, MM4_I_STAT_EN, MM4_I_SIGN_EN ************
+typedef struct
+{
+ unsigned int cmdcomp : 1; //0
+ unsigned int xfrcomp : 1; //1
+ unsigned int bgevnt : 1; //2
+ unsigned int dmaint : 1; //3
+ unsigned int bufwrrdy : 1; //4
+ unsigned int bufrdrdy : 1; //5
+ unsigned int cdins : 1; //6
+ unsigned int cdrem : 1; //7
+ unsigned int cdint : 1; //8
+ unsigned int int_a : 1; //9
+ unsigned int int_b : 1; //10
+ unsigned int int_c : 1; //11
+ unsigned int retuninig_int : 1; //12
+ unsigned int reserved0 : 2; //13
+ unsigned int errint : 1; //15
+ unsigned int ctoerr : 1; //16
+ unsigned int ccrcerr : 1; //17
+ unsigned int cenderr : 1; //18
+ unsigned int cidxerr : 1; //19
+ unsigned int dtoerr : 1; //20
+ unsigned int dcrcerr : 1; //21
+ unsigned int denderr : 1; //22
+ unsigned int ilmterr : 1; //23
+ unsigned int ac12err : 1; //24
+ unsigned int admaerr : 1; //25
+ unsigned int tune_err : 1; //26
+ unsigned int reserved1 : 1; //27
+ unsigned int spierr : 1; //28
+ unsigned int axi_resp_err : 1; //29
+ unsigned int cpl_tout_err : 1; //30
+ unsigned int crc_stat_err : 1; //31
+} MM4_I_STAT, *P_MM4_I_STAT, MM4_I_STAT_EN, *P_MM4_I_STAT_EN, MM4_I_SIGN_EN, *P_MM4_I_SIGN_EN;
+
+#define DISABLE_INTS 0
+#define ENABLE_INTS 1
+
+typedef union
+{
+ MM4_I_STAT mm4_i_stat_bits;
+ UINT_T mm4_i_stat_value;
+} MM4_I_STAT_UNION, *P_MM4_I_STAT_UNION;
+//#define CLEAR_INTS_MASK 0xFFFF7FFD
+#define CLEAR_INTS_MASK 0xFFFF7FCD
+
+
+// ********************* MM4_ACMD12_ER *******************************************
+typedef struct
+{
+ unsigned int ac12nexe : 1; // 0
+ unsigned int ac12toer : 1; // 1
+ unsigned int ac12crcer : 1; // 2
+ unsigned int ac12ender : 1; // 3
+ unsigned int ac12idxer : 1; // 4
+ unsigned int reserved0 : 2; // 5
+ unsigned int cmdnisud : 1; // 7
+ unsigned int reserved1 : 8; // 8
+ unsigned int uhs_mode_sel : 3; // 16
+ unsigned int sgh_v18_en : 1; // 19
+ unsigned int drv_strength_sel : 2; // 20
+ unsigned int exe_tuning : 1; // 22
+ unsigned int sampling_clk_sel : 1; // 23
+ unsigned int reserved2 : 6; // 24
+ unsigned int async_int_en : 1; // 30
+ unsigned int pre_val_en : 1; // 31
+} MM4_ACMD12_ER, *P_MM4_ACMD12_ER;
+
+// ********************* MM4_CAP0 *******************************************
+typedef struct
+{
+ unsigned int toclkfreq : 6;
+ unsigned int reserved0 : 1;
+ unsigned int toclkunit : 1;
+ unsigned int bsclkfreq : 8;
+ unsigned int max_blk_len : 2;
+ unsigned int ex_data_width_support : 1;
+ unsigned int reserved1 : 1;
+ unsigned int adma2_support : 1;
+ unsigned int adma1_support : 1;
+ unsigned int hi_speed_support : 1;
+ unsigned int sdma_support : 1;
+ unsigned int sus_res_support : 1;
+ unsigned int vlg_33_support : 1;
+ unsigned int vlg_30_support : 1;
+ unsigned int vlg_18_support : 1;
+ unsigned int reserved2 : 1;
+ unsigned int sys_bus_64_support : 1;
+ unsigned int async_int_support : 1;
+ unsigned int cfg_slot_type : 1;
+} MM4_CAP1_2, *P_MM4_CAP1_2;
+
+typedef union
+{
+ MM4_CAP1_2 mm4_cap1_2_bits;
+ UINT_T mm4_cap1_2_value;
+} MM4_CAP1_2_UNION, *P_MM4_CAP1_2_UNION;
+
+// ********************* MM4_SD_MAX_CURRENT1_2 *******************************************
+typedef struct
+{
+ unsigned int v3_3vmaxi : 8;
+ unsigned int v3_0vmaxi : 8;
+ unsigned int v1_8vmaxi : 8;
+ unsigned int reserved0 : 8;
+} MM4_SD_MAX_CURRENT1_2, *P_MM4_SD_MAX_CURRENT1_2;
+
+typedef union
+{
+ MM4_SD_MAX_CURRENT1_2 mm4_sd_max_current1_2_bits;
+ UINT_T mm4_sd_max_current1_2_value;
+} MM4_SD_MAX_CURRENT1_2_UNION, *P_MM4_SD_MAX_CURRENT1_2_UNION;
+
+// ********************* MM4_SD_LEGACY_CTRL_REG *******************************************
+typedef struct
+{
+ UINT pio_rdfc : 1; // Bit 0
+ UINT async_io_en : 1; // Bit 1
+ UINT inand_sel : 1; // Bit 2
+ UINT boot_ack : 1; // Bit 3
+ UINT squ_empty_check : 1; // Bit 4
+ UINT squ_full_check : 1; // Bit 5
+ UINT gen_pad_clk_on : 1; // Bit 6
+ UINT reserved0 : 1; // Bit 7
+ UINT spi_en : 1; // Bit 8
+ UINT spi_error_token : 5; // Bits 9-13
+ UINT reserved1 : 10; // Bits 14-23
+ UINT gen_pad_clk_cnt : 8; // Bits 24-31
+} MM4_SD_LEGACY_CTRL_REG, *P_MM4_SD_LEGACY_CTRL_REG;
+
+typedef union
+{
+ MM4_SD_LEGACY_CTRL_REG MM4_SD_LEGACY_CTRL_REG_bits;
+ UINT_T MM4_SD_LEGACY_CTRL_REG_value;
+} MM4_SD_LEGACY_CTRL_REG_UNION, *P_MM4_SD_LEGACY_CTRL_REG_UNION;
+
+#define DISABLE_PAD_SD_CLOCK_GATING_BIT (1 << 10) // 1 means disable dynamic clock gating.
+#define ENABLE_DYNAMIC_CLOCK_GATING_MASK (~(DISABLE_PAD_SD_CLOCK_GATING_BIT))
+
+// ********************* MM4_CTRL_REG *******************************************
+typedef struct
+{
+ UINT misc_int_int_en : 1; // Bit 0
+ UINT misc_int_en : 1; // Bit 1
+ UINT misc_int : 1; // Bit 2
+ UINT reserved1 : 1; // Bit 3
+ UINT cpl_complete_int_en : 1; // Bit 4
+ UINT cpl_complete_en : 1; // Bit 5
+ UINT cpl_complete : 1; // Bit 6
+ UINT reserved2 : 1; // Bit 7
+ UINT enhance_strobe_en : 1; // Bit 8
+ UINT mmc_hs400 : 1; // Bit 9
+ UINT mmc_hs200 : 1; // Bit 10
+ UINT mmc_resetn : 1; // Bit 11
+ UINT mmc_card : 1; // Bit 12
+ UINT reserved3 : 11; // Bit 13
+ UINT data_level : 8; // Bit 24
+} MM4_CTRL_REG, *P_MM4_CTRL_REG;
+
+typedef union
+{
+ MM4_CTRL_REG MM4_CTRL_REG_bits;
+ UINT_T MM4_CTRL_REG_value;
+} MM4_CTRL_REG_UNION, *PMM4_CTRL_REG_UNION;
+
+typedef struct
+{
+ unsigned int adma_state : 2;
+ unsigned int adma_len_err : 1;
+ unsigned int Rsvd : 29;
+} MM4_ADMA_ERROR_STAT, *P_MM4_ADMA_ERROR_STAT;
+
+typedef struct
+{
+ UINT txholddly0 : 10; //Bits 0-9
+ UINT rsvd : 6; //Bits 10-15
+ UINT txholddly1 : 10; //Bits 16-25
+ UINT rsvd1 : 3; //Bits 26-28
+ UINT tx_dline_src_sel : 1; //Bit 29
+ UINT tx_int_clk : 1; //Bit 30
+ UINT tx_mux_sel : 1; //Bit 31
+}MM4_TX_CFG, *P_MM4_TX_CFG;
+
+#define DDR_TX_DELAY 0x55
+#define TX_MUX_SEL (0x1<<31)
+#define TX_SEL_BUS_CLK (0x1<<30)
+#define TX_DELAY1_SHIFT 24
+#define TX_DELAY_MASK 0xFF
+
+typedef union
+{
+ MM4_TX_CFG MM4_TX_CFG_bits;
+ UINT_T MM4_TX_CFG_value;
+}MM4_TX_CFG_UNION, *P_MM4_TX_CFG_UNION;
+
+#define DDR_RX_DELAY 0x55
+#define RX_SDCLK_DELAY_SHIFT 16
+#define RX_SDCLK_DELAY_MASK 0xFF
+#define RX_SDCLK_SEL1_MASK 0x3
+#define RX_SDCLK_SEL1_SHIFT 2
+
+typedef struct
+{
+ unsigned int rsvd2 : 4;
+ unsigned int tuning_dly_inc: 10;
+ unsigned int sdclk_delay : 10;
+ unsigned int rsvd1 : 4;
+ unsigned int sdclk_sel1 : 2;
+ unsigned int sdclk_sel0 : 2;
+}MM4_RX_CFG, *P_MM4_RX_CFG;
+
+typedef union
+{
+ MM4_RX_CFG MM4_RX_CFG_bits;
+ UINT_T MM4_RX_CFG_value;
+}MM4_RX_CFG_UNION, *P_MM4_RX_CFG_UNION;
+
+typedef struct
+{
+ unsigned int dline_pu : 1;
+ unsigned int rsvd1 : 15;
+ unsigned int rx_dline_code : 8;
+ unsigned int tx_dline_code : 8;
+}MM4_SD_DLINE_CTRL, *P_MM4_SD_DLINE_CTRL;
+
+typedef union
+{
+ MM4_SD_DLINE_CTRL MM4_SD_DLINE_CTRL_bits;
+ UINT_T MM4_SD_DLINE_CTRL_value;
+}MM4_SD_DLINE_CTRL_UNION, *P_MM4_SD_DLINE_CTRL_UNION;
+
+typedef struct
+{
+ unsigned int rx_dline_reg : 8;
+ unsigned int rx_dline_gain : 1;
+ unsigned int rsvd1 : 7;
+ unsigned int tx_dline_reg : 8;
+ unsigned int tx_dline_gain : 1;
+ unsigned int rsvd2 : 7;
+}MM4_SD_DLINE_CFG, *P_MM4_SD_DLINE_CFG;
+
+typedef union
+{
+ MM4_SD_DLINE_CFG MM4_SD_DLINE_CFG_bits;
+ UINT_T MM4_SD_DLINE_CFG_value;
+}MM4_SD_DLINE_CFG_UNION, *P_MM4_SD_DLINE_CFG_UNION;
+
+/*********** End MM4 Register Def's **************************************/
+// response types
+enum {
+ MMC_RESPONSE_NONE = 1L<<8,
+ MMC_RESPONSE_R1 = 2L<<8,
+ MMC_RESPONSE_R1B = 3L<<8,
+ MMC_RESPONSE_R2 = 4L<<8,
+ MMC_RESPONSE_R3 = 5L<<8,
+ MMC_RESPONSE_R4 = 6L<<8,
+ MMC_RESPONSE_R5 = 7L<<8,
+ MMC_RESPONSE_R5B = 8L<<8,
+ MMC_RESPONSE_R6 = 9L<<8,
+ MMC_RESPONSE_R7 = 0xAL<<8,
+ MMC_RESPONSE_MASK = 0x0000FF00
+};
+
+#define SD_OCR_VOLTAGE_3_3_TO_3_6 0xE00000
+#define SD_OCR_VOLTAGE_1_8_TO_3_3 0x1F8000
+#define SD_OCR_VOLTAGE_1_8 0x80
+#define MMC_OCR_VOLTAGE_ALL 0xFF8000
+#define MM4FIFOWORDSIZE 0x80
+#define MMC_RESPONSE_R1B_TIMEOUT 0x100
+
+// device context for MMC API, containing anything needed to operate on
+// this API. It is always first parameter for all APIs.
+typedef struct
+{
+ P_MM4_SDMMC_T pMMC4Reg; // MMC1 register base
+} MM4_SDMMC_CONTEXT_T, *P_MM4_SDMMC_CONTEXT_T;
+
+//////////////////////ADMA DESCRIPTOR related////////////////////////////////
+//max no. of blocks transferrable by an ADMA descriptor
+#define MAX_TRANS_BLKS_ADMA_DESC 127
+
+//Max no of ADMA descriptors that define the max size of chunk of an image
+#define NO_ADMA_TX_DESCS 260 // 16MB / 127 / 512B = 258
+
+
+typedef enum
+{
+ INVALID_DESC = 0,
+ VALID_DESC = 1,
+}DESC_VAL_INVAL;
+
+typedef enum
+{
+ NOT_LAST_DESC = 0,
+ LAST_DESC = 1,
+}END_DESC;
+
+typedef enum
+{
+ NO_DMA_INT = 0,
+ DMA_INT = 1,
+}DMA_INT_EN;
+
+typedef enum
+{
+ NO_OP = 0,
+ RSVD = 1,
+ TRANSFER = 2,
+ LINK = 3,
+}ATTRIBUTES;
+
+typedef struct
+{
+ unsigned int desc_val_inval :1;
+ unsigned int end_desc :1;
+ unsigned int dma_int_en :1;
+ unsigned int Rsvd0 :1;
+ unsigned int attr :2;
+ unsigned int Rsvd :10;
+ unsigned int Length :16;
+ unsigned int Address :32;
+} ADMA_DESCRIPTOR, *P_ADMA_DESCRIPTOR;
+//////////////////////////////ADMA////////////////////////////////
+
+#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
+ /* DDR mode @1.8V or 3V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
+ /* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_200_1_8V (1<<4) /* Card can run at 200MHz */
+ /* SDR mode @1.8V I/O */
+#define EXT_CSD_CARD_TYPE_SDR_200_1_2V (1<<5) /* Card can run at 200MHz */
+ /* SDR mode @1.2V I/O */
+
+typedef enum
+{
+ SDR_1 = 0, // 1 bit data bus
+ SDR_4 = 1, // 4 bit data bus
+ SDR_8 = 2, // 8 bit data bus
+ DDR_4 = 5, // 4 bit data bus (dual data rate)
+ DDR_8 = 6, // 8 bit data bus (dual data rate)
+}BUS_Width;
+
+//Function Prototypes
+void MMC4StopInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4StartInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4StartBusClock(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4StopBusClock (P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SetBusRate(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T rate);
+void MMC4SelectUHSMode(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T mode);
+void MMC4SetTXIntCLKEnable(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SetTXConfig(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SetRXConfig(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4EnableDisableIntSources(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T Desire);
+void MMC4SetDataTimeout(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T CounterValue);
+void MMC4CMDSWReset(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4DataSWReset(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4FullSWReset(P_MM4_SDMMC_CONTEXT_T pContext);
+void MMC4SendDataCommand(P_MM4_SDMMC_CONTEXT_T pContext,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType,
+ UINT_T DMAMode,
+ UINT_T AutoCmd23En);
+
+void MMC4SendDataCommandNoAuto12(P_MM4_SDMMC_CONTEXT_T pContext,
+ UINT_T Cmd,
+ UINT_T Argument,
+ UINT_T BlockType,
+ UINT_T DataDirection,
+ UINT_T ResType,
+ UINT_T DMAMode,
+ UINT_T Blk_Cnt_Enable);
+
+void MMC4SendSetupCommand(P_MM4_SDMMC_CONTEXT_T pContext,
+ UINT_T Cmd,
+ UINT_T CmdType,
+ UINT_T Argument,
+ UINT_T ResType);
+#endif