dmaengine/ste_dma40: allow memory buswidth/burst to be configured
Currently the runtime config implementation forces the memory side parameters to be the same as the peripheral side. Allow these to be different, and check for misconfiguration. Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com> Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com> Tested-by: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> Reviewed-by: Per Forlin <per.forlin@stericsson.com> Reviewed-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> Cc: Robert Marklund <robert.marklund@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
Родитель
f4b89764c4
Коммит
98ca528916
|
@ -2179,17 +2179,78 @@ static void d40_issue_pending(struct dma_chan *chan)
|
||||||
spin_unlock_irqrestore(&d40c->lock, flags);
|
spin_unlock_irqrestore(&d40c->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dma40_config_to_halfchannel(struct d40_chan *d40c,
|
||||||
|
struct stedma40_half_channel_info *info,
|
||||||
|
enum dma_slave_buswidth width,
|
||||||
|
u32 maxburst)
|
||||||
|
{
|
||||||
|
enum stedma40_periph_data_width addr_width;
|
||||||
|
int psize;
|
||||||
|
|
||||||
|
switch (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",
|
||||||
|
width);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan_is_logical(d40c)) {
|
||||||
|
if (maxburst >= 16)
|
||||||
|
psize = STEDMA40_PSIZE_LOG_16;
|
||||||
|
else if (maxburst >= 8)
|
||||||
|
psize = STEDMA40_PSIZE_LOG_8;
|
||||||
|
else if (maxburst >= 4)
|
||||||
|
psize = STEDMA40_PSIZE_LOG_4;
|
||||||
|
else
|
||||||
|
psize = STEDMA40_PSIZE_LOG_1;
|
||||||
|
} else {
|
||||||
|
if (maxburst >= 16)
|
||||||
|
psize = STEDMA40_PSIZE_PHY_16;
|
||||||
|
else if (maxburst >= 8)
|
||||||
|
psize = STEDMA40_PSIZE_PHY_8;
|
||||||
|
else if (maxburst >= 4)
|
||||||
|
psize = STEDMA40_PSIZE_PHY_4;
|
||||||
|
else
|
||||||
|
psize = STEDMA40_PSIZE_PHY_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->data_width = addr_width;
|
||||||
|
info->psize = psize;
|
||||||
|
info->flow_ctrl = STEDMA40_NO_FLOW_CTRL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Runtime reconfiguration extension */
|
/* Runtime reconfiguration extension */
|
||||||
static void d40_set_runtime_config(struct dma_chan *chan,
|
static int d40_set_runtime_config(struct dma_chan *chan,
|
||||||
struct dma_slave_config *config)
|
struct dma_slave_config *config)
|
||||||
{
|
{
|
||||||
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
|
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
|
||||||
struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
|
struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
|
||||||
enum dma_slave_buswidth config_addr_width;
|
enum dma_slave_buswidth src_addr_width, dst_addr_width;
|
||||||
dma_addr_t config_addr;
|
dma_addr_t config_addr;
|
||||||
u32 config_maxburst;
|
u32 src_maxburst, dst_maxburst;
|
||||||
enum stedma40_periph_data_width addr_width;
|
int ret;
|
||||||
int psize;
|
|
||||||
|
src_addr_width = config->src_addr_width;
|
||||||
|
src_maxburst = config->src_maxburst;
|
||||||
|
dst_addr_width = config->dst_addr_width;
|
||||||
|
dst_maxburst = config->dst_maxburst;
|
||||||
|
|
||||||
if (config->direction == DMA_FROM_DEVICE) {
|
if (config->direction == DMA_FROM_DEVICE) {
|
||||||
dma_addr_t dev_addr_rx =
|
dma_addr_t dev_addr_rx =
|
||||||
|
@ -2208,8 +2269,11 @@ static void d40_set_runtime_config(struct dma_chan *chan,
|
||||||
cfg->dir);
|
cfg->dir);
|
||||||
cfg->dir = STEDMA40_PERIPH_TO_MEM;
|
cfg->dir = STEDMA40_PERIPH_TO_MEM;
|
||||||
|
|
||||||
config_addr_width = config->src_addr_width;
|
/* Configure the memory side */
|
||||||
config_maxburst = config->src_maxburst;
|
if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
|
||||||
|
dst_addr_width = src_addr_width;
|
||||||
|
if (dst_maxburst == 0)
|
||||||
|
dst_maxburst = src_maxburst;
|
||||||
|
|
||||||
} else if (config->direction == DMA_TO_DEVICE) {
|
} else if (config->direction == DMA_TO_DEVICE) {
|
||||||
dma_addr_t dev_addr_tx =
|
dma_addr_t dev_addr_tx =
|
||||||
|
@ -2228,68 +2292,39 @@ static void d40_set_runtime_config(struct dma_chan *chan,
|
||||||
cfg->dir);
|
cfg->dir);
|
||||||
cfg->dir = STEDMA40_MEM_TO_PERIPH;
|
cfg->dir = STEDMA40_MEM_TO_PERIPH;
|
||||||
|
|
||||||
config_addr_width = config->dst_addr_width;
|
/* Configure the memory side */
|
||||||
config_maxburst = config->dst_maxburst;
|
if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
|
||||||
|
src_addr_width = dst_addr_width;
|
||||||
|
if (src_maxburst == 0)
|
||||||
|
src_maxburst = dst_maxburst;
|
||||||
} else {
|
} else {
|
||||||
dev_err(d40c->base->dev,
|
dev_err(d40c->base->dev,
|
||||||
"unrecognized channel direction %d\n",
|
"unrecognized channel direction %d\n",
|
||||||
config->direction);
|
config->direction);
|
||||||
return;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (config_addr_width) {
|
if (src_maxburst * src_addr_width != dst_maxburst * dst_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,
|
dev_err(d40c->base->dev,
|
||||||
"illegal peripheral address width "
|
"src/dst width/maxburst mismatch: %d*%d != %d*%d\n",
|
||||||
"requested (%d)\n",
|
src_maxburst,
|
||||||
config->src_addr_width);
|
src_addr_width,
|
||||||
return;
|
dst_maxburst,
|
||||||
|
dst_addr_width);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan_is_logical(d40c)) {
|
ret = dma40_config_to_halfchannel(d40c, &cfg->src_info,
|
||||||
if (config_maxburst >= 16)
|
src_addr_width,
|
||||||
psize = STEDMA40_PSIZE_LOG_16;
|
src_maxburst);
|
||||||
else if (config_maxburst >= 8)
|
if (ret)
|
||||||
psize = STEDMA40_PSIZE_LOG_8;
|
return ret;
|
||||||
else if (config_maxburst >= 4)
|
|
||||||
psize = STEDMA40_PSIZE_LOG_4;
|
|
||||||
else
|
|
||||||
psize = STEDMA40_PSIZE_LOG_1;
|
|
||||||
} else {
|
|
||||||
if (config_maxburst >= 16)
|
|
||||||
psize = STEDMA40_PSIZE_PHY_16;
|
|
||||||
else if (config_maxburst >= 8)
|
|
||||||
psize = STEDMA40_PSIZE_PHY_8;
|
|
||||||
else if (config_maxburst >= 4)
|
|
||||||
psize = STEDMA40_PSIZE_PHY_4;
|
|
||||||
else if (config_maxburst >= 2)
|
|
||||||
psize = STEDMA40_PSIZE_PHY_2;
|
|
||||||
else
|
|
||||||
psize = STEDMA40_PSIZE_PHY_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up all the endpoint configs */
|
ret = dma40_config_to_halfchannel(d40c, &cfg->dst_info,
|
||||||
cfg->src_info.data_width = addr_width;
|
dst_addr_width,
|
||||||
cfg->src_info.psize = psize;
|
dst_maxburst);
|
||||||
cfg->src_info.big_endian = false;
|
if (ret)
|
||||||
cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
|
return ret;
|
||||||
cfg->dst_info.data_width = addr_width;
|
|
||||||
cfg->dst_info.psize = psize;
|
|
||||||
cfg->dst_info.big_endian = false;
|
|
||||||
cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
|
|
||||||
|
|
||||||
/* Fill in register values */
|
/* Fill in register values */
|
||||||
if (chan_is_logical(d40c))
|
if (chan_is_logical(d40c))
|
||||||
|
@ -2302,12 +2337,14 @@ static void d40_set_runtime_config(struct dma_chan *chan,
|
||||||
d40c->runtime_addr = config_addr;
|
d40c->runtime_addr = config_addr;
|
||||||
d40c->runtime_direction = config->direction;
|
d40c->runtime_direction = config->direction;
|
||||||
dev_dbg(d40c->base->dev,
|
dev_dbg(d40c->base->dev,
|
||||||
"configured channel %s for %s, data width %d, "
|
"configured channel %s for %s, data width %d/%d, "
|
||||||
"maxburst %d bytes, LE, no flow control\n",
|
"maxburst %d/%d elements, LE, no flow control\n",
|
||||||
dma_chan_name(chan),
|
dma_chan_name(chan),
|
||||||
(config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
|
(config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
|
||||||
config_addr_width,
|
src_addr_width, dst_addr_width,
|
||||||
config_maxburst);
|
src_maxburst, dst_maxburst);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -2328,9 +2365,8 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
|
||||||
case DMA_RESUME:
|
case DMA_RESUME:
|
||||||
return d40_resume(d40c);
|
return d40_resume(d40c);
|
||||||
case DMA_SLAVE_CONFIG:
|
case DMA_SLAVE_CONFIG:
|
||||||
d40_set_runtime_config(chan,
|
return d40_set_runtime_config(chan,
|
||||||
(struct dma_slave_config *) arg);
|
(struct dma_slave_config *) arg);
|
||||||
return 0;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче