Skip to content

Commit

Permalink
[ARM] 3531/1: i.MX/MX1 SD/MMC ensure, that clock are stopped before n…
Browse files Browse the repository at this point in the history
…ew command and cleanups

Patch from Pavel Pisa

There has been problems that for some paths that clock are not stopped
during new command programming and initiation. Result is issuing
of incorrect command to the card. Some other problems are cleaned too.
Noisy report of known ERRATUM #4 has been suppressed.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Pavel Pisa authored and Russell King committed May 19, 2006
1 parent a54c9d3 commit 2c171bf
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 19 deletions.
6 changes: 3 additions & 3 deletions drivers/mmc/au1xmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
}
else
data->bytes_xfered =
(data->blocks * (1 << data->blksz_bits)) -
(data->blocks * data->blksz) -
host->pio.len;
}

Expand Down Expand Up @@ -575,7 +575,7 @@ static int
au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
{

int datalen = data->blocks * (1 << data->blksz_bits);
int datalen = data->blocks * data->blksz;

if (dma != 0)
host->flags |= HOST_F_DMA;
Expand All @@ -596,7 +596,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
if (host->dma.len == 0)
return MMC_ERR_TIMEOUT;

au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host));
au_writel(data->blksz - 1, HOST_BLKSIZE(host));

if (host->flags & HOST_F_DMA) {
int i;
Expand Down
24 changes: 14 additions & 10 deletions drivers/mmc/imxmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,10 @@ static int imxmci_busy_wait_for_status(struct imxmci_host *host,
if(!loops)
return 0;

dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
loops, where, *pstat, stat_mask);
/* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
loops, where, *pstat, stat_mask);
return loops;
}

Expand Down Expand Up @@ -333,6 +335,9 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
WARN_ON(host->cmd != NULL);
host->cmd = cmd;

/* Ensure, that clock are stopped else command programming and start fails */
imxmci_stop_clock(host);

if (cmd->flags & MMC_RSP_BUSY)
cmdat |= CMD_DAT_CONT_BUSY;

Expand Down Expand Up @@ -553,7 +558,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
int trans_done = 0;
unsigned int stat = *pstat;

if(host->actual_bus_width == MMC_BUS_WIDTH_4)
if(host->actual_bus_width != MMC_BUS_WIDTH_4)
burst_len = 16;
else
burst_len = 64;
Expand Down Expand Up @@ -591,8 +596,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
stat = MMC_STATUS;

/* Flush extra bytes from FIFO */
while(flush_len >= 2){
flush_len -= 2;
while(flush_len && !(stat & STATUS_DATA_TRANS_DONE)){
i = MMC_BUFFER_ACCESS;
stat = MMC_STATUS;
stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */
Expand Down Expand Up @@ -746,10 +750,6 @@ static void imxmci_tasklet_fnc(unsigned long data)
data_dir_mask = STATUS_DATA_TRANS_DONE;
}

imxmci_busy_wait_for_status(host, &stat,
data_dir_mask,
50, "imxmci_tasklet_fnc data");

if(stat & data_dir_mask) {
clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
imxmci_data_done(host, stat);
Expand Down Expand Up @@ -865,7 +865,11 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)

imxmci_stop_clock(host);
MMC_CLK_RATE = (prescaler<<3) | clk;
imxmci_start_clock(host);
/*
* Under my understanding, clock should not be started there, because it would
* initiate SDHC sequencer and send last or random command into card
*/
/*imxmci_start_clock(host);*/

dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
} else {
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ static void mmc_read_scrs(struct mmc_host *host)
data.timeout_ns = card->csd.tacc_ns * 10;
data.timeout_clks = card->csd.tacc_clks * 10;
data.blksz_bits = 3;
data.blksz = 1 << 3;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/mmc_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.timeout_ns = card->csd.tacc_ns * 10;
brq.data.timeout_clks = card->csd.tacc_clks * 10;
brq.data.blksz_bits = md->block_bits;
brq.data.blksz = 1 << md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
Expand Down
4 changes: 2 additions & 2 deletions drivers/mmc/pxamci.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
nob = 0xffff;

writel(nob, host->base + MMC_NOB);
writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
writel(data->blksz, host->base + MMC_BLKLEN);

clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
do_div(clks, 1000000000UL);
Expand Down Expand Up @@ -283,7 +283,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
* data blocks as being in error.
*/
if (data->error == MMC_ERR_NONE)
data->bytes_xfered = data->blocks << data->blksz_bits;
data->bytes_xfered = data->blocks * data->blksz;
else
data->bytes_xfered = 0;

Expand Down
8 changes: 4 additions & 4 deletions drivers/mmc/wbsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,14 +662,14 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
unsigned long dmaflags;

DBGF("blksz %04x blks %04x flags %08x\n",
1 << data->blksz_bits, data->blocks, data->flags);
data->blksz, data->blocks, data->flags);
DBGF("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks);

/*
* Calculate size.
*/
host->size = data->blocks << data->blksz_bits;
host->size = data->blocks * data->blksz;

/*
* Check timeout values for overflow.
Expand All @@ -696,12 +696,12 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
* Two bytes are needed for each data line.
*/
if (host->bus_width == MMC_BUS_WIDTH_1) {
blksize = (1 << data->blksz_bits) + 2;
blksize = data->blksz + 2;

wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
} else if (host->bus_width == MMC_BUS_WIDTH_4) {
blksize = (1 << data->blksz_bits) + 2 * 4;
blksize = data->blksz + 2 * 4;

wbsd_write_index(host, WBSD_IDX_PBSMSB,
((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
Expand Down
1 change: 1 addition & 0 deletions include/linux/mmc/mmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct mmc_data {
unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
unsigned int timeout_clks; /* data timeout (in clocks) */
unsigned int blksz_bits; /* data block size */
unsigned int blksz; /* data block size */
unsigned int blocks; /* number of blocks */
unsigned int error; /* data error */
unsigned int flags;
Expand Down

0 comments on commit 2c171bf

Please sign in to comment.