blob: a13612c035aba4195ce944c965d2cf0de2e3dc47 [file] [log] [blame]
/*
* NDA AND NEED-TO-KNOW REQUIRED
*
* Copyright © 2013-2018 Synaptics Incorporated. All rights reserved.
*
* This file contains information that is proprietary to Synaptics
* Incorporated ("Synaptics"). The holder of this file shall treat all
* information contained herein as confidential, shall use the
* information only for its intended purpose, and shall not duplicate,
* disclose, or disseminate any of this information in any manner
* unless Synaptics has otherwise provided express, written
* permission.
*
* Use of the materials may require a license of intellectual property
* from a third party or from Synaptics. This file conveys no express
* or implied licenses to any intellectual property rights belonging
* to Synaptics.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND
* SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY
* INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE
* OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND
* BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF
* COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT
* DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY
* TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS.
*/
/******************************************************************************
**
** FILENAME: emmcHC.c
**
** PURPOSE: MMC and SD specific low level controller routines for the MM4 controller
**
**
**
**
******************************************************************************/
#include "com_type.h"
#include "emmcHC.h"
#include "debug.h"
#include "io.h"
//#define EMMC_DEBUG
#ifdef EMMC_DEBUG
#define EMMC_PRN(PRN_LEVEL,fmt, args...) dbg_printf(PRN_LEVEL, fmt, ## args)
#else
#define EMMC_PRN(PRN_LEVEL,fmt, args...)
#endif
/******************************************************************************
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
*******************************************************************************/
#if 0
void MMC4ModeSelect(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T sd_mode)
{
P_MM4_CNTL1 pMM4_CNTL1;
MM4_CNTL1_UNION MM4_cntl1;
pMM4_CNTL1 = (P_MM4_CNTL1)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl1);
MM4_cntl1.mm4_cntl1_value = *(VUINT_T *)pMM4_CNTL1;
MM4_cntl1.mm4_cntl1_bits.eightbitmd = sd_mode;
*(VUINT_T *)pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_value;
return;
}
#endif
void EMMCHC_HighSpeedSelect(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T hs_mode)
{
P_MM4_CNTL1 pMM4_CNTL1;
MM4_CNTL1_UNION MM4_cntl1;
pMM4_CNTL1 = (P_MM4_CNTL1)((uintptr_t) &pContext->pMMC4Reg->mm4_cntl1);
MM4_cntl1.mm4_cntl1_value = *(VUINT_T *)pMM4_CNTL1;
MM4_cntl1.mm4_cntl1_bits.hispeed = hs_mode & 0x1;
*(VUINT_T *)pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_value;
return;
}
/*******************************************************************
* BG6CD only support HS-SDR and HS-DDR mode
* set emmc mode, mode0: high speed SDR, mode1:high speed DDR
********************************************************************/
void EMMCHC_host_mode(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T uhs_mode)
{
volatile P_MM4_ACMD12_ER pMM4_crtl2;
UINT32_T MM4_crtl2;
MM4_crtl2 = pContext->pMMC4Reg->mm4_acmd12_er;
pMM4_crtl2 = (volatile P_MM4_ACMD12_ER)&MM4_crtl2;
if(uhs_mode == 0)
pMM4_crtl2->uhs_mode_sel = 1; //HS-SDR
else if(uhs_mode == 1)
pMM4_crtl2->uhs_mode_sel = 4; //HS DDR
else if(uhs_mode == 2)
pMM4_crtl2->uhs_mode_sel = 3; //HS200
else if(uhs_mode == 3)
pMM4_crtl2->uhs_mode_sel = 7; //HS400
pContext->pMMC4Reg->mm4_acmd12_er = MM4_crtl2;
}
#if 0
void MMC4BusWidthSelect(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T sd_4bit)
{
P_MM4_CNTL1 pMM4_CNTL1;
MM4_CNTL1_UNION MM4_cntl1;
pMM4_CNTL1 = (P_MM4_CNTL1)((VUINT32_T) &pContext->pMMC4Reg->mm4_cntl1);
MM4_cntl1.mm4_cntl1_value = *(VUINT_T *)pMM4_CNTL1;
MM4_cntl1.mm4_cntl1_bits.datawidth = sd_4bit;
*(VUINT_T *)pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_value;
return;
}
#endif
#if 1
void EMMCHC_DmaSelect(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T select)
{
P_MM4_CNTL1 pMM4_CNTL1;
MM4_CNTL1_UNION MM4_cntl1;
pMM4_CNTL1 = (P_MM4_CNTL1)((uintptr_t) &pContext->pMMC4Reg->mm4_cntl1);
MM4_cntl1.mm4_cntl1_value = *(VUINT_T *)pMM4_CNTL1;
MM4_cntl1.mm4_cntl1_bits.dma_sel = select & 0x3;
*(VUINT_T *)pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_value;
return;
}
#endif
/******************************************************************************
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 EMMCHC_StartInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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
delay_ms(10);
do
{
MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
delay_us(1);
} 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 EMMCHC_StopInternalBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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 EMMCHC_StartBusClock(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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 EMMCHC_StopBusClock (P_MM4_SDMMC_CONTEXT_T pContext)
{
//UINT32_T retry_count = 0xff;
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
// Request bus clock stop
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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;
}
extern void EMMC_PhyInitialization(void);
/******************************************************************************
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 EMMCHC_SetBusRate(P_MM4_SDMMC_CONTEXT_T pContext, UINT_T rate)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
unsigned int timeout = 0;
EMMC_PRN(PRN_INFO,"Start to setup freq divide rate = %d\n", rate);
// Request bus clock stop, set rate, start clock.
//EMMCHC_StopBusClock(pContext);
// BG6CD/NIUE design, internal clock must be off to change clock divider
// and on again to sync to target clock.
//EMMCHC_StopInternalBusClock(pContext);
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_t) &pContext->pMMC4Reg->mm4_cntl2);
MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
MM4_cntl2.mm4_cntl2_bits.mm4clken = 0;
MM4_cntl2.mm4_cntl2_bits.inter_clk_en = 0;
*(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
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.inter_clk_en = 1;
*(VUINT_T *)pMM4_CNTL2 = MM4_cntl2.mm4_cntl2_value;
// Wait for clock to become stable. * TBD * Add timeout
/* max 20ms */
timeout = 20;
do {
if(timeout == 0) {
dbg_printf(PRN_ERR, "%s: Internal clock never stabilised.\n",
__func__);
return;
}
delay_ms(1);
timeout--;
MM4_cntl2.mm4_cntl2_value = *(VUINT_T *)pMM4_CNTL2;
} while (!MM4_cntl2.mm4_cntl2_bits.inter_clk_stable);
//--------------------------------------------------
//EMMCHC_StartInternalBusClock(pContext);
EMMC_PRN(PRN_INFO,"freq divide rate = %d\n", rate);
EMMC_PhyInitialization();
//----------------------------------------------
EMMCHC_StartBusClock(pContext);
return;
}
/******************************************************************************
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 EMMCHC_EnableDisableIntSources(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)((uintptr_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.bufwrrdy = Desire;
MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire;
// KT added for card detection
MM4_i_stat.mm4_i_stat_bits.cdins = Desire;
MM4_i_stat.mm4_i_stat_bits.cdrem = Desire;
//
MM4_i_stat.mm4_i_stat_bits.cdint = Desire;
MM4_i_stat.mm4_i_stat_bits.errint = Desire;
MM4_i_stat.mm4_i_stat_bits.ctoerr = Desire; // KT added
MM4_i_stat.mm4_i_stat_bits.ccrcerr= Desire; // KT added
MM4_i_stat.mm4_i_stat_bits.cenderr = Desire;
MM4_i_stat.mm4_i_stat_bits.cidxerr = 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;
#if SDIO_DMA
MM4_i_stat.mm4_i_stat_bits.dmaint = Desire; //KT added
MM4_i_stat.mm4_i_stat_bits.ac12err = Desire; //KT added auto CMD12 error
#endif
// 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)((uintptr_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.bufwrrdy = Desire;
MM4_i_stat.mm4_i_stat_bits.bufrdrdy = Desire;
// KT added for card detection
MM4_i_stat.mm4_i_stat_bits.cdins = Desire;
MM4_i_stat.mm4_i_stat_bits.cdrem = Desire;
//
#ifndef CONFIG_FPGA
MM4_i_stat.mm4_i_stat_bits.cdint = Desire;// --> Satya ; KT removed the workaround
#endif
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.ccrcerr= Desire; // KT added
MM4_i_stat.mm4_i_stat_bits.cenderr = Desire; //
MM4_i_stat.mm4_i_stat_bits.cidxerr = 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;
#if SDIO_DMA
MM4_i_stat.mm4_i_stat_bits.dmaint = Desire; //KT added
MM4_i_stat.mm4_i_stat_bits.ac12err = Desire; //KT added auto CMD12 error
#endif
// Write it out
*(VUINT_T*)pMM4_I_STAT = MM4_i_stat.mm4_i_stat_value;
EMMC_PRN(PRN_INFO, "\n MM4_i_stat.mm4_i_stat_value is 0x%x\n", 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 EMMCHC_SetDataTimeout(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)((uintptr_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 EMMCHC_DataSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
// Set the register
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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 EMMCHC_FullSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
// Set the register
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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:
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 EMMCHC_CMDSWReset(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL2 pMM4_CNTL2;
MM4_CNTL2_UNION MM4_cntl2;
// Set the register
pMM4_CNTL2 = (P_MM4_CNTL2)((uintptr_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;
}
/**************************************************************************/
void EMMCHC_StopAtBlockGap(P_MM4_SDMMC_CONTEXT_T pContext)
{
P_MM4_CNTL1 pMM4_CNTL1;
MM4_CNTL1_UNION MM4_cntl1;
// Set the register
pMM4_CNTL1 = (P_MM4_CNTL1)((uintptr_t) &pContext->pMMC4Reg->mm4_cntl1);
MM4_cntl1.mm4_cntl1_value = *(VUINT_T *)pMM4_CNTL1;
MM4_cntl1.mm4_cntl1_bits.bgreqstp = 1;
// Write Back
*(VUINT_T *)pMM4_CNTL1 = MM4_cntl1.mm4_cntl1_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 EMMCHC_SendDataCommand(P_MM4_SDMMC_CONTEXT_T pContext,
UINT_T Cmd,
UINT_T Argument,
UINT_T BlockType,
UINT_T DataDirection,
UINT_T ResType)
{
MM4_CMD_XFRMD_UNION xfrmd;
P_MM4_STATE pMM4_STATE;
// Make sure the controller is ready to accept the next command
pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
while (pMM4_STATE->dcmdinhbt)
{;} // Wait.
// Set the Argument Field
pContext->pMMC4Reg->mm4_arg = Argument;
#if 0
// 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 = TRUE;
//xfrmd.mm4_cmd_xfrmd_bits.blkcbten = TRUE;
xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = FALSE;
xfrmd.mm4_cmd_xfrmd_bits.blkcbten = FALSE;
#endif
// 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;
xfrmd.mm4_cmd_xfrmd_bits.blkcbten = TRUE;
#if SDIO_DMA
// enable DMA
xfrmd.mm4_cmd_xfrmd_bits.dma_en = 1;
#if 1
if (Cmd==25 || Cmd==18 )
{ // multiple blocks with Auto STOP command
xfrmd.mm4_cmd_xfrmd_bits.autocmd12 = TRUE;
// xfrmd.mm4_cmd_xfrmd_bits.blkcbten = TRUE;
// Stop at Block Gap request; set bit 0 of 2Ah
//MMC4StopAtBlockGap(pContext);
}
#endif
#endif
EMMC_PRN(PRN_DBG,"\n Sending command: xfrmd = 0x%x ",xfrmd.mm4_cmd_xfrmd_value);
// 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 EMMCHC_SendDataCommandNoAuto12(P_MM4_SDMMC_CONTEXT_T pContext,
UINT_T Cmd,
UINT_T Argument,
UINT_T BlockType,
UINT_T DataDirection,
UINT_T ResType)
{
MM4_CMD_XFRMD_UNION xfrmd;
P_MM4_STATE pMM4_STATE;
// Make sure the controller is ready to accept the next command
pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
while (pMM4_STATE->dcmdinhbt)
{;} // Wait.
// 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;
xfrmd.mm4_cmd_xfrmd_bits.blkcbten = TRUE;
#if SDIO_DMA
xfrmd.mm4_cmd_xfrmd_bits.dma_en = TRUE;
#endif
EMMC_PRN(PRN_INFO,"\n %s, Sending command: xfrmd = 0x%x ",__func__, xfrmd.mm4_cmd_xfrmd_value);
// 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 EMMCHC_SendSetupCommand(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;
volatile uint32_t i = 0;
// Make sure the controller is ready to accept the next command
pMM4_STATE = (P_MM4_STATE) &pContext->pMMC4Reg->mm4_state;
while (pMM4_STATE->ccmdinhbt)
{i++; if(i > 100) { break;} delay_ms(10);} // Wait.
// 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;
if((ResType & 0x0000ff00) == MM4_RT_R3)
{
xfrmd.mm4_cmd_xfrmd_bits.idxchken = FALSE;
xfrmd.mm4_cmd_xfrmd_bits.crcchken = FALSE;
}
else if((ResType & 0x0000ff00) == MM4_RT_R2)
{
xfrmd.mm4_cmd_xfrmd_bits.idxchken = FALSE;
xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
}
else
{
xfrmd.mm4_cmd_xfrmd_bits.idxchken = TRUE;
xfrmd.mm4_cmd_xfrmd_bits.crcchken = TRUE;
}
xfrmd.mm4_cmd_xfrmd_bits.res_type = ResType;
EMMC_PRN(PRN_DBG,"\n Sending command: xfrmd = 0x%x ",xfrmd.mm4_cmd_xfrmd_value);
// Kick off the command
pContext->pMMC4Reg->mm4_cmd_xfrmd = xfrmd.mm4_cmd_xfrmd_value;
return;
}
/****************************************************************
* EMMCHC_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 EMMCHC_SetControllerVoltage (P_MM4_SDMMC_CONTEXT_T pContext, UINT_T vcc)
{
UINT_T controllervoltage = 0;
P_MM4_CAP1_2 pMM4_CAP0 = (P_MM4_CAP1_2) &pContext->pMMC4Reg->mm4_cap1_2;
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;
EMMC_PRN(PRN_DBG,"*pMM4_CNTL1 %x,\n",*pMM4_CNTL1);
EMMC_PRN(PRN_DBG,"*pMM4_CAP0 is %x, voltage supported bits: %d%d%d\n",
*pMM4_CAP0, pMM4_CAP0->vlg_33_support,
pMM4_CAP0->vlg_30_support, pMM4_CAP0->vlg_18_support);
// Read the CAP0 register
if (pMM4_CAP0->vlg_33_support && (vcc == 3))
controllervoltage = MM4_VLTGSEL_3_3;
else if (pMM4_CAP0->vlg_30_support && (vcc == 4))
controllervoltage = MM4_VLTGSEL_3_0;
else if (pMM4_CAP0->vlg_18_support && (vcc == 1))
controllervoltage = MM4_VLTGSEL_1_8;
else // default to 3.3V
controllervoltage = MM4_VLTGSEL_3_3;
if(MM4_VLTGSEL_1_8 == controllervoltage) {
volatile P_MM4_ACMD12_ER pMM4_crtl2 = \
(volatile P_MM4_ACMD12_ER) &pContext->pMMC4Reg->mm4_acmd12_er;
UINT_T data = *(VUINT_T*) pMM4_crtl2;
data |= (0x1 << 19); // sgh_v18_en
*(VUINT_T*) pMM4_crtl2 = data;
EMMC_PRN(PRN_RES, "SDHCI: switch host to 1.8V ! \n");
}
//EMMC_PRN(PRN_INFO,"controllervoltage: %d\n",controllervoltage);
// 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;
EMMC_PRN(PRN_DBG,"*pMM4_CNTL1 %x,\n",*pMM4_CNTL1);
return controllervoltage;
}
void EMMCHC_EnableCmdInterrupt(P_MM4_SDMMC_CONTEXT_T pContext, unsigned int enable)
{
//unsigned int data;
P_MM4_I_STAT_EN pMM4_I_STAT_EN;
P_MM4_I_SIGN_EN pMM4_I_SIGN_EN;
MM4_I_STAT_UNION MM4_i_stat;
// Capture existing Value
pMM4_I_SIGN_EN = (P_MM4_I_SIGN_EN)((uintptr_t) &pContext->pMMC4Reg->mm4_i_sig_en);
pMM4_I_STAT_EN = (P_MM4_I_STAT_EN)((uintptr_t) &pContext->pMMC4Reg->mm4_i_stat_en);
MM4_i_stat.mm4_i_stat_value = *(VUINT_T*)pMM4_I_STAT_EN;
// Route the interrupt signal enable register
MM4_i_stat.mm4_i_stat_bits.cmdcomp = enable&0x01;
// EMMC_PRN(PRN_INFO," enable is %x MM4_i_stat.mm4_i_stat_bits.cmdcomp : %x\n", enable,MM4_i_stat.mm4_i_stat_bits.cmdcomp);
// Write it out
*(VUINT_T*)pMM4_I_STAT_EN = MM4_i_stat.mm4_i_stat_value;
*(VUINT_T*)pMM4_I_SIGN_EN = MM4_i_stat.mm4_i_stat_value;
}
void EMMCHC_cdInt_enable(P_MM4_SDMMC_CONTEXT_T pContext, UINT8_T Desire)
{
P_MM4_I_STAT_UNION pMM4_I_STAT_EN_U;
MM4_I_STAT_UNION stat_en_copy;
pMM4_I_STAT_EN_U = (P_MM4_I_STAT_UNION) &pContext->pMMC4Reg->mm4_i_stat_en;
stat_en_copy.mm4_i_stat_value= pMM4_I_STAT_EN_U->mm4_i_stat_value;
if(Desire==1)
{
EMMC_PRN(PRN_INFO, "\n Interrupt Signal enable value is 0x%x",stat_en_copy.mm4_i_stat_value);
stat_en_copy.mm4_i_stat_bits.cdint = 1;
pMM4_I_STAT_EN_U->mm4_i_stat_value = stat_en_copy.mm4_i_stat_value;
stat_en_copy.mm4_i_stat_value= pMM4_I_STAT_EN_U->mm4_i_stat_value;
EMMC_PRN(PRN_INFO, "\n Interrupt Signal enable value is 0x%x",stat_en_copy.mm4_i_stat_value);
EMMC_PRN(PRN_RES, " Card Interrupt is enabled.\n ");
}
else
{
EMMC_PRN(PRN_INFO, "\n Interrupt Signal enable value is 0x%x",stat_en_copy);
stat_en_copy.mm4_i_stat_bits.cdint = 0;
pMM4_I_STAT_EN_U->mm4_i_stat_value = stat_en_copy.mm4_i_stat_value;
stat_en_copy.mm4_i_stat_value= pMM4_I_STAT_EN_U->mm4_i_stat_value;
EMMC_PRN(PRN_INFO, "\n Interrupt Signal enable value is 0x%x",stat_en_copy.mm4_i_stat_value);
EMMC_PRN(PRN_RES, " Card Interrupt is disabled.\n ");
}
return;
}