+static void rk29_sdmmc_request_end(struct rk29_sdmmc *host, struct mmc_command *cmd)
+{
+ u32 status = host->data_status;
+ int output=SDM_SUCCESS;
+
+ xbwprintk(7, "%s..%d... cmd=%d, host->state=0x%x,\n pendingEvent=0x%lu, completeEvents=0x%lu ====xbw=[%s]====\n\n",\
+ __FUNCTION__, __LINE__,cmd->opcode,host->state, host->pending_events,host->completed_events,host->dma_name);
+
+ del_timer_sync(&host->DTO_timer);
+
+ if(RK29_CTRL_SDMMC_ID == host->pdev->id)
+ {
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF); //added by xbw at 2011-08-15
+ }
+
+ //stop DMA
+ if(host->dodma)
+ {
+ rk29_sdmmc_stop_dma(host);
+ rk29_sdmmc_control_host_dma(host, FALSE);
+ host->dodma = 0;
+ }
+
+ if(cmd->error)
+ {
+ goto exit;//It need not to wait-for-busy if the CMD-ERROR happen.
+ }
+ host->errorstep = 0xf7;
+ if(cmd->data)
+ {
+ if(host->cmdr & SDMMC_CMD_DAT_WRITE)
+ {
+ if(status & (SDMMC_INT_DCRC | SDMMC_INT_EBE))
+ {
+ cmd->data->error = -EILSEQ;
+ output = SDM_DATA_CRC_ERROR;
+ host->errorstep = 0x16;
+ }
+ else
+ {
+ output = rk29_sdmmc_wait_unbusy(host);
+ if(SDM_SUCCESS != output)
+ {
+ host->errorstep = 0x17;
+ cmd->data->error = -ETIMEDOUT;
+ }
+
+ host->data->bytes_xfered = host->data->blocks * host->data->blksz;
+ }
+ }
+ else
+ {
+ if( status & SDMMC_INT_SBE)
+ {
+ cmd->data->error = -EIO;
+ host->errorstep = 0x18;
+ output = SDM_START_BIT_ERROR;
+ }
+ else if((status & SDMMC_INT_EBE) && (cmd->opcode != 14)) //MMC4.0, BUSTEST_R, A host read the reserved bus testing data parttern from a card.
+ {
+ cmd->data->error = -EILSEQ;
+ host->errorstep = 0x19;
+ output = SDM_END_BIT_ERROR;
+ }
+ else if(status & SDMMC_INT_DRTO)
+ {
+ cmd->data->error = -ETIMEDOUT;
+ host->errorstep = 0x1A;
+ output = SDM_DATA_READ_TIMEOUT;
+ }
+ else if(status & SDMMC_INT_DCRC)
+ {
+ host->errorstep = 0x1B;
+ cmd->data->error = -EILSEQ;
+ output = SDM_DATA_CRC_ERROR;
+ }
+ else
+ {
+ output = rk29_sdmmc_read_remain_data(host, (host->data->blocks * host->data->blksz), host->pbuf);
+ if(SDM_SUCCESS == output)
+ {
+ host->data->bytes_xfered = host->data->blocks * host->data->blksz;
+ }
+ }
+ }
+ }
+
+ if(SDM_SUCCESS == output)
+ {
+ if ((mmc_resp_type(cmd) == MMC_RSP_R1B) || (MMC_STOP_TRANSMISSION == cmd->opcode))
+ {
+ output = rk29_sdmmc_wait_unbusy(host);
+ if((SDM_SUCCESS != output) && (!host->mrq->cmd->error))
+ {
+ printk("%s..%d... CMD12 wait busy timeout!!!!! errorStep=0x%x ====xbw=[%s]====\n", \
+ __FUNCTION__, __LINE__, host->errorstep, host->dma_name);
+ rk29_sdmmc_clear_fifo(host);
+ cmd->error = -ETIMEDOUT;
+ host->mrq->cmd->error = -ETIMEDOUT;
+ host->errorstep = 0x1C;
+ }
+ }
+ }
+ host->errorstep = 0xf6;
+
+ //trace error
+ if(cmd->data && cmd->data->error)
+ {
+ if( (!cmd->error) && (0==cmd->retries))
+ {
+ printk("%s..%d......CMD=%d error!!!(arg=0x%x,cmdretry=%d,blksize=%d, blocks=%d), \n \
+ statusReg=0x%x, ctrlReg=0x%x, nerrorTimes=%d, errorStep=0x%x ====xbw[%s]====\n",\
+ __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, cmd->retries,cmd->data->blksz, cmd->data->blocks,
+ rk29_sdmmc_read(host->regs, SDMMC_STATUS),
+ rk29_sdmmc_read(host->regs, SDMMC_CTRL),
+ host->error_times,host->errorstep, host->dma_name);
+ }
+ cmd->error = -ENODATA;
+ }
+ host->errorstep = 0xf5;
+
+exit:
+
+#ifdef RK29_SDMMC_LIST_QUEUE
+ if (!list_empty(&host->queue))
+ {
+ printk("%s..%d.. Danger!Danger!. continue the next request in the queue. ====xbw[%s]====\n",\
+ __FUNCTION__, __LINE__, host->dma_name);
+
+ host = list_entry(host->queue.next,
+ struct rk29_sdmmc, queue_node);
+ list_del(&host->queue_node);
+ host->state = STATE_SENDING_CMD;
+ rk29_sdmmc_start_request(host->mmc);
+ }
+ else
+ {
+ dev_vdbg(&host->pdev->dev, "list empty\n");
+ host->state = STATE_IDLE;
+ }
+#else
+ dev_vdbg(&host->pdev->dev, "list empty\n");
+ host->state = STATE_IDLE;
+#endif
+
+}
+
+static int rk29_sdmmc_command_complete(struct rk29_sdmmc *host,
+ struct mmc_command *cmd)
+{
+ u32 value, status = host->cmd_status;
+ int timeout, output= SDM_SUCCESS;
+
+ xbwprintk(7, "%s..%d. cmd=%d, host->state=0x%x, cmdINT=0x%x\n,pendingEvent=0x%lu,completeEvents=0x%lu ===xbw[%s]===\n\n",\
+ __FUNCTION__, __LINE__,cmd->opcode,host->state,status, host->pending_events,host->completed_events,host->dma_name);
+
+
+ del_timer_sync(&host->request_timer);
+
+ host->cmd_status = 0;
+
+ if((RK29_CTRL_SDMMC_ID == host->pdev->id) && (host->cmdr & SDMMC_CMD_STOP))
+ {
+ output = rk29_sdmmc_reset_fifo(host);
+ if (SDM_SUCCESS != output)
+ {
+ printk("%s..%d......reset fifo fail! CMD%d(arg=0x%x, Retries=%d) =======xbw[%s]=====\n",__FUNCTION__, __LINE__, \
+ cmd->opcode, cmd->arg, cmd->retries,host->dma_name);
+
+ cmd->error = -ETIMEDOUT;
+ host->mrq->cmd->error = cmd->error;
+ output = SDM_ERROR;
+ host->errorstep = 0x1C;
+ goto CMD_Errror;
+ }
+ }
+
+ if(status & SDMMC_INT_RTO)
+ {
+ cmd->error = -ENOMEM;
+ host->mrq->cmd->error = cmd->error;
+ output = SDM_BUSY_TIMEOUT;
+
+ //rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RTO);
+ rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,0xFFFFFFFF); //modifyed by xbw at 2011-08-15
+
+ if(host->use_dma)//if(host->dodma)
+ {
+ if(host->dodma)
+ {
+ rk29_sdmmc_stop_dma(host);
+ rk29_sdmmc_control_host_dma(host, FALSE);
+ host->dodma = 0;
+ }
+
+ value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
+ value |= SDMMC_CTRL_FIFO_RESET;
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL, value);
+
+ timeout = 1000;
+ while (((value = rk29_sdmmc_read(host->regs, SDMMC_CTRL)) & (SDMMC_CTRL_FIFO_RESET)) && (timeout > 0))
+ {
+ udelay(1);
+ timeout--;
+ }
+ if (timeout == 0)
+ {
+ output = SDM_FALSE;
+ host->errorstep = 0x1D;
+ printk("%s..%d......reset CTRL fail! CMD%d(arg=0x%x, Retries=%d) ===xbw[%s]===\n",\
+ __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, cmd->retries,host->dma_name);
+
+ goto CMD_Errror;
+ }
+ }
+
+ }
+
+ if(cmd->flags & MMC_RSP_PRESENT)
+ {
+ if(cmd->flags & MMC_RSP_136)
+ {
+ cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0);
+ cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1);
+ cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2);
+ cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3);
+ }
+ else
+ {
+ cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0);
+ }
+ }
+
+ if(cmd->error)
+ {
+ del_timer_sync(&host->DTO_timer);
+
+ //trace error
+ if((0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0) && (12 != cmd->opcode))
+ {
+ if( ((RK29_CTRL_SDMMC_ID==host->pdev->id)&&(MMC_SLEEP_AWAKE!=cmd->opcode)) ||
+ ((RK29_CTRL_SDMMC_ID!=host->pdev->id)&&(MMC_SEND_EXT_CSD!=cmd->opcode)) )
+ {
+ printk("%s..%d...CMD%d(arg=0x%x), hoststate=%d, errorTimes=%d, errorStep=0x%x ! ===xbw[%s]===\n",\
+ __FUNCTION__, __LINE__, cmd->opcode, cmd->arg, host->state,host->error_times,host->errorstep, host->dma_name);
+ }
+ }
+
+ }
+ del_timer_sync(&host->request_timer);
+
+
+ return SDM_SUCCESS;
+
+CMD_Errror:
+ del_timer_sync(&host->request_timer);
+ del_timer_sync(&host->DTO_timer);
+
+ if((0==cmd->retries) && (host->error_times++%RK29_ERROR_PRINTK_INTERVAL == 0))
+ {
+ printk("%s..%d....command_complete(CMD=%d, arg=%x) error=%d =======xbw[%s]=====\n",\
+ __FUNCTION__, __LINE__, host->cmd->opcode,host->cmd->arg, output, host->dma_name);
+ }
+
+ return output;
+
+}
+
+
+static void rk29_sdmmc_start_error(struct rk29_sdmmc *host)
+{
+ host->cmd->error = -EIO;
+ host->mrq->cmd->error = -EIO;
+ host->cmd_status |= SDMMC_INT_RTO;
+
+ del_timer_sync(&host->request_timer);
+
+ rk29_sdmmc_command_complete(host, host->mrq->cmd);
+ rk29_sdmmc_request_end(host, host->mrq->cmd);
+
+}
+
+static void rk29_sdmmc_tasklet_func(unsigned long priv)
+{
+ struct rk29_sdmmc *host = (struct rk29_sdmmc *)priv;
+ struct mmc_data *data = host->cmd->data;
+ enum rk29_sdmmc_state state = host->state;
+ int pending_flag, stopflag;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&host->lock, iflags);
+
+ state = host->state;
+ pending_flag = 0;
+ stopflag = 0;
+
+ do
+ {
+ switch (state)
+ {
+ case STATE_IDLE:
+ {
+ xbwprintk(7, "%s..%d.. prev_state= STATE_IDLE ====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__, host->dma_name);
+ break;
+ }
+
+ case STATE_SENDING_CMD:
+ {
+ xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_CMD, pendingEvernt=0x%lu ====xbw[%s]====\n",\
+ __FUNCTION__, __LINE__,host->completed_events, host->dma_name);
+
+ if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE))
+ break;
+ host->errorstep = 0xfb;
+
+ del_timer_sync(&host->request_timer); //delete the timer for INT_COME_DONE
+
+ rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
+ rk29_sdmmc_command_complete(host, host->cmd);
+
+
+ if (!data)
+ {
+ rk29_sdmmc_request_end(host, host->cmd);
+
+ xbwprintk(7, "%s..%d.. CMD%d call mmc_request_done()====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name);
+
+ host->complete_done = 1;
+ break;
+ }
+ host->errorstep = 0xfa;
+ if(host->cmd->error)
+ {
+ del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
+
+ if(data->stop)
+ {
+ xbwprintk(7, "%s..%d.. cmderr, so call send_stop_cmd() ====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__, host->dma_name);
+
+ #if 0
+ state = STATE_SENDING_CMD;//STATE_SENDING_STOP;
+ send_stop_cmd(host);
+ #else
+ stopflag = 1; //Moidfyed by xbw at 2011-09-08
+ #endif
+ break;
+ }
+
+ rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
+ }
+
+ host->errorstep = 0xf9;
+ state = STATE_DATA_BUSY;
+ /* fall through */
+ }
+
+ case STATE_DATA_BUSY:
+ {
+ xbwprintk(7, "%s..%d.. prev_state= STATE_DATA_BUSY, pendingEvernt=0x%lu ====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__,host->pending_events, host->dma_name);
+
+ if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_DATA_COMPLETE))
+ break;
+ host->errorstep = 0xf8;
+ rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE);
+ del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
+
+ rk29_sdmmc_request_end(host, host->cmd);
+
+ if (data && !data->stop)
+ {
+ xbwprintk(7, "%s..%d.. CMD%d call mmc_request_done()====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__,host->cmd->opcode,host->dma_name);
+
+ if(!( (MMC_READ_SINGLE_BLOCK == host->cmd->opcode)&&( -EIO == data->error))) //deal with START_BIT_ERROR
+ {
+ host->complete_done = 2;
+ break;
+ }
+
+ }
+ host->errorstep = 0xf4;
+ xbwprintk(7, "%s..%d.. after DATA_COMPLETE, so call send_stop_cmd() ====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__, host->dma_name);
+
+ #if 0
+ state = STATE_SENDING_CMD;
+ send_stop_cmd(host);
+ #else
+ stopflag = 2; //Moidfyed by xbw at 2011-09-08
+ #endif
+
+ break;
+ }
+
+ case STATE_SENDING_STOP:
+ {
+ xbwprintk(7, "%s..%d.. prev_state= STATE_SENDING_STOP, pendingEvernt=0x%lu ====xbw[%s]====\n", \
+ __FUNCTION__, __LINE__, host->pending_events, host->dma_name);
+
+ if (!rk29_sdmmc_test_and_clear_pending(host, EVENT_CMD_COMPLETE))
+ break;
+
+ rk29_sdmmc_command_complete(host, host->cmd);
+ del_timer_sync(&host->request_timer); //delete the timer for INT_CMD_DONE int CMD12
+ rk29_sdmmc_request_end(host, host->cmd);
+
+ host->complete_done = 3;
+ break;
+ }
+
+ }
+
+ pending_flag = (host->complete_done > 0) && (host->retryfunc<50) \
+ && (rk29_sdmmc_test_pending(host, EVENT_CMD_COMPLETE)|| rk29_sdmmc_test_pending(host, EVENT_DATA_COMPLETE) );
+ if(pending_flag)
+ {
+ xbwprintk(7, "%s..%d... cmd=%d(arg=0x%x),completedone=%d, retrycount=%d, doneflag=%d, \n \
+ host->state=0x%x, switchstate=%x, \n \
+ pendingEvent=0x%lu, completeEvents=0x%lu, \n \
+ mrqCMD=%d, arg=0x%x \n ====xbw[%s]====\n",\
+
+ __FUNCTION__, __LINE__,host->cmd->opcode, host->cmd->arg, host->complete_done,\
+ host->retryfunc, host->mmc->doneflag,host->state, state, \
+ host->pending_events,host->completed_events,\
+ host->mrq->cmd->opcode, host->mrq->cmd->arg, host->dma_name);
+
+ cpu_relax();
+ }
+
+ } while(pending_flag && ++host->retryfunc); //while(0);
+
+ if(0!=stopflag)
+ {
+ if(host->cmd->error)
+ xbwprintk(3,"%d: call send_stop_cmd== %d, completedone=%d, doneflag=%d, hoststate=%x, statusReg=0x%x \n", \
+ __LINE__,stopflag, host->complete_done, host->mmc->doneflag, state, rk29_sdmmc_read(host->regs, SDMMC_STATUS));
+
+ state = STATE_SENDING_CMD;
+ send_stop_cmd(host); //Moidfyed by xbw at 2011-09-08
+ }
+
+ host->state = state;
+
+ if(0==host->complete_done)
+ {
+ host->errorstep = 0xf2;
+ spin_unlock_irqrestore(&host->lock, iflags);
+ return;
+ }
+ host->errorstep = 0xf3;
+ host->state = STATE_IDLE;
+
+ if(host->mrq && host->mmc->doneflag)
+ {
+ host->mmc->doneflag = 0;
+ spin_unlock_irqrestore(&host->lock, iflags);
+
+ mmc_request_done(host->mmc, host->mrq);
+ }
+ else
+ {
+ spin_unlock_irqrestore(&host->lock, iflags);
+ }
+}
+
+
+static inline void rk29_sdmmc_cmd_interrupt(struct rk29_sdmmc *host, u32 status)