mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 15:20:41 +00:00
DMAENGINE: add runtime slave config to DMA40 v3
This extends the DMA engine driver for the DMA40 used in the U8500 platform with the generic runtime slave configuration interface. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
c156d0a5b0
commit
95e1400fa1
1 changed files with 137 additions and 4 deletions
|
@ -208,6 +208,9 @@ struct d40_chan {
|
||||||
struct d40_def_lcsp log_def;
|
struct d40_def_lcsp log_def;
|
||||||
struct d40_lcla_elem lcla;
|
struct d40_lcla_elem lcla;
|
||||||
struct d40_log_lli_full *lcpa;
|
struct d40_log_lli_full *lcpa;
|
||||||
|
/* Runtime reconfiguration */
|
||||||
|
dma_addr_t runtime_addr;
|
||||||
|
enum dma_data_direction runtime_direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1886,9 +1889,16 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
|
||||||
d40d->lli_tx_len = 1;
|
d40d->lli_tx_len = 1;
|
||||||
|
|
||||||
if (direction == DMA_FROM_DEVICE)
|
if (direction == DMA_FROM_DEVICE)
|
||||||
dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
|
if (d40c->runtime_addr)
|
||||||
|
dev_addr = d40c->runtime_addr;
|
||||||
|
else
|
||||||
|
dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
|
||||||
else if (direction == DMA_TO_DEVICE)
|
else if (direction == DMA_TO_DEVICE)
|
||||||
dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
|
if (d40c->runtime_addr)
|
||||||
|
dev_addr = d40c->runtime_addr;
|
||||||
|
else
|
||||||
|
dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
|
||||||
|
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1931,9 +1941,15 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
|
||||||
|
|
||||||
if (direction == DMA_FROM_DEVICE) {
|
if (direction == DMA_FROM_DEVICE) {
|
||||||
dst_dev_addr = 0;
|
dst_dev_addr = 0;
|
||||||
src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
|
if (d40c->runtime_addr)
|
||||||
|
src_dev_addr = d40c->runtime_addr;
|
||||||
|
else
|
||||||
|
src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
|
||||||
} else if (direction == DMA_TO_DEVICE) {
|
} else if (direction == DMA_TO_DEVICE) {
|
||||||
dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
|
if (d40c->runtime_addr)
|
||||||
|
dst_dev_addr = d40c->runtime_addr;
|
||||||
|
else
|
||||||
|
dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
|
||||||
src_dev_addr = 0;
|
src_dev_addr = 0;
|
||||||
} else
|
} else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2070,6 +2086,117 @@ static void d40_issue_pending(struct dma_chan *chan)
|
||||||
spin_unlock_irqrestore(&d40c->lock, flags);
|
spin_unlock_irqrestore(&d40c->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Runtime reconfiguration extension */
|
||||||
|
static void d40_set_runtime_config(struct dma_chan *chan,
|
||||||
|
struct dma_slave_config *config)
|
||||||
|
{
|
||||||
|
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
|
||||||
|
struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
|
||||||
|
enum dma_slave_buswidth config_addr_width;
|
||||||
|
dma_addr_t config_addr;
|
||||||
|
u32 config_maxburst;
|
||||||
|
enum stedma40_periph_data_width addr_width;
|
||||||
|
int psize;
|
||||||
|
|
||||||
|
if (config->direction == DMA_FROM_DEVICE) {
|
||||||
|
dma_addr_t dev_addr_rx =
|
||||||
|
d40c->base->plat_data->dev_rx[cfg->src_dev_type];
|
||||||
|
|
||||||
|
config_addr = config->src_addr;
|
||||||
|
if (dev_addr_rx)
|
||||||
|
dev_dbg(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_dbg(d40c->base->dev,
|
||||||
|
"channel was not configured for peripheral "
|
||||||
|
"to memory transfer (%d) overriding\n",
|
||||||
|
cfg->dir);
|
||||||
|
cfg->dir = STEDMA40_PERIPH_TO_MEM;
|
||||||
|
|
||||||
|
config_addr_width = config->src_addr_width;
|
||||||
|
config_maxburst = config->src_maxburst;
|
||||||
|
|
||||||
|
} else if (config->direction == DMA_TO_DEVICE) {
|
||||||
|
dma_addr_t dev_addr_tx =
|
||||||
|
d40c->base->plat_data->dev_tx[cfg->dst_dev_type];
|
||||||
|
|
||||||
|
config_addr = config->dst_addr;
|
||||||
|
if (dev_addr_tx)
|
||||||
|
dev_dbg(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_dbg(d40c->base->dev,
|
||||||
|
"channel was not configured for memory "
|
||||||
|
"to peripheral transfer (%d) overriding\n",
|
||||||
|
cfg->dir);
|
||||||
|
cfg->dir = STEDMA40_MEM_TO_PERIPH;
|
||||||
|
|
||||||
|
config_addr_width = config->dst_addr_width;
|
||||||
|
config_maxburst = config->dst_maxburst;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
dev_err(d40c->base->dev,
|
||||||
|
"unrecognized channel direction %d\n",
|
||||||
|
config->direction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (config_addr_width) {
|
||||||
|
case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
||||||
|
addr_width = STEDMA40_BYTE_WIDTH;
|
||||||
|
break;
|
||||||
|
case DMA_SLAVE_BUSWIDTH_2_BYTES:
|
||||||
|
addr_width = STEDMA40_HALFWORD_WIDTH;
|
||||||
|
break;
|
||||||
|
case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
||||||
|
addr_width = STEDMA40_WORD_WIDTH;
|
||||||
|
break;
|
||||||
|
case DMA_SLAVE_BUSWIDTH_8_BYTES:
|
||||||
|
addr_width = STEDMA40_DOUBLEWORD_WIDTH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(d40c->base->dev,
|
||||||
|
"illegal peripheral address width "
|
||||||
|
"requested (%d)\n",
|
||||||
|
config->src_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;
|
||||||
|
|
||||||
|
/* 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->runtime_addr = config_addr;
|
||||||
|
d40c->runtime_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);
|
||||||
|
}
|
||||||
|
|
||||||
static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
|
@ -2092,6 +2219,12 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||||
return d40_pause(chan);
|
return d40_pause(chan);
|
||||||
case DMA_RESUME:
|
case DMA_RESUME:
|
||||||
return d40_resume(chan);
|
return d40_resume(chan);
|
||||||
|
case DMA_SLAVE_CONFIG:
|
||||||
|
d40_set_runtime_config(chan,
|
||||||
|
(struct dma_slave_config *) arg);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Other commands are unimplemented */
|
/* Other commands are unimplemented */
|
||||||
|
|
Loading…
Reference in a new issue