diff options
author | Pavel Pisa <ppisa@pikron.com> | 2006-05-19 16:48:03 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-05-19 16:48:03 -0400 |
commit | 2c171bf13423dc5293188cea7f6c2da1720926e2 (patch) | |
tree | d251705f564c8ffb081ba84c769fd2d1b229db53 | |
parent | a54c9d30dbb06391ec4422aaf0e1dc2c8c53bd3e (diff) |
[ARM] 3531/1: i.MX/MX1 SD/MMC ensure, that clock are stopped before new 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>
-rw-r--r-- | drivers/mmc/au1xmmc.c | 6 | ||||
-rw-r--r-- | drivers/mmc/imxmmc.c | 24 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 1 | ||||
-rw-r--r-- | drivers/mmc/mmc_block.c | 1 | ||||
-rw-r--r-- | drivers/mmc/pxamci.c | 4 | ||||
-rw-r--r-- | drivers/mmc/wbsd.c | 8 | ||||
-rw-r--r-- | include/linux/mmc/mmc.h | 1 |
7 files changed, 26 insertions, 19 deletions
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 914d62b24064..5dc4bee7abeb 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c | |||
@@ -310,7 +310,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) | |||
310 | } | 310 | } |
311 | else | 311 | else |
312 | data->bytes_xfered = | 312 | data->bytes_xfered = |
313 | (data->blocks * (1 << data->blksz_bits)) - | 313 | (data->blocks * data->blksz) - |
314 | host->pio.len; | 314 | host->pio.len; |
315 | } | 315 | } |
316 | 316 | ||
@@ -575,7 +575,7 @@ static int | |||
575 | au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) | 575 | au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) |
576 | { | 576 | { |
577 | 577 | ||
578 | int datalen = data->blocks * (1 << data->blksz_bits); | 578 | int datalen = data->blocks * data->blksz; |
579 | 579 | ||
580 | if (dma != 0) | 580 | if (dma != 0) |
581 | host->flags |= HOST_F_DMA; | 581 | host->flags |= HOST_F_DMA; |
@@ -596,7 +596,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) | |||
596 | if (host->dma.len == 0) | 596 | if (host->dma.len == 0) |
597 | return MMC_ERR_TIMEOUT; | 597 | return MMC_ERR_TIMEOUT; |
598 | 598 | ||
599 | au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host)); | 599 | au_writel(data->blksz - 1, HOST_BLKSIZE(host)); |
600 | 600 | ||
601 | if (host->flags & HOST_F_DMA) { | 601 | if (host->flags & HOST_F_DMA) { |
602 | int i; | 602 | int i; |
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 79358e223f57..a4eb1d0e7a71 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c | |||
@@ -218,8 +218,10 @@ static int imxmci_busy_wait_for_status(struct imxmci_host *host, | |||
218 | if(!loops) | 218 | if(!loops) |
219 | return 0; | 219 | return 0; |
220 | 220 | ||
221 | dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", | 221 | /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */ |
222 | loops, where, *pstat, stat_mask); | 222 | if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000)) |
223 | dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", | ||
224 | loops, where, *pstat, stat_mask); | ||
223 | return loops; | 225 | return loops; |
224 | } | 226 | } |
225 | 227 | ||
@@ -333,6 +335,9 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, | |||
333 | WARN_ON(host->cmd != NULL); | 335 | WARN_ON(host->cmd != NULL); |
334 | host->cmd = cmd; | 336 | host->cmd = cmd; |
335 | 337 | ||
338 | /* Ensure, that clock are stopped else command programming and start fails */ | ||
339 | imxmci_stop_clock(host); | ||
340 | |||
336 | if (cmd->flags & MMC_RSP_BUSY) | 341 | if (cmd->flags & MMC_RSP_BUSY) |
337 | cmdat |= CMD_DAT_CONT_BUSY; | 342 | cmdat |= CMD_DAT_CONT_BUSY; |
338 | 343 | ||
@@ -553,7 +558,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) | |||
553 | int trans_done = 0; | 558 | int trans_done = 0; |
554 | unsigned int stat = *pstat; | 559 | unsigned int stat = *pstat; |
555 | 560 | ||
556 | if(host->actual_bus_width == MMC_BUS_WIDTH_4) | 561 | if(host->actual_bus_width != MMC_BUS_WIDTH_4) |
557 | burst_len = 16; | 562 | burst_len = 16; |
558 | else | 563 | else |
559 | burst_len = 64; | 564 | burst_len = 64; |
@@ -591,8 +596,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) | |||
591 | stat = MMC_STATUS; | 596 | stat = MMC_STATUS; |
592 | 597 | ||
593 | /* Flush extra bytes from FIFO */ | 598 | /* Flush extra bytes from FIFO */ |
594 | while(flush_len >= 2){ | 599 | while(flush_len && !(stat & STATUS_DATA_TRANS_DONE)){ |
595 | flush_len -= 2; | ||
596 | i = MMC_BUFFER_ACCESS; | 600 | i = MMC_BUFFER_ACCESS; |
597 | stat = MMC_STATUS; | 601 | stat = MMC_STATUS; |
598 | stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */ | 602 | stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */ |
@@ -746,10 +750,6 @@ static void imxmci_tasklet_fnc(unsigned long data) | |||
746 | data_dir_mask = STATUS_DATA_TRANS_DONE; | 750 | data_dir_mask = STATUS_DATA_TRANS_DONE; |
747 | } | 751 | } |
748 | 752 | ||
749 | imxmci_busy_wait_for_status(host, &stat, | ||
750 | data_dir_mask, | ||
751 | 50, "imxmci_tasklet_fnc data"); | ||
752 | |||
753 | if(stat & data_dir_mask) { | 753 | if(stat & data_dir_mask) { |
754 | clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); | 754 | clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); |
755 | imxmci_data_done(host, stat); | 755 | imxmci_data_done(host, stat); |
@@ -865,7 +865,11 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
865 | 865 | ||
866 | imxmci_stop_clock(host); | 866 | imxmci_stop_clock(host); |
867 | MMC_CLK_RATE = (prescaler<<3) | clk; | 867 | MMC_CLK_RATE = (prescaler<<3) | clk; |
868 | imxmci_start_clock(host); | 868 | /* |
869 | * Under my understanding, clock should not be started there, because it would | ||
870 | * initiate SDHC sequencer and send last or random command into card | ||
871 | */ | ||
872 | /*imxmci_start_clock(host);*/ | ||
869 | 873 | ||
870 | dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE); | 874 | dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE); |
871 | } else { | 875 | } else { |
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 1ca2c8b9c9b5..6201f3086a02 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c | |||
@@ -951,6 +951,7 @@ static void mmc_read_scrs(struct mmc_host *host) | |||
951 | data.timeout_ns = card->csd.tacc_ns * 10; | 951 | data.timeout_ns = card->csd.tacc_ns * 10; |
952 | data.timeout_clks = card->csd.tacc_clks * 10; | 952 | data.timeout_clks = card->csd.tacc_clks * 10; |
953 | data.blksz_bits = 3; | 953 | data.blksz_bits = 3; |
954 | data.blksz = 1 << 3; | ||
954 | data.blocks = 1; | 955 | data.blocks = 1; |
955 | data.flags = MMC_DATA_READ; | 956 | data.flags = MMC_DATA_READ; |
956 | data.sg = &sg; | 957 | data.sg = &sg; |
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 06bd1f4cb9b1..e39cc05c64c2 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c | |||
@@ -175,6 +175,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) | |||
175 | brq.data.timeout_ns = card->csd.tacc_ns * 10; | 175 | brq.data.timeout_ns = card->csd.tacc_ns * 10; |
176 | brq.data.timeout_clks = card->csd.tacc_clks * 10; | 176 | brq.data.timeout_clks = card->csd.tacc_clks * 10; |
177 | brq.data.blksz_bits = md->block_bits; | 177 | brq.data.blksz_bits = md->block_bits; |
178 | brq.data.blksz = 1 << md->block_bits; | ||
178 | brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); | 179 | brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); |
179 | brq.stop.opcode = MMC_STOP_TRANSMISSION; | 180 | brq.stop.opcode = MMC_STOP_TRANSMISSION; |
180 | brq.stop.arg = 0; | 181 | brq.stop.arg = 0; |
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index f97b472085cb..b49368fd96b8 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c | |||
@@ -119,7 +119,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) | |||
119 | nob = 0xffff; | 119 | nob = 0xffff; |
120 | 120 | ||
121 | writel(nob, host->base + MMC_NOB); | 121 | writel(nob, host->base + MMC_NOB); |
122 | writel(1 << data->blksz_bits, host->base + MMC_BLKLEN); | 122 | writel(data->blksz, host->base + MMC_BLKLEN); |
123 | 123 | ||
124 | clks = (unsigned long long)data->timeout_ns * CLOCKRATE; | 124 | clks = (unsigned long long)data->timeout_ns * CLOCKRATE; |
125 | do_div(clks, 1000000000UL); | 125 | do_div(clks, 1000000000UL); |
@@ -283,7 +283,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) | |||
283 | * data blocks as being in error. | 283 | * data blocks as being in error. |
284 | */ | 284 | */ |
285 | if (data->error == MMC_ERR_NONE) | 285 | if (data->error == MMC_ERR_NONE) |
286 | data->bytes_xfered = data->blocks << data->blksz_bits; | 286 | data->bytes_xfered = data->blocks * data->blksz; |
287 | else | 287 | else |
288 | data->bytes_xfered = 0; | 288 | data->bytes_xfered = 0; |
289 | 289 | ||
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 39b3d97f891e..8167332d4013 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
@@ -662,14 +662,14 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) | |||
662 | unsigned long dmaflags; | 662 | unsigned long dmaflags; |
663 | 663 | ||
664 | DBGF("blksz %04x blks %04x flags %08x\n", | 664 | DBGF("blksz %04x blks %04x flags %08x\n", |
665 | 1 << data->blksz_bits, data->blocks, data->flags); | 665 | data->blksz, data->blocks, data->flags); |
666 | DBGF("tsac %d ms nsac %d clk\n", | 666 | DBGF("tsac %d ms nsac %d clk\n", |
667 | data->timeout_ns / 1000000, data->timeout_clks); | 667 | data->timeout_ns / 1000000, data->timeout_clks); |
668 | 668 | ||
669 | /* | 669 | /* |
670 | * Calculate size. | 670 | * Calculate size. |
671 | */ | 671 | */ |
672 | host->size = data->blocks << data->blksz_bits; | 672 | host->size = data->blocks * data->blksz; |
673 | 673 | ||
674 | /* | 674 | /* |
675 | * Check timeout values for overflow. | 675 | * Check timeout values for overflow. |
@@ -696,12 +696,12 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) | |||
696 | * Two bytes are needed for each data line. | 696 | * Two bytes are needed for each data line. |
697 | */ | 697 | */ |
698 | if (host->bus_width == MMC_BUS_WIDTH_1) { | 698 | if (host->bus_width == MMC_BUS_WIDTH_1) { |
699 | blksize = (1 << data->blksz_bits) + 2; | 699 | blksize = data->blksz + 2; |
700 | 700 | ||
701 | wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); | 701 | wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); |
702 | wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); | 702 | wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); |
703 | } else if (host->bus_width == MMC_BUS_WIDTH_4) { | 703 | } else if (host->bus_width == MMC_BUS_WIDTH_4) { |
704 | blksize = (1 << data->blksz_bits) + 2 * 4; | 704 | blksize = data->blksz + 2 * 4; |
705 | 705 | ||
706 | wbsd_write_index(host, WBSD_IDX_PBSMSB, | 706 | wbsd_write_index(host, WBSD_IDX_PBSMSB, |
707 | ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); | 707 | ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); |
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index bdc556d88498..03a14a30c46a 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h | |||
@@ -69,6 +69,7 @@ struct mmc_data { | |||
69 | unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ | 69 | unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ |
70 | unsigned int timeout_clks; /* data timeout (in clocks) */ | 70 | unsigned int timeout_clks; /* data timeout (in clocks) */ |
71 | unsigned int blksz_bits; /* data block size */ | 71 | unsigned int blksz_bits; /* data block size */ |
72 | unsigned int blksz; /* data block size */ | ||
72 | unsigned int blocks; /* number of blocks */ | 73 | unsigned int blocks; /* number of blocks */ |
73 | unsigned int error; /* data error */ | 74 | unsigned int error; /* data error */ |
74 | unsigned int flags; | 75 | unsigned int flags; |