blob: 860a42e99240e4990febbc2e86035f57255715bf [file] [log] [blame]
/******************************************************************************
*
* (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;
}