Commit 98ca5289 authored by Rabin Vincent's avatar Rabin Vincent Committed by Vinod Koul

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: default avatarRabin Vincent <rabin.vincent@stericsson.com>
Reviewed-by: default avatarUlf HANSSON <ulf.hansson@stericsson.com>
Tested-by: default avatarStefan Nilsson <stefan.xk.nilsson@stericsson.com>
Reviewed-by: default avatarPer Forlin <per.forlin@stericsson.com>
Reviewed-by: default avatarSrinidhi Kasagar <srinidhi.kasagar@stericsson.com>
Cc: Robert Marklund <robert.marklund@stericsson.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent f4b89764
...@@ -2179,17 +2179,78 @@ static void d40_issue_pending(struct dma_chan *chan) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment