diff options
Diffstat (limited to 'drivers/mmc/host/mmci.c')
-rw-r--r-- | drivers/mmc/host/mmci.c | 171 |
1 files changed, 153 insertions, 18 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fe140724a02..d8eac248ee4 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -226,6 +226,9 @@ static void __devinit mmci_dma_setup(struct mmci_host *host) | |||
226 | return; | 226 | return; |
227 | } | 227 | } |
228 | 228 | ||
229 | /* initialize pre request cookie */ | ||
230 | host->next_data.cookie = 1; | ||
231 | |||
229 | /* Try to acquire a generic DMA engine slave channel */ | 232 | /* Try to acquire a generic DMA engine slave channel */ |
230 | dma_cap_zero(mask); | 233 | dma_cap_zero(mask); |
231 | dma_cap_set(DMA_SLAVE, mask); | 234 | dma_cap_set(DMA_SLAVE, mask); |
@@ -335,7 +338,8 @@ static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) | |||
335 | dir = DMA_FROM_DEVICE; | 338 | dir = DMA_FROM_DEVICE; |
336 | } | 339 | } |
337 | 340 | ||
338 | dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); | 341 | if (!data->host_cookie) |
342 | dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); | ||
339 | 343 | ||
340 | /* | 344 | /* |
341 | * Use of DMA with scatter-gather is impossible. | 345 | * Use of DMA with scatter-gather is impossible. |
@@ -353,7 +357,8 @@ static void mmci_dma_data_error(struct mmci_host *host) | |||
353 | dmaengine_terminate_all(host->dma_current); | 357 | dmaengine_terminate_all(host->dma_current); |
354 | } | 358 | } |
355 | 359 | ||
356 | static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | 360 | static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, |
361 | struct mmci_host_next *next) | ||
357 | { | 362 | { |
358 | struct variant_data *variant = host->variant; | 363 | struct variant_data *variant = host->variant; |
359 | struct dma_slave_config conf = { | 364 | struct dma_slave_config conf = { |
@@ -364,13 +369,20 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | |||
364 | .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ | 369 | .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ |
365 | .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ | 370 | .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ |
366 | }; | 371 | }; |
367 | struct mmc_data *data = host->data; | ||
368 | struct dma_chan *chan; | 372 | struct dma_chan *chan; |
369 | struct dma_device *device; | 373 | struct dma_device *device; |
370 | struct dma_async_tx_descriptor *desc; | 374 | struct dma_async_tx_descriptor *desc; |
371 | int nr_sg; | 375 | int nr_sg; |
372 | 376 | ||
373 | host->dma_current = NULL; | 377 | /* Check if next job is already prepared */ |
378 | if (data->host_cookie && !next && | ||
379 | host->dma_current && host->dma_desc_current) | ||
380 | return 0; | ||
381 | |||
382 | if (!next) { | ||
383 | host->dma_current = NULL; | ||
384 | host->dma_desc_current = NULL; | ||
385 | } | ||
374 | 386 | ||
375 | if (data->flags & MMC_DATA_READ) { | 387 | if (data->flags & MMC_DATA_READ) { |
376 | conf.direction = DMA_FROM_DEVICE; | 388 | conf.direction = DMA_FROM_DEVICE; |
@@ -385,7 +397,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | |||
385 | return -EINVAL; | 397 | return -EINVAL; |
386 | 398 | ||
387 | /* If less than or equal to the fifo size, don't bother with DMA */ | 399 | /* If less than or equal to the fifo size, don't bother with DMA */ |
388 | if (host->size <= variant->fifosize) | 400 | if (data->blksz * data->blocks <= variant->fifosize) |
389 | return -EINVAL; | 401 | return -EINVAL; |
390 | 402 | ||
391 | device = chan->device; | 403 | device = chan->device; |
@@ -399,14 +411,38 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | |||
399 | if (!desc) | 411 | if (!desc) |
400 | goto unmap_exit; | 412 | goto unmap_exit; |
401 | 413 | ||
402 | /* Okay, go for it. */ | 414 | if (next) { |
403 | host->dma_current = chan; | 415 | next->dma_chan = chan; |
416 | next->dma_desc = desc; | ||
417 | } else { | ||
418 | host->dma_current = chan; | ||
419 | host->dma_desc_current = desc; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
404 | 423 | ||
424 | unmap_exit: | ||
425 | if (!next) | ||
426 | dmaengine_terminate_all(chan); | ||
427 | dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction); | ||
428 | return -ENOMEM; | ||
429 | } | ||
430 | |||
431 | static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | ||
432 | { | ||
433 | int ret; | ||
434 | struct mmc_data *data = host->data; | ||
435 | |||
436 | ret = mmci_dma_prep_data(host, host->data, NULL); | ||
437 | if (ret) | ||
438 | return ret; | ||
439 | |||
440 | /* Okay, go for it. */ | ||
405 | dev_vdbg(mmc_dev(host->mmc), | 441 | dev_vdbg(mmc_dev(host->mmc), |
406 | "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", | 442 | "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", |
407 | data->sg_len, data->blksz, data->blocks, data->flags); | 443 | data->sg_len, data->blksz, data->blocks, data->flags); |
408 | dmaengine_submit(desc); | 444 | dmaengine_submit(host->dma_desc_current); |
409 | dma_async_issue_pending(chan); | 445 | dma_async_issue_pending(host->dma_current); |
410 | 446 | ||
411 | datactrl |= MCI_DPSM_DMAENABLE; | 447 | datactrl |= MCI_DPSM_DMAENABLE; |
412 | 448 | ||
@@ -421,14 +457,90 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | |||
421 | writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, | 457 | writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, |
422 | host->base + MMCIMASK0); | 458 | host->base + MMCIMASK0); |
423 | return 0; | 459 | return 0; |
460 | } | ||
424 | 461 | ||
425 | unmap_exit: | 462 | static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) |
426 | dmaengine_terminate_all(chan); | 463 | { |
427 | dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction); | 464 | struct mmci_host_next *next = &host->next_data; |
428 | return -ENOMEM; | 465 | |
466 | if (data->host_cookie && data->host_cookie != next->cookie) { | ||
467 | printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" | ||
468 | " host->next_data.cookie %d\n", | ||
469 | __func__, data->host_cookie, host->next_data.cookie); | ||
470 | data->host_cookie = 0; | ||
471 | } | ||
472 | |||
473 | if (!data->host_cookie) | ||
474 | return; | ||
475 | |||
476 | host->dma_desc_current = next->dma_desc; | ||
477 | host->dma_current = next->dma_chan; | ||
478 | |||
479 | next->dma_desc = NULL; | ||
480 | next->dma_chan = NULL; | ||
429 | } | 481 | } |
482 | |||
483 | static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, | ||
484 | bool is_first_req) | ||
485 | { | ||
486 | struct mmci_host *host = mmc_priv(mmc); | ||
487 | struct mmc_data *data = mrq->data; | ||
488 | struct mmci_host_next *nd = &host->next_data; | ||
489 | |||
490 | if (!data) | ||
491 | return; | ||
492 | |||
493 | if (data->host_cookie) { | ||
494 | data->host_cookie = 0; | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | /* if config for dma */ | ||
499 | if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) || | ||
500 | ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) { | ||
501 | if (mmci_dma_prep_data(host, data, nd)) | ||
502 | data->host_cookie = 0; | ||
503 | else | ||
504 | data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, | ||
509 | int err) | ||
510 | { | ||
511 | struct mmci_host *host = mmc_priv(mmc); | ||
512 | struct mmc_data *data = mrq->data; | ||
513 | struct dma_chan *chan; | ||
514 | enum dma_data_direction dir; | ||
515 | |||
516 | if (!data) | ||
517 | return; | ||
518 | |||
519 | if (data->flags & MMC_DATA_READ) { | ||
520 | dir = DMA_FROM_DEVICE; | ||
521 | chan = host->dma_rx_channel; | ||
522 | } else { | ||
523 | dir = DMA_TO_DEVICE; | ||
524 | chan = host->dma_tx_channel; | ||
525 | } | ||
526 | |||
527 | |||
528 | /* if config for dma */ | ||
529 | if (chan) { | ||
530 | if (err) | ||
531 | dmaengine_terminate_all(chan); | ||
532 | if (err || data->host_cookie) | ||
533 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, | ||
534 | data->sg_len, dir); | ||
535 | mrq->data->host_cookie = 0; | ||
536 | } | ||
537 | } | ||
538 | |||
430 | #else | 539 | #else |
431 | /* Blank functions if the DMA engine is not available */ | 540 | /* Blank functions if the DMA engine is not available */ |
541 | static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) | ||
542 | { | ||
543 | } | ||
432 | static inline void mmci_dma_setup(struct mmci_host *host) | 544 | static inline void mmci_dma_setup(struct mmci_host *host) |
433 | { | 545 | { |
434 | } | 546 | } |
@@ -449,6 +561,10 @@ static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datac | |||
449 | { | 561 | { |
450 | return -ENOSYS; | 562 | return -ENOSYS; |
451 | } | 563 | } |
564 | |||
565 | #define mmci_pre_request NULL | ||
566 | #define mmci_post_request NULL | ||
567 | |||
452 | #endif | 568 | #endif |
453 | 569 | ||
454 | static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) | 570 | static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) |
@@ -557,7 +673,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
557 | unsigned int status) | 673 | unsigned int status) |
558 | { | 674 | { |
559 | /* First check for errors */ | 675 | /* First check for errors */ |
560 | if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { | 676 | if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| |
677 | MCI_TXUNDERRUN|MCI_RXOVERRUN)) { | ||
561 | u32 remain, success; | 678 | u32 remain, success; |
562 | 679 | ||
563 | /* Terminate the DMA transfer */ | 680 | /* Terminate the DMA transfer */ |
@@ -636,8 +753,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, | |||
636 | } | 753 | } |
637 | 754 | ||
638 | if (!cmd->data || cmd->error) { | 755 | if (!cmd->data || cmd->error) { |
639 | if (host->data) | 756 | if (host->data) { |
757 | /* Terminate the DMA transfer */ | ||
758 | if (dma_inprogress(host)) | ||
759 | mmci_dma_data_error(host); | ||
640 | mmci_stop_data(host); | 760 | mmci_stop_data(host); |
761 | } | ||
641 | mmci_request_end(host, cmd->mrq); | 762 | mmci_request_end(host, cmd->mrq); |
642 | } else if (!(cmd->data->flags & MMC_DATA_READ)) { | 763 | } else if (!(cmd->data->flags & MMC_DATA_READ)) { |
643 | mmci_start_data(host, cmd->data); | 764 | mmci_start_data(host, cmd->data); |
@@ -837,8 +958,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) | |||
837 | dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); | 958 | dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); |
838 | 959 | ||
839 | data = host->data; | 960 | data = host->data; |
840 | if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| | 961 | if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| |
841 | MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) | 962 | MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND| |
963 | MCI_DATABLOCKEND) && data) | ||
842 | mmci_data_irq(host, data, status); | 964 | mmci_data_irq(host, data, status); |
843 | 965 | ||
844 | cmd = host->cmd; | 966 | cmd = host->cmd; |
@@ -872,6 +994,9 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
872 | 994 | ||
873 | host->mrq = mrq; | 995 | host->mrq = mrq; |
874 | 996 | ||
997 | if (mrq->data) | ||
998 | mmci_get_next_data(host, mrq->data); | ||
999 | |||
875 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) | 1000 | if (mrq->data && mrq->data->flags & MMC_DATA_READ) |
876 | mmci_start_data(host, mrq->data); | 1001 | mmci_start_data(host, mrq->data); |
877 | 1002 | ||
@@ -986,6 +1111,8 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id) | |||
986 | 1111 | ||
987 | static const struct mmc_host_ops mmci_ops = { | 1112 | static const struct mmc_host_ops mmci_ops = { |
988 | .request = mmci_request, | 1113 | .request = mmci_request, |
1114 | .pre_req = mmci_pre_request, | ||
1115 | .post_req = mmci_post_request, | ||
989 | .set_ios = mmci_set_ios, | 1116 | .set_ios = mmci_set_ios, |
990 | .get_ro = mmci_get_ro, | 1117 | .get_ro = mmci_get_ro, |
991 | .get_cd = mmci_get_cd, | 1118 | .get_cd = mmci_get_cd, |
@@ -1063,7 +1190,15 @@ static int __devinit mmci_probe(struct amba_device *dev, | |||
1063 | } | 1190 | } |
1064 | 1191 | ||
1065 | mmc->ops = &mmci_ops; | 1192 | mmc->ops = &mmci_ops; |
1066 | mmc->f_min = (host->mclk + 511) / 512; | 1193 | /* |
1194 | * The ARM and ST versions of the block have slightly different | ||
1195 | * clock divider equations which means that the minimum divider | ||
1196 | * differs too. | ||
1197 | */ | ||
1198 | if (variant->st_clkdiv) | ||
1199 | mmc->f_min = DIV_ROUND_UP(host->mclk, 257); | ||
1200 | else | ||
1201 | mmc->f_min = DIV_ROUND_UP(host->mclk, 512); | ||
1067 | /* | 1202 | /* |
1068 | * If the platform data supplies a maximum operating | 1203 | * If the platform data supplies a maximum operating |
1069 | * frequency, this takes precedence. Else, we fall back | 1204 | * frequency, this takes precedence. Else, we fall back |