aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2007-10-09 17:07:58 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-10-10 14:13:29 -0400
commitc783837bc69dd0f329a441c1704f5a02d01d1bd5 (patch)
treeedeaf000845bc138ac1802ae8894b90b38c87729 /drivers/mmc
parent599473cf15a3fae78cbc3192cfb38ca04d5abc72 (diff)
pxamci: support arbitrary block size
The PXA has two transmit FIFOes, each32 byte deep. when one FIFO is full and the other one has been transmitted, they are automatically swapped and DMA is triggered for another 32 byte burst. However, when there is less than 32 bytes left to send, the FIFO swap has to be done manually. This is required for some SDIO transfers which are not required to be multiples of 32 bytes. A DMA completion interrupt is set for each descriptor which length isn't a multiple of 32 in order to force the FIFO swap. While at it, the DMA interrupt handler has been made a bit more resilient against errors. Signed-off-by: Nicolas Pitre <nico@marvell.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/pxamci.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 91e25683b397..657901eecfce 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -142,6 +142,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
142 host->dma_dir); 142 host->dma_dir);
143 143
144 for (i = 0; i < host->dma_len; i++) { 144 for (i = 0; i < host->dma_len; i++) {
145 unsigned int length = sg_dma_len(&data->sg[i]);
146 host->sg_cpu[i].dcmd = dcmd | length;
147 if (length & 31 && !(data->flags & MMC_DATA_READ))
148 host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
145 if (data->flags & MMC_DATA_READ) { 149 if (data->flags & MMC_DATA_READ) {
146 host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; 150 host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
147 host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); 151 host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -149,7 +153,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
149 host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); 153 host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
150 host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; 154 host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
151 } 155 }
152 host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
153 host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * 156 host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
154 sizeof(struct pxa_dma_desc); 157 sizeof(struct pxa_dma_desc);
155 } 158 }
@@ -414,8 +417,18 @@ static const struct mmc_host_ops pxamci_ops = {
414 417
415static void pxamci_dma_irq(int dma, void *devid) 418static void pxamci_dma_irq(int dma, void *devid)
416{ 419{
417 printk(KERN_ERR "DMA%d: IRQ???\n", dma); 420 struct pxamci_host *host = devid;
418 DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; 421 int dcsr = DCSR(dma);
422 DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
423
424 if (dcsr & DCSR_ENDINTR) {
425 writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
426 } else {
427 printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
428 mmc_hostname(host->mmc), dma, dcsr);
429 host->data->error = -EIO;
430 pxamci_data_done(host, 0);
431 }
419} 432}
420 433
421static irqreturn_t pxamci_detect_irq(int irq, void *devid) 434static irqreturn_t pxamci_detect_irq(int irq, void *devid)