summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/common/edma.c305
-rw-r--r--drivers/dma/edma.c79
-rw-r--r--include/linux/platform_data/edma.h38
3 files changed, 214 insertions, 208 deletions
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index 0b4c0ee59ed9..03692520812a 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -130,7 +130,7 @@ struct edma {
struct edma_soc_info *info;
int id;
-
+ bool unused_chan_list_done;
/* The edma_inuse bit for each PaRAM slot is clear unless the
* channel is in use ... by ARM or DSP, for QDMA, or whatever.
*/
@@ -264,7 +264,6 @@ static inline void clear_bits(int offset, int len, unsigned long *p)
}
/*****************************************************************************/
-static struct edma *edma_cc[EDMA_MAX_CC];
static int arch_num_cc;
/* dummy param set used to (re)initialize parameter RAM slots */
@@ -490,14 +489,18 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
static int prepare_unused_channel_list(struct device *dev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- int i, count, ctlr;
+ struct edma *cc = data;
+ int i, count;
struct of_phandle_args dma_spec;
if (dev->of_node) {
+ struct platform_device *dma_pdev;
+
count = of_property_count_strings(dev->of_node, "dma-names");
if (count < 0)
return 0;
for (i = 0; i < count; i++) {
+
if (of_parse_phandle_with_args(dev->of_node, "dmas",
"#dma-cells", i,
&dma_spec))
@@ -508,8 +511,12 @@ static int prepare_unused_channel_list(struct device *dev, void *data)
continue;
}
+ dma_pdev = of_find_device_by_node(dma_spec.np);
+ if (&dma_pdev->dev != cc->dev)
+ continue;
+
clear_bit(EDMA_CHAN_SLOT(dma_spec.args[0]),
- edma_cc[0]->edma_unused);
+ cc->edma_unused);
of_node_put(dma_spec.np);
}
return 0;
@@ -517,11 +524,11 @@ static int prepare_unused_channel_list(struct device *dev, void *data)
/* For non-OF case */
for (i = 0; i < pdev->num_resources; i++) {
- if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
- (int)pdev->resource[i].start >= 0) {
- ctlr = EDMA_CTLR(pdev->resource[i].start);
+ struct resource *res = &pdev->resource[i];
+
+ if ((res->flags & IORESOURCE_DMA) && (int)res->start >= 0) {
clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
- edma_cc[ctlr]->edma_unused);
+ cc->edma_unused);
}
}
@@ -530,8 +537,6 @@ static int prepare_unused_channel_list(struct device *dev, void *data)
/*-----------------------------------------------------------------------*/
-static bool unused_chan_list_done;
-
/* Resource alloc/free: dma channels, parameter RAM slots */
/**
@@ -564,77 +569,73 @@ static bool unused_chan_list_done;
*
* Returns the number of the channel, else negative errno.
*/
-int edma_alloc_channel(int channel,
+int edma_alloc_channel(struct edma *cc, int channel,
void (*callback)(unsigned channel, u16 ch_status, void *data),
void *data,
enum dma_event_q eventq_no)
{
- unsigned i, done = 0, ctlr = 0;
+ unsigned done = 0;
int ret = 0;
- if (!unused_chan_list_done) {
+ if (!cc->unused_chan_list_done) {
/*
* Scan all the platform devices to find out the EDMA channels
* used and clear them in the unused list, making the rest
* available for ARM usage.
*/
- ret = bus_for_each_dev(&platform_bus_type, NULL, NULL,
- prepare_unused_channel_list);
+ ret = bus_for_each_dev(&platform_bus_type, NULL, cc,
+ prepare_unused_channel_list);
if (ret < 0)
return ret;
- unused_chan_list_done = true;
+ cc->unused_chan_list_done = true;
}
if (channel >= 0) {
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n",
+ __func__, cc->id, EDMA_CTLR(channel));
+ return -EINVAL;
+ }
channel = EDMA_CHAN_SLOT(channel);
}
if (channel < 0) {
- for (i = 0; i < arch_num_cc; i++) {
- channel = 0;
- for (;;) {
- channel = find_next_bit(edma_cc[i]->edma_unused,
- edma_cc[i]->num_channels,
- channel);
- if (channel == edma_cc[i]->num_channels)
- break;
- if (!test_and_set_bit(channel,
- edma_cc[i]->edma_inuse)) {
- done = 1;
- ctlr = i;
- break;
- }
- channel++;
- }
- if (done)
+ channel = 0;
+ for (;;) {
+ channel = find_next_bit(cc->edma_unused,
+ cc->num_channels, channel);
+ if (channel == cc->num_channels)
+ break;
+ if (!test_and_set_bit(channel, cc->edma_inuse)) {
+ done = 1;
break;
+ }
+ channel++;
}
if (!done)
return -ENOMEM;
- } else if (channel >= edma_cc[ctlr]->num_channels) {
+ } else if (channel >= cc->num_channels) {
return -EINVAL;
- } else if (test_and_set_bit(channel, edma_cc[ctlr]->edma_inuse)) {
+ } else if (test_and_set_bit(channel, cc->edma_inuse)) {
return -EBUSY;
}
/* ensure access through shadow region 0 */
- edma_or_array2(edma_cc[ctlr], EDMA_DRAE, 0, channel >> 5, BIT(channel & 0x1f));
+ edma_or_array2(cc, EDMA_DRAE, 0, channel >> 5, BIT(channel & 0x1f));
/* ensure no events are pending */
- edma_stop(EDMA_CTLR_CHAN(ctlr, channel));
- memcpy_toio(edma_cc[ctlr]->base + PARM_OFFSET(channel), &dummy_paramset,
+ edma_stop(cc, EDMA_CTLR_CHAN(cc->id, channel));
+ memcpy_toio(cc->base + PARM_OFFSET(channel), &dummy_paramset,
PARM_SIZE);
if (callback)
- setup_dma_interrupt(edma_cc[ctlr],
- EDMA_CTLR_CHAN(ctlr, channel), callback,
- data);
+ setup_dma_interrupt(cc, EDMA_CTLR_CHAN(cc->id, channel),
+ callback, data);
- map_dmach_queue(edma_cc[ctlr], channel, eventq_no);
+ map_dmach_queue(cc, channel, eventq_no);
- return EDMA_CTLR_CHAN(ctlr, channel);
+ return EDMA_CTLR_CHAN(cc->id, channel);
}
EXPORT_SYMBOL(edma_alloc_channel);
@@ -650,22 +651,25 @@ EXPORT_SYMBOL(edma_alloc_channel);
* will not be reactivated by linking, chaining, or software calls to
* edma_start().
*/
-void edma_free_channel(unsigned channel)
+void edma_free_channel(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel >= edma_cc[ctlr]->num_channels)
+ if (channel >= cc->num_channels)
return;
- setup_dma_interrupt(edma_cc[ctlr], channel, NULL, NULL);
+ setup_dma_interrupt(cc, channel, NULL, NULL);
/* REVISIT should probably take out of shadow region 0 */
- memcpy_toio(edma_cc[ctlr]->base + PARM_OFFSET(channel), &dummy_paramset,
+ memcpy_toio(cc->base + PARM_OFFSET(channel), &dummy_paramset,
PARM_SIZE);
- clear_bit(channel, edma_cc[ctlr]->edma_inuse);
+ clear_bit(channel, cc->edma_inuse);
}
EXPORT_SYMBOL(edma_free_channel);
@@ -683,35 +687,29 @@ EXPORT_SYMBOL(edma_free_channel);
*
* Returns the number of the slot, else negative errno.
*/
-int edma_alloc_slot(unsigned ctlr, int slot)
+int edma_alloc_slot(struct edma *cc, int slot)
{
- if (!edma_cc[ctlr])
- return -EINVAL;
-
- if (slot >= 0)
+ if (slot > 0)
slot = EDMA_CHAN_SLOT(slot);
-
if (slot < 0) {
- slot = edma_cc[ctlr]->num_channels;
+ slot = cc->num_channels;
for (;;) {
- slot = find_next_zero_bit(edma_cc[ctlr]->edma_inuse,
- edma_cc[ctlr]->num_slots, slot);
- if (slot == edma_cc[ctlr]->num_slots)
+ slot = find_next_zero_bit(cc->edma_inuse, cc->num_slots,
+ slot);
+ if (slot == cc->num_slots)
return -ENOMEM;
- if (!test_and_set_bit(slot, edma_cc[ctlr]->edma_inuse))
+ if (!test_and_set_bit(slot, cc->edma_inuse))
break;
}
- } else if (slot < edma_cc[ctlr]->num_channels ||
- slot >= edma_cc[ctlr]->num_slots) {
+ } else if (slot < cc->num_channels || slot >= cc->num_slots) {
return -EINVAL;
- } else if (test_and_set_bit(slot, edma_cc[ctlr]->edma_inuse)) {
+ } else if (test_and_set_bit(slot, cc->edma_inuse)) {
return -EBUSY;
}
- memcpy_toio(edma_cc[ctlr]->base + PARM_OFFSET(slot), &dummy_paramset,
- PARM_SIZE);
+ memcpy_toio(cc->base + PARM_OFFSET(slot), &dummy_paramset, PARM_SIZE);
- return EDMA_CTLR_CHAN(ctlr, slot);
+ return slot;
}
EXPORT_SYMBOL(edma_alloc_slot);
@@ -723,20 +721,15 @@ EXPORT_SYMBOL(edma_alloc_slot);
* Callers are responsible for ensuring the slot is inactive, and will
* not be activated.
*/
-void edma_free_slot(unsigned slot)
+void edma_free_slot(struct edma *cc, unsigned slot)
{
- unsigned ctlr;
- ctlr = EDMA_CTLR(slot);
slot = EDMA_CHAN_SLOT(slot);
-
- if (slot < edma_cc[ctlr]->num_channels ||
- slot >= edma_cc[ctlr]->num_slots)
+ if (slot < cc->num_channels || slot >= cc->num_slots)
return;
- memcpy_toio(edma_cc[ctlr]->base + PARM_OFFSET(slot), &dummy_paramset,
- PARM_SIZE);
- clear_bit(slot, edma_cc[ctlr]->edma_inuse);
+ memcpy_toio(cc->base + PARM_OFFSET(slot), &dummy_paramset, PARM_SIZE);
+ clear_bit(slot, cc->edma_inuse);
}
EXPORT_SYMBOL(edma_free_slot);
@@ -751,16 +744,15 @@ EXPORT_SYMBOL(edma_free_slot);
*
* Returns the position of the current active slot
*/
-dma_addr_t edma_get_position(unsigned slot, bool dst)
+dma_addr_t edma_get_position(struct edma *cc, unsigned slot, bool dst)
{
- u32 offs, ctlr = EDMA_CTLR(slot);
+ u32 offs;
slot = EDMA_CHAN_SLOT(slot);
-
offs = PARM_OFFSET(slot);
offs += dst ? PARM_DST : PARM_SRC;
- return edma_read(edma_cc[ctlr], offs);
+ return edma_read(cc, offs);
}
/**
@@ -770,21 +762,15 @@ dma_addr_t edma_get_position(unsigned slot, bool dst)
*
* The originating slot should not be part of any active DMA transfer.
*/
-void edma_link(unsigned from, unsigned to)
+void edma_link(struct edma *cc, unsigned from, unsigned to)
{
- unsigned ctlr_from, ctlr_to;
-
- ctlr_from = EDMA_CTLR(from);
from = EDMA_CHAN_SLOT(from);
- ctlr_to = EDMA_CTLR(to);
to = EDMA_CHAN_SLOT(to);
-
- if (from >= edma_cc[ctlr_from]->num_slots)
+ if (from >= cc->num_slots || to >= cc->num_slots)
return;
- if (to >= edma_cc[ctlr_to]->num_slots)
- return;
- edma_parm_modify(edma_cc[ctlr_from], PARM_LINK_BCNTRLD, from, 0xffff0000,
- PARM_OFFSET(to));
+
+ edma_parm_modify(cc, PARM_LINK_BCNTRLD, from, 0xffff0000,
+ PARM_OFFSET(to));
}
EXPORT_SYMBOL(edma_link);
@@ -802,16 +788,13 @@ EXPORT_SYMBOL(edma_link);
* calls to set up those parameters in small pieces, and provides
* complete control over all transfer options.
*/
-void edma_write_slot(unsigned slot, const struct edmacc_param *param)
+void edma_write_slot(struct edma *cc, unsigned slot,
+ const struct edmacc_param *param)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(slot);
slot = EDMA_CHAN_SLOT(slot);
-
- if (slot >= edma_cc[ctlr]->num_slots)
+ if (slot >= cc->num_slots)
return;
- memcpy_toio(edma_cc[ctlr]->base + PARM_OFFSET(slot), param, PARM_SIZE);
+ memcpy_toio(cc->base + PARM_OFFSET(slot), param, PARM_SIZE);
}
EXPORT_SYMBOL(edma_write_slot);
@@ -823,17 +806,12 @@ EXPORT_SYMBOL(edma_write_slot);
* Use this to read data from a parameter RAM slot, perhaps to
* save them as a template for later reuse.
*/
-void edma_read_slot(unsigned slot, struct edmacc_param *param)
+void edma_read_slot(struct edma *cc, unsigned slot, struct edmacc_param *param)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(slot);
slot = EDMA_CHAN_SLOT(slot);
-
- if (slot >= edma_cc[ctlr]->num_slots)
+ if (slot >= cc->num_slots)
return;
- memcpy_fromio(param, edma_cc[ctlr]->base + PARM_OFFSET(slot),
- PARM_SIZE);
+ memcpy_fromio(param, cc->base + PARM_OFFSET(slot), PARM_SIZE);
}
EXPORT_SYMBOL(edma_read_slot);
@@ -848,18 +826,19 @@ EXPORT_SYMBOL(edma_read_slot);
* This temporarily disables EDMA hardware events on the specified channel,
* preventing them from triggering new transfers on its behalf
*/
-void edma_pause(unsigned channel)
+void edma_pause(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel < edma_cc[ctlr]->num_channels) {
+ if (channel < cc->num_channels) {
unsigned int mask = BIT(channel & 0x1f);
- edma_shadow0_write_array(edma_cc[ctlr], SH_EECR, channel >> 5,
- mask);
+ edma_shadow0_write_array(cc, SH_EECR, channel >> 5, mask);
}
}
EXPORT_SYMBOL(edma_pause);
@@ -870,36 +849,39 @@ EXPORT_SYMBOL(edma_pause);
*
* This re-enables EDMA hardware events on the specified channel.
*/
-void edma_resume(unsigned channel)
+void edma_resume(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel < edma_cc[ctlr]->num_channels) {
+ if (channel < cc->num_channels) {
unsigned int mask = BIT(channel & 0x1f);
- edma_shadow0_write_array(edma_cc[ctlr], SH_EESR, channel >> 5,
- mask);
+ edma_shadow0_write_array(cc, SH_EESR, channel >> 5, mask);
}
}
EXPORT_SYMBOL(edma_resume);
-int edma_trigger_channel(unsigned channel)
+int edma_trigger_channel(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
unsigned int mask;
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return -EINVAL;
+ }
channel = EDMA_CHAN_SLOT(channel);
mask = BIT(channel & 0x1f);
- edma_shadow0_write_array(edma_cc[ctlr], SH_ESR, (channel >> 5), mask);
+ edma_shadow0_write_array(cc, SH_ESR, (channel >> 5), mask);
pr_debug("EDMA: ESR%d %08x\n", (channel >> 5),
- edma_shadow0_read_array(edma_cc[ctlr], SH_ESR,
- (channel >> 5)));
+ edma_shadow0_read_array(cc, SH_ESR, (channel >> 5)));
return 0;
}
EXPORT_SYMBOL(edma_trigger_channel);
@@ -915,15 +897,16 @@ EXPORT_SYMBOL(edma_trigger_channel);
*
* Returns zero on success, else negative errno.
*/
-int edma_start(unsigned channel)
+int edma_start(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return -EINVAL;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel < edma_cc[ctlr]->num_channels) {
- struct edma *cc = edma_cc[ctlr];
+ if (channel < cc->num_channels) {
int j = channel >> 5;
unsigned int mask = BIT(channel & 0x1f);
@@ -962,15 +945,16 @@ EXPORT_SYMBOL(edma_start);
* may not be resumed, and the channel's Parameter RAM should be
* reinitialized before being reused.
*/
-void edma_stop(unsigned channel)
+void edma_stop(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel < edma_cc[ctlr]->num_channels) {
- struct edma *cc = edma_cc[ctlr];
+ if (channel < cc->num_channels) {
int j = channel >> 5;
unsigned int mask = BIT(channel & 0x1f);
@@ -1005,15 +989,16 @@ EXPORT_SYMBOL(edma_stop);
*
*****************************************************************************/
-void edma_clean_channel(unsigned channel)
+void edma_clean_channel(struct edma *cc, unsigned channel)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel < edma_cc[ctlr]->num_channels) {
- struct edma *cc = edma_cc[ctlr];
+ if (channel < cc->num_channels) {
int j = (channel >> 5);
unsigned int mask = BIT(channel & 0x1f);
@@ -1037,26 +1022,35 @@ EXPORT_SYMBOL(edma_clean_channel);
*
* Can be used to move a channel to a selected event queue.
*/
-void edma_assign_channel_eventq(unsigned channel, enum dma_event_q eventq_no)
+void edma_assign_channel_eventq(struct edma *cc, unsigned channel,
+ enum dma_event_q eventq_no)
{
- unsigned ctlr;
-
- ctlr = EDMA_CTLR(channel);
+ if (cc->id != EDMA_CTLR(channel)) {
+ dev_err(cc->dev, "%s: ID mismatch for eDMA%d: %d\n", __func__,
+ cc->id, EDMA_CTLR(channel));
+ return;
+ }
channel = EDMA_CHAN_SLOT(channel);
- if (channel >= edma_cc[ctlr]->num_channels)
+ if (channel >= cc->num_channels)
return;
/* default to low priority queue */
if (eventq_no == EVENTQ_DEFAULT)
- eventq_no = edma_cc[ctlr]->default_queue;
- if (eventq_no >= edma_cc[ctlr]->num_tc)
+ eventq_no = cc->default_queue;
+ if (eventq_no >= cc->num_tc)
return;
- map_dmach_queue(edma_cc[ctlr], channel, eventq_no);
+ map_dmach_queue(cc, channel, eventq_no);
}
EXPORT_SYMBOL(edma_assign_channel_eventq);
+struct edma *edma_get_data(struct device *edma_dev)
+{
+ return dev_get_drvdata(edma_dev);
+}
+
+
static int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata,
struct edma *edma_cc, int cc_id)
{
@@ -1278,11 +1272,10 @@ static int edma_probe(struct platform_device *pdev)
}
}
- edma_cc[dev_id] = devm_kzalloc(dev, sizeof(struct edma), GFP_KERNEL);
- if (!edma_cc[dev_id])
+ cc = devm_kzalloc(dev, sizeof(struct edma), GFP_KERNEL);
+ if (!cc)
return -ENOMEM;
- cc = edma_cc[dev_id];
cc->dev = dev;
cc->id = dev_id;
dev_set_drvdata(dev, cc);
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index fcb4680efed7..53d48b2a700d 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -119,6 +119,7 @@ struct edma_chan {
};
struct edma_cc {
+ struct edma *cc;
int ctlr;
struct dma_device dma_slave;
struct edma_chan slave_chans[EDMA_CHANS];
@@ -150,6 +151,7 @@ static void edma_desc_free(struct virt_dma_desc *vdesc)
/* Dispatch a queued descriptor to the controller (caller holds lock) */
static void edma_execute(struct edma_chan *echan)
{
+ struct edma *cc = echan->ecc->cc;
struct virt_dma_desc *vdesc;
struct edma_desc *edesc;
struct device *dev = echan->vchan.chan.device->dev;
@@ -174,7 +176,7 @@ static void edma_execute(struct edma_chan *echan)
/* Write descriptor PaRAM set(s) */
for (i = 0; i < nslots; i++) {
j = i + edesc->processed;
- edma_write_slot(echan->slot[i], &edesc->pset[j].param);
+ edma_write_slot(cc, echan->slot[i], &edesc->pset[j].param);
edesc->sg_len += edesc->pset[j].len;
dev_vdbg(echan->vchan.chan.device->dev,
"\n pset[%d]:\n"
@@ -199,7 +201,7 @@ static void edma_execute(struct edma_chan *echan)
edesc->pset[j].param.link_bcntrld);
/* Link to the previous slot if not the last set */
if (i != (nslots - 1))
- edma_link(echan->slot[i], echan->slot[i+1]);
+ edma_link(cc, echan->slot[i], echan->slot[i+1]);
}
edesc->processed += nslots;
@@ -211,9 +213,9 @@ static void edma_execute(struct edma_chan *echan)
*/
if (edesc->processed == edesc->pset_nr) {
if (edesc->cyclic)
- edma_link(echan->slot[nslots-1], echan->slot[1]);
+ edma_link(cc, echan->slot[nslots-1], echan->slot[1]);
else
- edma_link(echan->slot[nslots-1],
+ edma_link(cc, echan->slot[nslots-1],
echan->ecc->dummy_slot);
}
@@ -224,19 +226,19 @@ static void edma_execute(struct edma_chan *echan)
* transfers of MAX_NR_SG
*/
dev_dbg(dev, "missed event on channel %d\n", echan->ch_num);
- edma_clean_channel(echan->ch_num);
- edma_stop(echan->ch_num);
- edma_start(echan->ch_num);
- edma_trigger_channel(echan->ch_num);
+ edma_clean_channel(cc, echan->ch_num);
+ edma_stop(cc, echan->ch_num);
+ edma_start(cc, echan->ch_num);
+ edma_trigger_channel(cc, echan->ch_num);
echan->missed = 0;
} else if (edesc->processed <= MAX_NR_SG) {
dev_dbg(dev, "first transfer starting on channel %d\n",
echan->ch_num);
- edma_start(echan->ch_num);
+ edma_start(cc, echan->ch_num);
} else {
dev_dbg(dev, "chan: %d: completed %d elements, resuming\n",
echan->ch_num, edesc->processed);
- edma_resume(echan->ch_num);
+ edma_resume(cc, echan->ch_num);
}
}
@@ -254,10 +256,11 @@ static int edma_terminate_all(struct dma_chan *chan)
* echan->edesc is NULL and exit.)
*/
if (echan->edesc) {
- edma_stop(echan->ch_num);
+ edma_stop(echan->ecc->cc, echan->ch_num);
/* Move the cyclic channel back to default queue */
if (echan->edesc->cyclic)
- edma_assign_channel_eventq(echan->ch_num,
+ edma_assign_channel_eventq(echan->ecc->cc,
+ echan->ch_num,
EVENTQ_DEFAULT);
/*
* free the running request descriptor
@@ -295,7 +298,7 @@ static int edma_dma_pause(struct dma_chan *chan)
if (!echan->edesc)
return -EINVAL;
- edma_pause(echan->ch_num);
+ edma_pause(echan->ecc->cc, echan->ch_num);
return 0;
}
@@ -303,7 +306,7 @@ static int edma_dma_resume(struct dma_chan *chan)
{
struct edma_chan *echan = to_edma_chan(chan);
- edma_resume(echan->ch_num);
+ edma_resume(echan->ecc->cc, echan->ch_num);
return 0;
}
@@ -485,8 +488,7 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
for (i = 0; i < nslots; i++) {
if (echan->slot[i] < 0) {
echan->slot[i] =
- edma_alloc_slot(EDMA_CTLR(echan->ch_num),
- EDMA_SLOT_ANY);
+ edma_alloc_slot(echan->ecc->cc, EDMA_SLOT_ANY);
if (echan->slot[i] < 0) {
kfree(edesc);
dev_err(dev, "%s: Failed to allocate slot\n",
@@ -641,8 +643,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
/* Allocate a PaRAM slot, if needed */
if (echan->slot[i] < 0) {
echan->slot[i] =
- edma_alloc_slot(EDMA_CTLR(echan->ch_num),
- EDMA_SLOT_ANY);
+ edma_alloc_slot(echan->ecc->cc, EDMA_SLOT_ANY);
if (echan->slot[i] < 0) {
kfree(edesc);
dev_err(dev, "%s: Failed to allocate slot\n",
@@ -703,7 +704,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
}
/* Place the cyclic channel to highest priority queue */
- edma_assign_channel_eventq(echan->ch_num, EVENTQ_0);
+ edma_assign_channel_eventq(echan->ecc->cc, echan->ch_num, EVENTQ_0);
return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
}
@@ -711,6 +712,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
{
struct edma_chan *echan = data;
+ struct edma *cc = echan->ecc->cc;
struct device *dev = echan->vchan.chan.device->dev;
struct edma_desc *edesc;
struct edmacc_param p;
@@ -727,13 +729,13 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
} else if (edesc->processed == edesc->pset_nr) {
dev_dbg(dev, "Transfer complete, stopping channel %d\n", ch_num);
edesc->residue = 0;
- edma_stop(echan->ch_num);
+ edma_stop(cc, echan->ch_num);
vchan_cookie_complete(&edesc->vdesc);
echan->edesc = NULL;
} else {
dev_dbg(dev, "Intermediate transfer complete on channel %d\n", ch_num);
- edma_pause(echan->ch_num);
+ edma_pause(cc, echan->ch_num);
/* Update statistics for tx_status */
edesc->residue -= edesc->sg_len;
@@ -744,7 +746,7 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
}
break;
case EDMA_DMA_CC_ERROR:
- edma_read_slot(EDMA_CHAN_SLOT(echan->slot[0]), &p);
+ edma_read_slot(cc, echan->slot[0], &p);
/*
* Issue later based on missed flag which will be sure
@@ -767,10 +769,10 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
* missed, so its safe to issue it here.
*/
dev_dbg(dev, "Error occurred but slot is non-null, TRIGGERING\n");
- edma_clean_channel(echan->ch_num);
- edma_stop(echan->ch_num);
- edma_start(echan->ch_num);
- edma_trigger_channel(echan->ch_num);
+ edma_clean_channel(cc, echan->ch_num);
+ edma_stop(cc, echan->ch_num);
+ edma_start(cc, echan->ch_num);
+ edma_trigger_channel(cc, echan->ch_num);
}
break;
default:
@@ -789,8 +791,8 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
int a_ch_num;
LIST_HEAD(descs);
- a_ch_num = edma_alloc_channel(echan->ch_num, edma_callback,
- echan, EVENTQ_DEFAULT);
+ a_ch_num = edma_alloc_channel(echan->ecc->cc, echan->ch_num,
+ edma_callback, echan, EVENTQ_DEFAULT);
if (a_ch_num < 0) {
ret = -ENODEV;
@@ -814,7 +816,7 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
return 0;
err_wrong_chan:
- edma_free_channel(a_ch_num);
+ edma_free_channel(echan->ecc->cc, a_ch_num);
err_no_chan:
return ret;
}
@@ -827,21 +829,21 @@ static void edma_free_chan_resources(struct dma_chan *chan)
int i;
/* Terminate transfers */
- edma_stop(echan->ch_num);
+ edma_stop(echan->ecc->cc, echan->ch_num);
vchan_free_chan_resources(&echan->vchan);
/* Free EDMA PaRAM slots */
for (i = 1; i < EDMA_MAX_SLOTS; i++) {
if (echan->slot[i] >= 0) {
- edma_free_slot(echan->slot[i]);
+ edma_free_slot(echan->ecc->cc, echan->slot[i]);
echan->slot[i] = -1;
}
}
/* Free EDMA channel */
if (echan->alloced) {
- edma_free_channel(echan->ch_num);
+ edma_free_channel(echan->ecc->cc, echan->ch_num);
echan->alloced = false;
}
@@ -871,7 +873,8 @@ static u32 edma_residue(struct edma_desc *edesc)
* We always read the dst/src position from the first RamPar
* pset. That's the one which is active now.
*/
- pos = edma_get_position(edesc->echan->slot[0], dst);
+ pos = edma_get_position(edesc->echan->ecc->cc, edesc->echan->slot[0],
+ dst);
/*
* Cyclic is simple. Just subtract pset[0].addr from pos.
@@ -1008,8 +1011,12 @@ static int edma_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ecc->cc = edma_get_data(pdev->dev.parent);
+ if (!ecc->cc)
+ return -ENODEV;
+
ecc->ctlr = pdev->id;
- ecc->dummy_slot = edma_alloc_slot(ecc->ctlr, EDMA_SLOT_ANY);
+ ecc->dummy_slot = edma_alloc_slot(ecc->cc, EDMA_SLOT_ANY);
if (ecc->dummy_slot < 0) {
dev_err(&pdev->dev, "Can't allocate PaRAM dummy slot\n");
return ecc->dummy_slot;
@@ -1042,7 +1049,7 @@ static int edma_probe(struct platform_device *pdev)
return 0;
err_reg1:
- edma_free_slot(ecc->dummy_slot);
+ edma_free_slot(ecc->cc, ecc->dummy_slot);
return ret;
}
@@ -1055,7 +1062,7 @@ static int edma_remove(struct platform_device *pdev)
if (parent_node)
of_dma_controller_free(parent_node);
dma_async_device_unregister(&ecc->dma_slave);
- edma_free_slot(ecc->dummy_slot);
+ edma_free_slot(ecc->cc, ecc->dummy_slot);
return 0;
}
diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h
index c1862423b356..466021c03169 100644
--- a/include/linux/platform_data/edma.h
+++ b/include/linux/platform_data/edma.h
@@ -92,32 +92,40 @@ enum dma_event_q {
#define EDMA_MAX_CC 2
+struct edma;
+
+struct edma *edma_get_data(struct device *edma_dev);
+
/* alloc/free DMA channels and their dedicated parameter RAM slots */
-int edma_alloc_channel(int channel,
+int edma_alloc_channel(struct edma *cc, int channel,
void (*callback)(unsigned channel, u16 ch_status, void *data),
void *data, enum dma_event_q);
-void edma_free_channel(unsigned channel);
+void edma_free_channel(struct edma *cc, unsigned channel);
/* alloc/free parameter RAM slots */
-int edma_alloc_slot(unsigned ctlr, int slot);
-void edma_free_slot(unsigned slot);
+int edma_alloc_slot(struct edma *cc, int slot);
+void edma_free_slot(struct edma *cc, unsigned slot);
/* calls that operate on part of a parameter RAM slot */
-dma_addr_t edma_get_position(unsigned slot, bool dst);
-void edma_link(unsigned from, unsigned to);
+dma_addr_t edma_get_position(struct edma *cc, unsigned slot, bool dst);
+void edma_link(struct edma *cc, unsigned from, unsigned to);
/* calls that operate on an entire parameter RAM slot */
-void edma_write_slot(unsigned slot, const struct edmacc_param *params);
-void edma_read_slot(unsigned slot, struct edmacc_param *params);
+void edma_write_slot(struct edma *cc, unsigned slot,
+ const struct edmacc_param *params);
+void edma_read_slot(struct edma *cc, unsigned slot,
+ struct edmacc_param *params);
/* channel control operations */
-int edma_start(unsigned channel);
-void edma_stop(unsigned channel);
-void edma_clean_channel(unsigned channel);
-void edma_pause(unsigned channel);
-void edma_resume(unsigned channel);
+int edma_start(struct edma *cc, unsigned channel);
+void edma_stop(struct edma *cc, unsigned channel);
+void edma_clean_channel(struct edma *cc, unsigned channel);
+void edma_pause(struct edma *cc, unsigned channel);
+void edma_resume(struct edma *cc, unsigned channel);
+int edma_trigger_channel(struct edma *cc, unsigned channel);
-void edma_assign_channel_eventq(unsigned channel, enum dma_event_q eventq_no);
+void edma_assign_channel_eventq(struct edma *cc, unsigned channel,
+ enum dma_event_q eventq_no);
struct edma_rsv_info {
@@ -141,6 +149,4 @@ struct edma_soc_info {
const s16 (*xbar_chans)[2];
};
-int edma_trigger_channel(unsigned);
-
#endif