diff options
author | Russell King - ARM Linux <linux@arm.linux.org.uk> | 2011-07-21 12:13:48 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2011-07-26 06:03:29 -0400 |
commit | 121c8476a3c39a483326c33526e72a07661df1fc (patch) | |
tree | e0cdeae942aebffac59c4c375bc7eef9f0f549dc /drivers/dma/amba-pl08x.c | |
parent | aa88cdaa149e1c1cfc935ff73e50f3f9f3b2e3a1 (diff) |
DMA: PL08x: avoid recalculating cctl at each prepare
Now that we have separate cctl values for M>P and P>M transfers, we can
avoid calculating the cctl value each time we prepare a transaction.
Move the bus selection and increment setting to the slave configuration
and initialization functions.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/amba-pl08x.c')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 78 |
1 files changed, 42 insertions, 36 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 2dd37ff753ca..a84db8b39ba1 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -1095,6 +1095,23 @@ static const struct burst_table burst_sizes[] = { | |||
1095 | }, | 1095 | }, |
1096 | }; | 1096 | }; |
1097 | 1097 | ||
1098 | /* | ||
1099 | * Given the source and destination available bus masks, select which | ||
1100 | * will be routed to each port. We try to have source and destination | ||
1101 | * on separate ports, but always respect the allowable settings. | ||
1102 | */ | ||
1103 | static u32 pl08x_select_bus(u8 src, u8 dst) | ||
1104 | { | ||
1105 | u32 cctl = 0; | ||
1106 | |||
1107 | if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) | ||
1108 | cctl |= PL080_CONTROL_DST_AHB2; | ||
1109 | if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) | ||
1110 | cctl |= PL080_CONTROL_SRC_AHB2; | ||
1111 | |||
1112 | return cctl; | ||
1113 | } | ||
1114 | |||
1098 | static u32 pl08x_cctl(u32 cctl) | 1115 | static u32 pl08x_cctl(u32 cctl) |
1099 | { | 1116 | { |
1100 | cctl &= ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | | 1117 | cctl &= ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | |
@@ -1173,10 +1190,14 @@ static int dma_set_runtime_config(struct dma_chan *chan, | |||
1173 | 1190 | ||
1174 | if (plchan->runtime_direction == DMA_FROM_DEVICE) { | 1191 | if (plchan->runtime_direction == DMA_FROM_DEVICE) { |
1175 | plchan->src_addr = config->src_addr; | 1192 | plchan->src_addr = config->src_addr; |
1176 | plchan->src_cctl = pl08x_cctl(cctl); | 1193 | plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | |
1194 | pl08x_select_bus(plchan->cd->periph_buses, | ||
1195 | pl08x->mem_buses); | ||
1177 | } else { | 1196 | } else { |
1178 | plchan->dst_addr = config->dst_addr; | 1197 | plchan->dst_addr = config->dst_addr; |
1179 | plchan->dst_cctl = pl08x_cctl(cctl); | 1198 | plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR | |
1199 | pl08x_select_bus(pl08x->mem_buses, | ||
1200 | plchan->cd->periph_buses); | ||
1180 | } | 1201 | } |
1181 | 1202 | ||
1182 | dev_dbg(&pl08x->adev->dev, | 1203 | dev_dbg(&pl08x->adev->dev, |
@@ -1277,23 +1298,6 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, | |||
1277 | return 0; | 1298 | return 0; |
1278 | } | 1299 | } |
1279 | 1300 | ||
1280 | /* | ||
1281 | * Given the source and destination available bus masks, select which | ||
1282 | * will be routed to each port. We try to have source and destination | ||
1283 | * on separate ports, but always respect the allowable settings. | ||
1284 | */ | ||
1285 | static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) | ||
1286 | { | ||
1287 | u32 cctl = 0; | ||
1288 | |||
1289 | if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) | ||
1290 | cctl |= PL080_CONTROL_DST_AHB2; | ||
1291 | if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) | ||
1292 | cctl |= PL080_CONTROL_SRC_AHB2; | ||
1293 | |||
1294 | return cctl; | ||
1295 | } | ||
1296 | |||
1297 | static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, | 1301 | static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, |
1298 | unsigned long flags) | 1302 | unsigned long flags) |
1299 | { | 1303 | { |
@@ -1345,8 +1349,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( | |||
1345 | txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; | 1349 | txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; |
1346 | 1350 | ||
1347 | if (pl08x->vd->dualmaster) | 1351 | if (pl08x->vd->dualmaster) |
1348 | txd->cctl |= pl08x_select_bus(pl08x, | 1352 | txd->cctl |= pl08x_select_bus(pl08x->mem_buses, |
1349 | pl08x->mem_buses, pl08x->mem_buses); | 1353 | pl08x->mem_buses); |
1350 | 1354 | ||
1351 | ret = pl08x_prep_channel_resources(plchan, txd); | 1355 | ret = pl08x_prep_channel_resources(plchan, txd); |
1352 | if (ret) | 1356 | if (ret) |
@@ -1363,7 +1367,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( | |||
1363 | struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); | 1367 | struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); |
1364 | struct pl08x_driver_data *pl08x = plchan->host; | 1368 | struct pl08x_driver_data *pl08x = plchan->host; |
1365 | struct pl08x_txd *txd; | 1369 | struct pl08x_txd *txd; |
1366 | u8 src_buses, dst_buses; | ||
1367 | int ret; | 1370 | int ret; |
1368 | 1371 | ||
1369 | /* | 1372 | /* |
@@ -1399,26 +1402,20 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( | |||
1399 | 1402 | ||
1400 | if (direction == DMA_TO_DEVICE) { | 1403 | if (direction == DMA_TO_DEVICE) { |
1401 | txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; | 1404 | txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; |
1402 | txd->cctl = plchan->dst_cctl | PL080_CONTROL_SRC_INCR; | 1405 | txd->cctl = plchan->dst_cctl; |
1403 | txd->src_addr = sgl->dma_address; | 1406 | txd->src_addr = sgl->dma_address; |
1404 | txd->dst_addr = plchan->dst_addr; | 1407 | txd->dst_addr = plchan->dst_addr; |
1405 | src_buses = pl08x->mem_buses; | ||
1406 | dst_buses = plchan->cd->periph_buses; | ||
1407 | } else if (direction == DMA_FROM_DEVICE) { | 1408 | } else if (direction == DMA_FROM_DEVICE) { |
1408 | txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; | 1409 | txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; |
1409 | txd->cctl = plchan->src_cctl | PL080_CONTROL_DST_INCR; | 1410 | txd->cctl = plchan->src_cctl; |
1410 | txd->src_addr = plchan->src_addr; | 1411 | txd->src_addr = plchan->src_addr; |
1411 | txd->dst_addr = sgl->dma_address; | 1412 | txd->dst_addr = sgl->dma_address; |
1412 | src_buses = plchan->cd->periph_buses; | ||
1413 | dst_buses = pl08x->mem_buses; | ||
1414 | } else { | 1413 | } else { |
1415 | dev_err(&pl08x->adev->dev, | 1414 | dev_err(&pl08x->adev->dev, |
1416 | "%s direction unsupported\n", __func__); | 1415 | "%s direction unsupported\n", __func__); |
1417 | return NULL; | 1416 | return NULL; |
1418 | } | 1417 | } |
1419 | 1418 | ||
1420 | txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); | ||
1421 | |||
1422 | ret = pl08x_prep_channel_resources(plchan, txd); | 1419 | ret = pl08x_prep_channel_resources(plchan, txd); |
1423 | if (ret) | 1420 | if (ret) |
1424 | return NULL; | 1421 | return NULL; |
@@ -1669,6 +1666,20 @@ static irqreturn_t pl08x_irq(int irq, void *dev) | |||
1669 | return mask ? IRQ_HANDLED : IRQ_NONE; | 1666 | return mask ? IRQ_HANDLED : IRQ_NONE; |
1670 | } | 1667 | } |
1671 | 1668 | ||
1669 | static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan) | ||
1670 | { | ||
1671 | u32 cctl = pl08x_cctl(chan->cd->cctl); | ||
1672 | |||
1673 | chan->slave = true; | ||
1674 | chan->name = chan->cd->bus_id; | ||
1675 | chan->src_addr = chan->cd->addr; | ||
1676 | chan->dst_addr = chan->cd->addr; | ||
1677 | chan->src_cctl = cctl | PL080_CONTROL_DST_INCR | | ||
1678 | pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses); | ||
1679 | chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR | | ||
1680 | pl08x_select_bus(chan->host->mem_buses, chan->cd->periph_buses); | ||
1681 | } | ||
1682 | |||
1672 | /* | 1683 | /* |
1673 | * Initialise the DMAC memcpy/slave channels. | 1684 | * Initialise the DMAC memcpy/slave channels. |
1674 | * Make a local wrapper to hold required data | 1685 | * Make a local wrapper to hold required data |
@@ -1700,13 +1711,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, | |||
1700 | chan->state = PL08X_CHAN_IDLE; | 1711 | chan->state = PL08X_CHAN_IDLE; |
1701 | 1712 | ||
1702 | if (slave) { | 1713 | if (slave) { |
1703 | chan->slave = true; | ||
1704 | chan->name = pl08x->pd->slave_channels[i].bus_id; | ||
1705 | chan->cd = &pl08x->pd->slave_channels[i]; | 1714 | chan->cd = &pl08x->pd->slave_channels[i]; |
1706 | chan->src_addr = chan->cd->addr; | 1715 | pl08x_dma_slave_init(chan); |
1707 | chan->dst_addr = chan->cd->addr; | ||
1708 | chan->src_cctl = pl08x_cctl(chan->cd->cctl); | ||
1709 | chan->dst_cctl = pl08x_cctl(chan->cd->cctl); | ||
1710 | } else { | 1716 | } else { |
1711 | chan->cd = &pl08x->pd->memcpy_channel; | 1717 | chan->cd = &pl08x->pd->memcpy_channel; |
1712 | chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i); | 1718 | chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i); |