From: Linus Walleij <linus.walleij@stericsson.com> To: akpm@linux-foundation.org, Russell King - ARM Linux <linux@arm.linux.org.uk>, Grant Likely <grant.likely@secretlab.ca>, Dan Williams <dan.j.williams@intel.com> Cc: linux-arm-kernel@lists.infradead.org, linux-mmc@vger.kernel.org, STEricsson_nomadik_linux@list.st.com, linux-kernel@vger.kernel.org, Linus Walleij <linus.walleij@stericsson.com> Subject: [PATCH 06/11] ARM: add generic PrimeCell interface to DMA40 v1 Date: Thu, 8 Apr 2010 01:13:05 +0200 [thread overview] Message-ID: <1270681985-6022-1-git-send-email-linus.walleij@stericsson.com> (raw) This extends the DMA engine driver for the DMA40 used in the U8500 platform with the generic PrimeCell interface, Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> --- This is new in this patch set and applies on top of the driver queued in Andrew Mortons tree. --- drivers/dma/ste_dma40.c | 128 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 125 insertions(+), 3 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index e4295a2..f86b99f 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/amba/dma.h> #include <plat/ste_dma40.h> @@ -205,6 +206,9 @@ struct d40_chan { struct d40_def_lcsp log_def; struct d40_lcla_elem lcla; struct d40_log_lli_full *lcpa; + /* AMBA extensions */ + dma_addr_t amba_addr; + enum dma_data_direction amba_direction; }; /** @@ -1830,7 +1834,10 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, lli_max = 1; if (direction == DMA_FROM_DEVICE) { - dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; + if (d40c->amba_addr) + dev_addr = d40c->amba_addr; + else + dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; total_size = d40_log_sg_to_dev(&d40c->lcla, sgl, sg_len, &d40d->lli_log, @@ -1842,7 +1849,10 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, dev_addr, lli_max, d40c->base->plat_data->llis_per_log); } else if (direction == DMA_TO_DEVICE) { - dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; + if (d40c->amba_addr) + dev_addr = d40c->amba_addr; + else + dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; total_size = d40_log_sg_to_dev(&d40c->lcla, sgl, sg_len, &d40d->lli_log, @@ -1973,14 +1983,29 @@ static enum dma_status d40_tx_status(struct dma_chan *chan, struct dma_tx_state *txstate) { struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); + void __iomem *active_reg; dma_cookie_t last_used; dma_cookie_t last_complete; + u32 status; int ret; last_complete = d40c->completed; last_used = chan->cookie; - ret = dma_async_is_complete(cookie, last_complete, last_used); + /* check for pause first */ + if (d40c->phy_chan->num % 2 == 0) + active_reg = d40c->base->virtbase + D40_DREG_ACTIVE; + else + active_reg = d40c->base->virtbase + D40_DREG_ACTIVO; + + status = (readl(active_reg) & + D40_CHAN_POS_MASK(d40c->phy_chan->num)) >> + D40_CHAN_POS(d40c->phy_chan->num); + + if (status == D40_DMA_SUSPENDED) + ret = DMA_PAUSED; + else + ret = dma_async_is_complete(cookie, last_complete, last_used); if (txstate) { txstate->last = last_complete; @@ -2026,6 +2051,103 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) return -ENXIO; } +/* PrimeCell DMA extension */ +void dma_set_ambaconfig(struct dma_chan *chan, + struct amba_dma_channel_config *config) +{ + struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); + struct stedma40_chan_cfg *cfg = &d40c->dma_cfg; + enum stedma40_periph_data_width addr_width; + int psize; + + switch (config->addr_width) { + case 1: + addr_width = STEDMA40_BYTE_WIDTH; + break; + case 2: + addr_width = STEDMA40_HALFWORD_WIDTH; + break; + case 4: + addr_width = STEDMA40_WORD_WIDTH; + break; + case 8: + addr_width = STEDMA40_DOUBLEWORD_WIDTH; + break; + default: + dev_err(d40c->base->dev, + "illegal peripheral address width requested (%d)\n", + config->addr_width); + return; + } + + if (config->maxburst >= 16) + psize = STEDMA40_PSIZE_LOG_16; + else if (config->maxburst >= 8) + psize = STEDMA40_PSIZE_LOG_8; + else if (config->maxburst >= 4) + psize = STEDMA40_PSIZE_LOG_4; + else + psize = STEDMA40_PSIZE_LOG_1; + + if (config->direction == DMA_FROM_DEVICE) { + dma_addr_t dev_addr_rx = + d40c->base->plat_data->dev_rx[cfg->src_dev_type]; + + if (dev_addr_rx) + dev_warn(d40c->base->dev, + "channel has a pre-wired RX address %08x " + "overriding with %08x\n", + dev_addr_rx, config->addr); + if (cfg->dir != STEDMA40_PERIPH_TO_MEM) + dev_warn(d40c->base->dev, + "channel was not configured for peripheral " + "to memory transfer (%d) overriding\n", + cfg->dir); + cfg->dir = STEDMA40_PERIPH_TO_MEM; + } else if (config->direction == DMA_TO_DEVICE) { + dma_addr_t dev_addr_tx = + d40c->base->plat_data->dev_tx[cfg->dst_dev_type]; + + if (dev_addr_tx) + dev_warn(d40c->base->dev, + "channel has a pre-wired TX address %08x " + "overriding with %08x\n", + dev_addr_tx, config->addr); + if (cfg->dir != STEDMA40_MEM_TO_PERIPH) + dev_warn(d40c->base->dev, + "channel was not configured for memory " + "to peripheral transfer (%d) overriding\n", + cfg->dir); + cfg->dir = STEDMA40_MEM_TO_PERIPH; + } else { + dev_err(d40c->base->dev, + "unrecognized channel direction %d\n", + config->direction); + return; + } + + /* Set up all the endpoint configs */ + cfg->src_info.data_width = addr_width; + cfg->src_info.psize = psize; + cfg->src_info.endianess = STEDMA40_LITTLE_ENDIAN; + cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; + cfg->dst_info.data_width = addr_width; + cfg->dst_info.psize = psize; + cfg->dst_info.endianess = STEDMA40_LITTLE_ENDIAN; + cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; + + /* These settings will take precedence later */ + d40c->amba_addr = config->addr; + d40c->amba_direction = config->direction; + dev_dbg(d40c->base->dev, + "configured channel %s for %s, data width %d, " + "maxburst %d bytes, LE, no flow control\n", + dma_chan_name(chan), + (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", + config->addr_width, + config->maxburst); +} + /* Initialization functions */ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, -- 1.6.3.3
WARNING: multiple messages have this Message-ID (diff)
From: linus.walleij@stericsson.com (Linus Walleij) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 06/11] ARM: add generic PrimeCell interface to DMA40 v1 Date: Thu, 8 Apr 2010 01:13:05 +0200 [thread overview] Message-ID: <1270681985-6022-1-git-send-email-linus.walleij@stericsson.com> (raw) This extends the DMA engine driver for the DMA40 used in the U8500 platform with the generic PrimeCell interface, Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> --- This is new in this patch set and applies on top of the driver queued in Andrew Mortons tree. --- drivers/dma/ste_dma40.c | 128 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 125 insertions(+), 3 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index e4295a2..f86b99f 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/amba/dma.h> #include <plat/ste_dma40.h> @@ -205,6 +206,9 @@ struct d40_chan { struct d40_def_lcsp log_def; struct d40_lcla_elem lcla; struct d40_log_lli_full *lcpa; + /* AMBA extensions */ + dma_addr_t amba_addr; + enum dma_data_direction amba_direction; }; /** @@ -1830,7 +1834,10 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, lli_max = 1; if (direction == DMA_FROM_DEVICE) { - dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; + if (d40c->amba_addr) + dev_addr = d40c->amba_addr; + else + dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; total_size = d40_log_sg_to_dev(&d40c->lcla, sgl, sg_len, &d40d->lli_log, @@ -1842,7 +1849,10 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, dev_addr, lli_max, d40c->base->plat_data->llis_per_log); } else if (direction == DMA_TO_DEVICE) { - dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; + if (d40c->amba_addr) + dev_addr = d40c->amba_addr; + else + dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; total_size = d40_log_sg_to_dev(&d40c->lcla, sgl, sg_len, &d40d->lli_log, @@ -1973,14 +1983,29 @@ static enum dma_status d40_tx_status(struct dma_chan *chan, struct dma_tx_state *txstate) { struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); + void __iomem *active_reg; dma_cookie_t last_used; dma_cookie_t last_complete; + u32 status; int ret; last_complete = d40c->completed; last_used = chan->cookie; - ret = dma_async_is_complete(cookie, last_complete, last_used); + /* check for pause first */ + if (d40c->phy_chan->num % 2 == 0) + active_reg = d40c->base->virtbase + D40_DREG_ACTIVE; + else + active_reg = d40c->base->virtbase + D40_DREG_ACTIVO; + + status = (readl(active_reg) & + D40_CHAN_POS_MASK(d40c->phy_chan->num)) >> + D40_CHAN_POS(d40c->phy_chan->num); + + if (status == D40_DMA_SUSPENDED) + ret = DMA_PAUSED; + else + ret = dma_async_is_complete(cookie, last_complete, last_used); if (txstate) { txstate->last = last_complete; @@ -2026,6 +2051,103 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) return -ENXIO; } +/* PrimeCell DMA extension */ +void dma_set_ambaconfig(struct dma_chan *chan, + struct amba_dma_channel_config *config) +{ + struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); + struct stedma40_chan_cfg *cfg = &d40c->dma_cfg; + enum stedma40_periph_data_width addr_width; + int psize; + + switch (config->addr_width) { + case 1: + addr_width = STEDMA40_BYTE_WIDTH; + break; + case 2: + addr_width = STEDMA40_HALFWORD_WIDTH; + break; + case 4: + addr_width = STEDMA40_WORD_WIDTH; + break; + case 8: + addr_width = STEDMA40_DOUBLEWORD_WIDTH; + break; + default: + dev_err(d40c->base->dev, + "illegal peripheral address width requested (%d)\n", + config->addr_width); + return; + } + + if (config->maxburst >= 16) + psize = STEDMA40_PSIZE_LOG_16; + else if (config->maxburst >= 8) + psize = STEDMA40_PSIZE_LOG_8; + else if (config->maxburst >= 4) + psize = STEDMA40_PSIZE_LOG_4; + else + psize = STEDMA40_PSIZE_LOG_1; + + if (config->direction == DMA_FROM_DEVICE) { + dma_addr_t dev_addr_rx = + d40c->base->plat_data->dev_rx[cfg->src_dev_type]; + + if (dev_addr_rx) + dev_warn(d40c->base->dev, + "channel has a pre-wired RX address %08x " + "overriding with %08x\n", + dev_addr_rx, config->addr); + if (cfg->dir != STEDMA40_PERIPH_TO_MEM) + dev_warn(d40c->base->dev, + "channel was not configured for peripheral " + "to memory transfer (%d) overriding\n", + cfg->dir); + cfg->dir = STEDMA40_PERIPH_TO_MEM; + } else if (config->direction == DMA_TO_DEVICE) { + dma_addr_t dev_addr_tx = + d40c->base->plat_data->dev_tx[cfg->dst_dev_type]; + + if (dev_addr_tx) + dev_warn(d40c->base->dev, + "channel has a pre-wired TX address %08x " + "overriding with %08x\n", + dev_addr_tx, config->addr); + if (cfg->dir != STEDMA40_MEM_TO_PERIPH) + dev_warn(d40c->base->dev, + "channel was not configured for memory " + "to peripheral transfer (%d) overriding\n", + cfg->dir); + cfg->dir = STEDMA40_MEM_TO_PERIPH; + } else { + dev_err(d40c->base->dev, + "unrecognized channel direction %d\n", + config->direction); + return; + } + + /* Set up all the endpoint configs */ + cfg->src_info.data_width = addr_width; + cfg->src_info.psize = psize; + cfg->src_info.endianess = STEDMA40_LITTLE_ENDIAN; + cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; + cfg->dst_info.data_width = addr_width; + cfg->dst_info.psize = psize; + cfg->dst_info.endianess = STEDMA40_LITTLE_ENDIAN; + cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; + + /* These settings will take precedence later */ + d40c->amba_addr = config->addr; + d40c->amba_direction = config->direction; + dev_dbg(d40c->base->dev, + "configured channel %s for %s, data width %d, " + "maxburst %d bytes, LE, no flow control\n", + dma_chan_name(chan), + (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", + config->addr_width, + config->maxburst); +} + /* Initialization functions */ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, -- 1.6.3.3
next reply other threads:[~2010-04-07 23:13 UTC|newest] Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top 2010-04-07 23:13 Linus Walleij [this message] 2010-04-07 23:13 ` [PATCH 06/11] ARM: add generic PrimeCell interface to DMA40 v1 Linus Walleij
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1270681985-6022-1-git-send-email-linus.walleij@stericsson.com \ --to=linus.walleij@stericsson.com \ --cc=STEricsson_nomadik_linux@list.st.com \ --cc=akpm@linux-foundation.org \ --cc=dan.j.williams@intel.com \ --cc=grant.likely@secretlab.ca \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-mmc@vger.kernel.org \ --cc=linux@arm.linux.org.uk \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.