aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/s3cmci.c
diff options
context:
space:
mode:
authorVasily Khoruzhick <anarsoul@gmail.com>2014-06-01 13:22:09 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2014-07-09 05:26:13 -0400
commitb45e4b5093298e5d42f4a80f95f08e511dc06767 (patch)
treeec73d222490a07b750f1b84a2e92369de6183b21 /drivers/mmc/host/s3cmci.c
parent1b3f626e64b50e4ac3bca046c71cfbaec815670d (diff)
mmc: s3cmci: port DMA code to dmaengine API
Utilise new s3c24xx-dma dmaengine driver for DMA ops. Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/s3cmci.c')
-rw-r--r--drivers/mmc/host/s3cmci.c180
1 files changed, 50 insertions, 130 deletions
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 501ec210780c..e5516a226362 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -12,6 +12,7 @@
12 */ 12 */
13 13
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/dmaengine.h>
15#include <linux/dma-mapping.h> 16#include <linux/dma-mapping.h>
16#include <linux/clk.h> 17#include <linux/clk.h>
17#include <linux/mmc/host.h> 18#include <linux/mmc/host.h>
@@ -27,6 +28,7 @@
27#include <mach/dma.h> 28#include <mach/dma.h>
28#include <mach/gpio-samsung.h> 29#include <mach/gpio-samsung.h>
29 30
31#include <linux/platform_data/dma-s3c24xx.h>
30#include <linux/platform_data/mmc-s3cmci.h> 32#include <linux/platform_data/mmc-s3cmci.h>
31 33
32#include "s3cmci.h" 34#include "s3cmci.h"
@@ -140,10 +142,6 @@ static const int dbgmap_debug = dbg_err | dbg_debug;
140 dev_dbg(&host->pdev->dev, args); \ 142 dev_dbg(&host->pdev->dev, args); \
141 } while (0) 143 } while (0)
142 144
143static struct s3c2410_dma_client s3cmci_dma_client = {
144 .name = "s3c-mci",
145};
146
147static void finalize_request(struct s3cmci_host *host); 145static void finalize_request(struct s3cmci_host *host);
148static void s3cmci_send_request(struct mmc_host *mmc); 146static void s3cmci_send_request(struct mmc_host *mmc);
149static void s3cmci_reset(struct s3cmci_host *host); 147static void s3cmci_reset(struct s3cmci_host *host);
@@ -256,25 +254,8 @@ static inline bool s3cmci_host_usedma(struct s3cmci_host *host)
256{ 254{
257#ifdef CONFIG_MMC_S3C_PIO 255#ifdef CONFIG_MMC_S3C_PIO
258 return false; 256 return false;
259#elif defined(CONFIG_MMC_S3C_DMA) 257#else /* CONFIG_MMC_S3C_DMA */
260 return true; 258 return true;
261#else
262 return host->dodma;
263#endif
264}
265
266/**
267 * s3cmci_host_canpio - return true if host has pio code available
268 *
269 * Return true if the driver has been compiled with the PIO support code
270 * available.
271 */
272static inline bool s3cmci_host_canpio(void)
273{
274#ifdef CONFIG_MMC_S3C_PIO
275 return true;
276#else
277 return false;
278#endif 259#endif
279} 260}
280 261
@@ -841,60 +822,24 @@ static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
841 return IRQ_HANDLED; 822 return IRQ_HANDLED;
842} 823}
843 824
844static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, 825static void s3cmci_dma_done_callback(void *arg)
845 void *buf_id, int size,
846 enum s3c2410_dma_buffresult result)
847{ 826{
848 struct s3cmci_host *host = buf_id; 827 struct s3cmci_host *host = arg;
849 unsigned long iflags; 828 unsigned long iflags;
850 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;
851
852 mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
853 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
854 mci_fsta = readl(host->base + S3C2410_SDIFSTA);
855 mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
856 829
857 BUG_ON(!host->mrq); 830 BUG_ON(!host->mrq);
858 BUG_ON(!host->mrq->data); 831 BUG_ON(!host->mrq->data);
859 BUG_ON(!host->dmatogo);
860 832
861 spin_lock_irqsave(&host->complete_lock, iflags); 833 spin_lock_irqsave(&host->complete_lock, iflags);
862 834
863 if (result != S3C2410_RES_OK) { 835 dbg(host, dbg_dma, "DMA FINISHED\n");
864 dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
865 "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
866 mci_csta, mci_dsta, mci_fsta,
867 mci_dcnt, result, host->dmatogo);
868
869 goto fail_request;
870 }
871
872 host->dmatogo--;
873 if (host->dmatogo) {
874 dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
875 "DCNT:[%08x] toGo:%u\n",
876 size, mci_dsta, mci_dcnt, host->dmatogo);
877
878 goto out;
879 }
880
881 dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
882 size, mci_dsta, mci_dcnt);
883 836
884 host->dma_complete = 1; 837 host->dma_complete = 1;
885 host->complete_what = COMPLETION_FINALIZE; 838 host->complete_what = COMPLETION_FINALIZE;
886 839
887out:
888 tasklet_schedule(&host->pio_tasklet); 840 tasklet_schedule(&host->pio_tasklet);
889 spin_unlock_irqrestore(&host->complete_lock, iflags); 841 spin_unlock_irqrestore(&host->complete_lock, iflags);
890 return;
891 842
892fail_request:
893 host->mrq->data->error = -EINVAL;
894 host->complete_what = COMPLETION_FINALIZE;
895 clear_imask(host);
896
897 goto out;
898} 843}
899 844
900static void finalize_request(struct s3cmci_host *host) 845static void finalize_request(struct s3cmci_host *host)
@@ -966,7 +911,7 @@ static void finalize_request(struct s3cmci_host *host)
966 * DMA channel and the fifo to clear out any garbage. */ 911 * DMA channel and the fifo to clear out any garbage. */
967 if (mrq->data->error != 0) { 912 if (mrq->data->error != 0) {
968 if (s3cmci_host_usedma(host)) 913 if (s3cmci_host_usedma(host))
969 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); 914 dmaengine_terminate_all(host->dma);
970 915
971 if (host->is2440) { 916 if (host->is2440) {
972 /* Clear failure register and reset fifo. */ 917 /* Clear failure register and reset fifo. */
@@ -992,29 +937,6 @@ request_done:
992 mmc_request_done(host->mmc, mrq); 937 mmc_request_done(host->mmc, mrq);
993} 938}
994 939
995static void s3cmci_dma_setup(struct s3cmci_host *host,
996 enum dma_data_direction source)
997{
998 static enum dma_data_direction last_source = -1;
999 static int setup_ok;
1000
1001 if (last_source == source)
1002 return;
1003
1004 last_source = source;
1005
1006 s3c2410_dma_devconfig(host->dma, source,
1007 host->mem->start + host->sdidata);
1008
1009 if (!setup_ok) {
1010 s3c2410_dma_config(host->dma, 4);
1011 s3c2410_dma_set_buffdone_fn(host->dma,
1012 s3cmci_dma_done_callback);
1013 s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
1014 setup_ok = 1;
1015 }
1016}
1017
1018static void s3cmci_send_command(struct s3cmci_host *host, 940static void s3cmci_send_command(struct s3cmci_host *host,
1019 struct mmc_command *cmd) 941 struct mmc_command *cmd)
1020{ 942{
@@ -1162,43 +1084,45 @@ static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
1162 1084
1163static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) 1085static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1164{ 1086{
1165 int dma_len, i;
1166 int rw = data->flags & MMC_DATA_WRITE; 1087 int rw = data->flags & MMC_DATA_WRITE;
1088 struct dma_async_tx_descriptor *desc;
1089 struct dma_slave_config conf = {
1090 .src_addr = host->mem->start + host->sdidata,
1091 .dst_addr = host->mem->start + host->sdidata,
1092 .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
1093 .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
1094 };
1167 1095
1168 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); 1096 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
1169 1097
1170 s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 1098 /* Restore prescaler value */
1171 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); 1099 writel(host->prescaler, host->base + S3C2410_SDIPRE);
1172
1173 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1174 rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
1175
1176 if (dma_len == 0)
1177 return -ENOMEM;
1178
1179 host->dma_complete = 0;
1180 host->dmatogo = dma_len;
1181
1182 for (i = 0; i < dma_len; i++) {
1183 int res;
1184
1185 dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i,
1186 sg_dma_address(&data->sg[i]),
1187 sg_dma_len(&data->sg[i]));
1188 1100
1189 res = s3c2410_dma_enqueue(host->dma, host, 1101 if (!rw)
1190 sg_dma_address(&data->sg[i]), 1102 conf.direction = DMA_DEV_TO_MEM;
1191 sg_dma_len(&data->sg[i])); 1103 else
1104 conf.direction = DMA_MEM_TO_DEV;
1192 1105
1193 if (res) { 1106 dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1194 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); 1107 rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
1195 return -EBUSY;
1196 }
1197 }
1198 1108
1199 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START); 1109 dmaengine_slave_config(host->dma, &conf);
1110 desc = dmaengine_prep_slave_sg(host->dma, data->sg, data->sg_len,
1111 conf.direction,
1112 DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
1113 if (!desc)
1114 goto unmap_exit;
1115 desc->callback = s3cmci_dma_done_callback;
1116 desc->callback_param = host;
1117 dmaengine_submit(desc);
1118 dma_async_issue_pending(host->dma);
1200 1119
1201 return 0; 1120 return 0;
1121
1122unmap_exit:
1123 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1124 rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
1125 return -ENOMEM;
1202} 1126}
1203 1127
1204static void s3cmci_send_request(struct mmc_host *mmc) 1128static void s3cmci_send_request(struct mmc_host *mmc)
@@ -1676,10 +1600,6 @@ static int s3cmci_probe(struct platform_device *pdev)
1676 host->complete_what = COMPLETION_NONE; 1600 host->complete_what = COMPLETION_NONE;
1677 host->pio_active = XFER_NONE; 1601 host->pio_active = XFER_NONE;
1678 1602
1679#ifdef CONFIG_MMC_S3C_PIODMA
1680 host->dodma = host->pdata->use_dma;
1681#endif
1682
1683 host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1603 host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1684 if (!host->mem) { 1604 if (!host->mem) {
1685 dev_err(&pdev->dev, 1605 dev_err(&pdev->dev,
@@ -1765,17 +1685,17 @@ static int s3cmci_probe(struct platform_device *pdev)
1765 /* depending on the dma state, get a dma channel to use. */ 1685 /* depending on the dma state, get a dma channel to use. */
1766 1686
1767 if (s3cmci_host_usedma(host)) { 1687 if (s3cmci_host_usedma(host)) {
1768 host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client, 1688 dma_cap_mask_t mask;
1769 host); 1689
1770 if (host->dma < 0) { 1690 dma_cap_zero(mask);
1691 dma_cap_set(DMA_SLAVE, mask);
1692
1693 host->dma = dma_request_slave_channel_compat(mask,
1694 s3c24xx_dma_filter, (void *)DMACH_SDI, &pdev->dev, "rx-tx");
1695 if (!host->dma) {
1771 dev_err(&pdev->dev, "cannot get DMA channel.\n"); 1696 dev_err(&pdev->dev, "cannot get DMA channel.\n");
1772 if (!s3cmci_host_canpio()) { 1697 ret = -EBUSY;
1773 ret = -EBUSY; 1698 goto probe_free_gpio_wp;
1774 goto probe_free_gpio_wp;
1775 } else {
1776 dev_warn(&pdev->dev, "falling back to PIO.\n");
1777 host->dodma = 0;
1778 }
1779 } 1699 }
1780 } 1700 }
1781 1701
@@ -1816,7 +1736,7 @@ static int s3cmci_probe(struct platform_device *pdev)
1816 mmc->max_segs = 128; 1736 mmc->max_segs = 128;
1817 1737
1818 dbg(host, dbg_debug, 1738 dbg(host, dbg_debug,
1819 "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n", 1739 "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%p.\n",
1820 (host->is2440?"2440":""), 1740 (host->is2440?"2440":""),
1821 host->base, host->irq, host->irq_cd, host->dma); 1741 host->base, host->irq, host->irq_cd, host->dma);
1822 1742
@@ -1852,7 +1772,7 @@ static int s3cmci_probe(struct platform_device *pdev)
1852 1772
1853 probe_free_dma: 1773 probe_free_dma:
1854 if (s3cmci_host_usedma(host)) 1774 if (s3cmci_host_usedma(host))
1855 s3c2410_dma_free(host->dma, &s3cmci_dma_client); 1775 dma_release_channel(host->dma);
1856 1776
1857 probe_free_gpio_wp: 1777 probe_free_gpio_wp:
1858 if (!host->pdata->no_wprotect) 1778 if (!host->pdata->no_wprotect)
@@ -1914,7 +1834,7 @@ static int s3cmci_remove(struct platform_device *pdev)
1914 tasklet_disable(&host->pio_tasklet); 1834 tasklet_disable(&host->pio_tasklet);
1915 1835
1916 if (s3cmci_host_usedma(host)) 1836 if (s3cmci_host_usedma(host))
1917 s3c2410_dma_free(host->dma, &s3cmci_dma_client); 1837 dma_release_channel(host->dma);
1918 1838
1919 free_irq(host->irq, host); 1839 free_irq(host->irq, host);
1920 1840