diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/omap.c | 199 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 3 |
2 files changed, 190 insertions, 12 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 3e8dcf8d2e05..25e7efee5733 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c | |||
@@ -17,10 +17,12 @@ | |||
17 | #include <linux/ioport.h> | 17 | #include <linux/ioport.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/dmaengine.h> | ||
20 | #include <linux/dma-mapping.h> | 21 | #include <linux/dma-mapping.h> |
21 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
23 | #include <linux/timer.h> | 24 | #include <linux/timer.h> |
25 | #include <linux/omap-dma.h> | ||
24 | #include <linux/mmc/host.h> | 26 | #include <linux/mmc/host.h> |
25 | #include <linux/mmc/card.h> | 27 | #include <linux/mmc/card.h> |
26 | #include <linux/clk.h> | 28 | #include <linux/clk.h> |
@@ -99,6 +101,8 @@ | |||
99 | 101 | ||
100 | struct mmc_omap_host; | 102 | struct mmc_omap_host; |
101 | 103 | ||
104 | #define USE_DMA_PRIVATE | ||
105 | |||
102 | struct mmc_omap_slot { | 106 | struct mmc_omap_slot { |
103 | int id; | 107 | int id; |
104 | unsigned int vdd; | 108 | unsigned int vdd; |
@@ -128,6 +132,10 @@ struct mmc_omap_host { | |||
128 | unsigned char id; /* 16xx chips have 2 MMC blocks */ | 132 | unsigned char id; /* 16xx chips have 2 MMC blocks */ |
129 | struct clk * iclk; | 133 | struct clk * iclk; |
130 | struct clk * fclk; | 134 | struct clk * fclk; |
135 | struct dma_chan *dma_rx; | ||
136 | u32 dma_rx_burst; | ||
137 | struct dma_chan *dma_tx; | ||
138 | u32 dma_tx_burst; | ||
131 | struct resource *mem_res; | 139 | struct resource *mem_res; |
132 | void __iomem *virt_base; | 140 | void __iomem *virt_base; |
133 | unsigned int phys_base; | 141 | unsigned int phys_base; |
@@ -153,12 +161,14 @@ struct mmc_omap_host { | |||
153 | 161 | ||
154 | unsigned use_dma:1; | 162 | unsigned use_dma:1; |
155 | unsigned brs_received:1, dma_done:1; | 163 | unsigned brs_received:1, dma_done:1; |
156 | unsigned dma_is_read:1; | ||
157 | unsigned dma_in_use:1; | 164 | unsigned dma_in_use:1; |
165 | #ifdef USE_DMA_PRIVATE | ||
166 | unsigned dma_is_read:1; | ||
158 | int dma_ch; | 167 | int dma_ch; |
159 | spinlock_t dma_lock; | ||
160 | struct timer_list dma_timer; | 168 | struct timer_list dma_timer; |
161 | unsigned dma_len; | 169 | unsigned dma_len; |
170 | #endif | ||
171 | spinlock_t dma_lock; | ||
162 | 172 | ||
163 | struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; | 173 | struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; |
164 | struct mmc_omap_slot *current_slot; | 174 | struct mmc_omap_slot *current_slot; |
@@ -406,18 +416,32 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, | |||
406 | int abort) | 416 | int abort) |
407 | { | 417 | { |
408 | enum dma_data_direction dma_data_dir; | 418 | enum dma_data_direction dma_data_dir; |
419 | struct device *dev = mmc_dev(host->mmc); | ||
420 | struct dma_chan *c; | ||
409 | 421 | ||
422 | #ifdef USE_DMA_PRIVATE | ||
410 | BUG_ON(host->dma_ch < 0); | 423 | BUG_ON(host->dma_ch < 0); |
411 | if (data->error) | 424 | if (data->error) |
412 | omap_stop_dma(host->dma_ch); | 425 | omap_stop_dma(host->dma_ch); |
413 | /* Release DMA channel lazily */ | 426 | /* Release DMA channel lazily */ |
414 | mod_timer(&host->dma_timer, jiffies + HZ); | 427 | mod_timer(&host->dma_timer, jiffies + HZ); |
415 | if (data->flags & MMC_DATA_WRITE) | 428 | #endif |
429 | if (data->flags & MMC_DATA_WRITE) { | ||
416 | dma_data_dir = DMA_TO_DEVICE; | 430 | dma_data_dir = DMA_TO_DEVICE; |
417 | else | 431 | c = host->dma_tx; |
432 | } else { | ||
418 | dma_data_dir = DMA_FROM_DEVICE; | 433 | dma_data_dir = DMA_FROM_DEVICE; |
419 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, | 434 | c = host->dma_rx; |
420 | dma_data_dir); | 435 | } |
436 | if (c) { | ||
437 | if (data->error) { | ||
438 | dmaengine_terminate_all(c); | ||
439 | /* Claim nothing transferred on error... */ | ||
440 | data->bytes_xfered = 0; | ||
441 | } | ||
442 | dev = c->device->dev; | ||
443 | } | ||
444 | dma_unmap_sg(dev, data->sg, host->sg_len, dma_data_dir); | ||
421 | } | 445 | } |
422 | 446 | ||
423 | static void mmc_omap_send_stop_work(struct work_struct *work) | 447 | static void mmc_omap_send_stop_work(struct work_struct *work) |
@@ -524,6 +548,7 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) | |||
524 | mmc_omap_xfer_done(host, data); | 548 | mmc_omap_xfer_done(host, data); |
525 | } | 549 | } |
526 | 550 | ||
551 | #ifdef USE_DMA_PRIVATE | ||
527 | static void | 552 | static void |
528 | mmc_omap_dma_timer(unsigned long data) | 553 | mmc_omap_dma_timer(unsigned long data) |
529 | { | 554 | { |
@@ -533,6 +558,7 @@ mmc_omap_dma_timer(unsigned long data) | |||
533 | omap_free_dma(host->dma_ch); | 558 | omap_free_dma(host->dma_ch); |
534 | host->dma_ch = -1; | 559 | host->dma_ch = -1; |
535 | } | 560 | } |
561 | #endif | ||
536 | 562 | ||
537 | static void | 563 | static void |
538 | mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) | 564 | mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) |
@@ -891,6 +917,18 @@ static void mmc_omap_cover_handler(unsigned long param) | |||
891 | jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); | 917 | jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); |
892 | } | 918 | } |
893 | 919 | ||
920 | static void mmc_omap_dma_callback(void *priv) | ||
921 | { | ||
922 | struct mmc_omap_host *host = priv; | ||
923 | struct mmc_data *data = host->data; | ||
924 | |||
925 | /* If we got to the end of DMA, assume everything went well */ | ||
926 | data->bytes_xfered += data->blocks * data->blksz; | ||
927 | |||
928 | mmc_omap_dma_done(host, data); | ||
929 | } | ||
930 | |||
931 | #ifdef USE_DMA_PRIVATE | ||
894 | /* Prepare to transfer the next segment of a scatterlist */ | 932 | /* Prepare to transfer the next segment of a scatterlist */ |
895 | static void | 933 | static void |
896 | mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) | 934 | mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) |
@@ -1045,6 +1083,7 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data | |||
1045 | 1083 | ||
1046 | return 0; | 1084 | return 0; |
1047 | } | 1085 | } |
1086 | #endif | ||
1048 | 1087 | ||
1049 | static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) | 1088 | static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) |
1050 | { | 1089 | { |
@@ -1118,6 +1157,80 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) | |||
1118 | 1157 | ||
1119 | host->sg_idx = 0; | 1158 | host->sg_idx = 0; |
1120 | if (use_dma) { | 1159 | if (use_dma) { |
1160 | enum dma_data_direction dma_data_dir; | ||
1161 | struct dma_async_tx_descriptor *tx; | ||
1162 | struct dma_chan *c; | ||
1163 | u32 burst, *bp; | ||
1164 | u16 buf; | ||
1165 | |||
1166 | /* | ||
1167 | * FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx | ||
1168 | * and 24xx. Use 16 or 32 word frames when the | ||
1169 | * blocksize is at least that large. Blocksize is | ||
1170 | * usually 512 bytes; but not for some SD reads. | ||
1171 | */ | ||
1172 | burst = cpu_is_omap15xx() ? 32 : 64; | ||
1173 | if (burst > data->blksz) | ||
1174 | burst = data->blksz; | ||
1175 | |||
1176 | burst >>= 1; | ||
1177 | |||
1178 | if (data->flags & MMC_DATA_WRITE) { | ||
1179 | c = host->dma_tx; | ||
1180 | bp = &host->dma_tx_burst; | ||
1181 | buf = 0x0f80 | (burst - 1) << 0; | ||
1182 | dma_data_dir = DMA_TO_DEVICE; | ||
1183 | } else { | ||
1184 | c = host->dma_rx; | ||
1185 | bp = &host->dma_rx_burst; | ||
1186 | buf = 0x800f | (burst - 1) << 8; | ||
1187 | dma_data_dir = DMA_FROM_DEVICE; | ||
1188 | } | ||
1189 | |||
1190 | if (!c) | ||
1191 | goto use_pio; | ||
1192 | |||
1193 | /* Only reconfigure if we have a different burst size */ | ||
1194 | if (*bp != burst) { | ||
1195 | struct dma_slave_config cfg; | ||
1196 | |||
1197 | cfg.src_addr = host->phys_base + OMAP_MMC_REG(host, DATA); | ||
1198 | cfg.dst_addr = host->phys_base + OMAP_MMC_REG(host, DATA); | ||
1199 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
1200 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
1201 | cfg.src_maxburst = burst; | ||
1202 | cfg.dst_maxburst = burst; | ||
1203 | |||
1204 | if (dmaengine_slave_config(c, &cfg)) | ||
1205 | goto use_pio; | ||
1206 | |||
1207 | *bp = burst; | ||
1208 | } | ||
1209 | |||
1210 | host->sg_len = dma_map_sg(c->device->dev, data->sg, sg_len, | ||
1211 | dma_data_dir); | ||
1212 | if (host->sg_len == 0) | ||
1213 | goto use_pio; | ||
1214 | |||
1215 | tx = dmaengine_prep_slave_sg(c, data->sg, host->sg_len, | ||
1216 | data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, | ||
1217 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
1218 | if (!tx) | ||
1219 | goto use_pio; | ||
1220 | |||
1221 | OMAP_MMC_WRITE(host, BUF, buf); | ||
1222 | |||
1223 | tx->callback = mmc_omap_dma_callback; | ||
1224 | tx->callback_param = host; | ||
1225 | dmaengine_submit(tx); | ||
1226 | host->brs_received = 0; | ||
1227 | host->dma_done = 0; | ||
1228 | host->dma_in_use = 1; | ||
1229 | return; | ||
1230 | } | ||
1231 | use_pio: | ||
1232 | #ifdef USE_DMA_PRIVATE | ||
1233 | if (use_dma) { | ||
1121 | if (mmc_omap_get_dma_channel(host, data) == 0) { | 1234 | if (mmc_omap_get_dma_channel(host, data) == 0) { |
1122 | enum dma_data_direction dma_data_dir; | 1235 | enum dma_data_direction dma_data_dir; |
1123 | 1236 | ||
@@ -1136,6 +1249,9 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) | |||
1136 | } else | 1249 | } else |
1137 | use_dma = 0; | 1250 | use_dma = 0; |
1138 | } | 1251 | } |
1252 | #else | ||
1253 | use_dma = 0; | ||
1254 | #endif | ||
1139 | 1255 | ||
1140 | /* Revert to PIO? */ | 1256 | /* Revert to PIO? */ |
1141 | if (!use_dma) { | 1257 | if (!use_dma) { |
@@ -1157,8 +1273,17 @@ static void mmc_omap_start_request(struct mmc_omap_host *host, | |||
1157 | /* only touch fifo AFTER the controller readies it */ | 1273 | /* only touch fifo AFTER the controller readies it */ |
1158 | mmc_omap_prepare_data(host, req); | 1274 | mmc_omap_prepare_data(host, req); |
1159 | mmc_omap_start_command(host, req->cmd); | 1275 | mmc_omap_start_command(host, req->cmd); |
1160 | if (host->dma_in_use) | 1276 | if (host->dma_in_use) { |
1161 | omap_start_dma(host->dma_ch); | 1277 | struct dma_chan *c = host->data->flags & MMC_DATA_WRITE ? |
1278 | host->dma_tx : host->dma_rx; | ||
1279 | |||
1280 | if (c) | ||
1281 | dma_async_issue_pending(c); | ||
1282 | #ifdef USE_DMA_PRIVATE | ||
1283 | else | ||
1284 | omap_start_dma(host->dma_ch); | ||
1285 | #endif | ||
1286 | } | ||
1162 | } | 1287 | } |
1163 | 1288 | ||
1164 | static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) | 1289 | static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) |
@@ -1400,6 +1525,8 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) | |||
1400 | struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; | 1525 | struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; |
1401 | struct mmc_omap_host *host = NULL; | 1526 | struct mmc_omap_host *host = NULL; |
1402 | struct resource *res; | 1527 | struct resource *res; |
1528 | dma_cap_mask_t mask; | ||
1529 | unsigned sig; | ||
1403 | int i, ret = 0; | 1530 | int i, ret = 0; |
1404 | int irq; | 1531 | int irq; |
1405 | 1532 | ||
@@ -1439,7 +1566,9 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) | |||
1439 | setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); | 1566 | setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); |
1440 | 1567 | ||
1441 | spin_lock_init(&host->dma_lock); | 1568 | spin_lock_init(&host->dma_lock); |
1569 | #ifdef USE_DMA_PRIVATE | ||
1442 | setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); | 1570 | setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); |
1571 | #endif | ||
1443 | spin_lock_init(&host->slot_lock); | 1572 | spin_lock_init(&host->slot_lock); |
1444 | init_waitqueue_head(&host->slot_wq); | 1573 | init_waitqueue_head(&host->slot_wq); |
1445 | 1574 | ||
@@ -1452,8 +1581,10 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) | |||
1452 | host->irq = irq; | 1581 | host->irq = irq; |
1453 | 1582 | ||
1454 | host->use_dma = 1; | 1583 | host->use_dma = 1; |
1584 | #ifdef USE_DMA_PRIVATE | ||
1455 | host->dev->dma_mask = &pdata->dma_mask; | 1585 | host->dev->dma_mask = &pdata->dma_mask; |
1456 | host->dma_ch = -1; | 1586 | host->dma_ch = -1; |
1587 | #endif | ||
1457 | 1588 | ||
1458 | host->irq = irq; | 1589 | host->irq = irq; |
1459 | host->phys_base = host->mem_res->start; | 1590 | host->phys_base = host->mem_res->start; |
@@ -1474,9 +1605,48 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) | |||
1474 | goto err_free_iclk; | 1605 | goto err_free_iclk; |
1475 | } | 1606 | } |
1476 | 1607 | ||
1608 | dma_cap_zero(mask); | ||
1609 | dma_cap_set(DMA_SLAVE, mask); | ||
1610 | |||
1611 | host->dma_tx_burst = -1; | ||
1612 | host->dma_rx_burst = -1; | ||
1613 | |||
1614 | if (cpu_is_omap24xx()) | ||
1615 | sig = host->id == 0 ? OMAP24XX_DMA_MMC1_TX : OMAP24XX_DMA_MMC2_TX; | ||
1616 | else | ||
1617 | sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX; | ||
1618 | host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); | ||
1619 | #if 0 | ||
1620 | if (!host->dma_tx) { | ||
1621 | dev_err(host->dev, "unable to obtain TX DMA engine channel %u\n", | ||
1622 | sig); | ||
1623 | goto err_dma; | ||
1624 | } | ||
1625 | #else | ||
1626 | if (!host->dma_tx) | ||
1627 | dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n", | ||
1628 | sig); | ||
1629 | #endif | ||
1630 | if (cpu_is_omap24xx()) | ||
1631 | sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX; | ||
1632 | else | ||
1633 | sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX; | ||
1634 | host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); | ||
1635 | #if 0 | ||
1636 | if (!host->dma_rx) { | ||
1637 | dev_err(host->dev, "unable to obtain RX DMA engine channel %u\n", | ||
1638 | sig); | ||
1639 | goto err_dma; | ||
1640 | } | ||
1641 | #else | ||
1642 | if (!host->dma_rx) | ||
1643 | dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n", | ||
1644 | sig); | ||
1645 | #endif | ||
1646 | |||
1477 | ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); | 1647 | ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); |
1478 | if (ret) | 1648 | if (ret) |
1479 | goto err_free_fclk; | 1649 | goto err_free_dma; |
1480 | 1650 | ||
1481 | if (pdata->init != NULL) { | 1651 | if (pdata->init != NULL) { |
1482 | ret = pdata->init(&pdev->dev); | 1652 | ret = pdata->init(&pdev->dev); |
@@ -1510,7 +1680,11 @@ err_plat_cleanup: | |||
1510 | pdata->cleanup(&pdev->dev); | 1680 | pdata->cleanup(&pdev->dev); |
1511 | err_free_irq: | 1681 | err_free_irq: |
1512 | free_irq(host->irq, host); | 1682 | free_irq(host->irq, host); |
1513 | err_free_fclk: | 1683 | err_free_dma: |
1684 | if (host->dma_tx) | ||
1685 | dma_release_channel(host->dma_tx); | ||
1686 | if (host->dma_rx) | ||
1687 | dma_release_channel(host->dma_rx); | ||
1514 | clk_put(host->fclk); | 1688 | clk_put(host->fclk); |
1515 | err_free_iclk: | 1689 | err_free_iclk: |
1516 | clk_disable(host->iclk); | 1690 | clk_disable(host->iclk); |
@@ -1545,6 +1719,11 @@ static int __devexit mmc_omap_remove(struct platform_device *pdev) | |||
1545 | clk_disable(host->iclk); | 1719 | clk_disable(host->iclk); |
1546 | clk_put(host->iclk); | 1720 | clk_put(host->iclk); |
1547 | 1721 | ||
1722 | if (host->dma_tx) | ||
1723 | dma_release_channel(host->dma_tx); | ||
1724 | if (host->dma_rx) | ||
1725 | dma_release_channel(host->dma_rx); | ||
1726 | |||
1548 | iounmap(host->virt_base); | 1727 | iounmap(host->virt_base); |
1549 | release_mem_region(pdev->resource[0].start, | 1728 | release_mem_region(pdev->resource[0].start, |
1550 | pdev->resource[0].end - pdev->resource[0].start + 1); | 1729 | pdev->resource[0].end - pdev->resource[0].start + 1); |
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2b2c98773f15..2338703746a4 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/of.h> | 30 | #include <linux/of.h> |
31 | #include <linux/of_gpio.h> | 31 | #include <linux/of_gpio.h> |
32 | #include <linux/of_device.h> | 32 | #include <linux/of_device.h> |
33 | #include <linux/omap-dma.h> | ||
33 | #include <linux/mmc/host.h> | 34 | #include <linux/mmc/host.h> |
34 | #include <linux/mmc/core.h> | 35 | #include <linux/mmc/core.h> |
35 | #include <linux/mmc/mmc.h> | 36 | #include <linux/mmc/mmc.h> |
@@ -1766,8 +1767,6 @@ static inline struct omap_mmc_platform_data | |||
1766 | } | 1767 | } |
1767 | #endif | 1768 | #endif |
1768 | 1769 | ||
1769 | extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param); | ||
1770 | |||
1771 | static int __devinit omap_hsmmc_probe(struct platform_device *pdev) | 1770 | static int __devinit omap_hsmmc_probe(struct platform_device *pdev) |
1772 | { | 1771 | { |
1773 | struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; | 1772 | struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; |