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

/* 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;
}