static void sdmmc_send_cmd(struct rk29_sdmmc *host, unsigned int cmd, int arg)
{
int tmo = 10000;
-
+ while(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_MC_BUSY){
+ /* reset all blocks */
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+ /* wait till resets clear */
+ dev_info(&host->pdev->dev, "sdmmc_send cmd mci busy, ctrl reset ");
+ while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+ printk("done\n");
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL, rk29_sdmmc_read(host->regs, SDMMC_CTRL) | SDMMC_CTRL_INT_ENABLE);
+ }
rk29_sdmmc_write(host->regs, SDMMC_CMDARG, arg);
rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd);
while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START);
u32 div;
if (host->clock != host->current_speed) {
+ //rk29_sdmmc_write(host->regs, SDMMC_INTMASK,0);
div = (((host->bus_hz + (host->bus_hz / 5)) / host->clock)) >> 1;
if(!div)
div = 1;
sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
host->current_speed = host->clock;
+ //if(host->use_dma)
+ //rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD);
+ //else
+ //rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_TXDR | SDMMC_INT_RXDR | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD);
}
/* Set the current bus width */
host->cmd = NULL;
rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
- rk29_sdmmc_command_complete(host, mrq->cmd);
- if (!mrq->data || cmd->error) {
- rk29_sdmmc_request_end(host, host->curr_mrq);
- goto unlock;
+ if(mrq)
+ {
+ rk29_sdmmc_command_complete(host, mrq->cmd);
+ if (!mrq->data || (cmd && cmd->error)) {
+ rk29_sdmmc_request_end(host, host->curr_mrq);
+ goto unlock;
+ }
}
-
prev_state = state = STATE_SENDING_DATA;
/* fall through */
if (rk29_sdmmc_test_and_clear_pending(host,
EVENT_DATA_ERROR)) {
rk29_sdmmc_stop_dma(host);
- if (data->stop)
+ if (data && data->stop)
send_stop_cmd(host, data);
state = STATE_DATA_ERROR;
break;
rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE);
status = host->data_status;
+ if(data) {
if (unlikely(status & RK29_SDMMC_DATA_ERROR_FLAGS)) {
if (status & SDMMC_INT_DRTO) {
dev_err(&host->pdev->dev,
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
}
-
- if (!data->stop) {
+ }
+ if (!data->stop && host->curr_mrq) {
rk29_sdmmc_request_end(host, host->curr_mrq);
goto unlock;
}
prev_state = state = STATE_SENDING_STOP;
- if (!data->error)
+ if (data && !data->error)
send_stop_cmd(host, data);
/* fall through */
host->cmd = NULL;
rk29_sdmmc_command_complete(host, mrq->stop);
- rk29_sdmmc_request_end(host, host->curr_mrq);
+ if(host->curr_mrq)
+ rk29_sdmmc_request_end(host, host->curr_mrq);
goto unlock;
case STATE_DATA_ERROR:
if (!rk29_sdmmc_test_and_clear_pending(host,
host->cmd_status = status;
smp_wmb();
rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
- tasklet_schedule(&host->tasklet);
- printk("[zwp] %s :cmd transfer error(int status 0x%x cmd %d host->state %d pending_events %d)\n",
- __FUNCTION__,status,host->cmd->opcode,host->state,host->pending_events);
+ if(host->cmd == NULL) {
+ printk("host->cmd == NULL\n");
+ }
+ else
+ printk("[zwp] %s :cmd transfer error(int status 0x%x cmd %d host->state %d pending_events %d)\n",
+ __FUNCTION__,status,host->cmd->opcode,host->state,host->pending_events);
+ tasklet_schedule(&host->tasklet);
}
if (pending & RK29_SDMMC_DATA_ERROR_FLAGS) { // if there is an error, let report DATA_ERROR
break;
/* fall through */
case STATE_SENDING_DATA:
- mrq->data->error = -ENOMEDIUM;
+ if(mrq->data)
+ mrq->data->error = -ENOMEDIUM;
rk29_sdmmc_stop_dma(host);
break;
case STATE_DATA_BUSY:
case STATE_DATA_ERROR:
- if (mrq->data->error == -EINPROGRESS)
+ if (mrq->data && mrq->data->error == -EINPROGRESS)
mrq->data->error = -ENOMEDIUM;
if (!mrq->stop)
break;
spin_lock(&host->lock);
}
}
- spin_unlock(&host->lock);
+ spin_unlock(&host->lock);
+ while(rk29_sdmmc_read(host->regs, SDMMC_STATUS) & SDMMC_STAUTS_MC_BUSY){
+ /* reset all blocks */
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+ /* wait till resets clear */
+ printk("mmc_detect_change: mci busy, ctrl reset ");
+ while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+ printk("done\n");
+ rk29_sdmmc_write(host->regs, SDMMC_CTRL, rk29_sdmmc_read(host->regs, SDMMC_CTRL) | SDMMC_CTRL_INT_ENABLE);
+ }
mmc_detect_change(host->mmc, 0);
}