OMAP DMA engine conversion
Subsystems (12)
cover OMAP DMA engine conversion
For the full text, please see
http://lists.arm.linux.org.uk/lurker/message/20120418.100954.7fa7acf8.en.html
This version contains updates for some of the comments received from the previous round, and adds the OMAP1/2 MMC and SPI drivers to the conversion.
I've also added a note to feature-removal noting that the existing APIs will be removed around 2013 - I'm planning January for that at the moment. Having drivers around which are unconverted blocks further work on the DMA engine conversion, so it's actually important that we get as many drivers converted as soon as possible.
Anything which isn't converted will probably have its DMA code removed, or if that results in the driver not being usable, the driver itself will be removed.
This series is still in RFC mode...
Documentation/feature-removal-schedule.txt | 11 + arch/arm/mach-omap1/board-h2-mmc.c | 1 - arch/arm/mach-omap1/board-h3-mmc.c | 1 - arch/arm/mach-omap1/board-nokia770.c | 1 - arch/arm/mach-omap2/board-n8x0.c | 1 - arch/arm/mach-omap2/hsmmc.c | 1 - arch/arm/plat-omap/dma.c | 14 + arch/arm/plat-omap/include/plat/mmc.h | 2 - drivers/dma/Kconfig | 10 + drivers/dma/Makefile | 2 + drivers/dma/omap-dma.c | 521 ++++++++++++++++++++++++++++ drivers/dma/sa11x0-dma.c | 249 ++++--------- drivers/dma/virt-dma.c | 99 ++++++ drivers/dma/virt-dma.h | 138 ++++++++ drivers/mmc/host/omap.c | 369 +++++++++----------- drivers/mmc/host/omap_hsmmc.c | 206 ++++++------ drivers/spi/spi-omap2-mcspi.c | 228 +++++++------ 17 files changed, 1268 insertions(+), 586 deletions(-)
PATCH 1/12 ARM: OMAP: fix DMA vs memory ordering
Using coherent DMA memory with the OMAP DMA engine results in unpredictable behaviour due to memory ordering issues; as things stand, there is no guarantee that data written to coherent DMA memory will be visible to the DMA hardware.
This is because the OMAP dma_write() accessor contains no barriers, necessary on ARMv6 and above. The effect of this can be seen in comments in the OMAP serial driver, which incorrectly talks about cache flushing for the coherent DMA stuff.
Rather than adding barriers to the accessors, add it in the DMA support code just before we enable DMA, and just after we disable DMA. This avoids having barriers for every DMA register access.
--- arch/arm/plat-omap/dma.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
arch/arm/plat-omap/dma.c +14 -0
@@ -916,6 +916,13 @@ void omap_start_dma(int lch) l |=OMAP_DMA_CCR_BUFFERING_DISABLE ; l |=OMAP_DMA_CCR_EN ; +/* +* As dma_write() uses IO accessors which are weakly ordered, there +* is no guarantee that data in coherent DMA memory will be visible +* to the DMA device. Add a memory barrier here to ensure that any +* such data is visible prior to enabling DMA. +*/ +mb (); p->dma_write (l,CCR , lch); dma_chan[lch].flags |=OMAP_DMA_ACTIVE ;
@@ -965,6 +972,13 @@ void omap_stop_dma(int lch) p->dma_write (l,CCR , lch); } +/* +* Ensure that data transferred by DMA is visible to any access +* after DMA has been disabled. This is important for coherent +* DMA regions. +*/ +mb (); +if (!omap_dma_in_1510_mode () && dma_chan[lch].next_lch !=-1 ) {int next_lch, cur_lch = lch;char dma_chan_link_map[dma_lch_count];
Signature · 1 line
1.7.4.4
PATCH 2/12 dmaengine: split out virtual channel DMA support from sa11x0 driver
In reply to Russell King - ARM LinuxSplit the virtual slave channel DMA support from the sa11x0 driver so this code can be shared with other slave DMA engine drivers.
--- drivers/dma/Kconfig | 4 + drivers/dma/Makefile | 1 + drivers/dma/sa11x0-dma.c | 249 ++++++++++++++------------------------------- drivers/dma/virt-dma.c | 99 ++++++++++++++++++ drivers/dma/virt-dma.h | 138 +++++++++++++++++++++++++ 5 files changed, 320 insertions(+), 171 deletions(-) create mode 100644 drivers/dma/virt-dma.c create mode 100644 drivers/dma/virt-dma.h
drivers/dma/Kconfig +4 -0
@@ -255,6 +255,7 @@ config DMA_SA11X0 tristate "SA-11x0 DMA support" depends on ARCH_SA1100 select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS help Support the DMA engine found on Intel StrongARM SA-1100 and SA-1110 SoCs. This DMA engine can only be used with on-chip
@@ -263,6 +264,9 @@ config DMA_SA11X0 config DMA_ENGINE bool +config DMA_VIRTUAL_CHANNELS + tristate + comment "DMA Clients" depends on DMA_ENGINE
drivers/dma/Makefile +1 -0
@@ -2,6 +2,7 @@ ccflags-$(CONFIG_DMADEVICES_DEBUG) := -DDEBUG ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG obj-$(CONFIG_DMA_ENGINE) += dmaengine.o +obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o obj-$(CONFIG_NET_DMA) += iovlock.o obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o obj-$(CONFIG_DMATEST) += dmatest.o
drivers/dma/sa11x0-dma.c +78 -171
517 lines not on this page · raw message
drivers/dma/virt-dma.c new file +99 -0
99 lines not on this page · raw message
drivers/dma/virt-dma.h new file +138 -0
138 lines not on this page · raw message
Signature · 1 line
1.7.4.4
PATCH 2/12 dmaengine: split out virtual channel DMA support from sa11x0 driver
Quoted 4 lines · Russell King
Split the virtual slave channel DMA support from the sa11x0 driver so this code can be shared with other slave DMA engine drivers.
Signed-off-by Russell King <[email protected]>
I really like the direction of this thing.
Yours,
Linus Walleij
PATCH 3/12 dmaengine: add OMAP DMA engine driver
In reply to Russell King - ARM Linux--- drivers/dma/Kconfig | 6 + drivers/dma/Makefile | 1 + drivers/dma/omap-dma.c | 521 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 528 insertions(+), 0 deletions(-) create mode 100644 drivers/dma/omap-dma.c
drivers/dma/Kconfig +6 -0
@@ -261,6 +261,12 @@ config DMA_SA11X0 SA-1110 SoCs. This DMA engine can only be used with on-chip devices. +config DMA_OMAP + tristate "OMAP DMA support" + depends on ARCH_OMAP + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + config DMA_ENGINE bool
drivers/dma/Makefile +1 -0
@@ -29,3 +29,4 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o +obj-$(CONFIG_DMA_OMAP) += omap-dma.o
drivers/dma/omap-dma.c new file +521 -0
521 lines not on this page · raw message
Signature · 1 line
1.7.4.4
PATCH 4/12 mmc: omap_hsmmc: release correct resource
In reply to Russell King - ARM Linuxres can be one of several resources, as this variable is re-used several times during probe. This can cause the wrong resource parameters to be passed to release_mem_region().
Get the original memory resource before calling release_mem_region().
--- drivers/mmc/host/omap_hsmmc.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mmc/host/omap_hsmmc.c +3 -1
@@ -2030,7 +2030,9 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) err_alloc:omap_hsmmc_gpio_free (pdata); err: -release_mem_region (res->start,resource_size (res)); + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res) +release_mem_region (res->start,resource_size (res));return ret; }
Signature · 1 line
1.7.4.4
PATCH 5/12 mmc: omap_hsmmc: add DMA engine support
In reply to Russell King - ARM LinuxAdd DMA engine support to the OMAP HSMMC driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
--- drivers/mmc/host/omap_hsmmc.c | 192 +++++++++++++++++++++++++++++++++++------ 1 files changed, 165 insertions(+), 27 deletions(-)
drivers/mmc/host/omap_hsmmc.c +165 -27
@@ -19,6 +19,7 @@#include <linux/init.h> #include <linux/kernel.h> #include <linux/debugfs.h> +#include <linux/dmaengine.h> #include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/delay.h>
@@ -164,7 +165,9 @@ struct omap_hsmmc_host {u32 bytesleft;int suspended;int irq; -int use_dma, dma_ch; +int use_dma, dma_ch, dma2; +struct dma_chan *tx_chan; +struct dma_chan *rx_chan;int dma_line_tx, dma_line_rx;int slot_id;int got_dbclk;
@@ -793,18 +796,25 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)return DMA_FROM_DEVICE ; } +static struct dma_chan *omap_hsmmc_get_dma_chan (struct omap_hsmmc_host *host, +struct mmc_data *data) +{ +return data->flags &MMC_DATA_WRITE ? host->tx_chan : host->rx_chan; +} +static void omap_hsmmc_request_done (struct omap_hsmmc_host *host,struct mmc_request *mrq) { -int dma_ch; +int dma_ch, dma2;spin_lock (&host->irq_lock); host->req_in_progress =0 ; dma_ch = host->dma_ch; + dma2 = host->dma2;spin_unlock (&host->irq_lock);omap_hsmmc_disable_irq (host);/* Do not complete the request if DMA is still in progress */ -if (mrq->data && host->use_dma && dma_ch !=-1 ) +if (mrq->data && host->use_dma && (dma_ch !=-1 || dma2 !=-1 ))return ; host->mrq =NULL ;mmc_request_done (host->mmc, mrq);
@@ -873,15 +883,27 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)*/ static void omap_hsmmc_dma_cleanup (struct omap_hsmmc_host *host,int errno) { -int dma_ch; +int dma_ch, dma2; host->data->error = errno;spin_lock (&host->irq_lock); dma_ch = host->dma_ch; host->dma_ch =-1 ; + dma2 = host->dma2; + host->dma2 =-1 ;spin_unlock (&host->irq_lock); +if (host->use_dma && dma2 !=-1 ) { +struct dma_chan *chan =omap_hsmmc_get_dma_chan (host, host->data); + +dmaengine_terminate_all (chan); +dma_unmap_sg (chan->device->dev, + host->data->sg, host->data->sg_len, +omap_hsmmc_get_dma_dir (host, host->data)); + + host->data->host_cookie =0 ; + }if (host->use_dma && dma_ch !=-1 ) { dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len,
@@ -1277,9 +1299,43 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) } } +static void omap_hsmmc_dma_callback (void *param) +{ +struct omap_hsmmc_host *host = param; +struct dma_chan *chan; +struct mmc_data *data; +int req_in_progress; + +spin_lock_irq (&host->irq_lock); +if (host->dma2 <0 ) { +spin_unlock_irq (&host->irq_lock); +return ; + } + + data = host->mrq->data; + chan =omap_hsmmc_get_dma_chan (host, data); +if (!data->host_cookie) +dma_unmap_sg (chan->device->dev, + data->sg, data->sg_len, +omap_hsmmc_get_dma_dir (host, data)); + + req_in_progress = host->req_in_progress; + host->dma2 =-1 ; +spin_unlock_irq (&host->irq_lock); + +/* If DMA has finished after TC, complete the request */ +if (!req_in_progress) { +struct mmc_request *mrq = host->mrq; + + host->mrq =NULL ; +mmc_request_done (host->mmc, mrq); + } +} +static int omap_hsmmc_pre_dma_transfer (struct omap_hsmmc_host *host,struct mmc_data *data, -struct omap_hsmmc_next *next) +struct omap_hsmmc_next *next, +struct device *dev) {int dma_len;
@@ -1294,8 +1350,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,/* Check if next job is already prepared */ if (next || (!next && data->host_cookie != host->next_data.cookie)) { - dma_len =dma_map_sg (mmc_dev (host->mmc), data->sg, - data->sg_len, + dma_len =dma_map_sg (dev, data->sg, data->sg_len,omap_hsmmc_get_dma_dir (host, data)); }else {
@@ -1324,6 +1379,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, {int dma_ch =0 , ret =0 , i;struct mmc_data *data = req->data; +struct dma_chan *chan;/* Sanity check: all the SG entries must be aligned by block size. */ for (i =0 ; i < data->sg_len; i++) {
@@ -1339,24 +1395,66 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,*/ return -EINVAL ; -BUG_ON (host->dma_ch !=-1 ); +BUG_ON (host->dma_ch !=-1 || host->dma2 !=-1 ); - ret =omap_request_dma (omap_hsmmc_get_dma_sync_dev (host, data), -"MMC/SD" , omap_hsmmc_dma_cb, host, &dma_ch); -if (ret !=0 ) { -dev_err (mmc_dev (host->mmc), -"%s: omap_request_dma() failed with %d\n" , -mmc_hostname (host->mmc), ret); -return ret; - } - ret =omap_hsmmc_pre_dma_transfer (host, data,NULL ); -if (ret) -return ret; + chan =omap_hsmmc_get_dma_chan (host, data); +if (!chan) { + ret =omap_request_dma (omap_hsmmc_get_dma_sync_dev (host, data), +"MMC/SD" , omap_hsmmc_dma_cb, host, &dma_ch); +if (ret !=0 ) { +dev_err (mmc_dev (host->mmc), +"%s: omap_request_dma() failed with %d\n" , +mmc_hostname (host->mmc), ret); +return ret; + } + ret =omap_hsmmc_pre_dma_transfer (host, data,NULL , +mmc_dev (host->mmc)); +if (ret) +return ret; + + host->dma_ch = dma_ch; + host->dma_sg_idx =0 ; + +omap_hsmmc_config_dma_params (host, data, data->sg); + }else { +struct dma_slave_config cfg; +struct dma_async_tx_descriptor *tx; + + cfg.src_addr = host->mapbase +OMAP_HSMMC_DATA ; + cfg.dst_addr = host->mapbase +OMAP_HSMMC_DATA ; + cfg.src_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.dst_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.src_maxburst = data->blksz /4 ; + cfg.dst_maxburst = data->blksz /4 ; + + ret =dmaengine_slave_config (chan, &cfg); +if (ret) +return ret; + + ret =omap_hsmmc_pre_dma_transfer (host, data,NULL , + chan->device->dev); +if (ret) +return ret; + + tx =dmaengine_prep_slave_sg (chan, data->sg, data->sg_len, + data->flags &MMC_DATA_WRITE ?DMA_MEM_TO_DEV :DMA_DEV_TO_MEM , +DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (!tx) { +dev_err (mmc_dev (host->mmc),"prep_slave_sg() failed\n" ); +/* FIXME: cleanup */ +return -1 ; + } - host->dma_ch = dma_ch; - host->dma_sg_idx =0 ; + tx->callback = omap_hsmmc_dma_callback; + tx->callback_param = host; -omap_hsmmc_config_dma_params (host, data, data->sg); +/* Does not fail */ +dmaengine_submit (tx); + + host->dma2 =1 ; + +dma_async_issue_pending (chan); + }return 0 ; }
@@ -1439,9 +1537,12 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,struct mmc_data *data = mrq->data;if (host->use_dma) { +struct dma_chan *c =omap_hsmmc_get_dma_chan (host, data); +struct device *dev = c ? c->device->dev :mmc_dev (mmc); +if (data->host_cookie) -dma_unmap_sg (mmc_dev (host->mmc), data->sg, - data->sg_len, +dma_unmap_sg (dev, + data->sg, data->sg_len,omap_hsmmc_get_dma_dir (host, data)); data->host_cookie =0 ; }
@@ -1457,10 +1558,14 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,return ; } -if (host->use_dma) +if (host->use_dma) { +struct dma_chan *c =omap_hsmmc_get_dma_chan (host, mrq->data); +struct device *dev = c ? c->device->dev :mmc_dev (mmc); +if (omap_hsmmc_pre_dma_transfer (host, mrq->data, - &host->next_data)) + &host->next_data, dev)) mrq->data->host_cookie =0 ; + } }/*
@@ -1472,7 +1577,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)int err;BUG_ON (host->req_in_progress); -BUG_ON (host->dma_ch !=-1 ); +BUG_ON (host->dma_ch !=-1 || host->dma2 !=-1 );if (host->protect_card) {if (host->reqs_blocked <3 ) {/*
@@ -1839,6 +1944,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->use_dma =1 ; host->dev->dma_mask = &pdata->dma_mask; host->dma_ch =-1 ; + host->dma2 =-1 ; host->irq = irq; host->slot_id =0 ; host->mapbase = res->start + pdata->reg_offset;
@@ -1939,6 +2045,29 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) } host->dma_line_rx = res->start; + { +dma_cap_mask_t mask; +unsigned sig; +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); + +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); +#if 1 + sig = host->dma_line_rx; + host->rx_chan =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!host->rx_chan) { +dev_warn (mmc_dev (host->mmc),"unable to obtain RX DMA engine channel %u\n" , sig); + } +#endif +#if 1 + sig = host->dma_line_tx; + host->tx_chan =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!host->tx_chan) { +dev_warn (mmc_dev (host->mmc),"unable to obtain TX DMA engine channel %u\n" , sig); + } +#endif + } +/* Request IRQ for MMC operations */ ret =request_irq (host->irq, omap_hsmmc_irq,0 ,mmc_hostname (mmc), host);
@@ -2016,6 +2145,10 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) err_irq_cd_init:free_irq (host->irq, host); err_irq: +if (host->tx_chan) +dma_release_channel (host->tx_chan); +if (host->rx_chan) +dma_release_channel (host->rx_chan);pm_runtime_put_sync (host->dev);pm_runtime_disable (host->dev);clk_put (host->fclk);
@@ -2051,6 +2184,11 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)if (mmc_slot (host).card_detect_irq)free_irq (mmc_slot (host).card_detect_irq, host); +if (host->tx_chan) +dma_release_channel (host->tx_chan); +if (host->rx_chan) +dma_release_channel (host->rx_chan); +pm_runtime_put_sync (host->dev);pm_runtime_disable (host->dev);clk_put (host->fclk);
Signature · 1 line
1.7.4.4
Tony Lindgren
maintainerPATCH 5/12 mmc: omap_hsmmc: add DMA engine support
Quoted 6 lines · Russell King
Add DMA engine support to the OMAP HSMMC driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
Signed-off-by Russell King <[email protected]>
Tested on 770, n800, 2430sdp, n900, zoom3 and blaze:
PATCH 5/12 mmc: omap_hsmmc: add DMA engine support
In reply to Russell KingQuoted 6 lines · Russell King
Add DMA engine support to the OMAP HSMMC driver. ?This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
Signed-off-by Russell King <[email protected]>
Great,
Quoted 4 lines
(quoted diff) +4
-0+#if 1 + ? ? ? ? ? ? ? sig = host->dma_line_rx; + ? ? ? ? ? ? ? host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); + ? ? ? ? ? ? ? if (!host->rx_chan) {
Review
Quoted 10 lines
(quoted diff) +10
-0+ ? ? ? ? ? ? ? ? ? ? ? dev_warn(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", sig); + ? ? ? ? ? ? ? } +#endif +#if 1 + ? ? ? ? ? ? ? sig = host->dma_line_tx; + ? ? ? ? ? ? ? host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); + ? ? ? ? ? ? ? if (!host->tx_chan) { + ? ? ? ? ? ? ? ? ? ? ? dev_warn(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", sig); + ? ? ? ? ? ? ? } +#endif
Are these development artifacts?
Apart from that:
Yours,
Linus Walleij
PATCH 5/12 mmc: omap_hsmmc: add DMA engine support
Quoted 12 lines · Linus Walleij
Quoted 6 lines · Russell King
Add DMA engine support to the OMAP HSMMC driver. ?This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
Signed-off-by Russell King <[email protected]>Great,
Quoted 16 lines
Quoted 4 lines
(quoted diff) +4
-0+#if 1 + ? ? ? ? ? ? ? sig = host->dma_line_rx; + ? ? ? ? ? ? ? host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); + ? ? ? ? ? ? ? if (!host->rx_chan) {Review
Quoted 10 lines
(quoted diff) +10
-0+ ? ? ? ? ? ? ? ? ? ? ? dev_warn(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", sig); + ? ? ? ? ? ? ? } +#endif +#if 1 + ? ? ? ? ? ? ? sig = host->dma_line_tx; + ? ? ? ? ? ? ? host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); + ? ? ? ? ? ? ? if (!host->tx_chan) { + ? ? ? ? ? ? ? ? ? ? ? dev_warn(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", sig); + ? ? ? ? ? ? ? } +#endifAre these development artifacts?
Read the commit message. ;)
They're there (and removed by the next patch) so that the driver can be easily switched between DMA engine and the private DMA API. Simply change the relevant #if to zero at build time.
I don't think it warrants config symbols or trying to do it via module params as its just a stepping stone through the process.
PATCH 5/12 mmc: omap_hsmmc: add DMA engine support
Quoted 9 lines · Russell King - ARM Linux
Quoted 1 line · Linus Walleij
Are these development artifacts?
Read the commit message. ;)
They're there (and removed by the next patch) so that the driver can be easily switched between DMA engine and the private DMA API. ?Simply change the relevant #if to zero at build time.
Yeah I saw now when reading through the series...
The whole thing looks very good, since I'm not that into OMAP stuff I'm trying now to glance over the dmaengine semantics part that I understand a bit atleast.
Thanks,
Linus Walleij
PATCH 6/12 mmc: omap_hsmmc: remove private DMA API implementation
In reply to Russell King - ARM LinuxRemove the private DMA API implementation from omap_hsmmc, making it use entirely the DMA engine API.
--- drivers/mmc/host/omap_hsmmc.c | 264 ++++++++++------------------------------- 1 files changed, 64 insertions(+), 200 deletions(-)
drivers/mmc/host/omap_hsmmc.c +63 -199
@@ -38,7 +38,6 @@#include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> -#include <plat/dma.h> #include <mach/hardware.h> #include <plat/board.h> #include <plat/mmc.h>
@@ -165,10 +164,9 @@ struct omap_hsmmc_host {u32 bytesleft;int suspended;int irq; -int use_dma, dma_ch, dma2; +int use_dma, dma_ch;struct dma_chan *tx_chan;struct dma_chan *rx_chan; -int dma_line_tx, dma_line_rx;int slot_id;int got_dbclk;int response_busy;
@@ -804,17 +802,16 @@ static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,static void omap_hsmmc_request_done (struct omap_hsmmc_host *host,struct mmc_request *mrq) { -int dma_ch, dma2; +int dma_ch;spin_lock (&host->irq_lock); host->req_in_progress =0 ; dma_ch = host->dma_ch; - dma2 = host->dma2;spin_unlock (&host->irq_lock);omap_hsmmc_disable_irq (host);/* Do not complete the request if DMA is still in progress */ -if (mrq->data && host->use_dma && (dma_ch !=-1 || dma2 !=-1 )) +if (mrq->data && host->use_dma && dma_ch !=-1 )return ; host->mrq =NULL ;mmc_request_done (host->mmc, mrq);
@@ -883,18 +880,16 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)*/ static void omap_hsmmc_dma_cleanup (struct omap_hsmmc_host *host,int errno) { -int dma_ch, dma2; +int dma_ch; host->data->error = errno;spin_lock (&host->irq_lock); dma_ch = host->dma_ch; host->dma_ch =-1 ; - dma2 = host->dma2; - host->dma2 =-1 ;spin_unlock (&host->irq_lock); -if (host->use_dma && dma2 !=-1 ) { +if (host->use_dma && dma_ch !=-1 ) {struct dma_chan *chan =omap_hsmmc_get_dma_chan (host, host->data);dmaengine_terminate_all (chan);
@@ -904,13 +899,6 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) host->data->host_cookie =0 ; } -if (host->use_dma && dma_ch !=-1 ) { -dma_unmap_sg (mmc_dev (host->mmc), host->data->sg, - host->data->sg_len, -omap_hsmmc_get_dma_dir (host, host->data)); -omap_free_dma (dma_ch); - host->data->host_cookie =0 ; - } host->data =NULL ; }
@@ -1206,99 +1194,6 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)return IRQ_HANDLED ; } -static int omap_hsmmc_get_dma_sync_dev (struct omap_hsmmc_host *host, -struct mmc_data *data) -{ -int sync_dev; - -if (data->flags &MMC_DATA_WRITE ) - sync_dev = host->dma_line_tx; -else - sync_dev = host->dma_line_rx; -return sync_dev; -} - -static void omap_hsmmc_config_dma_params (struct omap_hsmmc_host *host, -struct mmc_data *data, -struct scatterlist *sgl) -{ -int blksz, nblk, dma_ch; - - dma_ch = host->dma_ch; -if (data->flags &MMC_DATA_WRITE ) { -omap_set_dma_dest_params (dma_ch,0 ,OMAP_DMA_AMODE_CONSTANT , - (host->mapbase +OMAP_HSMMC_DATA ),0 ,0 ); -omap_set_dma_src_params (dma_ch,0 ,OMAP_DMA_AMODE_POST_INC , -sg_dma_address (sgl),0 ,0 ); - }else { -omap_set_dma_src_params (dma_ch,0 ,OMAP_DMA_AMODE_CONSTANT , - (host->mapbase +OMAP_HSMMC_DATA ),0 ,0 ); -omap_set_dma_dest_params (dma_ch,0 ,OMAP_DMA_AMODE_POST_INC , -sg_dma_address (sgl),0 ,0 ); - } - - blksz = host->data->blksz; - nblk =sg_dma_len (sgl) / blksz; - -omap_set_dma_transfer_params (dma_ch,OMAP_DMA_DATA_TYPE_S32 , - blksz /4 , nblk,OMAP_DMA_SYNC_FRAME , -omap_hsmmc_get_dma_sync_dev (host, data), - !(data->flags &MMC_DATA_WRITE )); - -omap_start_dma (dma_ch); -} - -/* -* DMA call back function -*/ -static void omap_hsmmc_dma_cb (int lch,u16 ch_status,void *cb_data) -{ -struct omap_hsmmc_host *host = cb_data; -struct mmc_data *data; -int dma_ch, req_in_progress; - -if (!(ch_status &OMAP_DMA_BLOCK_IRQ )) { -dev_warn (mmc_dev (host->mmc),"unexpected dma status %x\n" , - ch_status); -return ; - } - -spin_lock (&host->irq_lock); -if (host->dma_ch <0 ) { -spin_unlock (&host->irq_lock); -return ; - } - - data = host->mrq->data; - host->dma_sg_idx++; -if (host->dma_sg_idx < host->dma_len) { -/* Fire up the next transfer. */ -omap_hsmmc_config_dma_params (host, data, - data->sg + host->dma_sg_idx); -spin_unlock (&host->irq_lock); -return ; - } - -if (!data->host_cookie) -dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, -omap_hsmmc_get_dma_dir (host, data)); - - req_in_progress = host->req_in_progress; - dma_ch = host->dma_ch; - host->dma_ch =-1 ; -spin_unlock (&host->irq_lock); - -omap_free_dma (dma_ch); - -/* If DMA has finished after TC, complete the request */ -if (!req_in_progress) { -struct mmc_request *mrq = host->mrq; - - host->mrq =NULL ; -mmc_request_done (host->mmc, mrq); - } -} -static void omap_hsmmc_dma_callback (void *param) {struct omap_hsmmc_host *host = param;
@@ -1307,7 +1202,7 @@ static void omap_hsmmc_dma_callback(void *param)int req_in_progress;spin_lock_irq (&host->irq_lock); -if (host->dma2 <0 ) { +if (host->dma_ch <0 ) {spin_unlock_irq (&host->irq_lock);return ; }
@@ -1320,7 +1215,7 @@ static void omap_hsmmc_dma_callback(void *param) omap_hsmmc_get_dma_dir(host, data)); req_in_progress = host->req_in_progress; - host->dma2 =-1 ; + host->dma_ch =-1 ;spin_unlock_irq (&host->irq_lock);/* If DMA has finished after TC, complete the request */
@@ -1335,7 +1230,7 @@ static void omap_hsmmc_dma_callback(void *param)static int omap_hsmmc_pre_dma_transfer (struct omap_hsmmc_host *host,struct mmc_data *data,struct omap_hsmmc_next *next, -struct device *dev) +struct dma_chan *chan) {int dma_len;
@@ -1350,7 +1245,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,/* Check if next job is already prepared */ if (next || (!next && data->host_cookie != host->next_data.cookie)) { - dma_len =dma_map_sg (dev, data->sg, data->sg_len, + dma_len =dma_map_sg (chan->device->dev, data->sg, data->sg_len,omap_hsmmc_get_dma_dir (host, data)); }else {
@@ -1377,7 +1272,9 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,static int omap_hsmmc_start_dma_transfer (struct omap_hsmmc_host *host,struct mmc_request *req) { -int dma_ch =0 , ret =0 , i; +struct dma_slave_config cfg; +struct dma_async_tx_descriptor *tx; +int ret =0 , i;struct mmc_data *data = req->data;struct dma_chan *chan;
@@ -1395,66 +1292,43 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,*/ return -EINVAL ; -BUG_ON (host->dma_ch !=-1 || host->dma2 !=-1 ); +BUG_ON (host->dma_ch !=-1 ); chan =omap_hsmmc_get_dma_chan (host, data); -if (!chan) { - ret =omap_request_dma (omap_hsmmc_get_dma_sync_dev (host, data), -"MMC/SD" , omap_hsmmc_dma_cb, host, &dma_ch); -if (ret !=0 ) { -dev_err (mmc_dev (host->mmc), -"%s: omap_request_dma() failed with %d\n" , -mmc_hostname (host->mmc), ret); -return ret; - } - ret =omap_hsmmc_pre_dma_transfer (host, data,NULL , -mmc_dev (host->mmc)); -if (ret) -return ret; - - host->dma_ch = dma_ch; - host->dma_sg_idx =0 ; -omap_hsmmc_config_dma_params (host, data, data->sg); - }else { -struct dma_slave_config cfg; -struct dma_async_tx_descriptor *tx; + cfg.src_addr = host->mapbase +OMAP_HSMMC_DATA ; + cfg.dst_addr = host->mapbase +OMAP_HSMMC_DATA ; + cfg.src_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.dst_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.src_maxburst = data->blksz /4 ; + cfg.dst_maxburst = data->blksz /4 ; - cfg.src_addr = host->mapbase +OMAP_HSMMC_DATA ; - cfg.dst_addr = host->mapbase +OMAP_HSMMC_DATA ; - cfg.src_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; - cfg.dst_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; - cfg.src_maxburst = data->blksz /4 ; - cfg.dst_maxburst = data->blksz /4 ; - - ret =dmaengine_slave_config (chan, &cfg); -if (ret) -return ret; + ret =dmaengine_slave_config (chan, &cfg); +if (ret) +return ret; - ret =omap_hsmmc_pre_dma_transfer (host, data,NULL , - chan->device->dev); -if (ret) -return ret; + ret =omap_hsmmc_pre_dma_transfer (host, data,NULL , chan); +if (ret) +return ret; - tx =dmaengine_prep_slave_sg (chan, data->sg, data->sg_len, - data->flags &MMC_DATA_WRITE ?DMA_MEM_TO_DEV :DMA_DEV_TO_MEM , -DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); -if (!tx) { -dev_err (mmc_dev (host->mmc),"prep_slave_sg() failed\n" ); -/* FIXME: cleanup */ -return -1 ; - } + tx =dmaengine_prep_slave_sg (chan, data->sg, data->sg_len, + data->flags &MMC_DATA_WRITE ?DMA_MEM_TO_DEV :DMA_DEV_TO_MEM , +DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (!tx) { +dev_err (mmc_dev (host->mmc),"prep_slave_sg() failed\n" ); +/* FIXME: cleanup */ +return -1 ; + } - tx->callback = omap_hsmmc_dma_callback; - tx->callback_param = host; + tx->callback = omap_hsmmc_dma_callback; + tx->callback_param = host; -/* Does not fail */ -dmaengine_submit (tx); +/* Does not fail */ +dmaengine_submit (tx); - host->dma2 =1 ; + host->dma_ch =1 ; -dma_async_issue_pending (chan); - } +dma_async_issue_pending (chan);return 0 ; }
@@ -1536,14 +1410,11 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,struct omap_hsmmc_host *host =mmc_priv (mmc);struct mmc_data *data = mrq->data; -if (host->use_dma) { +if (host->use_dma && data->host_cookie) {struct dma_chan *c =omap_hsmmc_get_dma_chan (host, data); -struct device *dev = c ? c->device->dev :mmc_dev (mmc); -if (data->host_cookie) -dma_unmap_sg (dev, - data->sg, data->sg_len, -omap_hsmmc_get_dma_dir (host, data)); +dma_unmap_sg (c->device->dev, data->sg, data->sg_len, +omap_hsmmc_get_dma_dir (host, data)); data->host_cookie =0 ; } }
@@ -1560,10 +1431,9 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,if (host->use_dma) {struct dma_chan *c =omap_hsmmc_get_dma_chan (host, mrq->data); -struct device *dev = c ? c->device->dev :mmc_dev (mmc);if (omap_hsmmc_pre_dma_transfer (host, mrq->data, - &host->next_data, dev)) + &host->next_data, c)) mrq->data->host_cookie =0 ; } }
@@ -1577,7 +1447,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)int err;BUG_ON (host->req_in_progress); -BUG_ON (host->dma_ch !=-1 || host->dma2 !=-1 ); +BUG_ON (host->dma_ch !=-1 );if (host->protect_card) {if (host->reqs_blocked <3 ) {/*
@@ -1890,6 +1760,8 @@ static inline struct omap_mmc_platform_data }#endif +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); +static int __devinit omap_hsmmc_probe (struct platform_device *pdev) {struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
@@ -1898,6 +1770,8 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)struct resource *res;int ret, irq;const struct of_device_id *match; +dma_cap_mask_t mask; +unsigned tx_req, rx_req; match =of_match_device (of_match_ptr (omap_mmc_of_match), &pdev->dev);if (match) {
@@ -1942,9 +1816,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->pdata = pdata; host->dev = &pdev->dev; host->use_dma =1 ; - host->dev->dma_mask = &pdata->dma_mask; host->dma_ch =-1 ; - host->dma2 =-1 ; host->irq = irq; host->slot_id =0 ; host->mapbase = res->start + pdata->reg_offset;
@@ -2036,36 +1908,28 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)dev_err (mmc_dev (host->mmc),"cannot get DMA TX channel\n" ); goto err_irq; } - host->dma_line_tx = res->start; + tx_req = res->start; res =platform_get_resource_byname (pdev,IORESOURCE_DMA ,"rx" );if (!res) {dev_err (mmc_dev (host->mmc),"cannot get DMA RX channel\n" ); goto err_irq; } - host->dma_line_rx = res->start; + rx_req = res->start; - { -dma_cap_mask_t mask; -unsigned sig; -extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); - -dma_cap_zero (mask); -dma_cap_set (DMA_SLAVE , mask); -#if 1 - sig = host->dma_line_rx; - host->rx_chan =dma_request_channel (mask, omap_dma_filter_fn, &sig); -if (!host->rx_chan) { -dev_warn (mmc_dev (host->mmc),"unable to obtain RX DMA engine channel %u\n" , sig); - } -#endif -#if 1 - sig = host->dma_line_tx; - host->tx_chan =dma_request_channel (mask, omap_dma_filter_fn, &sig); -if (!host->tx_chan) { -dev_warn (mmc_dev (host->mmc),"unable to obtain TX DMA engine channel %u\n" , sig); - } -#endif +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); + + host->rx_chan =dma_request_channel (mask, omap_dma_filter_fn, &rx_req); +if (!host->rx_chan) { +dev_err (mmc_dev (host->mmc),"unable to obtain RX DMA engine channel %u\n" , rx_req); + goto err_irq; + } + + host->tx_chan =dma_request_channel (mask, omap_dma_filter_fn, &tx_req); +if (!host->tx_chan) { +dev_err (mmc_dev (host->mmc),"unable to obtain TX DMA engine channel %u\n" , tx_req); + goto err_irq; }/* Request IRQ for MMC operations */
Signature · 1 line
1.7.4.4
Tony Lindgren
maintainerPATCH 6/12 mmc: omap_hsmmc: remove private DMA API implementation
Quoted 4 lines · Russell King
Remove the private DMA API implementation from
omap_hsmmc, making it use entirely the DMA engine API.Signed-off-by Russell King <[email protected]>
Tested on 770, n800, 2430sdp, n900, zoom3 and blaze:
PATCH 6/12 mmc: omap_hsmmc: remove private DMA API implementation
In reply to Russell KingQuoted 4 lines · Russell King
Remove the private DMA API implementation from
omap_hsmmc, making it use entirely the DMA engine API.Signed-off-by Russell King <[email protected]>
Since the driver becomes useless without DMA_ENGINE, we probably want a 'depends on'?
Signature · 1 line
Gra?vydas
PATCH 6/12 mmc: omap_hsmmc: remove private DMA API implementation
Quoted 9 lines · Grazvydas Ignotas
Quoted 4 lines · Russell King
Remove the private DMA API implementation from
omap_hsmmc, making it use entirely the DMA engine API.Signed-off-by Russell King <[email protected]>Since the driver becomes useless without
DMA_ENGINE, we probably want a 'depends on'?
I think it's possible to use tweak this to use PIO should DMA_ENGINE not be available - though first we need to sort out all the filter functions and how we select the DMA channels. That's pretty much an open question (which was brought up in my original set of patches) and remains to these ones.
How we did this with the AMBA Primecell drivers was to pass in the filter function and filter argument from platform code, allowing the primecell drivers to be used with any DMA engine. That doesn't work with DT though...
At the moment, I don't have an answer for this, because of the DT implications here. So, the issue is rather stuck, and as a result I'm just sticking the "extern" declarations for the filter function into drivers that have been converted.
PATCH 7/12 mmc: omap: add DMA engine support
In reply to Russell King - ARM LinuxAdd DMA engine support to the OMAP driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
--- drivers/mmc/host/omap.c | 200 ++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 190 insertions(+), 10 deletions(-)
drivers/mmc/host/omap.c +190 -10
@@ -17,6 +17,7 @@#include <linux/ioport.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/spinlock.h>
@@ -99,6 +100,8 @@struct mmc_omap_host ; +#define USE_DMA_PRIVATE +struct mmc_omap_slot {int id;unsigned int vdd;
@@ -128,6 +131,10 @@ struct mmc_omap_host {unsigned char id;/* 16xx chips have 2 MMC blocks */ struct clk * iclk;struct clk * fclk; +struct dma_chan *dma_rx; +u32 dma_rx_burst; +struct dma_chan *dma_tx; +u32 dma_tx_burst;struct resource *mem_res;void __iomem *virt_base;unsigned int phys_base;
@@ -153,12 +160,14 @@ struct mmc_omap_host { unsigned use_dma:1; unsigned brs_received:1, dma_done:1; - unsigned dma_is_read:1; unsigned dma_in_use:1; +#ifdef USE_DMA_PRIVATE + unsigned dma_is_read:1;int dma_ch; -spinlock_t dma_lock;struct timer_list dma_timer;unsigned dma_len; +#endif +spinlock_t dma_lock;struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS ];struct mmc_omap_slot *current_slot;
@@ -406,18 +415,32 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, int abort) {enum dma_data_direction dma_data_dir; +struct device *dev =mmc_dev (host->mmc); +struct dma_chan *c; +#ifdef USE_DMA_PRIVATE BUG_ON (host->dma_ch <0 );if (data->error)omap_stop_dma (host->dma_ch);/* Release DMA channel lazily */ mod_timer (&host->dma_timer, jiffies +HZ ); -if (data->flags &MMC_DATA_WRITE ) +#endif +if (data->flags &MMC_DATA_WRITE ) { dma_data_dir =DMA_TO_DEVICE ; -else + c = host->dma_tx; + }else { dma_data_dir =DMA_FROM_DEVICE ; -dma_unmap_sg (mmc_dev (host->mmc), data->sg, host->sg_len, - dma_data_dir); + c = host->dma_rx; + } +if (c) { +if (data->error) { +dmaengine_terminate_all (c); +/* Claim nothing transferred on error... */ + data->bytes_xfered =0 ; + } + dev = c->device->dev; + } +dma_unmap_sg (dev, data->sg, host->sg_len, dma_data_dir); }static void mmc_omap_send_stop_work (struct work_struct *work)
@@ -524,6 +547,7 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)mmc_omap_xfer_done (host, data); } +#ifdef USE_DMA_PRIVATE static void mmc_omap_dma_timer (unsigned long data) {
@@ -533,6 +557,7 @@ mmc_omap_dma_timer(unsigned long data)omap_free_dma (host->dma_ch); host->dma_ch = -1; } +#endif static void mmc_omap_dma_done (struct mmc_omap_host *host,struct mmc_data *data)
@@ -891,6 +916,18 @@ static void mmc_omap_cover_handler(unsigned long param) jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); } +static void mmc_omap_dma_callback (void *priv) +{ +struct mmc_omap_host *host = priv; +struct mmc_data *data = host->data; + +/* If we got to the end of DMA, assume everything went well */ + data->bytes_xfered += data->blocks * data->blksz; + +mmc_omap_dma_done (host, data); +} + +#ifdef USE_DMA_PRIVATE /* Prepare to transfer the next segment of a scatterlist */ static void mmc_omap_prepare_dma (struct mmc_omap_host *host,struct mmc_data *data)
@@ -1045,6 +1082,7 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data return 0; } +#endif static inline void set_cmd_timeout (struct mmc_omap_host *host,struct mmc_request *req) {
@@ -1118,6 +1156,80 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) host->sg_idx =0 ;if (use_dma) { +enum dma_data_direction dma_data_dir; +struct dma_async_tx_descriptor *tx; +struct dma_chan *c; +u32 burst, *bp; +u16 buf; + +/* +* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx +* and 24xx. Use 16 or 32 word frames when the +* blocksize is at least that large. Blocksize is +* usually 512 bytes; but not for some SD reads. +*/ + burst =cpu_is_omap15xx () ?32 :64 ; +if (burst > data->blksz) + burst = data->blksz; + + burst >>=1 ; + +if (data->flags &MMC_DATA_WRITE ) { + c = host->dma_tx; + bp = &host->dma_tx_burst; + buf =0x0f80 | (burst -1 ) <<0 ; + dma_data_dir =DMA_TO_DEVICE ; + }else { + c = host->dma_rx; + bp = &host->dma_rx_burst; + buf =0x800f | (burst -1 ) <<8 ; + dma_data_dir =DMA_FROM_DEVICE ; + } + +if (!c) + goto use_pio; + +/* Only reconfigure if we have a different burst size */ +if (*bp != burst) { +struct dma_slave_config cfg; + + cfg.src_addr = host->phys_base +OMAP_MMC_REG (host,DATA ); + cfg.dst_addr = host->phys_base +OMAP_MMC_REG (host,DATA ); + cfg.src_addr_width =DMA_SLAVE_BUSWIDTH_2_BYTES ; + cfg.dst_addr_width =DMA_SLAVE_BUSWIDTH_2_BYTES ; + cfg.src_maxburst = burst; + cfg.dst_maxburst = burst; + +if (dmaengine_slave_config (c, &cfg)) + goto use_pio; + + *bp = burst; + } + + host->sg_len =dma_map_sg (c->device->dev, data->sg, sg_len, + dma_data_dir); +if (host->sg_len ==0 ) + goto use_pio; + + tx =dmaengine_prep_slave_sg (c, data->sg, host->sg_len, + data->flags &MMC_DATA_WRITE ?DMA_MEM_TO_DEV :DMA_DEV_TO_MEM , +DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (!tx) + goto use_pio; + +OMAP_MMC_WRITE (host,BUF , buf); + + tx->callback = mmc_omap_dma_callback; + tx->callback_param = host; +dmaengine_submit (tx); + host->brs_received =0 ; + host->dma_done =0 ; + host->dma_in_use =1 ; +return ; + } + use_pio: +#ifdef USE_DMA_PRIVATE +if (use_dma) {if (mmc_omap_get_dma_channel (host, data) ==0 ) {enum dma_data_direction dma_data_dir;
@@ -1136,6 +1248,9 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) } else use_dma =0 ; } +#else + use_dma =0 ; +#endif /* Revert to PIO? */ if (!use_dma) {
@@ -1157,8 +1272,17 @@ static void mmc_omap_start_request(struct mmc_omap_host *host,/* only touch fifo AFTER the controller readies it */ mmc_omap_prepare_data (host, req);mmc_omap_start_command (host, req->cmd); -if (host->dma_in_use) -omap_start_dma (host->dma_ch); +if (host->dma_in_use) { +struct dma_chan *c = host->data->flags &MMC_DATA_WRITE ? + host->dma_tx : host->dma_rx; + +if (c) +dma_async_issue_pending (c); +#ifdef USE_DMA_PRIVATE + else + omap_start_dma(host->dma_ch); +#endif + } }static void mmc_omap_request (struct mmc_host *mmc,struct mmc_request *req)
@@ -1395,11 +1519,15 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)mmc_free_host (mmc); } +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); +static int __init mmc_omap_probe (struct platform_device *pdev) {struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;struct mmc_omap_host *host =NULL ;struct resource *res; +dma_cap_mask_t mask; +unsigned sig;int i, ret =0 ;int irq;
@@ -1439,7 +1567,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)setup_timer (&host->clk_timer, mmc_omap_clk_timer, (unsigned long ) host);spin_lock_init (&host->dma_lock); +#ifdef USE_DMA_PRIVATE setup_timer (&host->dma_timer, mmc_omap_dma_timer, (unsigned long ) host); +#endif spin_lock_init (&host->slot_lock);init_waitqueue_head (&host->slot_wq);
@@ -1452,8 +1582,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->irq = irq; host->use_dma =1 ; +#ifdef USE_DMA_PRIVATE host->dev->dma_mask = &pdata->dma_mask; host->dma_ch =-1 ; +#endif host->irq = irq; host->phys_base = host->mem_res->start;
@@ -1474,9 +1606,48 @@ static int __init mmc_omap_probe(struct platform_device *pdev) goto err_free_iclk; } +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); + + host->dma_tx_burst =-1 ; + host->dma_rx_burst =-1 ; + +if (cpu_is_omap24xx ()) + sig = host->id ==0 ?OMAP24XX_DMA_MMC1_TX :OMAP24XX_DMA_MMC2_TX ; +else + sig = host->id ==0 ?OMAP_DMA_MMC_TX :OMAP_DMA_MMC2_TX ; + host->dma_tx =dma_request_channel (mask, omap_dma_filter_fn, &sig); +#if 0 +if (!host->dma_tx) { +dev_err (host->dev,"unable to obtain TX DMA engine channel %u\n" , + sig); + goto err_dma; + } +#else +if (!host->dma_tx) +dev_warn (host->dev,"unable to obtain TX DMA engine channel %u\n" , + sig); +#endif +if (cpu_is_omap24xx ()) + sig = host->id ==0 ?OMAP24XX_DMA_MMC1_RX :OMAP24XX_DMA_MMC2_RX ; +else + sig = host->id ==0 ?OMAP_DMA_MMC_RX :OMAP_DMA_MMC2_RX ; + host->dma_rx =dma_request_channel (mask, omap_dma_filter_fn, &sig); +#if 0 +if (!host->dma_rx) { +dev_err (host->dev,"unable to obtain RX DMA engine channel %u\n" , + sig); + goto err_dma; + } +#else +if (!host->dma_rx) +dev_warn (host->dev,"unable to obtain RX DMA engine channel %u\n" , + sig); +#endif + ret =request_irq (host->irq, mmc_omap_irq,0 ,DRIVER_NAME , host);if (ret) - goto err_free_fclk; + goto err_free_dma;if (pdata->init !=NULL ) { ret = pdata->init (&pdev->dev);
@@ -1504,7 +1675,11 @@ static int __init mmc_omap_probe(struct platform_device *pdev) pdata->cleanup (&pdev->dev); err_free_irq:free_irq (host->irq, host); -err_free_fclk: +err_free_dma: +if (host->dma_tx) +dma_release_channel (host->dma_tx); +if (host->dma_rx) +dma_release_channel (host->dma_rx);clk_put (host->fclk); err_free_iclk:clk_disable (host->iclk);
@@ -1539,6 +1714,11 @@ static int mmc_omap_remove(struct platform_device *pdev)clk_disable (host->iclk);clk_put (host->iclk); +if (host->dma_tx) +dma_release_channel (host->dma_tx); +if (host->dma_rx) +dma_release_channel (host->dma_rx); +iounmap (host->virt_base);release_mem_region (pdev->resource[0 ].start, pdev->resource[0 ].end - pdev->resource[0 ].start +1 );
Signature · 1 line
1.7.4.4
Tony Lindgren
maintainerPATCH 7/12 mmc: omap: add DMA engine support
Quoted 4 lines · Russell King
Add DMA engine support to the OMAP driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
Below is what's needed to use DMA request lines from platform data. Note also the release_mem_region change that we'll now need for this one also (but not as a fix).
I've posted a cleanup patch series to mostly remove plat-omap/devices.c that takes care of passing the DMA request lines in platform data. That series should get merged before the driver changes for this driver to keep DMA working.
Regards,
Tony
drivers/mmc/host/omap.c +27 -18
@@ -1313,7 +1313,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)struct mmc_omap_host *host =NULL ;struct resource *res;dma_cap_mask_t mask; -unsigned sig; +unsigned tx_req, rx_req;int i, ret =0 ;int irq;
@@ -1389,37 +1389,44 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->dma_tx_burst =-1 ; host->dma_rx_burst =-1 ; -if (cpu_is_omap24xx ()) - sig = host->id ==0 ?OMAP24XX_DMA_MMC1_TX :OMAP24XX_DMA_MMC2_TX ; -else - sig = host->id ==0 ?OMAP_DMA_MMC_TX :OMAP_DMA_MMC2_TX ; - host->dma_tx =dma_request_channel (mask, omap_dma_filter_fn, &sig); + res =platform_get_resource_byname (pdev,IORESOURCE_DMA ,"tx" ); +if (!res) { +dev_err (host->dev,"cannot get DMA TX channel\n" ); + goto err_free_dma; + } + tx_req = res->start; + + res =platform_get_resource_byname (pdev,IORESOURCE_DMA ,"rx" ); +if (!res) { +dev_err (host->dev,"cannot get DMA RX channel\n" ); + goto err_free_dma; + } + rx_req = res->start; + + host->dma_tx =dma_request_channel (mask, omap_dma_filter_fn, &tx_req);#if 0 if (!host->dma_tx) {dev_err (host->dev,"unable to obtain TX DMA engine channel %u\n" , - sig); - goto err_dma; + tx_req); + goto err_free_dma; }#else if (!host->dma_tx)dev_warn (host->dev,"unable to obtain TX DMA engine channel %u\n" , - sig); + tx_req);#endif -if (cpu_is_omap24xx ()) - sig = host->id ==0 ?OMAP24XX_DMA_MMC1_RX :OMAP24XX_DMA_MMC2_RX ; -else - sig = host->id ==0 ?OMAP_DMA_MMC_RX :OMAP_DMA_MMC2_RX ; - host->dma_rx =dma_request_channel (mask, omap_dma_filter_fn, &sig); + + host->dma_rx =dma_request_channel (mask, omap_dma_filter_fn, &rx_req);#if 0 if (!host->dma_rx) {dev_err (host->dev,"unable to obtain RX DMA engine channel %u\n" , - sig); - goto err_dma; + rx_req); + goto err_free_dma; }#else if (!host->dma_rx)dev_warn (host->dev,"unable to obtain RX DMA engine channel %u\n" , - sig); + rx_req);#endif ret =request_irq (host->irq, mmc_omap_irq,0 ,DRIVER_NAME , host);
@@ -1466,7 +1473,9 @@ err_free_mmc_host: err_ioremap:kfree (host); err_free_mem_region: -release_mem_region (res->start,resource_size (res)); + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res) +release_mem_region (res->start,resource_size (res));return ret; }
PATCH 7/12 mmc: omap: add DMA engine support
Quoted 6 lines · Tony Lindgren
Quoted 4 lines · Russell King
Add DMA engine support to the OMAP driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
Quoted 8 lines
Below is what's needed to use DMA request lines from platform data. Note also the
release_mem_regionchange that we'll now need for this one also (but not as a fix).I've posted a cleanup patch series to mostly remove
plat-omap/devices.cthat takes care of passing the DMA request lines in platform data. That series should get merged before the driver changes for this driver to keep DMA working.
Okay, how do we want to handle this patch? I don't think there's any urgency for this patch at the present time, so I'm quite happy for this to be delayed after the next merge window after we have the pre-requisits for it in place. (And trying to get it in earlier is only going to give us git tree dependencies to deal with.)
Tony Lindgren
maintainerPATCH 7/12 mmc: omap: add DMA engine support
Quoted 16 lines · Russell King - ARM Linux
Quoted 6 lines · Tony Lindgren
Quoted 4 lines · Russell King
Add DMA engine support to the OMAP driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API.
Quoted 8 lines
Below is what's needed to use DMA request lines from platform data. Note also the
release_mem_regionchange that we'll now need for this one also (but not as a fix).I've posted a cleanup patch series to mostly remove
plat-omap/devices.cthat takes care of passing the DMA request lines in platform data. That series should get merged before the driver changes for this driver to keep DMA working.
Quoted 5 lines
Okay, how do we want to handle this patch? I don't think there's any urgency for this patch at the present time, so I'm quite happy for this to be delayed after the next merge window after we have the pre-requisits for it in place. (And trying to get it in earlier is only going to give us git tree dependencies to deal with.)
Sounds good to me.
Regards,
Tony
PATCH 8/12 mmc: omap: remove private DMA API implementation
In reply to Russell King - ARM LinuxRemove the private DMA API implementation from omap, making it use entirely the DMA engine API.
--- drivers/mmc/host/omap.c | 235 +--------------------------------------------- 1 files changed, 6 insertions(+), 229 deletions(-)
drivers/mmc/host/omap.c +6 -229
@@ -100,8 +100,6 @@struct mmc_omap_host ; -#define USE_DMA_PRIVATE -struct mmc_omap_slot {int id;unsigned int vdd;
@@ -161,12 +159,6 @@ struct mmc_omap_host { unsigned use_dma:1; unsigned brs_received:1, dma_done:1; unsigned dma_in_use:1; -#ifdef USE_DMA_PRIVATE - unsigned dma_is_read:1; -int dma_ch; -struct timer_list dma_timer; -unsigned dma_len; -#endif spinlock_t dma_lock;struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS ];
@@ -418,13 +410,6 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data,struct device *dev =mmc_dev (host->mmc);struct dma_chan *c; -#ifdef USE_DMA_PRIVATE -BUG_ON (host->dma_ch <0 ); -if (data->error) -omap_stop_dma (host->dma_ch); -/* Release DMA channel lazily */ -mod_timer (&host->dma_timer, jiffies +HZ ); -#endif if (data->flags &MMC_DATA_WRITE ) { dma_data_dir =DMA_TO_DEVICE ; c = host->dma_tx;
@@ -547,18 +532,6 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)mmc_omap_xfer_done (host, data); } -#ifdef USE_DMA_PRIVATE -static void -mmc_omap_dma_timer (unsigned long data) -{ -struct mmc_omap_host *host = (struct mmc_omap_host *) data; - -BUG_ON (host->dma_ch <0 ); -omap_free_dma (host->dma_ch); - host->dma_ch =-1 ; -} -#endif -static void mmc_omap_dma_done (struct mmc_omap_host *host,struct mmc_data *data) {
@@ -927,163 +900,6 @@ static void mmc_omap_dma_callback(void *priv)mmc_omap_dma_done (host, data); } -#ifdef USE_DMA_PRIVATE -/* Prepare to transfer the next segment of a scatterlist */ -static void -mmc_omap_prepare_dma (struct mmc_omap_host *host,struct mmc_data *data) -{ -int dma_ch = host->dma_ch; -unsigned long data_addr; -u16 buf, frame; -u32 count; -struct scatterlist *sg = &data->sg[host->sg_idx]; -int src_port =0 ; -int dst_port =0 ; -int sync_dev =0 ; - - data_addr = host->phys_base +OMAP_MMC_REG (host,DATA ); - frame = data->blksz; - count =sg_dma_len (sg); - -if ((data->blocks ==1 ) && (count > data->blksz)) - count = frame; - - host->dma_len = count; - -/* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. -* Use 16 or 32 word frames when the blocksize is at least that large. -* Blocksize is usually 512 bytes; but not for some SD reads. -*/ -if (cpu_is_omap15xx () && frame >32 ) - frame =32 ; -else if (frame >64 ) - frame =64 ; - count /= frame; - frame >>=1 ; - -if (!(data->flags &MMC_DATA_WRITE )) { - buf =0x800f | ((frame -1 ) <<8 ); - -if (cpu_class_is_omap1 ()) { - src_port =OMAP_DMA_PORT_TIPB ; - dst_port =OMAP_DMA_PORT_EMIFF ; - } -if (cpu_is_omap24xx ()) - sync_dev =OMAP24XX_DMA_MMC1_RX ; - -omap_set_dma_src_params (dma_ch, src_port, -OMAP_DMA_AMODE_CONSTANT , - data_addr,0 ,0 ); -omap_set_dma_dest_params (dma_ch, dst_port, -OMAP_DMA_AMODE_POST_INC , -sg_dma_address (sg),0 ,0 ); -omap_set_dma_dest_data_pack (dma_ch,1 ); -omap_set_dma_dest_burst_mode (dma_ch,OMAP_DMA_DATA_BURST_4 ); - }else { - buf =0x0f80 | ((frame -1 ) <<0 ); - -if (cpu_class_is_omap1 ()) { - src_port =OMAP_DMA_PORT_EMIFF ; - dst_port =OMAP_DMA_PORT_TIPB ; - } -if (cpu_is_omap24xx ()) - sync_dev =OMAP24XX_DMA_MMC1_TX ; - -omap_set_dma_dest_params (dma_ch, dst_port, -OMAP_DMA_AMODE_CONSTANT , - data_addr,0 ,0 ); -omap_set_dma_src_params (dma_ch, src_port, -OMAP_DMA_AMODE_POST_INC , -sg_dma_address (sg),0 ,0 ); -omap_set_dma_src_data_pack (dma_ch,1 ); -omap_set_dma_src_burst_mode (dma_ch,OMAP_DMA_DATA_BURST_4 ); - } - -/* Max limit for DMA frame count is 0xffff */ -BUG_ON (count >0xffff ); - -OMAP_MMC_WRITE (host,BUF , buf); -omap_set_dma_transfer_params (dma_ch,OMAP_DMA_DATA_TYPE_S16 , - frame, count,OMAP_DMA_SYNC_FRAME , - sync_dev,0 ); -} - -/* A scatterlist segment completed */ -static void mmc_omap_dma_cb (int lch,u16 ch_status,void *data) -{ -struct mmc_omap_host *host = (struct mmc_omap_host *) data; -struct mmc_data *mmcdat = host->data; - -if (unlikely (host->dma_ch <0 )) { -dev_err (mmc_dev (host->mmc), -"DMA callback while DMA not enabled\n" ); -return ; - } -/* FIXME: We really should do something to _handle_ the errors */ -if (ch_status &OMAP1_DMA_TOUT_IRQ ) { -dev_err (mmc_dev (host->mmc),"DMA timeout\n" ); -return ; - } -if (ch_status &OMAP_DMA_DROP_IRQ ) { -dev_err (mmc_dev (host->mmc),"DMA sync error\n" ); -return ; - } -if (!(ch_status &OMAP_DMA_BLOCK_IRQ )) { -return ; - } - mmcdat->bytes_xfered += host->dma_len; - host->sg_idx++; -if (host->sg_idx < host->sg_len) { -mmc_omap_prepare_dma (host, host->data); -omap_start_dma (host->dma_ch); - }else -mmc_omap_dma_done (host, host->data); -} - -static int mmc_omap_get_dma_channel (struct mmc_omap_host *host,struct mmc_data *data) -{ -const char *dma_dev_name; -int sync_dev, dma_ch, is_read, r; - - is_read = !(data->flags &MMC_DATA_WRITE ); -del_timer_sync (&host->dma_timer); -if (host->dma_ch >=0 ) { -if (is_read == host->dma_is_read) -return 0 ; -omap_free_dma (host->dma_ch); - host->dma_ch =-1 ; - } - -if (is_read) { -if (host->id ==0 ) { - sync_dev =OMAP_DMA_MMC_RX ; - dma_dev_name ="MMC1 read" ; - }else { - sync_dev =OMAP_DMA_MMC2_RX ; - dma_dev_name ="MMC2 read" ; - } - }else { -if (host->id ==0 ) { - sync_dev =OMAP_DMA_MMC_TX ; - dma_dev_name ="MMC1 write" ; - }else { - sync_dev =OMAP_DMA_MMC2_TX ; - dma_dev_name ="MMC2 write" ; - } - } - r =omap_request_dma (sync_dev, dma_dev_name, mmc_omap_dma_cb, - host, &dma_ch); -if (r !=0 ) { -dev_dbg (mmc_dev (host->mmc),"omap_request_dma() failed with %d\n" , r); -return r; - } - host->dma_ch = dma_ch; - host->dma_is_read = is_read; - -return 0 ; -} -#endif -static inline void set_cmd_timeout (struct mmc_omap_host *host,struct mmc_request *req) {u16 reg;
@@ -1228,38 +1044,13 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)return ; } use_pio: -#ifdef USE_DMA_PRIVATE -if (use_dma) { -if (mmc_omap_get_dma_channel (host, data) ==0 ) { -enum dma_data_direction dma_data_dir; - -if (data->flags &MMC_DATA_WRITE ) - dma_data_dir =DMA_TO_DEVICE ; -else - dma_data_dir =DMA_FROM_DEVICE ; - - host->sg_len =dma_map_sg (mmc_dev (host->mmc), data->sg, - sg_len, dma_data_dir); - host->total_bytes_left =0 ; -mmc_omap_prepare_dma (host, req->data); - host->brs_received =0 ; - host->dma_done =0 ; - host->dma_in_use =1 ; - }else - use_dma =0 ; - } -#else - use_dma =0 ; -#endif /* Revert to PIO? */ -if (!use_dma) { -OMAP_MMC_WRITE (host,BUF ,0x1f1f ); - host->total_bytes_left = data->blocks * block_size; - host->sg_len = sg_len; -mmc_omap_sg_to_buf (host); - host->dma_in_use =0 ; - } +OMAP_MMC_WRITE (host,BUF ,0x1f1f ); + host->total_bytes_left = data->blocks * block_size; + host->sg_len = sg_len; +mmc_omap_sg_to_buf (host); + host->dma_in_use =0 ; } static void mmc_omap_start_request(struct mmc_omap_host *host,
@@ -1276,12 +1067,7 @@ static void mmc_omap_start_request(struct mmc_omap_host *host,struct dma_chan *c = host->data->flags &MMC_DATA_WRITE ? host->dma_tx : host->dma_rx; -if (c) -dma_async_issue_pending (c); -#ifdef USE_DMA_PRIVATE - else - omap_start_dma(host->dma_ch); -#endif +dma_async_issue_pending (c); } }
@@ -1567,9 +1353,6 @@ static int __init mmc_omap_probe(struct platform_device *pdev)setup_timer (&host->clk_timer, mmc_omap_clk_timer, (unsigned long ) host);spin_lock_init (&host->dma_lock); -#ifdef USE_DMA_PRIVATE -setup_timer (&host->dma_timer, mmc_omap_dma_timer, (unsigned long ) host); -#endif spin_lock_init (&host->slot_lock);init_waitqueue_head (&host->slot_wq);
@@ -1580,13 +1363,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->id = pdev->id; host->mem_res = res; host->irq = irq; - host->use_dma =1 ; -#ifdef USE_DMA_PRIVATE - host->dev->dma_mask = &pdata->dma_mask; - host->dma_ch =-1 ; -#endif - host->irq = irq; host->phys_base = host->mem_res->start; host->virt_base =ioremap (res->start,resource_size (res));
Signature · 1 line
1.7.4.4
PATCH 9/12 ARM: omap: remove mmc platform data dma_mask and initialization
In reply to Russell King - ARM LinuxDMAengine uses the DMA engine device structure when mapping/unmapping memory for DMA, so the MMC devices do not need their DMA masks initialized (this reflects hardware: the MMC device is not the device doing DMA.)
--- arch/arm/mach-omap1/board-h2-mmc.c | 1 - arch/arm/mach-omap1/board-h3-mmc.c | 1 - arch/arm/mach-omap1/board-nokia770.c | 1 - arch/arm/mach-omap2/board-n8x0.c | 1 - arch/arm/mach-omap2/hsmmc.c | 1 - arch/arm/plat-omap/include/plat/mmc.h | 2 -- 6 files changed, 0 insertions(+), 7 deletions(-)
arch/arm/mach-omap1/board-h2-mmc.c +0 -1
@@ -54,7 +54,6 @@ static struct omap_mmc_platform_data mmc1_data = { .nr_slots = 1, .init = mmc_late_init, .cleanup = mmc_cleanup, - .dma_mask = 0xffffffff, .slots[0] = { .set_power = mmc_set_power, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
arch/arm/mach-omap1/board-h3-mmc.c +0 -1
@@ -36,7 +36,6 @@ static int mmc_set_power(struct device *dev, int slot, int power_on,*/ static struct omap_mmc_platform_data mmc1_data = { .nr_slots =1 , - .dma_mask =0xffffffff , .slots[0 ] = { .set_power = mmc_set_power, .ocr_mask =MMC_VDD_32_33 |MMC_VDD_33_34 ,
arch/arm/mach-omap1/board-nokia770.c +0 -1
@@ -185,7 +185,6 @@ static int nokia770_mmc_get_cover_state(struct device *dev, int slot)static struct omap_mmc_platform_data nokia770_mmc2_data = { .nr_slots =1 , - .dma_mask =0xffffffff , .max_freq =12000000 , .slots[0 ] = { .set_power = nokia770_mmc_set_power,
arch/arm/mach-omap2/board-n8x0.c +0 -1
@@ -470,7 +470,6 @@ static struct omap_mmc_platform_data mmc1_data = { .cleanup = n8x0_mmc_cleanup, .shutdown = n8x0_mmc_shutdown, .max_freq = 24000000, - .dma_mask = 0xffffffff, .slots[0] = { .wires = 4, .set_power = n8x0_mmc_set_power,
arch/arm/mach-omap2/hsmmc.c +0 -1
@@ -315,7 +315,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc->slots[0 ].caps = c->caps; mmc->slots[0 ].pm_caps = c->pm_caps; mmc->slots[0 ].internal_clock = !c->ext_clock; - mmc->dma_mask =0xffffffff ; mmc->max_freq = c->max_freq;if (cpu_is_omap44xx ()) mmc->reg_offset =OMAP4_MMC_REG_OFFSET ;
arch/arm/plat-omap/include/plat/mmc.h +0 -2
@@ -80,8 +80,6 @@ struct omap_mmc_platform_data {/* Return context loss count due to PM states changing */ int (*get_context_loss_count)(struct device *dev); -u64 dma_mask; -/* Integrating attributes from the omap_hwmod layer */ u8 controller_flags;
Signature · 1 line
1.7.4.4
PATCH 10/12 spi: omap2-mcspi: add DMA engine support
In reply to Russell King - ARM LinuxAdd DMA engine support to the OMAP SPI driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API for the transmit and receive sides.
--- drivers/spi/spi-omap2-mcspi.c | 184 ++++++++++++++++++++++++++++++++++------- 1 files changed, 152 insertions(+), 32 deletions(-)
drivers/spi/spi-omap2-mcspi.c +151 -31
@@ -20,6 +20,8 @@* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ +#define USE_DMA_ENGINE_RX +#define USE_DMA_ENGINE_TX #include <linux/kernel.h> #include <linux/init.h>
@@ -28,6 +30,7 @@#include <linux/device.h> #include <linux/delay.h> #include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/platform_device.h> #include <linux/err.h> #include <linux/clk.h>
@@ -95,6 +98,8 @@/* We have 2 DMA channels per CS, one for RX and one for TX */ struct omap2_mcspi_dma { +struct dma_chan *dma_tx; +struct dma_chan *dma_rx;int dma_tx_channel;int dma_rx_channel;
@@ -290,6 +295,30 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)return 0 ; } +static void omap2_mcspi_rx_callback (void *data) +{ +struct spi_device *spi = data; +struct omap2_mcspi *mcspi =spi_master_get_devdata (spi->master); +struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; + +complete (&mcspi_dma->dma_rx_completion); + +/* We must disable the DMA RX request */ +omap2_mcspi_set_dma_req (spi,1 ,0 ); +} + +static void omap2_mcspi_tx_callback (void *data) +{ +struct spi_device *spi = data; +struct omap2_mcspi *mcspi =spi_master_get_devdata (spi->master); +struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; + +complete (&mcspi_dma->dma_tx_completion); + +/* We must disable the DMA TX request */ +omap2_mcspi_set_dma_req (spi,0 ,0 ); +} +static unsigned omap2_mcspi_txrx_dma (struct spi_device *spi,struct spi_transfer *xfer) {
@@ -304,6 +333,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)u8 * rx;const u8 * tx;void __iomem *chstat_reg; +struct dma_slave_config cfg; +enum dma_slave_buswidth width; +unsigned es; mcspi =spi_master_get_devdata (spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -311,6 +343,71 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) chstat_reg = cs->base +OMAP2_MCSPI_CHSTAT0 ; +if (cs->word_len <=8 ) { + width =DMA_SLAVE_BUSWIDTH_1_BYTE ; + es =1 ; + }else if (cs->word_len <=16 ) { + width =DMA_SLAVE_BUSWIDTH_2_BYTES ; + es =2 ; + }else { + width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + es =4 ; + } + +memset (&cfg,0 ,sizeof (cfg)); + cfg.src_addr = cs->phys +OMAP2_MCSPI_RX0 ; + cfg.dst_addr = cs->phys +OMAP2_MCSPI_TX0 ; + cfg.src_addr_width = width; + cfg.dst_addr_width = width; + cfg.src_maxburst =1 ; + cfg.dst_maxburst =1 ; + +if (xfer->tx_buf && mcspi_dma->dma_tx) { +struct dma_async_tx_descriptor *tx; +struct scatterlist sg; + +dmaengine_slave_config (mcspi_dma->dma_tx, &cfg); + +sg_init_table (&sg,1 ); +sg_dma_address (&sg) = xfer->tx_dma; +sg_dma_len (&sg) = xfer->len; + + tx =dmaengine_prep_slave_sg (mcspi_dma->dma_tx, &sg,1 , +DMA_MEM_TO_DEV ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (tx) { + tx->callback = omap2_mcspi_tx_callback; + tx->callback_param = spi; +dmaengine_submit (tx); + }else { +/* FIXME: fall back to PIO? */ + } + } + +if (xfer->rx_buf && mcspi_dma->dma_rx) { +struct dma_async_tx_descriptor *tx; +struct scatterlist sg; +size_t len = xfer->len - es; + +dmaengine_slave_config (mcspi_dma->dma_rx, &cfg); + +if (l &OMAP2_MCSPI_CHCONF_TURBO ) + len -= es; + +sg_init_table (&sg,1 ); +sg_dma_address (&sg) = xfer->rx_dma; +sg_dma_len (&sg) = len; + + tx =dmaengine_prep_slave_sg (mcspi_dma->dma_rx, &sg,1 , +DMA_DEV_TO_MEM ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (tx) { + tx->callback = omap2_mcspi_rx_callback; + tx->callback_param = spi; +dmaengine_submit (tx); + }else { +/* FIXME: fall back to PIO? */ + } + } + count = xfer->len; c = count; word_len = cs->word_len;
@@ -332,7 +429,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) element_count = count >>2 ; } -if (tx !=NULL ) { +if (tx !=NULL && mcspi_dma->dma_tx_channel !=-1 ) { omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel, data_type, element_count, 1, OMAP_DMA_SYNC_ELEMENT,
@@ -347,7 +444,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) xfer->tx_dma, 0, 0); } -if (rx !=NULL ) { +if (rx !=NULL && mcspi_dma->dma_rx_channel !=-1 ) { elements = element_count -1 ;if (l &OMAP2_MCSPI_CHCONF_TURBO ) elements--;
@@ -367,12 +464,18 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) }if (tx !=NULL ) { -omap_start_dma (mcspi_dma->dma_tx_channel); +if (mcspi_dma->dma_tx) +dma_async_issue_pending (mcspi_dma->dma_tx); +else +omap_start_dma (mcspi_dma->dma_tx_channel);omap2_mcspi_set_dma_req (spi,0 ,1 ); }if (rx !=NULL ) { -omap_start_dma (mcspi_dma->dma_rx_channel); +if (mcspi_dma->dma_rx) +dma_async_issue_pending (mcspi_dma->dma_rx); +else +omap_start_dma (mcspi_dma->dma_rx_channel);omap2_mcspi_set_dma_req (spi,1 ,1 ); }
@@ -396,7 +499,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)dma_unmap_single (&spi->dev, xfer->rx_dma, count,DMA_FROM_DEVICE );omap2_mcspi_set_enable (spi,0 ); + elements = element_count -1 ; +if (l &OMAP2_MCSPI_CHCONF_TURBO ) { + elements--;if (likely (mcspi_read_cs_reg (spi,OMAP2_MCSPI_CHSTAT0 ) &OMAP2_MCSPI_CHSTAT_RXS )) {
@@ -715,50 +821,58 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,static void omap2_mcspi_dma_rx_callback (int lch,u16 ch_status,void *data) { -struct spi_device *spi = data; -struct omap2_mcspi *mcspi; -struct omap2_mcspi_dma *mcspi_dma; - - mcspi =spi_master_get_devdata (spi->master); - mcspi_dma = &(mcspi->dma_channels[spi->chip_select]); - -complete (&mcspi_dma->dma_rx_completion); - -/* We must disable the DMA RX request */ -omap2_mcspi_set_dma_req (spi,1 ,0 ); +omap2_mcspi_rx_callback (data); }static void omap2_mcspi_dma_tx_callback (int lch,u16 ch_status,void *data) { -struct spi_device *spi = data; -struct omap2_mcspi *mcspi; -struct omap2_mcspi_dma *mcspi_dma; - - mcspi =spi_master_get_devdata (spi->master); - mcspi_dma = &(mcspi->dma_channels[spi->chip_select]); - -complete (&mcspi_dma->dma_tx_completion); - -/* We must disable the DMA TX request */ -omap2_mcspi_set_dma_req (spi,0 ,0 ); +omap2_mcspi_tx_callback (data); } +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); +static int omap2_mcspi_request_dma (struct spi_device *spi) {struct spi_master *master = spi->master;struct omap2_mcspi *mcspi;struct omap2_mcspi_dma *mcspi_dma; +dma_cap_mask_t mask; +unsigned sig; mcspi =spi_master_get_devdata (master); mcspi_dma = mcspi->dma_channels + spi->chip_select; +init_completion (&mcspi_dma->dma_rx_completion); +init_completion (&mcspi_dma->dma_tx_completion); + +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); +#ifdef USE_DMA_ENGINE_RX + sig = mcspi_dma->dma_rx_sync_dev; + mcspi_dma->dma_rx =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!mcspi_dma->dma_rx) { +dev_err (&spi->dev,"no RX DMA engine channel for McSPI\n" ); +return -EAGAIN ; + } +#else if (omap_request_dma (mcspi_dma->dma_rx_sync_dev,"McSPI RX" , omap2_mcspi_dma_rx_callback, spi, &mcspi_dma->dma_rx_channel)) {dev_err (&spi->dev,"no RX DMA channel for McSPI\n" );return -EAGAIN ; } +#endif +#ifdef USE_DMA_ENGINE_TX + sig = mcspi_dma->dma_tx_sync_dev; + mcspi_dma->dma_tx =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!mcspi_dma->dma_tx) { +dev_err (&spi->dev,"no TX DMA engine channel for McSPI\n" ); +dma_release_channel (mcspi_dma->dma_rx); + mcspi_dma->dma_rx =NULL ; +return -EAGAIN ; + } +#else if (omap_request_dma (mcspi_dma->dma_tx_sync_dev,"McSPI TX" , omap2_mcspi_dma_tx_callback, spi, &mcspi_dma->dma_tx_channel)) {
@@ -767,9 +881,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)dev_err (&spi->dev,"no TX DMA channel for McSPI\n" ); return -EAGAIN; } - -init_completion (&mcspi_dma->dma_rx_completion); -init_completion (&mcspi_dma->dma_tx_completion); +#endif return 0 ; }
@@ -803,8 +915,8 @@ static int omap2_mcspi_setup(struct spi_device *spi) &omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs); } -if (mcspi_dma->dma_rx_channel ==-1 - || mcspi_dma->dma_tx_channel ==-1 ) { +if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel ==-1 ) || + (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel ==-1 )) { ret =omap2_mcspi_request_dma (spi);if (ret <0 )return ret;
@@ -839,6 +951,14 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)if (spi->chip_select < spi->master->num_chipselect) { mcspi_dma = &mcspi->dma_channels[spi->chip_select]; +if (mcspi_dma->dma_rx) { +dma_release_channel (mcspi_dma->dma_rx); + mcspi_dma->dma_rx =NULL ; + } +if (mcspi_dma->dma_tx) { +dma_release_channel (mcspi_dma->dma_tx); + mcspi_dma->dma_tx =NULL ; + }if (mcspi_dma->dma_rx_channel !=-1 ) {omap_free_dma (mcspi_dma->dma_rx_channel); mcspi_dma->dma_rx_channel =-1 ;
Signature · 1 line
1.7.4.4
PATCH 10/12 spi: omap2-mcspi: add DMA engine support
Quoted 10 lines · Russell King
Add DMA engine support to the OMAP SPI driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API for the transmit and receive sides.
Tested-by Shubhrajyoti <[email protected]>Signed-off-by Russell King <[email protected]>--- drivers/spi/spi-omap2-mcspi.c | 184 ++++++++++++++++++++++++++++++++++------- 1 files changed, 152 insertions(+), 32 deletions(-)
This patch and the next one appear to be part of a larger series. Feel free to take them through whatever tree you need to.
g.
Quoted 320 lines
drivers/spi/spi-omap2-mcspi.c +151
-31@@ -20,6 +20,8 @@* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ +#define USE_DMA_ENGINE_RX +#define USE_DMA_ENGINE_TX #include <linux/kernel.h> #include <linux/init.h> @@ -28,6 +30,7 @@#include <linux/device.h> #include <linux/delay.h> #include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/platform_device.h> #include <linux/err.h> #include <linux/clk.h> @@ -95,6 +98,8 @@/* We have 2 DMA channels per CS, one for RX and one for TX */ struct omap2_mcspi_dma { +struct dma_chan *dma_tx; +struct dma_chan *dma_rx;int dma_tx_channel;int dma_rx_channel;@@ -290,6 +295,30 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)return 0 ; } +static void omap2_mcspi_rx_callback (void *data) +{ +struct spi_device *spi = data; +struct omap2_mcspi *mcspi =spi_master_get_devdata (spi->master); +struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; + +complete (&mcspi_dma->dma_rx_completion); + +/* We must disable the DMA RX request */ +omap2_mcspi_set_dma_req (spi,1 ,0 ); +} + +static void omap2_mcspi_tx_callback (void *data) +{ +struct spi_device *spi = data; +struct omap2_mcspi *mcspi =spi_master_get_devdata (spi->master); +struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; + +complete (&mcspi_dma->dma_tx_completion); + +/* We must disable the DMA TX request */ +omap2_mcspi_set_dma_req (spi,0 ,0 ); +} +static unsigned omap2_mcspi_txrx_dma (struct spi_device *spi,struct spi_transfer *xfer) {@@ -304,6 +333,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)u8 * rx;const u8 * tx;void __iomem *chstat_reg; +struct dma_slave_config cfg; +enum dma_slave_buswidth width; +unsigned es; mcspi =spi_master_get_devdata (spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select];@@ -311,6 +343,71 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) chstat_reg = cs->base +OMAP2_MCSPI_CHSTAT0 ; +if (cs->word_len <=8 ) { + width =DMA_SLAVE_BUSWIDTH_1_BYTE ; + es =1 ; + }else if (cs->word_len <=16 ) { + width =DMA_SLAVE_BUSWIDTH_2_BYTES ; + es =2 ; + }else { + width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + es =4 ; + } + +memset (&cfg,0 ,sizeof (cfg)); + cfg.src_addr = cs->phys +OMAP2_MCSPI_RX0 ; + cfg.dst_addr = cs->phys +OMAP2_MCSPI_TX0 ; + cfg.src_addr_width = width; + cfg.dst_addr_width = width; + cfg.src_maxburst =1 ; + cfg.dst_maxburst =1 ; + +if (xfer->tx_buf && mcspi_dma->dma_tx) { +struct dma_async_tx_descriptor *tx; +struct scatterlist sg; + +dmaengine_slave_config (mcspi_dma->dma_tx, &cfg); + +sg_init_table (&sg,1 ); +sg_dma_address (&sg) = xfer->tx_dma; +sg_dma_len (&sg) = xfer->len; + + tx =dmaengine_prep_slave_sg (mcspi_dma->dma_tx, &sg,1 , +DMA_MEM_TO_DEV ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (tx) { + tx->callback = omap2_mcspi_tx_callback; + tx->callback_param = spi; +dmaengine_submit (tx); + }else { +/* FIXME: fall back to PIO? */ + } + } + +if (xfer->rx_buf && mcspi_dma->dma_rx) { +struct dma_async_tx_descriptor *tx; +struct scatterlist sg; +size_t len = xfer->len - es; + +dmaengine_slave_config (mcspi_dma->dma_rx, &cfg); + +if (l &OMAP2_MCSPI_CHCONF_TURBO ) + len -= es; + +sg_init_table (&sg,1 ); +sg_dma_address (&sg) = xfer->rx_dma; +sg_dma_len (&sg) = len; + + tx =dmaengine_prep_slave_sg (mcspi_dma->dma_rx, &sg,1 , +DMA_DEV_TO_MEM ,DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (tx) { + tx->callback = omap2_mcspi_rx_callback; + tx->callback_param = spi; +dmaengine_submit (tx); + }else { +/* FIXME: fall back to PIO? */ + } + } + count = xfer->len; c = count; word_len = cs->word_len;@@ -332,7 +429,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) element_count = count >>2 ; } -if (tx !=NULL ) { +if (tx !=NULL && mcspi_dma->dma_tx_channel !=-1 ) { omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel, data_type, element_count, 1, OMAP_DMA_SYNC_ELEMENT,@@ -347,7 +444,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) xfer->tx_dma, 0, 0); } -if (rx !=NULL ) { +if (rx !=NULL && mcspi_dma->dma_rx_channel !=-1 ) { elements = element_count -1 ;if (l &OMAP2_MCSPI_CHCONF_TURBO ) elements--;@@ -367,12 +464,18 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) }if (tx !=NULL ) { -omap_start_dma (mcspi_dma->dma_tx_channel); +if (mcspi_dma->dma_tx) +dma_async_issue_pending (mcspi_dma->dma_tx); +else +omap_start_dma (mcspi_dma->dma_tx_channel);omap2_mcspi_set_dma_req (spi,0 ,1 ); }if (rx !=NULL ) { -omap_start_dma (mcspi_dma->dma_rx_channel); +if (mcspi_dma->dma_rx) +dma_async_issue_pending (mcspi_dma->dma_rx); +else +omap_start_dma (mcspi_dma->dma_rx_channel);omap2_mcspi_set_dma_req (spi,1 ,1 ); }@@ -396,7 +499,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)dma_unmap_single (&spi->dev, xfer->rx_dma, count,DMA_FROM_DEVICE );omap2_mcspi_set_enable (spi,0 ); + elements = element_count -1 ; +if (l &OMAP2_MCSPI_CHCONF_TURBO ) { + elements--;if (likely (mcspi_read_cs_reg (spi,OMAP2_MCSPI_CHSTAT0 ) &OMAP2_MCSPI_CHSTAT_RXS )) {@@ -715,50 +821,58 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,static void omap2_mcspi_dma_rx_callback (int lch,u16 ch_status,void *data) { -struct spi_device *spi = data; -struct omap2_mcspi *mcspi; -struct omap2_mcspi_dma *mcspi_dma; - - mcspi =spi_master_get_devdata (spi->master); - mcspi_dma = &(mcspi->dma_channels[spi->chip_select]); - -complete (&mcspi_dma->dma_rx_completion); - -/* We must disable the DMA RX request */ -omap2_mcspi_set_dma_req (spi,1 ,0 ); +omap2_mcspi_rx_callback (data); }static void omap2_mcspi_dma_tx_callback (int lch,u16 ch_status,void *data) { -struct spi_device *spi = data; -struct omap2_mcspi *mcspi; -struct omap2_mcspi_dma *mcspi_dma; - - mcspi =spi_master_get_devdata (spi->master); - mcspi_dma = &(mcspi->dma_channels[spi->chip_select]); - -complete (&mcspi_dma->dma_tx_completion); - -/* We must disable the DMA TX request */ -omap2_mcspi_set_dma_req (spi,0 ,0 ); +omap2_mcspi_tx_callback (data); } +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); +static int omap2_mcspi_request_dma (struct spi_device *spi) {struct spi_master *master = spi->master;struct omap2_mcspi *mcspi;struct omap2_mcspi_dma *mcspi_dma; +dma_cap_mask_t mask; +unsigned sig; mcspi =spi_master_get_devdata (master); mcspi_dma = mcspi->dma_channels + spi->chip_select; +init_completion (&mcspi_dma->dma_rx_completion); +init_completion (&mcspi_dma->dma_tx_completion); + +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); +#ifdef USE_DMA_ENGINE_RX + sig = mcspi_dma->dma_rx_sync_dev; + mcspi_dma->dma_rx =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!mcspi_dma->dma_rx) { +dev_err (&spi->dev,"no RX DMA engine channel for McSPI\n" ); +return -EAGAIN ; + } +#else if (omap_request_dma (mcspi_dma->dma_rx_sync_dev,"McSPI RX" , omap2_mcspi_dma_rx_callback, spi, &mcspi_dma->dma_rx_channel)) {dev_err (&spi->dev,"no RX DMA channel for McSPI\n" );return -EAGAIN ; } +#endif +#ifdef USE_DMA_ENGINE_TX + sig = mcspi_dma->dma_tx_sync_dev; + mcspi_dma->dma_tx =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!mcspi_dma->dma_tx) { +dev_err (&spi->dev,"no TX DMA engine channel for McSPI\n" ); +dma_release_channel (mcspi_dma->dma_rx); + mcspi_dma->dma_rx =NULL ; +return -EAGAIN ; + } +#else if (omap_request_dma (mcspi_dma->dma_tx_sync_dev,"McSPI TX" , omap2_mcspi_dma_tx_callback, spi, &mcspi_dma->dma_tx_channel)) {@@ -767,9 +881,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)dev_err (&spi->dev,"no TX DMA channel for McSPI\n" ); return -EAGAIN; } - -init_completion (&mcspi_dma->dma_rx_completion); -init_completion (&mcspi_dma->dma_tx_completion); +#endif return 0 ; }@@ -803,8 +915,8 @@ static int omap2_mcspi_setup(struct spi_device *spi) &omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs); } -if (mcspi_dma->dma_rx_channel ==-1 - || mcspi_dma->dma_tx_channel ==-1 ) { +if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel ==-1 ) || + (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel ==-1 )) { ret =omap2_mcspi_request_dma (spi);if (ret <0 )return ret;@@ -839,6 +951,14 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)if (spi->chip_select < spi->master->num_chipselect) { mcspi_dma = &mcspi->dma_channels[spi->chip_select]; +if (mcspi_dma->dma_rx) { +dma_release_channel (mcspi_dma->dma_rx); + mcspi_dma->dma_rx =NULL ; + } +if (mcspi_dma->dma_tx) { +dma_release_channel (mcspi_dma->dma_tx); + mcspi_dma->dma_tx =NULL ; + }if (mcspi_dma->dma_rx_channel !=-1 ) {omap_free_dma (mcspi_dma->dma_rx_channel); mcspi_dma->dma_rx_channel =-1 ;Signature · 7 lines
1.7.4.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel at lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Signature · 2 lines
Grant Likely, B.Sc, P.Eng. Secret Lab Technologies, Ltd.
PATCH 11/12 spi: omap2-mcspi: remove private DMA API implementation
In reply to Russell King - ARM LinuxRemove the private DMA API implementation from spi-omap2-mcspi.c, making it use entirely the DMA engine API.
--- drivers/spi/spi-omap2-mcspi.c | 104 ++--------------------------------------- 1 files changed, 5 insertions(+), 99 deletions(-)
drivers/spi/spi-omap2-mcspi.c +5 -99
@@ -20,8 +20,6 @@* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#define USE_DMA_ENGINE_RX -#define USE_DMA_ENGINE_TX #include <linux/kernel.h> #include <linux/init.h>
@@ -42,7 +40,6 @@#include <linux/spi/spi.h> -#include <plat/dma.h> #include <plat/clock.h> #include <plat/mcspi.h>
@@ -100,8 +97,6 @@struct omap2_mcspi_dma {struct dma_chan *dma_tx;struct dma_chan *dma_rx; -int dma_tx_channel; -int dma_rx_channel;int dma_tx_sync_dev;int dma_rx_sync_dev;
@@ -325,9 +320,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)struct omap2_mcspi *mcspi;struct omap2_mcspi_cs *cs = spi->controller_state;struct omap2_mcspi_dma *mcspi_dma; -unsigned int count, c; -unsigned long base, tx_reg, rx_reg; -int word_len, data_type, element_count; +unsigned int count; +int word_len, element_count;int elements =0 ;u32 l;u8 * rx;
@@ -409,73 +403,26 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) } count = xfer->len; - c = count; word_len = cs->word_len; - base = cs->phys; - tx_reg = base +OMAP2_MCSPI_TX0 ; - rx_reg = base +OMAP2_MCSPI_RX0 ; rx = xfer->rx_buf; tx = xfer->tx_buf;if (word_len <=8 ) { - data_type =OMAP_DMA_DATA_TYPE_S8 ; element_count = count; }else if (word_len <=16 ) { - data_type =OMAP_DMA_DATA_TYPE_S16 ; element_count = count >>1 ; }else /* word_len <= 32 */ { - data_type =OMAP_DMA_DATA_TYPE_S32 ; element_count = count >>2 ; } -if (tx !=NULL && mcspi_dma->dma_tx_channel !=-1 ) { -omap_set_dma_transfer_params (mcspi_dma->dma_tx_channel, - data_type, element_count,1 , -OMAP_DMA_SYNC_ELEMENT , - mcspi_dma->dma_tx_sync_dev,0 ); - -omap_set_dma_dest_params (mcspi_dma->dma_tx_channel,0 , -OMAP_DMA_AMODE_CONSTANT , - tx_reg,0 ,0 ); - -omap_set_dma_src_params (mcspi_dma->dma_tx_channel,0 , -OMAP_DMA_AMODE_POST_INC , - xfer->tx_dma,0 ,0 ); - } - -if (rx !=NULL && mcspi_dma->dma_rx_channel !=-1 ) { - elements = element_count -1 ; -if (l &OMAP2_MCSPI_CHCONF_TURBO ) - elements--; - -omap_set_dma_transfer_params (mcspi_dma->dma_rx_channel, - data_type, elements,1 , -OMAP_DMA_SYNC_ELEMENT , - mcspi_dma->dma_rx_sync_dev,1 ); - -omap_set_dma_src_params (mcspi_dma->dma_rx_channel,0 , -OMAP_DMA_AMODE_CONSTANT , - rx_reg,0 ,0 ); - -omap_set_dma_dest_params (mcspi_dma->dma_rx_channel,0 , -OMAP_DMA_AMODE_POST_INC , - xfer->rx_dma,0 ,0 ); - } -if (tx !=NULL ) { -if (mcspi_dma->dma_tx) -dma_async_issue_pending (mcspi_dma->dma_tx); -else -omap_start_dma (mcspi_dma->dma_tx_channel); +dma_async_issue_pending (mcspi_dma->dma_tx);omap2_mcspi_set_dma_req (spi,0 ,1 ); }if (rx !=NULL ) { -if (mcspi_dma->dma_rx) -dma_async_issue_pending (mcspi_dma->dma_rx); -else -omap_start_dma (mcspi_dma->dma_rx_channel); +dma_async_issue_pending (mcspi_dma->dma_rx);omap2_mcspi_set_dma_req (spi,1 ,1 ); }
@@ -819,16 +766,6 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,return 0 ; } -static void omap2_mcspi_dma_rx_callback (int lch,u16 ch_status,void *data) -{ -omap2_mcspi_rx_callback (data); -} - -static void omap2_mcspi_dma_tx_callback (int lch,u16 ch_status,void *data) -{ -omap2_mcspi_tx_callback (data); -} -extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param);static int omap2_mcspi_request_dma (struct spi_device *spi)
@@ -847,23 +784,13 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)dma_cap_zero (mask);dma_cap_set (DMA_SLAVE , mask); -#ifdef USE_DMA_ENGINE_RX sig = mcspi_dma->dma_rx_sync_dev; mcspi_dma->dma_rx =dma_request_channel (mask, omap_dma_filter_fn, &sig);if (!mcspi_dma->dma_rx) {dev_err (&spi->dev,"no RX DMA engine channel for McSPI\n" );return -EAGAIN ; } -#else -if (omap_request_dma (mcspi_dma->dma_rx_sync_dev,"McSPI RX" , - omap2_mcspi_dma_rx_callback, spi, - &mcspi_dma->dma_rx_channel)) { -dev_err (&spi->dev,"no RX DMA channel for McSPI\n" ); -return -EAGAIN ; - } -#endif -#ifdef USE_DMA_ENGINE_TX sig = mcspi_dma->dma_tx_sync_dev; mcspi_dma->dma_tx =dma_request_channel (mask, omap_dma_filter_fn, &sig);if (!mcspi_dma->dma_tx) {
@@ -872,16 +799,6 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) mcspi_dma->dma_rx =NULL ;return -EAGAIN ; } -#else -if (omap_request_dma (mcspi_dma->dma_tx_sync_dev,"McSPI TX" , - omap2_mcspi_dma_tx_callback, spi, - &mcspi_dma->dma_tx_channel)) { -omap_free_dma (mcspi_dma->dma_rx_channel); - mcspi_dma->dma_rx_channel =-1 ; -dev_err (&spi->dev,"no TX DMA channel for McSPI\n" ); -return -EAGAIN ; - } -#endif return 0 ; }
@@ -915,8 +832,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) &omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs); } -if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel ==-1 ) || - (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel ==-1 )) { +if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) { ret =omap2_mcspi_request_dma (spi);if (ret <0 )return ret;
@@ -959,14 +875,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)dma_release_channel (mcspi_dma->dma_tx); mcspi_dma->dma_tx =NULL ; } -if (mcspi_dma->dma_rx_channel !=-1 ) { -omap_free_dma (mcspi_dma->dma_rx_channel); - mcspi_dma->dma_rx_channel =-1 ; - } -if (mcspi_dma->dma_tx_channel !=-1 ) { -omap_free_dma (mcspi_dma->dma_tx_channel); - mcspi_dma->dma_tx_channel =-1 ; - } } }
@@ -1326,7 +1234,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)break ; } - mcspi->dma_channels[i].dma_rx_channel =-1 ; mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;sprintf (dma_ch_name,"tx%d" , i); dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
@@ -1337,7 +1244,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)break ; } - mcspi->dma_channels[i].dma_tx_channel =-1 ; mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; }
Signature · 1 line
1.7.4.4
PATCH 12/12 Add removal of old OMAP private DMA implementation to feature removal
In reply to Russell King - ARM Linux--- Documentation/feature-removal-schedule.txt | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
Documentation/feature-removal-schedule.txt +11 -0
@@ -539,3 +539,14 @@ When: 3.6 Why: setitimer is not returning -EFAULT if user pointer is NULL. This violates the spec. Who: Sasikantha Babu <[email protected]> + +---------------------------- + +What: OMAP private DMA implementation +When: 2013 +Why: We have a DMA engine implementation; all users should be updated + to use this rather than persisting with the old APIs. The old APIs + block merging the old DMA engine implementation into the DMA + engine driver. +Who: Russell King <[email protected]>, + Santosh Shilimkar <[email protected]>
Signature · 1 line
1.7.4.4
Tony Lindgren
maintainerPATCH 12/12 Add removal of old OMAP private DMA implementation to feature removal
Quoted 1 line · Russell King
Signed-off-by Russell King <[email protected]>
Quoted 30 lines
--- Documentation/feature-removal-schedule.txt | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)Documentation/feature-removal-schedule.txt +11
-0@@ -539,3 +539,14 @@ When: 3.6 Why: setitimer is not returning -EFAULT if user pointer is NULL. This violates the spec. Who: Sasikantha Babu <[email protected]> + +---------------------------- + +What: OMAP private DMA implementation +When: 2013 +Why: We have a DMA engine implementation; all users should be updated + to use this rather than persisting with the old APIs. The old APIs + block merging the old DMA engine implementation into the DMA + engine driver. +Who: Russell King <[email protected]>, + Santosh Shilimkar <[email protected]>Signature · 6 lines
1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 12/12 Add removal of old OMAP private DMA implementation to feature removal
In reply to Russell KingQuoted 4 lines · Russell King
Signed-off-by Russell King <[email protected]>---
?Documentation/feature-removal-schedule.txt | ? 11 +++++++++++ ?1 files changed, 11 insertions(+), 0 deletions(-)
Your effort on this is much appreciated.
Thanks,
Linus Walleij
cover OMAP DMA engine conversion
In reply to Russell King - ARM LinuxHere's another patch - for the OMAP NAND driver.
One thing this doesn't do is configure up the source/destination bursts, which the old code did:
omap_set_dma_dest_burst_mode(info->dma_ch,
OMAP_DMA_DATA_BURST_16);
omap_set_dma_src_burst_mode(info->dma_ch,
OMAP_DMA_DATA_BURST_16);In dma-engine speak, I'm using "burst" for the number of elements to transfer for each frame, with frame sync in place (in other words, the number of transfers to occur for every assertion of the DMA request.) That's how burst is defined on other DMA hardware, so I'm not entirely sure at the moment how critical (or what) the above bursts are doing, whether they're configuring the memory side of the transfer or not. I'll take a deeper look into that this evening, but in the mean time, what's below should be a direct conversion.
MTD does have this weirdness that it uses vmalloc regions and passes addresses in vmalloc regions into drivers - I've left that hack in but it is _highly_ undefined whether the DMA activity would be visible via the vmalloc mapping as things currently stand. (You're probably going to be okay with non-aliasing VIPT caches, but VIVT and aliasing VIPT caches are potential random data corruption candidates.) That's a short-coming across many MTD drivers, one which needs sorting out across the board.
drivers/mtd/nand/omap2.c | 93 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 92 insertions(+), 1 deletions(-)
drivers/mtd/nand/omap2.c +92 -1
@@ -9,6 +9,7 @@*/ #include <linux/platform_device.h> +#include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/module.h>
@@ -119,6 +120,7 @@ struct omap_nand_info {int gpmc_cs;unsigned long phys_base;struct completion comp; +struct dma_chan *dma;int dma_ch;int gpmc_irq;enum {
@@ -336,6 +338,10 @@ static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {complete ((struct completion *) data); } +static void omap_nand_dma_callback (void *data) +{ +complete ((struct completion *) data); +}/* * omap_nand_dma_transfer: configer and start dma transfer
@@ -373,6 +379,56 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, addr =page_address (p1) + ((size_t )addr & ~PAGE_MASK ); } +if (info->dma) { +struct dma_async_tx_descriptor *tx; +struct scatterlist sg; +unsigned n; + +sg_init_one (&sg, addr, len); + n =dma_map_sg (info->dma->device->dev, &sg,1 , dir); +if (n ==0 ) { +dev_err (&info->pdev->dev, +"Couldn't DMA map a %d byte buffer\n" , len); + goto out_copy; + } + + tx =dmaengine_prep_slave_sg (info->dma, &sg, n, + is_write ?DMA_MEM_TO_DEV :DMA_DEV_TO_MEM , +DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (!tx) { +dma_unmap_sg (info->dma->device->dev, &sg,1 , dir); + goto out_copy; + } + tx->callback = omap_nand_dma_callback; + tx->callback_param = &info->comp; +dmaengine_submit (tx); + +/* configure and start prefetch transfer */ + ret =gpmc_prefetch_enable (info->gpmc_cs, +PREFETCH_FIFOTHRESHOLD_MAX ,0x1 , len, is_write); +if (ret) { +/* PFPW engine is busy, use cpu copy method */ +dma_unmap_sg (info->dma->device->dev, &sg,1 , dir); + goto out_copy; + } + +init_completion (&info->comp); +dma_async_issue_pending (info->dma); + +/* setup and start DMA using dma_addr */ +wait_for_completion (&info->comp); + tim =0 ; + limit = (loops_per_jiffy *msecs_to_jiffies (OMAP_NAND_TIMEOUT_MS )); +while (gpmc_read_status (GPMC_PREFETCH_COUNT ) && (tim++ < limit)) +cpu_relax (); + +/* disable and stop the PFPW engine */ +gpmc_prefetch_reset (info->gpmc_cs); + +dma_unmap_sg (info->dma->device->dev, &sg,1 , dir); +return 0 ; + } + dma_addr =dma_map_single (&info->pdev->dev, addr, len, dir);if (dma_mapping_error (&info->pdev->dev, dma_addr)) { dev_err(&info->pdev->dev,
@@ -405,7 +461,6 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, goto out_copy;init_completion (&info->comp); -omap_start_dma (info->dma_ch);/* setup and start DMA using dma_addr */
@@ -925,12 +980,16 @@ static int omap_dev_ready(struct mtd_info *mtd)return 1 ; } +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); +static int __devinit omap_nand_probe (struct platform_device *pdev) {struct omap_nand_info *info;struct omap_nand_platform_data *pdata;int err;int i, offset; +dma_cap_mask_t mask; +unsigned sig; pdata = pdev->dev.platform_data;if (pdata ==NULL ) {
@@ -1011,6 +1070,33 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)break ;case NAND_OMAP_PREFETCH_DMA : +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); + sig =OMAP24XX_DMA_GPMC ; + info->dma =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!info->dma) { +dev_warn (&pdev->dev,"DMA engine request failed\n" ); + }else { +struct dma_slave_config cfg; +int rc; + +memset (&cfg,0 ,sizeof (cfg)); + cfg.src_addr = info->phys_base; + cfg.dst_addr = info->phys_base; + cfg.src_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.dst_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.src_maxburst =16 ; + cfg.dst_maxburst =16 ; + rc =dmaengine_slave_config (info->dma, &cfg); +if (rc) { +dev_err (&pdev->dev,"DMA engine slave config failed: %d\n" , + rc); + goto out_release_mem_region; + } + info->nand.read_buf = omap_read_buf_dma_pref; + info->nand.write_buf = omap_write_buf_dma_pref; +break ; + } err =omap_request_dma (OMAP24XX_DMA_GPMC ,"NAND" , omap_nand_dma_cb, &info->comp, &info->dma_ch);if (err <0 ) {
@@ -1110,6 +1196,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)return 0 ; out_release_mem_region: +if (info->dma) +dma_release_channel (info->dma);release_mem_region (info->phys_base,NAND_IO_SIZE ); out_free_info:kfree (info);
@@ -1127,6 +1215,9 @@ static int omap_nand_remove(struct platform_device *pdev)if (info->dma_ch !=-1 )omap_free_dma (info->dma_ch); +if (info->dma) +dma_release_channel (info->dma); +if (info->gpmc_irq)free_irq (info->gpmc_irq, info);
Tony Lindgren
maintainercover OMAP DMA engine conversion
Quoted 9 lines · Russell King - ARM Linux
Here's another patch - for the OMAP NAND driver.
One thing this doesn't do is configure up the source/destination bursts, which the old code did:
omap_set_dma_dest_burst_mode(info->dma_ch, OMAP_DMA_DATA_BURST_16); omap_set_dma_src_burst_mode(info->dma_ch, OMAP_DMA_DATA_BURST_16);
Grazvydas, care to give this patch a go?
Quoted 8 lines
In dma-engine speak, I'm using "burst" for the number of elements to transfer for each frame, with frame sync in place (in other words, the number of transfers to occur for every assertion of the DMA request.) That's how burst is defined on other DMA hardware, so I'm not entirely sure at the moment how critical (or what) the above bursts are doing, whether they're configuring the memory side of the transfer or not. I'll take a deeper look into that this evening, but in the mean time, what's below should be a direct conversion.
For omaps it enables multiple access.
Quoted 183 lines
MTD does have this weirdness that it uses vmalloc regions and passes addresses in vmalloc regions into drivers - I've left that hack in but it is _highly_ undefined whether the DMA activity would be visible via the vmalloc mapping as things currently stand. (You're probably going to be okay with non-aliasing VIPT caches, but VIVT and aliasing VIPT caches are potential random data corruption candidates.) That's a short-coming across many MTD drivers, one which needs sorting out across the board.
drivers/mtd/nand/omap2.c | 93 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 92 insertions(+), 1 deletions(-)drivers/mtd/nand/omap2.c +92
-2@@ -9,6 +9,7 @@*/ #include <linux/platform_device.h> +#include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/module.h> @@ -119,6 +120,7 @@ struct omap_nand_info {int gpmc_cs;unsigned long phys_base;struct completion comp; +struct dma_chan *dma;int dma_ch;int gpmc_irq;enum {@@ -336,6 +338,10 @@ static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {complete ((struct completion *) data); } +static void omap_nand_dma_callback (void *data) +{ +complete ((struct completion *) data); +}/* * omap_nand_dma_transfer: configer and start dma transfer @@ -373,6 +379,56 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, addr =page_address (p1) + ((size_t )addr & ~PAGE_MASK ); } +if (info->dma) { +struct dma_async_tx_descriptor *tx; +struct scatterlist sg; +unsigned n; + +sg_init_one (&sg, addr, len); + n =dma_map_sg (info->dma->device->dev, &sg,1 , dir); +if (n ==0 ) { +dev_err (&info->pdev->dev, +"Couldn't DMA map a %d byte buffer\n" , len); + goto out_copy; + } + + tx =dmaengine_prep_slave_sg (info->dma, &sg, n, + is_write ?DMA_MEM_TO_DEV :DMA_DEV_TO_MEM , +DMA_PREP_INTERRUPT |DMA_CTRL_ACK ); +if (!tx) { +dma_unmap_sg (info->dma->device->dev, &sg,1 , dir); + goto out_copy; + } + tx->callback = omap_nand_dma_callback; + tx->callback_param = &info->comp; +dmaengine_submit (tx); + +/* configure and start prefetch transfer */ + ret =gpmc_prefetch_enable (info->gpmc_cs, +PREFETCH_FIFOTHRESHOLD_MAX ,0x1 , len, is_write); +if (ret) { +/* PFPW engine is busy, use cpu copy method */ +dma_unmap_sg (info->dma->device->dev, &sg,1 , dir); + goto out_copy; + } + +init_completion (&info->comp); +dma_async_issue_pending (info->dma); + +/* setup and start DMA using dma_addr */ +wait_for_completion (&info->comp); + tim =0 ; + limit = (loops_per_jiffy *msecs_to_jiffies (OMAP_NAND_TIMEOUT_MS )); +while (gpmc_read_status (GPMC_PREFETCH_COUNT ) && (tim++ < limit)) +cpu_relax (); + +/* disable and stop the PFPW engine */ +gpmc_prefetch_reset (info->gpmc_cs); + +dma_unmap_sg (info->dma->device->dev, &sg,1 , dir); +return 0 ; + } + dma_addr =dma_map_single (&info->pdev->dev, addr, len, dir);if (dma_mapping_error (&info->pdev->dev, dma_addr)) { dev_err(&info->pdev->dev,@@ -405,7 +461,6 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, goto out_copy;init_completion (&info->comp); -omap_start_dma (info->dma_ch);/* setup and start DMA using dma_addr */ @@ -925,12 +980,16 @@ static int omap_dev_ready(struct mtd_info *mtd)return 1 ; } +extern bool omap_dma_filter_fn (struct dma_chan *chan,void *param); +static int __devinit omap_nand_probe (struct platform_device *pdev) {struct omap_nand_info *info;struct omap_nand_platform_data *pdata;int err;int i, offset; +dma_cap_mask_t mask; +unsigned sig; pdata = pdev->dev.platform_data;if (pdata ==NULL ) {@@ -1011,6 +1070,33 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)break ;case NAND_OMAP_PREFETCH_DMA : +dma_cap_zero (mask); +dma_cap_set (DMA_SLAVE , mask); + sig =OMAP24XX_DMA_GPMC ; + info->dma =dma_request_channel (mask, omap_dma_filter_fn, &sig); +if (!info->dma) { +dev_warn (&pdev->dev,"DMA engine request failed\n" ); + }else { +struct dma_slave_config cfg; +int rc; + +memset (&cfg,0 ,sizeof (cfg)); + cfg.src_addr = info->phys_base; + cfg.dst_addr = info->phys_base; + cfg.src_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.dst_addr_width =DMA_SLAVE_BUSWIDTH_4_BYTES ; + cfg.src_maxburst =16 ; + cfg.dst_maxburst =16 ; + rc =dmaengine_slave_config (info->dma, &cfg); +if (rc) { +dev_err (&pdev->dev,"DMA engine slave config failed: %d\n" , + rc); + goto out_release_mem_region; + } + info->nand.read_buf = omap_read_buf_dma_pref; + info->nand.write_buf = omap_write_buf_dma_pref; +break ; + } err =omap_request_dma (OMAP24XX_DMA_GPMC ,"NAND" , omap_nand_dma_cb, &info->comp, &info->dma_ch);if (err <0 ) {@@ -1110,6 +1196,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)return 0 ; out_release_mem_region: +if (info->dma) +dma_release_channel (info->dma);release_mem_region (info->phys_base,NAND_IO_SIZE ); out_free_info:kfree (info);@@ -1127,6 +1215,9 @@ static int omap_nand_remove(struct platform_device *pdev)if (info->dma_ch !=-1 )omap_free_dma (info->dma_ch); +if (info->dma) +dma_release_channel (info->dma); +if (info->gpmc_irq)free_irq (info->gpmc_irq, info); --To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
cover OMAP DMA engine conversion
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Russell King - ARM Linux
Here's another patch - for the OMAP NAND driver.
One thing this doesn't do is configure up the source/destination bursts, which the old code did:
Quoted 6 lines
Quoted 4 lines
? ? ? ? ? ? ? ? ? ? ? ?
omap_set_dma_dest_burst_mode(info->dma_ch, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_DMA_DATA_BURST_16); ? ? ? ? ? ? ? ? ? ? ? ?omap_set_dma_src_burst_mode(info->dma_ch, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_DMA_DATA_BURST_16);Grazvydas, care to give this patch a go?
for:
- SD card connected over transceiver to MMC2
- touchscreen connected over SPI
- NAND on GPMC in DMA mode
Seems to be working just as they did before, except that I'm not sure SPI was crossing PIO threshold.
Signature · 1 line
Gra?vydas
cover OMAP DMA engine conversion
Quoted 14 lines · Grazvydas Ignotas
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Russell King - ARM Linux
Here's another patch - for the OMAP NAND driver.
One thing this doesn't do is configure up the source/destination bursts, which the old code did:
Quoted 6 lines
Quoted 4 lines
? ? ? ? ? ? ? ? ? ? ? ?
omap_set_dma_dest_burst_mode(info->dma_ch, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_DMA_DATA_BURST_16); ? ? ? ? ? ? ? ? ? ? ? ?omap_set_dma_src_burst_mode(info->dma_ch, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_DMA_DATA_BURST_16);Grazvydas, care to give this patch a go?
Quoted 7 lines
Tested-by Grazvydas Ignotas <[email protected]>for:
- SD card connected over transceiver to MMC2
- touchscreen connected over SPI
- NAND on GPMC in DMA mode
Seems to be working just as they did before, except that I'm not sure SPI was crossing PIO threshold.
I think my testing on OMAP4430SDP with the SPI based ethernet should've caught anything untoward there.
For the MMC2, could you say whether this was the hsmmc driver or the older omap1/2 driver please?
Thanks.
cover OMAP DMA engine conversion
Quoted 23 lines · Russell King - ARM Linux
Quoted 14 lines · Grazvydas Ignotas
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Russell King - ARM Linux
Here's another patch - for the OMAP NAND driver.
One thing this doesn't do is configure up the source/destination bursts, which the old code did:
Quoted 6 lines
Quoted 4 lines
? ? ? ? ? ? ? ? ? ? ? ?
omap_set_dma_dest_burst_mode(info->dma_ch, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_DMA_DATA_BURST_16); ? ? ? ? ? ? ? ? ? ? ? ?omap_set_dma_src_burst_mode(info->dma_ch, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_DMA_DATA_BURST_16);Grazvydas, care to give this patch a go?
Quoted 7 lines
Tested-by Grazvydas Ignotas <[email protected]>for:
- SD card connected over transceiver to MMC2
- touchscreen connected over SPI
- NAND on GPMC in DMA mode
Seems to be working just as they did before, except that I'm not sure SPI was crossing PIO threshold.
Quoted 5 lines
I think my testing on OMAP4430SDP with the SPI based ethernet should've caught anything untoward there.
For the MMC2, could you say whether this was the hsmmc driver or the older omap1/2 driver please?
hsmmc running on OMAP3 pandora.
Signature · 1 line
Gra?vydas
cover OMAP DMA engine conversion
In reply to Russell King - ARM LinuxQuoted 6 lines · Russell King - ARM Linux
For the full text, please see
http://lists.arm.linux.org.uk/lurker/message/20120418.100954.7fa7acf8.en.html
This version contains updates for some of the comments received from the previous round, and adds the OMAP1/2 MMC and SPI drivers to the conversion.
Tested eMMC, SD on omap4 Blaze
Quoted 36 lines
I've also added a note to feature-removal noting that the existing APIs will be removed around 2013 - I'm planning January for that at the moment. ?Having drivers around which are unconverted blocks further work on the DMA engine conversion, so it's actually important that we get as many drivers converted as soon as possible.
Anything which isn't converted will probably have its DMA code removed, or if that results in the driver not being usable, the driver itself will be removed.
This series is still in RFC mode...
?Documentation/feature-removal-schedule.txt | ? 11 + ?arch/arm/mach-omap1/board-h2-mmc.c ? ? ? ? | ? ?1 - ?arch/arm/mach-omap1/board-h3-mmc.c ? ? ? ? | ? ?1 - ?arch/arm/mach-omap1/board-nokia770.c ? ? ? | ? ?1 - ?arch/arm/mach-omap2/board-n8x0.c ? ? ? ? ? | ? ?1 - ?arch/arm/mach-omap2/hsmmc.c ? ? ? ? ? ? ? ?| ? ?1 - ?arch/arm/plat-omap/dma.c ? ? ? ? ? ? ? ? ? | ? 14 + ?arch/arm/plat-omap/include/plat/mmc.h ? ? ?| ? ?2 - ?drivers/dma/Kconfig ? ? ? ? ? ? ? ? ? ? ? ?| ? 10 + ?drivers/dma/Makefile ? ? ? ? ? ? ? ? ? ? ? | ? ?2 + ?drivers/dma/omap-dma.c ? ? ? ? ? ? ? ? ? ? | ?521 ++++++++++++++++++++++++++++ ?drivers/dma/sa11x0-dma.c ? ? ? ? ? ? ? ? ? | ?249 ++++--------- ?drivers/dma/virt-dma.c ? ? ? ? ? ? ? ? ? ? | ? 99 ++++++ ?drivers/dma/virt-dma.h ? ? ? ? ? ? ? ? ? ? | ?138 ++++++++ ?drivers/mmc/host/omap.c ? ? ? ? ? ? ? ? ? ?| ?369 +++++++++----------- ?drivers/mmc/host/omap_hsmmc.c ? ? ? ? ? ? ?| ?206 ++++++------ ?drivers/spi/spi-omap2-mcspi.c ? ? ? ? ? ? ?| ?228 +++++++------?17 files changed, 1268 insertions(+), 586 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html
cover OMAP DMA engine conversion
In reply to Russell King - ARM LinuxQuoted 13 lines · Russell King - ARM Linux
For the full text, please see
http://lists.arm.linux.org.uk/lurker/message/20120418.100954.7fa7acf8.en.html
This version contains updates for some of the comments received from the previous round, and adds the OMAP1/2 MMC and SPI drivers to the conversion.
I've also added a note to feature-removal noting that the existing APIs will be removed around 2013 - I'm planning January for that at the moment. Having drivers around which are unconverted blocks further work on the DMA engine conversion, so it's actually important that we get as many drivers converted as soon as possible.
Quoted 5 lines
Anything which isn't converted will probably have its DMA code removed, or if that results in the driver not being usable, the driver itself will be removed.
This series is still in RFC mode...
Hi Russell,
What is the state of this series, would be good to have this merged in upcoming merge window.
Quoted 25 lines
Documentation/feature-removal-schedule.txt | 11 + arch/arm/mach-omap1/board-h2-mmc.c | 1 - arch/arm/mach-omap1/board-h3-mmc.c | 1 - arch/arm/mach-omap1/board-nokia770.c | 1 - arch/arm/mach-omap2/board-n8x0.c | 1 - arch/arm/mach-omap2/hsmmc.c | 1 - arch/arm/plat-omap/dma.c | 14 + arch/arm/plat-omap/include/plat/mmc.h | 2 - drivers/dma/Kconfig | 10 + drivers/dma/Makefile | 2 + drivers/dma/omap-dma.c | 521 ++++++++++++++++++++++++++++ drivers/dma/sa11x0-dma.c | 249 ++++--------- drivers/dma/virt-dma.c | 99 ++++++ drivers/dma/virt-dma.h | 138 ++++++++ drivers/mmc/host/omap.c | 369 +++++++++----------- drivers/mmc/host/omap_hsmmc.c | 206 ++++++------ drivers/spi/spi-omap2-mcspi.c | 228 +++++++------ 17 files changed, 1268 insertions(+), 586 deletions(-)_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Signature · 1 line
~Vinod
cover OMAP DMA engine conversion
Quoted 18 lines · Vinod Koul
Quoted 17 lines · Russell King - ARM Linux
For the full text, please see
http://lists.arm.linux.org.uk/lurker/message/20120418.100954.7fa7acf8.en.html
This version contains updates for some of the comments received from the previous round, and adds the OMAP1/2 MMC and SPI drivers to the conversion.
I've also added a note to feature-removal noting that the existing APIs will be removed around 2013 - I'm planning January for that at the moment. Having drivers around which are unconverted blocks further work on the DMA engine conversion, so it's actually important that we get as many drivers converted as soon as possible.
Anything which isn't converted will probably have its DMA code removed, or if that results in the driver not being usable, the driver itself will be removed.
Quoted 5 lines
Quoted 1 line
This series is still in RFC mode...
Hi Russell,
What is the state of this series, would be good to have this merged in upcoming merge window.
It's not ready for merging. While it allows some of the OMAP drivers to be converted, there's others which need changes to omap-dma.c.
So, I'm _not_ planning to see this in for the upcoming merge window.
cover OMAP DMA engine conversion
Quoted 22 lines · Russell King - ARM Linux
Quoted 21 lines · Vinod Koul
Quoted 13 lines · Russell King - ARM Linux
For the full text, please see
http://lists.arm.linux.org.uk/lurker/message/20120418.100954.7fa7acf8.en.html
This version contains updates for some of the comments received from the previous round, and adds the OMAP1/2 MMC and SPI drivers to the conversion.
I've also added a note to feature-removal noting that the existing APIs will be removed around 2013 - I'm planning January for that at the moment. Having drivers around which are unconverted blocks further work on the DMA engine conversion, so it's actually important that we get as many drivers converted as soon as possible.
Quoted 5 lines
Anything which isn't converted will probably have its DMA code removed, or if that results in the driver not being usable, the driver itself will be removed.
This series is still in RFC mode...
Hi Russell,
Quoted 7 lines
Quoted 2 lines
What is the state of this series, would be good to have this merged in upcoming merge window.
It's not ready for merging. While it allows some of the OMAP drivers to be converted, there's others which need changes to
omap-dma.c.So, I'm _not_ planning to see this in for the upcoming merge window.
Okay, Thanks for the update. I am waiting for the virtual channel support in this series.
Signature · 1 line
~Vinod
cover OMAP DMA engine conversion
Quoted 7 lines · Vinod Koul
Quoted 4 lines · Russell King - ARM Linux
It's not ready for merging. While it allows some of the OMAP drivers to be converted, there's others which need changes to
omap-dma.c.So, I'm _not_ planning to see this in for the upcoming merge window.
Okay, Thanks for the update. I am waiting for the virtual channel support in this series.
It's changed a little since the last post to allow it to support the tx_status semantics we discussed, and has some rudimentary and untested cyclic support.
As we're in the final week before the merge window, and this stuff has not had any time in linux-next, it's rather late to think about putting it in for v3.5.