You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1261 lines
36 KiB
1261 lines
36 KiB
3 weeks ago
|
/* vxbFtSdCtrl.c - SD card driver */
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
|
||
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <vxWorks.h>
|
||
|
#include <stdio.h>
|
||
|
#include <String.h>
|
||
|
#include <semLib.h>
|
||
|
#include <sysLib.h>
|
||
|
#include <taskLib.h>
|
||
|
#include <vxBusLib.h>
|
||
|
#include <cacheLib.h>
|
||
|
#include <hwif/vxbus/vxBus.h>
|
||
|
#include <hwif/vxbus/hwConf.h>
|
||
|
#include <hwif/util/vxbParamSys.h>
|
||
|
#include <hwif/vxbus/vxbPciLib.h>
|
||
|
#include <hwif/vxbus/hwConf.h>
|
||
|
#include <drv/pci/pciConfigLib.h>
|
||
|
#include <drv/pci/pciIntLib.h>
|
||
|
#include <hwif/vxbus/vxbSdLib.h>
|
||
|
#include <../src/hwif/h/vxbus/vxbAccess.h>
|
||
|
#include "vxbFtSdCtrl.h"
|
||
|
|
||
|
#ifdef SDHC_DBG_ON
|
||
|
|
||
|
#ifdef LOCAL
|
||
|
#undef LOCAL
|
||
|
#define LOCAL
|
||
|
#endif
|
||
|
|
||
|
#define SDHC_DBG_IRQ 0x00000001
|
||
|
#define SDHC_DBG_RW 0x00000002
|
||
|
#define SDHC_DBG_XBD 0x00000004
|
||
|
#define SDHC_DBG_ERR 0x00000008
|
||
|
#define SDHC_DBG_ALL 0xffffffff
|
||
|
#define SDHC_DBG_OFF 0x00000000
|
||
|
|
||
|
UINT32 ftSdhcDbgMask = SDHC_DBG_OFF;
|
||
|
|
||
|
IMPORT FUNCPTR _func_logMsg;
|
||
|
|
||
|
#define SDHC_DBG(mask, string, a, b, c, d, e, f) \
|
||
|
if ((ftSdhcDbgMask & mask) || (mask == SDHC_DBG_ALL)) \
|
||
|
if (_func_logMsg != NULL) \
|
||
|
(* _func_logMsg)(string, a, b, c, d, e, f)
|
||
|
#else
|
||
|
#define SDHC_DBG(mask, string, a, b, c, d, e, f)
|
||
|
#endif /* SDHC_DBG_ON */
|
||
|
|
||
|
/*irq*/
|
||
|
LOCAL void ftSdhcNorIrq(FTSDHC_DEV_CTRL * pDrvCtrl);
|
||
|
LOCAL void ftSdhcDmaIrq(FTSDHC_DEV_CTRL * pDrvCtrl);
|
||
|
LOCAL void ftSdhcErrIrq(FTSDHC_DEV_CTRL * pDrvCtrl);
|
||
|
|
||
|
/* locals */
|
||
|
LOCAL void ftSdhcResetHw(VXB_DEVICE_ID);
|
||
|
LOCAL BOOL ftSdhcCtrlCardWpCheck (VXB_DEVICE_ID);
|
||
|
LOCAL BOOL ftSdhcCtrlCardInsertSts(VXB_DEVICE_ID);
|
||
|
LOCAL int ftSdCtrlReadBlock(VXB_DEVICE_ID pDev,SD_CMD * pSdCmd);
|
||
|
LOCAL int ftSdCtrlWriteBlock(VXB_DEVICE_ID pDev,SD_CMD * pSdCmd);
|
||
|
LOCAL uint32_t ftSdhcPrepareCmdRaw(SD_CMD * pSdCmd);
|
||
|
LOCAL uint32_t ftSdhcCmdFindResp(SD_CMD * pSdCmd);
|
||
|
LOCAL int ftSdhcWaitCmdEnd(VXB_DEVICE_ID pDev,SD_CMD * pSdCmd);
|
||
|
LOCAL int ftSdhcDoCmd( VXB_DEVICE_ID pDev,SD_CMD * pSdCmd);
|
||
|
IMPORT void vxbUsDelay (int delayTime);
|
||
|
IMPORT void vxbMsDelay (int delayTime);
|
||
|
LOCAL void ftSdhcInstInit(VXB_DEVICE_ID pInst);
|
||
|
LOCAL void ftSdhcInstInit2 (VXB_DEVICE_ID pInst);
|
||
|
LOCAL void ftSdhcInstConnect (VXB_DEVICE_ID pInst);
|
||
|
LOCAL void ftSdhcClkFreqSetup(VXB_DEVICE_ID pDev, UINT32 clk);
|
||
|
LOCAL STATUS ftSdhcInit(VXB_DEVICE_ID pDev);
|
||
|
LOCAL STATUS ftSdhcCmdIssue (VXB_DEVICE_ID pDev, SD_CMD * pSdCmd);
|
||
|
LOCAL int ftSdhcGetCd(VXB_DEVICE_ID pDev);
|
||
|
LOCAL void ftSdhcPrivateSendCmd(VXB_DEVICE_ID pDev, uint32_t cmd, uint32_t resp_type,uint32_t arg);
|
||
|
LOCAL STATUS ftSdhcCtrlInstConnect(SD_HOST_CTRL * pSdHostCtrl);
|
||
|
LOCAL STATUS ftSdhcSpecInfoGet (VXB_DEVICE_ID pDev, void ** pHostSpec,VXB_SD_CMDISSUE_FUNC * pCmdIssue);
|
||
|
LOCAL void ftSdhcCtrlMonitor (VXB_DEVICE_ID pDev);
|
||
|
LOCAL void ftSdhcVddSetup(VXB_DEVICE_ID pDev, UINT32 vdd);
|
||
|
LOCAL DRIVER_INITIALIZATION ftSdhcFuncs =
|
||
|
{
|
||
|
ftSdhcInstInit, /* devInstanceInit */
|
||
|
ftSdhcInstInit2, /* devInstanceInit2 */
|
||
|
ftSdhcInstConnect /* devConnect */
|
||
|
};
|
||
|
|
||
|
LOCAL device_method_t vxbftSdhcCtrl_methods[] =
|
||
|
{
|
||
|
DEVMETHOD (vxbSdSpecInfoGet, ftSdhcSpecInfoGet),
|
||
|
DEVMETHOD_END
|
||
|
};
|
||
|
|
||
|
LOCAL DRIVER_REGISTRATION ftSdhcPlbRegistration =
|
||
|
{
|
||
|
NULL,
|
||
|
VXB_DEVID_DEVICE, /* devID */
|
||
|
VXB_BUSID_PLB, /* busID = PLB */
|
||
|
VXB_VER_5_0_0, /* vxbVersion */
|
||
|
FT_SDHC_NAME, /* drvName */
|
||
|
&ftSdhcFuncs, /* pDrvBusFuncs */
|
||
|
vxbftSdhcCtrl_methods, /* pMethods */
|
||
|
NULL, /* devProbe */
|
||
|
NULL /* pParamDefaults */
|
||
|
};
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcRegister - register FT2000/4 SDHC driver
|
||
|
*
|
||
|
* This routine registers the FT2000/4 SDHC driver with the vxbus subsystem.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*
|
||
|
* \NOMANUAL
|
||
|
*/
|
||
|
|
||
|
void ftSdhcRegister (void)
|
||
|
{
|
||
|
(void)vxbDevRegister (&ftSdhcPlbRegistration);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcInstInit - first level initialization routine of FT2000/4 SDHC device
|
||
|
*
|
||
|
* This routine performs the first level initialization of the FT2000/4 SDHC device.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*
|
||
|
* \NOMANUAL
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcInstInit
|
||
|
(
|
||
|
VXB_DEVICE_ID pInst
|
||
|
)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcInstInit2 - second level initialization routine of FT2000/4 SDHC device
|
||
|
*
|
||
|
* This routine performs the second level initialization of the FT2000/4 SDHC device.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*
|
||
|
* \NOMANUAL
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcInstInit2
|
||
|
(
|
||
|
VXB_DEVICE_ID pInst
|
||
|
)
|
||
|
{
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl;
|
||
|
|
||
|
FUNCPTR clkFunc = NULL;
|
||
|
|
||
|
const struct hcfDevice * pHcf;
|
||
|
|
||
|
pDrvCtrl = (FTSDHC_DEV_CTRL *)malloc (sizeof(FTSDHC_DEV_CTRL));
|
||
|
if (pDrvCtrl == NULL)
|
||
|
return;
|
||
|
bzero ((char *)pDrvCtrl, sizeof(FTSDHC_DEV_CTRL));
|
||
|
|
||
|
|
||
|
pDrvCtrl->sdHostCtrl.pDev = pInst;
|
||
|
pDrvCtrl->sdHostCtrl.attached = FALSE;
|
||
|
pDrvCtrl->sdHostCtrl.isInsert = FALSE;
|
||
|
pDrvCtrl->pDev = pInst;
|
||
|
pInst->pDrvCtrl = pDrvCtrl;
|
||
|
pDrvCtrl->regBase = pInst->pRegBase[0];
|
||
|
vxbRegMap (pInst, 0, &pDrvCtrl->regHandle);
|
||
|
pDrvCtrl->sdHostCtrl.sdHostDmaParentTag = vxbDmaBufTagParentGet (pInst, 0);
|
||
|
pDrvCtrl->sdHostCtrl.sdHostDmaTag = vxbDmaBufTagCreate
|
||
|
(pInst,
|
||
|
pDrvCtrl->sdHostCtrl.sdHostDmaParentTag, /* parent */
|
||
|
_CACHE_ALIGN_SIZE, /* alignment */
|
||
|
0, /* boundary */
|
||
|
VXB_SPACE_MAXADDR_32BIT, /* lowaddr */
|
||
|
VXB_SPACE_MAXADDR, /* highaddr */
|
||
|
NULL, /* filter */
|
||
|
NULL, /* filterarg */
|
||
|
SDHC_MAX_RW_SECTORS * SDMMC_BLOCK_SIZE, /* max size */
|
||
|
1, /* nSegments */
|
||
|
SDHC_MAX_RW_SECTORS * SDMMC_BLOCK_SIZE, /* max seg size */
|
||
|
VXB_DMABUF_ALLOCNOW | VXB_DMABUF_NOCACHE,/* flags */
|
||
|
NULL, /* lockfunc */
|
||
|
NULL, /* lockarg */
|
||
|
NULL);
|
||
|
if (pDrvCtrl->sdHostCtrl.sdHostDmaTag == NULL)
|
||
|
{
|
||
|
SDHC_DBG (SDHC_DBG_ERR, "sdHostDmaTag create fault\n",
|
||
|
0, 0, 0, 0, 0, 0);
|
||
|
free (pDrvCtrl);
|
||
|
return;
|
||
|
}
|
||
|
pHcf = (struct hcfDevice *)hcfDeviceGet (pInst);
|
||
|
|
||
|
if (pHcf != NULL)
|
||
|
{
|
||
|
/*
|
||
|
* resourceDesc {
|
||
|
* The polling resource specifies whether
|
||
|
* the driver uses polling mode or not.
|
||
|
* If this property is not explicitly
|
||
|
* specified, the driver uses interrupt
|
||
|
* by default. }
|
||
|
*/
|
||
|
|
||
|
(void)devResourceGet (pHcf, "clkFreq", HCF_RES_ADDR,
|
||
|
(void *)&clkFunc);
|
||
|
|
||
|
if (clkFunc)
|
||
|
{
|
||
|
pDrvCtrl->sdHostCtrl.curClkFreq = (*clkFunc) ();
|
||
|
}
|
||
|
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)devResourceGet (pHcf, "polling", HCF_RES_INT,
|
||
|
(void *)&(pDrvCtrl->sdHostCtrl.polling));
|
||
|
|
||
|
/*
|
||
|
* resourceDesc {
|
||
|
* The clkFreq resource specifies clock
|
||
|
* frequency of SDHC base clock. }
|
||
|
*/
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)devResourceGet (pHcf, "cardWpCheck", HCF_RES_ADDR,
|
||
|
(void *)
|
||
|
&(pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdCardWpCheck));
|
||
|
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)devResourceGet (pHcf, "cardDetect", HCF_RES_ADDR,
|
||
|
(void *)
|
||
|
&(pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdCardInsertSts));
|
||
|
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)devResourceGet (pHcf, "vddSetup", HCF_RES_ADDR,
|
||
|
(void *)
|
||
|
&(pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdVddSetup));
|
||
|
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)devResourceGet (pHcf, "boardTuning", HCF_RES_ADDR,
|
||
|
(void *)
|
||
|
&(pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdBoardTuning));
|
||
|
|
||
|
|
||
|
}
|
||
|
/* initialize SDIO configuration library */
|
||
|
|
||
|
pDrvCtrl->pIntInfo = (struct vxbSdioInt *)malloc(sizeof(struct vxbSdioInt));
|
||
|
if(pDrvCtrl->pIntInfo == NULL)
|
||
|
return;
|
||
|
|
||
|
vxbSdioIntLibInit(pDrvCtrl->pIntInfo);
|
||
|
|
||
|
pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdCardInsertSts = ftSdhcCtrlCardInsertSts;
|
||
|
pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdCardWpCheck = ftSdhcCtrlCardWpCheck;
|
||
|
pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdHostCtrlInit = ftSdhcInit;
|
||
|
pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdClkFreqSetup = ftSdhcClkFreqSetup;
|
||
|
pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdVddSetup = ftSdhcVddSetup;
|
||
|
pDrvCtrl->sdHostCtrl.sdHostOps.vxbSdResumeSet = NULL;
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)vxbBusAnnounce (pInst, VXB_BUSID_SD);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcInstConnect - third level initialization routine of FT2000/4 SDHC device
|
||
|
*
|
||
|
* This routine performs the third level initialization of the FT2000/4 SDHC device.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcInstConnect
|
||
|
(
|
||
|
VXB_DEVICE_ID pInst
|
||
|
)
|
||
|
{
|
||
|
STATUS rc;
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl;
|
||
|
SD_HOST_CTRL * pHostCtrl;
|
||
|
TASK_ID monTaskId;
|
||
|
pDrvCtrl = (FTSDHC_DEV_CTRL *)(pInst->pDrvCtrl);
|
||
|
if (pDrvCtrl == NULL)
|
||
|
return;
|
||
|
|
||
|
pHostCtrl = (SD_HOST_CTRL *)pDrvCtrl;
|
||
|
rc = ftSdhcCtrlInstConnect(pHostCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pHostCtrl->sdHostSpec.vxbSdBusWidthSetup = pHostCtrl->sdHostOps.vxbSdBusWidthSetup;
|
||
|
pHostCtrl->sdHostSpec.vxbSdCardWpCheck = pHostCtrl->sdHostOps.vxbSdCardWpCheck;
|
||
|
pHostCtrl->sdHostSpec.vxbSdClkFreqSetup = pHostCtrl->sdHostOps.vxbSdClkFreqSetup;
|
||
|
pHostCtrl->sdHostSpec.vxbSdResumeSet = pHostCtrl->sdHostOps.vxbSdResumeSet;
|
||
|
pHostCtrl->sdHostSpec.vxbSdVddSetup = pHostCtrl->sdHostOps.vxbSdVddSetup;
|
||
|
pHostCtrl->sdHostSpec.capbility = pHostCtrl->capbility;
|
||
|
pHostCtrl->sdHostSpec.directBio = pHostCtrl->directBio;
|
||
|
|
||
|
monTaskId = taskSpawn ("sdBusMonitor", 100, 0,
|
||
|
8192, (FUNCPTR)ftSdhcCtrlMonitor,
|
||
|
(_Vx_usr_arg_t)pInst,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||
|
if (pHostCtrl->polling !=TRUE)
|
||
|
{
|
||
|
rc = vxbIntConnect (pInst, 1,ftSdhcNorIrq,pDrvCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
rc = vxbIntEnable (pInst, 1,ftSdhcNorIrq, pDrvCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
/* connect and enable dma interrupt */
|
||
|
rc = vxbIntConnect (pInst,0,ftSdhcDmaIrq,pDrvCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
rc = vxbIntEnable (pInst, 0,ftSdhcDmaIrq,pDrvCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
/* connect and enable err interrupt */
|
||
|
rc = vxbIntConnect (pInst,2,ftSdhcErrIrq, pDrvCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
rc = vxbIntEnable (pInst, 2, ftSdhcErrIrq, pDrvCtrl);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcCtrlInstConnect - third level initialization routine of FT2000/4 SDHC device
|
||
|
*
|
||
|
* This routine performs the third level initialization of the FT2000/4 SDHC device.
|
||
|
*
|
||
|
* RETURNS: OK/ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL STATUS ftSdhcCtrlInstConnect
|
||
|
(
|
||
|
SD_HOST_CTRL * pSdHostCtrl
|
||
|
)
|
||
|
{
|
||
|
STATUS rc;
|
||
|
/*
|
||
|
* The devChange semaphore is used by the interrupt service routine
|
||
|
* to inform the card monitor task that a state change has occurred.
|
||
|
*/
|
||
|
|
||
|
pSdHostCtrl->devChange = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
|
||
|
if (pSdHostCtrl->devChange == NULL)
|
||
|
{
|
||
|
return ERROR;
|
||
|
}
|
||
|
|
||
|
pSdHostCtrl->cmdDone = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
|
||
|
if (pSdHostCtrl->cmdDone == NULL)
|
||
|
{
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
pSdHostCtrl->dataDone = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
|
||
|
if (pSdHostCtrl->dataDone == NULL)
|
||
|
{
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
pSdHostCtrl->pioReady = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
|
||
|
if (pSdHostCtrl->pioReady == NULL)
|
||
|
{
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
pSdHostCtrl->hostDevSem = semMCreate(SEM_Q_PRIORITY |
|
||
|
SEM_DELETE_SAFE |
|
||
|
SEM_INVERSION_SAFE);
|
||
|
if (pSdHostCtrl->hostDevSem == NULL)
|
||
|
{
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
/* per-device init */
|
||
|
if (pSdHostCtrl->sdHostOps.vxbSdHostCtrlInit != NULL)
|
||
|
{
|
||
|
rc = pSdHostCtrl->sdHostOps.vxbSdHostCtrlInit(pSdHostCtrl->pDev);
|
||
|
if (rc == ERROR)
|
||
|
{
|
||
|
goto err;
|
||
|
}
|
||
|
}
|
||
|
return OK;
|
||
|
err:
|
||
|
if (pSdHostCtrl->dataDone != NULL)
|
||
|
{
|
||
|
if (semDelete(pSdHostCtrl->dataDone) != OK)
|
||
|
{
|
||
|
logMsg("semDelete dataDone delete error\r\n",1,2,3,4,5,6);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pSdHostCtrl->cmdDone != NULL)
|
||
|
{
|
||
|
if (semDelete(pSdHostCtrl->cmdDone) != OK)
|
||
|
{
|
||
|
logMsg("semDelete cmdDone delete error\r\n",1,2,3,4,5,6);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if (pSdHostCtrl->devChange != NULL)
|
||
|
{
|
||
|
if (semDelete(pSdHostCtrl->devChange) != OK)
|
||
|
{
|
||
|
logMsg("semDelete devChange delete error\r\n",1,2,3,4,5,6);
|
||
|
}
|
||
|
}
|
||
|
if (pSdHostCtrl->pioReady != NULL)
|
||
|
{
|
||
|
if (semDelete(pSdHostCtrl->pioReady) != OK)
|
||
|
{
|
||
|
logMsg("semDelete pioReady delete error\r\n",1,2,3,4,5,6);
|
||
|
}
|
||
|
}
|
||
|
if (pSdHostCtrl->hostDevSem != NULL)
|
||
|
{
|
||
|
if (semDelete(pSdHostCtrl->hostDevSem) != OK)
|
||
|
{
|
||
|
logMsg("semDelete hostDevSem delete error\r\n",1,2,3,4,5,6);
|
||
|
}
|
||
|
}
|
||
|
return ERROR;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcResetHw - hardware reset of FT2000/4 SDHC device
|
||
|
*
|
||
|
* This routine performs Hardware reset of the FT2000/4 SDHC device.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcResetHw(VXB_DEVICE_ID pDev)
|
||
|
{
|
||
|
CSR_SETBIT_4(pDev,SDCI_SOFTWARE, SDCI_SOFTWARE_SRST);
|
||
|
vxbUsDelay(1); /* 1us is enough */
|
||
|
CSR_CLRBIT_4(pDev,SDCI_SOFTWARE, SDCI_SOFTWARE_SRST);
|
||
|
while (!(CSR_READ_4(pDev,SDCI_STATUS) & SDCI_STATUS_IDIE))
|
||
|
taskDelay(1);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcCtrlCardInsertSts - check if card is inserted
|
||
|
*
|
||
|
* This routine checks if card is inserted.
|
||
|
*
|
||
|
* RETURNS: TRUE/FALSE
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL BOOL ftSdhcCtrlCardInsertSts
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
SD_HOST_CTRL * pSdHostCtrl;
|
||
|
uint32_t status;
|
||
|
pSdHostCtrl = (SD_HOST_CTRL *)pDev->pDrvCtrl;
|
||
|
status = CSR_READ_4(pDev,SDCI_STATUS);
|
||
|
if (((status >> 19) & 0x1) == 0x1)
|
||
|
{
|
||
|
pSdHostCtrl->isInsert = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pSdHostCtrl->isInsert = TRUE; /* bit[19]=0 inserted. */
|
||
|
}
|
||
|
return (pSdHostCtrl->isInsert);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcCtrlCardWpCheck - check if card is write protected
|
||
|
*
|
||
|
* This routine check if card is write protected.
|
||
|
*
|
||
|
* RETURNS: TRUE/FALSE
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL BOOL ftSdhcCtrlCardWpCheck
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
BOOL wp;
|
||
|
wp = FALSE;
|
||
|
return (wp);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcClkFreqSetup - setup the clock frequency for FT2000/4 SDHC device
|
||
|
*
|
||
|
* This routine setups the clock frequency. This routine will
|
||
|
* be called in the SDHC driver. The clock frequency calculation
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcClkFreqSetup
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
UINT32 clk
|
||
|
)
|
||
|
{
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl = (FTSDHC_DEV_CTRL *)(pDev->pDrvCtrl);
|
||
|
UINT32 div = 0xffffffff;
|
||
|
unsigned long clk_rate;
|
||
|
|
||
|
if(clk)
|
||
|
{
|
||
|
clk_rate = pDrvCtrl->sdHostCtrl.curClkFreq;
|
||
|
div = ((clk_rate / (2 * clk)) - 1);
|
||
|
CSR_WRITE_4(pDev,SDCI_CLOCK_D,div);
|
||
|
CSR_WRITE_4(pDev,SDCI_SD_SAMP,11);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcVddSetup - setup the SD bus voltage level and power it up
|
||
|
*
|
||
|
* This routine setups the SD bus voltage and powers it up. This
|
||
|
* routine will be called in the SDHC driver.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcVddSetup
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
UINT32 vdd
|
||
|
)
|
||
|
{
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcInit - FT2000/4 SDHC per device specific initialization
|
||
|
*
|
||
|
* This routine performs per device specific initialization of FT2000/4 SDHC.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL STATUS ftSdhcInit
|
||
|
(
|
||
|
VXB_DEVICE_ID pInst
|
||
|
)
|
||
|
{
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl = (FTSDHC_DEV_CTRL *)(pInst->pDrvCtrl);
|
||
|
ftSdhcResetHw(pInst);
|
||
|
/* Disable card detection */
|
||
|
CSR_WRITE_4(pInst, SDCI_SD_SEN,0);
|
||
|
|
||
|
/* Disable all interrupts */
|
||
|
CSR_WRITE_4(pInst, SDCI_NORMAL_ISER,0);
|
||
|
CSR_WRITE_4(pInst, SDCI_ERROR_ISER,0);
|
||
|
CSR_WRITE_4(pInst,SDCI_BD_ISER,0);
|
||
|
|
||
|
/* clear status register */
|
||
|
CSR_WRITE_4(pInst, SDCI_NORMAL_ISR,0);
|
||
|
CSR_WRITE_4(pInst, SDCI_ERROR_ISR,0);
|
||
|
CSR_WRITE_4(pInst, SDCI_BD_ISR,0);
|
||
|
CSR_SETBIT_4(pInst,SDCI_NORMAL_ISER, SDCI_SDCI_NORMAL_ISER_ECR);
|
||
|
|
||
|
CSR_WRITE_4(pInst, SDCI_CONTROLLER,0x0F00);
|
||
|
|
||
|
CSR_WRITE_4(pInst, SDCI_SD_DRV,0);
|
||
|
CSR_WRITE_4(pInst, SDCI_SD_SAMP,0);
|
||
|
|
||
|
|
||
|
/* Configure to default cmd data timeout */
|
||
|
CSR_WRITE_4(pInst, SDCI_TIMEOUT_CMD,0xFFFFFFFF);
|
||
|
if (vxbDmaBufMapCreate (pInst, pDrvCtrl->sdHostCtrl.sdHostDmaTag, 0,
|
||
|
&(pDrvCtrl->sdHostCtrl.sdHostDmaMap)) == NULL)
|
||
|
return ERROR;
|
||
|
|
||
|
return OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcCtrlMonitor - FT2000/4 SDHC insert status monitor
|
||
|
*
|
||
|
* This function will check FT2000/4 SDHC insert/remove status. If target device
|
||
|
* insert status is TRUE, the function will run sdioBusAnnounceDevices to add
|
||
|
* target device to vxbus system. If FLASE, will run vxbDevRemovalAnnounce to
|
||
|
* remove the target device from vxbus system.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcCtrlMonitor
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
SD_HOST_CTRL * pSdHostCtrl;
|
||
|
|
||
|
pSdHostCtrl = (SD_HOST_CTRL *)(pDev->pDrvCtrl);
|
||
|
if (pSdHostCtrl == NULL)
|
||
|
return;
|
||
|
pSdHostCtrl->attached = FALSE;
|
||
|
while(1)
|
||
|
{
|
||
|
int cardin;
|
||
|
taskDelay ( sysClkRateGet());
|
||
|
|
||
|
cardin= ftSdhcGetCd(pDev);
|
||
|
if(cardin==1)
|
||
|
{
|
||
|
if ( pSdHostCtrl->attached == TRUE)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
if (pSdHostCtrl->sdHostOps.vxbSdClkFreqSetup != NULL)
|
||
|
pSdHostCtrl->sdHostOps.vxbSdClkFreqSetup(pDev, SDMMC_CLK_FREQ_400KHZ);
|
||
|
|
||
|
|
||
|
if (pSdHostCtrl->sdHostOps.vxbSdBusWidthSetup != NULL)
|
||
|
pSdHostCtrl->sdHostOps.vxbSdBusWidthSetup (pDev, SDMMC_BUS_WIDTH_1BIT);
|
||
|
|
||
|
/* Need not check return status at here*/
|
||
|
|
||
|
(void)sdBusAnnounceDevices(pDev, NULL);
|
||
|
pSdHostCtrl->attached = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
VXB_DEVICE_ID pDevList;
|
||
|
int i=0;
|
||
|
if ( pSdHostCtrl->attached == FALSE)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
pDevList = pDev->u.pSubordinateBus->instList;
|
||
|
for(i = 0; i < MAX_TARGET_DEV; i++)
|
||
|
{
|
||
|
if (pDevList != NULL)
|
||
|
{
|
||
|
|
||
|
/* Need not check return status at here */
|
||
|
|
||
|
(void)vxbDevRemovalAnnounce(pDevList);
|
||
|
pDevList = pDevList->pNext;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
pSdHostCtrl->attached = FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcGetCd - get card insert status
|
||
|
*
|
||
|
* This routine get card insert status.
|
||
|
*
|
||
|
* RETURNS: 1/0
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL int ftSdhcGetCd(VXB_DEVICE_ID pDev)
|
||
|
{
|
||
|
uint32_t status = CSR_READ_4(pDev,SDCI_STATUS);
|
||
|
if (((status >> 19) & 0x1) == 0x1)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcCmdIssue - issue the command to be sent
|
||
|
*
|
||
|
* This routine issue the command to be sent.
|
||
|
*
|
||
|
* RETURNS: OK or ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL STATUS ftSdhcCmdIssue
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
SD_CMD * pSdCmd
|
||
|
)
|
||
|
{
|
||
|
int result;
|
||
|
|
||
|
if((pSdCmd->cmdIdx==5)||(pSdCmd->cmdIdx==1))
|
||
|
{
|
||
|
pSdCmd->cmdErr=0x00000002;
|
||
|
return 0;
|
||
|
}
|
||
|
if (pSdCmd->hasData)
|
||
|
{
|
||
|
SD_HOST_CTRL * pSdHostCtrl;
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl = (FTSDHC_DEV_CTRL *)(pDev->pDrvCtrl);
|
||
|
pSdHostCtrl = (SD_HOST_CTRL *)pDrvCtrl;
|
||
|
result = vxbDmaBufMapLoad (pDev, pDrvCtrl->sdHostCtrl.sdHostDmaTag,
|
||
|
pDrvCtrl->sdHostCtrl.sdHostDmaMap,
|
||
|
pSdCmd->cmdData.buffer,
|
||
|
pSdCmd->cmdData.blkNum * pSdCmd->cmdData.blkSize,
|
||
|
0);
|
||
|
if (pSdCmd->cmdData.isRead == TRUE)
|
||
|
{
|
||
|
result= ftSdCtrlReadBlock(pDev, pSdCmd);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = ftSdCtrlWriteBlock(pDev, pSdCmd);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = ftSdhcDoCmd(pDev, pSdCmd);
|
||
|
}
|
||
|
return OK;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcNorIrq - normal interrupt service routine
|
||
|
*
|
||
|
* This routine handles normal interrupts of SDHC.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcNorIrq(FTSDHC_DEV_CTRL * pDrvCtrl)
|
||
|
{
|
||
|
uint32_t intSts;
|
||
|
VXB_DEVICE_ID pDev= pDrvCtrl->pDev;
|
||
|
intSts = CSR_READ_4(pDev,SDCI_NORMAL_ISR);
|
||
|
/* clear interrupts */
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,0);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcDmaIrq - dma interrupt service routine
|
||
|
*
|
||
|
* This routine handles dma interrupts of SDHC.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcDmaIrq(FTSDHC_DEV_CTRL * pDrvCtrl)
|
||
|
{
|
||
|
uint32_t intSts;
|
||
|
VXB_DEVICE_ID pDev= pDrvCtrl->pDev;
|
||
|
intSts = CSR_READ_4(pDev,SDCI_BD_ISR);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_ISR,0);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcErrIrq - error interrupt service routine
|
||
|
*
|
||
|
* This routine handles error interrupts of SDHC.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcErrIrq(FTSDHC_DEV_CTRL * pDrvCtrl)
|
||
|
{
|
||
|
uint32_t intSts;
|
||
|
VXB_DEVICE_ID pDev= pDrvCtrl->pDev;
|
||
|
intSts = CSR_READ_4(pDev,SDCI_ERROR_ISR);
|
||
|
CSR_WRITE_4(pDev, SDCI_ERROR_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_ERROR_ISR,0);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcSpecInfoGet - get host controller spec info
|
||
|
*
|
||
|
* This routine gets host controller spec info.
|
||
|
*
|
||
|
* RETURNS: OK or ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL STATUS ftSdhcSpecInfoGet
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
void ** pHostSpec,
|
||
|
VXB_SD_CMDISSUE_FUNC * pCmdIssue
|
||
|
)
|
||
|
{
|
||
|
|
||
|
SD_HOST_CTRL * pSdHostCtrl;
|
||
|
|
||
|
pSdHostCtrl = (SD_HOST_CTRL *)pDev->pDrvCtrl;
|
||
|
if (pSdHostCtrl == NULL)
|
||
|
return ERROR;
|
||
|
|
||
|
*pHostSpec = (void *)(&(pSdHostCtrl->sdHostSpec));
|
||
|
|
||
|
*pCmdIssue = ftSdhcCmdIssue;
|
||
|
|
||
|
return (OK);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcPrivateSendCmd - send pravate command
|
||
|
*
|
||
|
* This routine send pravate command.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ftSdhcPrivateSendCmd(VXB_DEVICE_ID pDev, uint32_t cmd, uint32_t resp_type,uint32_t arg)
|
||
|
{
|
||
|
uint32_t temp,sd_cmd,sd_arg;
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,0);
|
||
|
CSR_WRITE_4(pDev, SDCI_ERROR_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_ERROR_ISR,0);
|
||
|
sd_cmd = (cmd << 8) | resp_type;
|
||
|
sd_arg = arg;
|
||
|
CSR_WRITE_4(pDev, SDCI_COMMAND,sd_cmd);
|
||
|
CSR_WRITE_4(pDev, SDCI_ARGUMENT,sd_arg);
|
||
|
temp =CSR_READ_4(pDev,SDCI_NORMAL_ISR);
|
||
|
while ((temp & SDCI_NORMAL_ISR_CC) != SDCI_NORMAL_ISR_CC){
|
||
|
temp = CSR_READ_4(pDev,SDCI_NORMAL_ISR);
|
||
|
taskDelay(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcDoCmd - send sd command
|
||
|
*
|
||
|
* This routine send sd command.
|
||
|
*
|
||
|
* RETURNS: OK or ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL int ftSdhcDoCmd
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
SD_CMD * pSdCmd
|
||
|
)
|
||
|
{
|
||
|
int result = 0;
|
||
|
uint32_t sdci_cmd = 0;
|
||
|
|
||
|
/* clear normal interrupt status */
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,1);
|
||
|
|
||
|
|
||
|
/* set command*/
|
||
|
sdci_cmd = ftSdhcPrepareCmdRaw(pSdCmd);
|
||
|
CSR_WRITE_4(pDev, SDCI_COMMAND,sdci_cmd);
|
||
|
|
||
|
if(pSdCmd->cmdIdx==41)
|
||
|
{
|
||
|
pSdCmd->cmdArg=0x40ff8000;
|
||
|
}
|
||
|
|
||
|
CSR_WRITE_4(pDev, SDCI_ARGUMENT,pSdCmd->cmdArg);
|
||
|
|
||
|
result = ftSdhcWaitCmdEnd(pDev, pSdCmd);
|
||
|
/* After CMD2 set RCA to a none zero value. */
|
||
|
if ((result == 0) && (pSdCmd->cmdIdx == MMC_CMD_ALL_SEND_CID))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdCtrlReadBlock - read data from SD card
|
||
|
*
|
||
|
* This routine read data from SD card.
|
||
|
*
|
||
|
* RETURNS: OK or ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL int ftSdCtrlReadBlock(VXB_DEVICE_ID pDev,SD_CMD * pSdCmd)
|
||
|
{
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl = (FTSDHC_DEV_CTRL *)(pDev->pDrvCtrl);
|
||
|
uint32_t status, statusmask;
|
||
|
int timeout = SDCI_TIMEOUT_DATA_VALUE;
|
||
|
uint32_t sdci_cmd;
|
||
|
SD_HOST_CTRL * pSdHostCtrl;
|
||
|
uint32_t addrl = 0;
|
||
|
pSdHostCtrl = (SD_HOST_CTRL *)pDrvCtrl;
|
||
|
vxbDmaBufMapSync (pDev,
|
||
|
pSdHostCtrl->sdHostDmaTag,
|
||
|
pSdHostCtrl->sdHostDmaMap,
|
||
|
0,
|
||
|
pSdCmd->cmdData.blkNum * pSdCmd->cmdData.blkSize,
|
||
|
_VXB_DMABUFSYNC_DMA_PREREAD);
|
||
|
if(pSdCmd->cmdData.blkSize < 512)
|
||
|
{
|
||
|
/* ADTC command */
|
||
|
/* clear interrupt status */
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,1);
|
||
|
|
||
|
/* set command and parameter registers,trigger a send command */
|
||
|
sdci_cmd = ftSdhcPrepareCmdRaw(pSdCmd);
|
||
|
sdci_cmd |= SDCI_CMD_ADTC_MASK;
|
||
|
CSR_WRITE_4(pDev, SDCI_COMMAND,sdci_cmd);
|
||
|
}
|
||
|
addrl= (UINT32)(pSdHostCtrl->sdHostDmaMap->fragList[0].frag);
|
||
|
/* clear data status register and command status register*/
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,1);
|
||
|
|
||
|
/* resetDMA BD */
|
||
|
CSR_SETBIT_4(pDev,SDCI_SOFTWARE, SDCI_BDRST);
|
||
|
CSR_CLRBIT_4(pDev,SDCI_SOFTWARE, SDCI_BDRST);
|
||
|
|
||
|
/* set transfer lenth */
|
||
|
CSR_WRITE_4(pDev, SDCI_BLK_CNT,pSdCmd->cmdData.blkNum);
|
||
|
|
||
|
/* set DMA discriptor data low address,data high address,card low address,card high address*/
|
||
|
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_RX,addrl);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_RX,0);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_RX,pSdCmd->cmdArg);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_RX,0);
|
||
|
ftSdhcWaitCmdEnd(pDev, pSdCmd);
|
||
|
statusmask = SDCI_BD_RESPE_STATUS | SDCI_BD_DAIS_ERROR_STATUS;
|
||
|
do
|
||
|
{
|
||
|
|
||
|
status = CSR_READ_4(pDev,SDCI_BD_ISR) & statusmask;
|
||
|
vxbUsDelay(1);
|
||
|
timeout--;
|
||
|
} while ((!status) && timeout);
|
||
|
|
||
|
if(status & SDCI_BD_DAIS_ERROR_STATUS)
|
||
|
{
|
||
|
if(status & (SDCI_BD_NRCRC_ERROR_STATUS | SDCI_BD_TRE_ERROR_STATUS | SDCI_BD_CMDE_ERROR_STATUS))
|
||
|
return -EILSEQ;
|
||
|
if(!timeout)
|
||
|
{
|
||
|
return -ETIMEDOUT;
|
||
|
}
|
||
|
}
|
||
|
vxbDmaBufMapSync (pDev,
|
||
|
pSdHostCtrl->sdHostDmaTag,
|
||
|
pSdHostCtrl->sdHostDmaMap,
|
||
|
0,
|
||
|
pSdCmd->cmdData.blkNum * pSdCmd->cmdData.blkSize,
|
||
|
_VXB_DMABUFSYNC_DMA_POSTREAD);
|
||
|
|
||
|
vxbDmaBufMapUnload(pSdHostCtrl->sdHostDmaTag, pSdHostCtrl->sdHostDmaMap);
|
||
|
/* multi block needs MMC_STOP_TRANSMISSION to stop process*/
|
||
|
if(pSdCmd->cmdData.blkNum > 1)
|
||
|
ftSdhcPrivateSendCmd(pDev,MMC_STOP_TRANSMISSION,0x2,0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdCtrlWriteBlock - send data to SD card
|
||
|
*
|
||
|
* This routine send data to SD card.
|
||
|
*
|
||
|
* RETURNS: OK or ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL int ftSdCtrlWriteBlock(VXB_DEVICE_ID pDev,SD_CMD * pSdCmd)
|
||
|
{
|
||
|
FTSDHC_DEV_CTRL * pDrvCtrl = (FTSDHC_DEV_CTRL *)(pDev->pDrvCtrl);
|
||
|
uint32_t status, statusmask;
|
||
|
int timeout = SDCI_TIMEOUT_DATA_VALUE;
|
||
|
uint32_t addrl = 0;
|
||
|
SD_HOST_CTRL * pSdHostCtrl = (SD_HOST_CTRL *)pDrvCtrl;
|
||
|
|
||
|
vxbDmaBufMapSync (pDev,
|
||
|
pSdHostCtrl->sdHostDmaTag,
|
||
|
pSdHostCtrl->sdHostDmaMap,
|
||
|
0,
|
||
|
pSdCmd->cmdData.blkNum * pSdCmd->cmdData.blkSize,
|
||
|
_VXB_DMABUFSYNC_DMA_PREWRITE);
|
||
|
addrl = (UINT32)(pSdHostCtrl->sdHostDmaMap->fragList[0].frag);
|
||
|
/* clear data status register and command status register */
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_ISR,1);
|
||
|
CSR_WRITE_4(pDev, SDCI_NORMAL_ISR,1);
|
||
|
|
||
|
/* set DMA BD */
|
||
|
CSR_SETBIT_4(pDev,SDCI_SOFTWARE, SDCI_BDRST);
|
||
|
CSR_CLRBIT_4(pDev,SDCI_SOFTWARE, SDCI_BDRST);
|
||
|
|
||
|
/* set transfer lenth */
|
||
|
CSR_WRITE_4(pDev, SDCI_BLK_CNT,pSdCmd->cmdData.blkNum);
|
||
|
|
||
|
/* set DMA discriptor data low address,data high address,card low address,card high address*/
|
||
|
CSR_WRITE_4(pDev,SDCI_BD_TX,addrl);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_TX,0);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_TX,pSdCmd->cmdArg);
|
||
|
CSR_WRITE_4(pDev, SDCI_BD_TX,0);
|
||
|
|
||
|
ftSdhcWaitCmdEnd(pDev, pSdCmd);
|
||
|
statusmask = SDCI_BD_TRS_STATUS | SDCI_BD_DAIS_ERROR_STATUS;
|
||
|
do
|
||
|
{
|
||
|
status = CSR_READ_4(pDev,SDCI_BD_ISR) & statusmask;
|
||
|
vxbUsDelay(1);
|
||
|
timeout--;
|
||
|
} while ((!status) && timeout);
|
||
|
|
||
|
if(status & SDCI_BD_DAIS_ERROR_STATUS)
|
||
|
{
|
||
|
printf("sd data write error:[0x%08x]\n",CSR_READ_4(pDev,SDCI_BD_ISR));
|
||
|
if(status & (SDCI_BD_NRCRC_ERROR_STATUS | SDCI_BD_TRE_ERROR_STATUS | SDCI_BD_CMDE_ERROR_STATUS))
|
||
|
return -EILSEQ;
|
||
|
if(!timeout)
|
||
|
{
|
||
|
printf("sd data write timeout:[0x%08x]\n",CSR_READ_4(pDev,SDCI_BD_ISR));
|
||
|
return -ETIMEDOUT;
|
||
|
}
|
||
|
}
|
||
|
vxbDmaBufMapSync (pDev,
|
||
|
pSdHostCtrl->sdHostDmaTag,
|
||
|
pSdHostCtrl->sdHostDmaMap,
|
||
|
0,
|
||
|
pSdCmd->cmdData.blkNum * pSdCmd->cmdData.blkSize,
|
||
|
_VXB_DMABUFSYNC_DMA_POSTWRITE);
|
||
|
vxbDmaBufMapUnload(pSdHostCtrl->sdHostDmaTag, pSdHostCtrl->sdHostDmaMap);
|
||
|
/* multi block needs MMC_STOP_TRANSMISSION to stop process*/
|
||
|
if(pSdCmd->cmdData.blkNum > 1)
|
||
|
ftSdhcPrivateSendCmd(pDev,MMC_STOP_TRANSMISSION,0x2,0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcPrepareCmdRaw - prepare commond
|
||
|
*
|
||
|
* This routine prepare commond.
|
||
|
*
|
||
|
* RETURNS: commond
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL uint32_t ftSdhcPrepareCmdRaw(SD_CMD * pSdCmd)
|
||
|
{
|
||
|
|
||
|
uint32_t resp, rawcmd;
|
||
|
uint32_t opcode = pSdCmd->cmdIdx;
|
||
|
|
||
|
resp = ftSdhcCmdFindResp(pSdCmd);
|
||
|
rawcmd = ((opcode << SDCI_CMD_INDEX_SHIFT) & SDCI_CMD_INDEX_MASK);
|
||
|
|
||
|
rawcmd |= resp;
|
||
|
|
||
|
if((pSdCmd->rspType & SDMMC_CMD_RSP_CRC) && (pSdCmd->rspType != SDMMC_CMD_RSP_R2))
|
||
|
rawcmd |= SDCI_CMD_CRCE_MASK;
|
||
|
|
||
|
if(pSdCmd->rspType & SDMMC_CMD_RSP_CMDIDX)
|
||
|
rawcmd |= SDCI_CMD_CICE_MASK;
|
||
|
|
||
|
return rawcmd;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcCmdFindResp - get response mask
|
||
|
*
|
||
|
* This routine get response mask.
|
||
|
*
|
||
|
* RETURNS: response
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL uint32_t ftSdhcCmdFindResp(SD_CMD * pSdCmd)
|
||
|
{
|
||
|
uint32_t resp;
|
||
|
switch (pSdCmd->rspType)
|
||
|
{
|
||
|
case SDMMC_CMD_RSP_R1:
|
||
|
resp = SDCI_CMD_RES_SHORT_MASK;
|
||
|
break;
|
||
|
case SDMMC_CMD_RSP_R1B:
|
||
|
resp = SDCI_CMD_RES_SHORT_MASK;
|
||
|
break;
|
||
|
case SDMMC_CMD_RSP_R2:
|
||
|
resp = SDCI_CMD_RES_LONG_MASK;
|
||
|
break;
|
||
|
case SDMMC_CMD_RSP_R3:
|
||
|
resp = SDCI_CMD_RES_SHORT_MASK;
|
||
|
break;
|
||
|
default:
|
||
|
resp = SDCI_CMD_RES_NONE_MASK;
|
||
|
break;
|
||
|
}
|
||
|
return resp;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ftSdhcWaitCmdEnd - wait commond end and get response
|
||
|
*
|
||
|
* This routine wait commond end and get response.
|
||
|
*
|
||
|
* RETURNS: OK or ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL int ftSdhcWaitCmdEnd(VXB_DEVICE_ID pDev,SD_CMD * pSdCmd)
|
||
|
{
|
||
|
uint32_t status, statusmask;
|
||
|
int timeout = SDCI_TIMEOUT_CMD_VALUE;
|
||
|
statusmask = SDCI_NORMAL_CC_STATUS | SDCI_NORMAL_EI_STATUS;
|
||
|
do
|
||
|
{
|
||
|
status =CSR_READ_4(pDev,SDCI_NORMAL_ISR) & statusmask;
|
||
|
SDHC_DBG (SDHC_DBG_ERR,"cmd->status:[0x%08x]\n",CSR_READ_4(pDev,SDCI_NORMAL_ISR),2,3,4,5,6);
|
||
|
vxbUsDelay (1 );
|
||
|
timeout--;
|
||
|
} while ((!status) && timeout);
|
||
|
|
||
|
if(status & SDCI_NORMAL_EI_STATUS)
|
||
|
{
|
||
|
status = CSR_READ_4(pDev,SDCI_ERROR_ISR);
|
||
|
|
||
|
if (!timeout) {
|
||
|
return -ETIMEDOUT;
|
||
|
} else if ((status & SDCI_ERROR_CCRCE_ERROR_STATUS) &&
|
||
|
(pSdCmd->rspType & MMC_RSP_CRC)) {
|
||
|
return -EILSEQ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pSdCmd->rspType != SDMMC_CMD_RSP_NONE) {
|
||
|
if (pSdCmd->rspType & SDMMC_CMD_RSP_LEN136)
|
||
|
{
|
||
|
UINT32 cmdRsp[4];
|
||
|
|
||
|
cmdRsp[0] = CSR_READ_4(pDev,SDCI_RESP0);
|
||
|
cmdRsp[1] = CSR_READ_4(pDev,SDCI_RESP1);
|
||
|
cmdRsp[2] = CSR_READ_4(pDev,SDCI_RESP2);
|
||
|
cmdRsp[3] = CSR_READ_4(pDev,SDCI_RESP3);
|
||
|
|
||
|
pSdCmd->cmdRsp[0] = be32toh (cmdRsp[0]);
|
||
|
pSdCmd->cmdRsp[1] = be32toh (cmdRsp[1]);
|
||
|
pSdCmd->cmdRsp[2] = be32toh (cmdRsp[2]);
|
||
|
pSdCmd->cmdRsp[3] = be32toh (cmdRsp[3]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pSdCmd->cmdRsp[0] = CSR_READ_4(pDev,SDCI_RESP0);
|
||
|
pSdCmd->cmdRsp[1] = 0;
|
||
|
pSdCmd->cmdRsp[2] = 0;
|
||
|
pSdCmd->cmdRsp[3] = 0;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|