aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-06 16:36:30 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-06 16:36:30 -0500
commitb69fc2efc9205d58c820eb2eb1caa6bf873b4b0d (patch)
tree99a505e56cd10e883ee87ced7ebc26811be341e1 /drivers/mmc
parent84b7290cca16c61a167c7e1912cd84a479852165 (diff)
parentc6d92e9b84da2002ee7a75b784834970ddfd3bfd (diff)
Merge branch 'for-linus' of git://codeaurora.org/quic/kernel/davidb/linux-msm
* 'for-linus' of git://codeaurora.org/quic/kernel/davidb/linux-msm: (35 commits) mmc: msm_sdcc: Check for only DATA_END interrupt to end a request mmc: msm_sdcc: Fix bug in PIO mode when data size is not word aligned mmc: msm_sdcc: Reset SDCC in case of data transfer errors mmc: msm_sdcc: Add prog done interrupt support mmc: msm_sdcc: Fix possible circular locking dependency warning MSM: Add USB support for MSM7x30 MSM: Add USB suport for QSD8x50 msm: initial framebuffer support msm: add handling for clocks tagged as CLK_MINMAX msm: trout: change name of pmdh_clk to mddi_clk msm: add CLK_MINMAX to pmdh_clk msm: trout: add gpio_to_irq msm: iommu: Use the correct memory allocation flag msm_serial: Remove redundant unlikely() msm: iommu: Miscellaneous code cleanup msm: iommu: Support cache-coherent memory access msm: iommu: Definitions for extended memory attributes msm: iommu: Kconfig dependency for the IOMMU API msm: iommu: Check if device is already attached msm: iommu: Kconfig item for cacheable page tables ...
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/msm_sdcc.c139
-rw-r--r--drivers/mmc/host/msm_sdcc.h8
2 files changed, 113 insertions, 34 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 1290d14c5839..5decfd0bd61d 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -44,6 +44,7 @@
44#include <mach/mmc.h> 44#include <mach/mmc.h>
45#include <mach/msm_iomap.h> 45#include <mach/msm_iomap.h>
46#include <mach/dma.h> 46#include <mach/dma.h>
47#include <mach/clk.h>
47 48
48#include "msm_sdcc.h" 49#include "msm_sdcc.h"
49 50
@@ -126,6 +127,40 @@ static void
126msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, 127msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
127 u32 c); 128 u32 c);
128 129
130static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
131{
132 u32 mci_clk = 0;
133 u32 mci_mask0 = 0;
134 int ret = 0;
135
136 /* Save the controller state */
137 mci_clk = readl(host->base + MMCICLOCK);
138 mci_mask0 = readl(host->base + MMCIMASK0);
139
140 /* Reset the controller */
141 ret = clk_reset(host->clk, CLK_RESET_ASSERT);
142 if (ret)
143 pr_err("%s: Clock assert failed at %u Hz with err %d\n",
144 mmc_hostname(host->mmc), host->clk_rate, ret);
145
146 ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
147 if (ret)
148 pr_err("%s: Clock deassert failed at %u Hz with err %d\n",
149 mmc_hostname(host->mmc), host->clk_rate, ret);
150
151 pr_info("%s: Controller has been re-initialiazed\n",
152 mmc_hostname(host->mmc));
153
154 /* Restore the contoller state */
155 writel(host->pwr, host->base + MMCIPOWER);
156 writel(mci_clk, host->base + MMCICLOCK);
157 writel(mci_mask0, host->base + MMCIMASK0);
158 ret = clk_set_rate(host->clk, host->clk_rate);
159 if (ret)
160 pr_err("%s: Failed to set clk rate %u Hz (%d)\n",
161 mmc_hostname(host->mmc), host->clk_rate, ret);
162}
163
129static void 164static void
130msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) 165msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
131{ 166{
@@ -155,7 +190,7 @@ static void
155msmsdcc_stop_data(struct msmsdcc_host *host) 190msmsdcc_stop_data(struct msmsdcc_host *host)
156{ 191{
157 host->curr.data = NULL; 192 host->curr.data = NULL;
158 host->curr.got_dataend = host->curr.got_datablkend = 0; 193 host->curr.got_dataend = 0;
159} 194}
160 195
161uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) 196uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
@@ -189,42 +224,42 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
189} 224}
190 225
191static void 226static void
192msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, 227msmsdcc_dma_complete_tlet(unsigned long data)
193 unsigned int result,
194 struct msm_dmov_errdata *err)
195{ 228{
196 struct msmsdcc_dma_data *dma_data = 229 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
197 container_of(cmd, struct msmsdcc_dma_data, hdr);
198 struct msmsdcc_host *host = dma_data->host;
199 unsigned long flags; 230 unsigned long flags;
200 struct mmc_request *mrq; 231 struct mmc_request *mrq;
232 struct msm_dmov_errdata err;
201 233
202 spin_lock_irqsave(&host->lock, flags); 234 spin_lock_irqsave(&host->lock, flags);
203 host->dma.active = 0; 235 host->dma.active = 0;
204 236
237 err = host->dma.err;
205 mrq = host->curr.mrq; 238 mrq = host->curr.mrq;
206 BUG_ON(!mrq); 239 BUG_ON(!mrq);
207 WARN_ON(!mrq->data); 240 WARN_ON(!mrq->data);
208 241
209 if (!(result & DMOV_RSLT_VALID)) { 242 if (!(host->dma.result & DMOV_RSLT_VALID)) {
210 pr_err("msmsdcc: Invalid DataMover result\n"); 243 pr_err("msmsdcc: Invalid DataMover result\n");
211 goto out; 244 goto out;
212 } 245 }
213 246
214 if (result & DMOV_RSLT_DONE) { 247 if (host->dma.result & DMOV_RSLT_DONE) {
215 host->curr.data_xfered = host->curr.xfer_size; 248 host->curr.data_xfered = host->curr.xfer_size;
216 } else { 249 } else {
217 /* Error or flush */ 250 /* Error or flush */
218 if (result & DMOV_RSLT_ERROR) 251 if (host->dma.result & DMOV_RSLT_ERROR)
219 pr_err("%s: DMA error (0x%.8x)\n", 252 pr_err("%s: DMA error (0x%.8x)\n",
220 mmc_hostname(host->mmc), result); 253 mmc_hostname(host->mmc), host->dma.result);
221 if (result & DMOV_RSLT_FLUSH) 254 if (host->dma.result & DMOV_RSLT_FLUSH)
222 pr_err("%s: DMA channel flushed (0x%.8x)\n", 255 pr_err("%s: DMA channel flushed (0x%.8x)\n",
223 mmc_hostname(host->mmc), result); 256 mmc_hostname(host->mmc), host->dma.result);
224 if (err) 257
225 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", 258 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
226 err->flush[0], err->flush[1], err->flush[2], 259 err.flush[0], err.flush[1], err.flush[2],
227 err->flush[3], err->flush[4], err->flush[5]); 260 err.flush[3], err.flush[4], err.flush[5]);
261
262 msmsdcc_reset_and_restore(host);
228 if (!mrq->data->error) 263 if (!mrq->data->error)
229 mrq->data->error = -EIO; 264 mrq->data->error = -EIO;
230 } 265 }
@@ -242,8 +277,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
242 host->dma.sg = NULL; 277 host->dma.sg = NULL;
243 host->dma.busy = 0; 278 host->dma.busy = 0;
244 279
245 if ((host->curr.got_dataend && host->curr.got_datablkend) 280 if (host->curr.got_dataend || mrq->data->error) {
246 || mrq->data->error) {
247 281
248 /* 282 /*
249 * If we've already gotten our DATAEND / DATABLKEND 283 * If we've already gotten our DATAEND / DATABLKEND
@@ -273,6 +307,22 @@ out:
273 return; 307 return;
274} 308}
275 309
310static void
311msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
312 unsigned int result,
313 struct msm_dmov_errdata *err)
314{
315 struct msmsdcc_dma_data *dma_data =
316 container_of(cmd, struct msmsdcc_dma_data, hdr);
317 struct msmsdcc_host *host = dma_data->host;
318
319 dma_data->result = result;
320 if (err)
321 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
322
323 tasklet_schedule(&host->dma_tlet);
324}
325
276static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) 326static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
277{ 327{
278 if (host->dma.channel == -1) 328 if (host->dma.channel == -1)
@@ -424,6 +474,11 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host,
424 (cmd->opcode == 53)) 474 (cmd->opcode == 53))
425 *c |= MCI_CSPM_DATCMD; 475 *c |= MCI_CSPM_DATCMD;
426 476
477 if (host->prog_scan && (cmd->opcode == 12)) {
478 *c |= MCI_CPSM_PROGENA;
479 host->prog_enable = true;
480 }
481
427 if (cmd == cmd->mrq->stop) 482 if (cmd == cmd->mrq->stop)
428 *c |= MCI_CSPM_MCIABORT; 483 *c |= MCI_CSPM_MCIABORT;
429 484
@@ -450,7 +505,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
450 host->curr.xfer_remain = host->curr.xfer_size; 505 host->curr.xfer_remain = host->curr.xfer_size;
451 host->curr.data_xfered = 0; 506 host->curr.data_xfered = 0;
452 host->curr.got_dataend = 0; 507 host->curr.got_dataend = 0;
453 host->curr.got_datablkend = 0;
454 508
455 memset(&host->pio, 0, sizeof(host->pio)); 509 memset(&host->pio, 0, sizeof(host->pio));
456 510
@@ -494,6 +548,8 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
494 host->cmd_c = c; 548 host->cmd_c = c;
495 } 549 }
496 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); 550 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
551 if (data->flags & MMC_DATA_WRITE)
552 host->prog_scan = true;
497 } else { 553 } else {
498 msmsdcc_writel(host, timeout, MMCIDATATIMER); 554 msmsdcc_writel(host, timeout, MMCIDATATIMER);
499 555
@@ -555,6 +611,9 @@ msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
555 uint32_t *ptr = (uint32_t *) buffer; 611 uint32_t *ptr = (uint32_t *) buffer;
556 int count = 0; 612 int count = 0;
557 613
614 if (remain % 4)
615 remain = ((remain >> 2) + 1) << 2;
616
558 while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { 617 while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
559 *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); 618 *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
560 ptr++; 619 ptr++;
@@ -575,13 +634,14 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
575 char *ptr = buffer; 634 char *ptr = buffer;
576 635
577 do { 636 do {
578 unsigned int count, maxcnt; 637 unsigned int count, maxcnt, sz;
579 638
580 maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : 639 maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
581 MCI_FIFOHALFSIZE; 640 MCI_FIFOHALFSIZE;
582 count = min(remain, maxcnt); 641 count = min(remain, maxcnt);
583 642
584 writesl(base + MMCIFIFO, ptr, count >> 2); 643 sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
644 writesl(base + MMCIFIFO, ptr, sz);
585 ptr += count; 645 ptr += count;
586 remain -= count; 646 remain -= count;
587 647
@@ -702,10 +762,26 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
702 msm_dmov_stop_cmd(host->dma.channel, 762 msm_dmov_stop_cmd(host->dma.channel,
703 &host->dma.hdr, 0); 763 &host->dma.hdr, 0);
704 else if (host->curr.data) { /* Non DMA */ 764 else if (host->curr.data) { /* Non DMA */
765 msmsdcc_reset_and_restore(host);
705 msmsdcc_stop_data(host); 766 msmsdcc_stop_data(host);
706 msmsdcc_request_end(host, cmd->mrq); 767 msmsdcc_request_end(host, cmd->mrq);
707 } else /* host->data == NULL */ 768 } else { /* host->data == NULL */
708 msmsdcc_request_end(host, cmd->mrq); 769 if (!cmd->error && host->prog_enable) {
770 if (status & MCI_PROGDONE) {
771 host->prog_scan = false;
772 host->prog_enable = false;
773 msmsdcc_request_end(host, cmd->mrq);
774 } else {
775 host->curr.cmd = cmd;
776 }
777 } else {
778 if (host->prog_enable) {
779 host->prog_scan = false;
780 host->prog_enable = false;
781 }
782 msmsdcc_request_end(host, cmd->mrq);
783 }
784 }
709 } else if (cmd->data) 785 } else if (cmd->data)
710 if (!(cmd->data->flags & MMC_DATA_READ)) 786 if (!(cmd->data->flags & MMC_DATA_READ))
711 msmsdcc_start_data(host, cmd->data, 787 msmsdcc_start_data(host, cmd->data,
@@ -719,7 +795,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
719 struct mmc_data *data = host->curr.data; 795 struct mmc_data *data = host->curr.data;
720 796
721 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | 797 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
722 MCI_CMDTIMEOUT) && host->curr.cmd) { 798 MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) {
723 msmsdcc_do_cmdirq(host, status); 799 msmsdcc_do_cmdirq(host, status);
724 } 800 }
725 801
@@ -735,6 +811,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
735 msm_dmov_stop_cmd(host->dma.channel, 811 msm_dmov_stop_cmd(host->dma.channel,
736 &host->dma.hdr, 0); 812 &host->dma.hdr, 0);
737 else { 813 else {
814 msmsdcc_reset_and_restore(host);
738 if (host->curr.data) 815 if (host->curr.data)
739 msmsdcc_stop_data(host); 816 msmsdcc_stop_data(host);
740 if (!data->stop) 817 if (!data->stop)
@@ -748,14 +825,10 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
748 if (!host->curr.got_dataend && (status & MCI_DATAEND)) 825 if (!host->curr.got_dataend && (status & MCI_DATAEND))
749 host->curr.got_dataend = 1; 826 host->curr.got_dataend = 1;
750 827
751 if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND))
752 host->curr.got_datablkend = 1;
753
754 /* 828 /*
755 * If DMA is still in progress, we complete via the completion handler 829 * If DMA is still in progress, we complete via the completion handler
756 */ 830 */
757 if (host->curr.got_dataend && host->curr.got_datablkend && 831 if (host->curr.got_dataend && !host->dma.busy) {
758 !host->dma.busy) {
759 /* 832 /*
760 * There appears to be an issue in the controller where 833 * There appears to be an issue in the controller where
761 * if you request a small block transfer (< fifo size), 834 * if you request a small block transfer (< fifo size),
@@ -792,8 +865,7 @@ msmsdcc_irq(int irq, void *dev_id)
792 865
793 do { 866 do {
794 status = msmsdcc_readl(host, MMCISTATUS); 867 status = msmsdcc_readl(host, MMCISTATUS);
795 status &= (msmsdcc_readl(host, MMCIMASK0) | 868 status &= msmsdcc_readl(host, MMCIMASK0);
796 MCI_DATABLOCKENDMASK);
797 msmsdcc_writel(host, status, MMCICLEAR); 869 msmsdcc_writel(host, status, MMCICLEAR);
798 870
799 if (status & MCI_SDIOINTR) 871 if (status & MCI_SDIOINTR)
@@ -1118,6 +1190,9 @@ msmsdcc_probe(struct platform_device *pdev)
1118 host->dmares = dmares; 1190 host->dmares = dmares;
1119 spin_lock_init(&host->lock); 1191 spin_lock_init(&host->lock);
1120 1192
1193 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
1194 (unsigned long)host);
1195
1121 /* 1196 /*
1122 * Setup DMA 1197 * Setup DMA
1123 */ 1198 */
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ff2b0f74f6f4..939557af266d 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -138,7 +138,7 @@
138#define MCI_IRQENABLE \ 138#define MCI_IRQENABLE \
139 (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ 139 (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
140 MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ 140 MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
141 MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK) 141 MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK)
142 142
143/* 143/*
144 * The size of the FIFO in bytes. 144 * The size of the FIFO in bytes.
@@ -172,6 +172,8 @@ struct msmsdcc_dma_data {
172 struct msmsdcc_host *host; 172 struct msmsdcc_host *host;
173 int busy; /* Set if DM is busy */ 173 int busy; /* Set if DM is busy */
174 int active; 174 int active;
175 unsigned int result;
176 struct msm_dmov_errdata err;
175}; 177};
176 178
177struct msmsdcc_pio_data { 179struct msmsdcc_pio_data {
@@ -188,7 +190,6 @@ struct msmsdcc_curr_req {
188 unsigned int xfer_remain; /* Bytes remaining to send */ 190 unsigned int xfer_remain; /* Bytes remaining to send */
189 unsigned int data_xfered; /* Bytes acked by BLKEND irq */ 191 unsigned int data_xfered; /* Bytes acked by BLKEND irq */
190 int got_dataend; 192 int got_dataend;
191 int got_datablkend;
192 int user_pages; 193 int user_pages;
193}; 194};
194 195
@@ -235,6 +236,7 @@ struct msmsdcc_host {
235 int cmdpoll; 236 int cmdpoll;
236 struct msmsdcc_stats stats; 237 struct msmsdcc_stats stats;
237 238
239 struct tasklet_struct dma_tlet;
238 /* Command parameters */ 240 /* Command parameters */
239 unsigned int cmd_timeout; 241 unsigned int cmd_timeout;
240 unsigned int cmd_pio_irqmask; 242 unsigned int cmd_pio_irqmask;
@@ -242,6 +244,8 @@ struct msmsdcc_host {
242 struct mmc_command *cmd_cmd; 244 struct mmc_command *cmd_cmd;
243 u32 cmd_c; 245 u32 cmd_c;
244 246
247 bool prog_scan;
248 bool prog_enable;
245}; 249};
246 250
247#endif 251#endif