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