Skip to content

Commit

Permalink
mmc: bcm2835: Make sure the controller is idle after a request
Browse files Browse the repository at this point in the history
Some situations like sending MMC_SEND_EXT_CSD command to a SD card
seems to confuse the controller / driver. The command fails before
the controller FSM is finished. So add this band-aid to make sure
the controller is idle before accepting new requests.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
  • Loading branch information
lategoodbye committed Oct 26, 2018
1 parent 7bee8e0 commit 74eb7a8
Showing 1 changed file with 31 additions and 13 deletions.
44 changes: 31 additions & 13 deletions drivers/mmc/host/bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,12 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host)
int timediff;
u32 alternate_idle;

alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ?
SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1;
alternate_idle = SDEDM_FSM_IDENTMODE;

if (host->mrq->data) {
alternate_idle = (host->mrq->data->flags & MMC_DATA_READ) ?
SDEDM_FSM_READWAIT : SDEDM_FSM_WRITESTART1;
}

timediff = 0;

Expand All @@ -322,7 +326,8 @@ static void bcm2835_wait_transfer_complete(struct bcm2835_host *host)
"wait_transfer_complete - still waiting after %d retries\n",
timediff);
bcm2835_dumpregs(host);
host->mrq->data->error = -ETIMEDOUT;
if (host->mrq->data)
host->mrq->data->error = -ETIMEDOUT;
return;
}
cpu_relax();
Expand Down Expand Up @@ -605,29 +610,42 @@ static u32 bcm2835_read_wait_sdcmd(struct bcm2835_host *host, u32 max_ms)

static void bcm2835_finish_request(struct bcm2835_host *host)
{
struct dma_chan *terminate_chan = NULL;
struct mmc_request *mrq;
u32 edm, fsm;

cancel_delayed_work_sync(&host->timeout_work);

if (host->dma_chan) {
int err = dmaengine_terminate_sync(host->dma_chan);

if (err)
dev_err(&host->pdev->dev,
"failed to terminate DMA (%d)\n", err);
}

/*
* Some situations like sending MMC_SEND_EXT_CSD command to a SD card
* seems to confuse the controller / driver. The command fails before
* the controller FSM is finished. So make sure the FSM is idle.
*/
edm = readl(host->ioaddr + SDEDM);
fsm = edm & SDEDM_FSM_MASK;

if ((fsm != SDEDM_FSM_IDENTMODE) &&
(fsm != SDEDM_FSM_DATAMODE))
dev_err(&host->pdev->dev, "FSM still busy\n");

bcm2835_wait_transfer_complete(host);

mrq = host->mrq;

host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;

host->dma_desc = NULL;
terminate_chan = host->dma_chan;
host->dma_chan = NULL;

if (terminate_chan) {
int err = dmaengine_terminate_all(terminate_chan);

if (err)
dev_err(&host->pdev->dev,
"failed to terminate DMA (%d)\n", err);
}

mmc_request_done(host->mmc, mrq);
}

Expand Down

0 comments on commit 74eb7a8

Please sign in to comment.