diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2015-10-14 14:42:46 +0300 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2015-10-14 17:27:11 +0300 |
commit | d4cb7f404247173e2c760a01bf06fd1016a8b0d4 (patch) | |
tree | 3efac8cfaf3d4ccd02fb8494e6e43f6ba0306d09 /arch/arm/common | |
parent | 8fa7ff4fc01d7f43cd03143e4ec58323865bfacf (diff) | |
download | linux-d4cb7f404247173e2c760a01bf06fd1016a8b0d4.tar.xz |
ARM: davinci/common: Convert edma driver to handle one eDMA instance per driver
Currently we have one device created to handle all (maximum 2) eDMAs in the
system.
With this change all eDMA instance will have it's own device/driver.
This change is needed for further cleanups in the eDMA driver stack since
the one device/driver to handle all eDMAs in the system was not flexible
enough and prevents the upcoming work.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Acked-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/edma.c | 356 |
1 files changed, 160 insertions, 196 deletions
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index e9c4cb16a47e..7c2fe527e53b 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -235,6 +235,7 @@ static inline void clear_bits(int offset, int len, unsigned long *p) /* actual number of DMA channels and slots on this silicon */ struct edma { + struct device *dev; /* how many dma resources of each type */ unsigned num_channels; unsigned num_region; @@ -246,6 +247,7 @@ struct edma { const s8 *noevent; struct edma_soc_info *info; + int id; /* The edma_inuse bit for each PaRAM slot is clear unless the * channel is in use ... by ARM or DSP, for QDMA, or whatever. @@ -258,9 +260,6 @@ struct edma { */ DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH); - unsigned irq_res_start; - unsigned irq_res_end; - struct dma_interrupt_data { void (*callback)(unsigned channel, unsigned short ch_status, void *data); @@ -349,17 +348,6 @@ setup_dma_interrupt(unsigned lch, } } -static int irq2ctlr(int irq) -{ - if (irq >= edma_cc[0]->irq_res_start && irq <= edma_cc[0]->irq_res_end) - return 0; - else if (irq >= edma_cc[1]->irq_res_start && - irq <= edma_cc[1]->irq_res_end) - return 1; - - return -1; -} - /****************************************************************************** * * DMA interrupt handler @@ -367,16 +355,17 @@ static int irq2ctlr(int irq) *****************************************************************************/ static irqreturn_t dma_irq_handler(int irq, void *data) { + struct edma *cc = data; int ctlr; u32 sh_ier; u32 sh_ipr; u32 bank; - ctlr = irq2ctlr(irq); + ctlr = cc->id; if (ctlr < 0) return IRQ_NONE; - dev_dbg(data, "dma_irq_handler\n"); + dev_dbg(cc->dev, "dma_irq_handler\n"); sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 0); if (!sh_ipr) { @@ -394,7 +383,7 @@ static irqreturn_t dma_irq_handler(int irq, void *data) u32 slot; u32 channel; - dev_dbg(data, "IPR%d %08x\n", bank, sh_ipr); + dev_dbg(cc->dev, "IPR%d %08x\n", bank, sh_ipr); slot = __ffs(sh_ipr); sh_ipr &= ~(BIT(slot)); @@ -404,11 +393,11 @@ static irqreturn_t dma_irq_handler(int irq, void *data) /* Clear the corresponding IPR bits */ edma_shadow0_write_array(ctlr, SH_ICR, bank, BIT(slot)); - if (edma_cc[ctlr]->intr_data[channel].callback) - edma_cc[ctlr]->intr_data[channel].callback( + if (cc->intr_data[channel].callback) + cc->intr_data[channel].callback( EDMA_CTLR_CHAN(ctlr, channel), EDMA_DMA_COMPLETE, - edma_cc[ctlr]->intr_data[channel].data); + cc->intr_data[channel].data); } } while (sh_ipr); @@ -423,15 +412,16 @@ static irqreturn_t dma_irq_handler(int irq, void *data) *****************************************************************************/ static irqreturn_t dma_ccerr_handler(int irq, void *data) { + struct edma *cc = data; int i; int ctlr; unsigned int cnt = 0; - ctlr = irq2ctlr(irq); + ctlr = cc->id; if (ctlr < 0) return IRQ_NONE; - dev_dbg(data, "dma_ccerr_handler\n"); + dev_dbg(cc->dev, "dma_ccerr_handler\n"); if ((edma_read_array(ctlr, EDMA_EMR, 0) == 0) && (edma_read_array(ctlr, EDMA_EMR, 1) == 0) && @@ -446,8 +436,8 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) else if (edma_read_array(ctlr, EDMA_EMR, 1)) j = 1; if (j >= 0) { - dev_dbg(data, "EMR%d %08x\n", j, - edma_read_array(ctlr, EDMA_EMR, j)); + dev_dbg(cc->dev, "EMR%d %08x\n", j, + edma_read_array(ctlr, EDMA_EMR, j)); for (i = 0; i < 32; i++) { int k = (j << 5) + i; if (edma_read_array(ctlr, EDMA_EMR, j) & @@ -458,19 +448,16 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) /* Clear any SER */ edma_shadow0_write_array(ctlr, SH_SECR, j, BIT(i)); - if (edma_cc[ctlr]->intr_data[k]. - callback) { - edma_cc[ctlr]->intr_data[k]. - callback( - EDMA_CTLR_CHAN(ctlr, k), - EDMA_DMA_CC_ERROR, - edma_cc[ctlr]->intr_data - [k].data); + if (cc->intr_data[k].callback) { + cc->intr_data[k].callback( + EDMA_CTLR_CHAN(ctlr, k), + EDMA_DMA_CC_ERROR, + cc->intr_data[k].data); } } } } else if (edma_read(ctlr, EDMA_QEMR)) { - dev_dbg(data, "QEMR %02x\n", + dev_dbg(cc->dev, "QEMR %02x\n", edma_read(ctlr, EDMA_QEMR)); for (i = 0; i < 8; i++) { if (edma_read(ctlr, EDMA_QEMR) & BIT(i)) { @@ -483,7 +470,7 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data) } } } else if (edma_read(ctlr, EDMA_CCERR)) { - dev_dbg(data, "CCERR %08x\n", + dev_dbg(cc->dev, "CCERR %08x\n", edma_read(ctlr, EDMA_CCERR)); /* FIXME: CCERR.BIT(16) ignored! much better * to just write CCERRCLR with CCERR value... @@ -1239,21 +1226,19 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev, static int edma_probe(struct platform_device *pdev) { - struct edma_soc_info **info = pdev->dev.platform_data; - struct edma_soc_info *ninfo[EDMA_MAX_CC] = {NULL}; + struct edma_soc_info *info = pdev->dev.platform_data; s8 (*queue_priority_mapping)[2]; - int i, j, off, ln, found = 0; - int status = -1; + int i, off, ln; const s16 (*rsv_chans)[2]; const s16 (*rsv_slots)[2]; const s16 (*xbar_chans)[2]; - int irq[EDMA_MAX_CC] = {0, 0}; - int err_irq[EDMA_MAX_CC] = {0, 0}; - struct resource *r[EDMA_MAX_CC] = {NULL}; - struct resource res[EDMA_MAX_CC]; - char res_name[10]; + int irq; + char *irq_name; + struct resource *mem; struct device_node *node = pdev->dev.of_node; struct device *dev = &pdev->dev; + int dev_id = pdev->id; + struct edma *cc; int ret; struct platform_device_info edma_dev_info = { .name = "edma-dma-engine", @@ -1261,6 +1246,17 @@ static int edma_probe(struct platform_device *pdev) .parent = &pdev->dev, }; + /* When booting with DT the pdev->id is -1 */ + if (dev_id < 0) + dev_id = arch_num_cc; + + if (dev_id >= EDMA_MAX_CC) { + dev_err(dev, + "eDMA3 with device id 0 and 1 is supported (id: %d)\n", + dev_id); + return -EINVAL; + } + if (node) { /* Check if this is a second instance registered */ if (arch_num_cc) { @@ -1268,13 +1264,11 @@ static int edma_probe(struct platform_device *pdev) return -ENODEV; } - ninfo[0] = edma_setup_info_from_dt(dev, node); - if (IS_ERR(ninfo[0])) { + info = edma_setup_info_from_dt(dev, node); + if (IS_ERR(info)) { dev_err(dev, "failed to get DT data\n"); - return PTR_ERR(ninfo[0]); + return PTR_ERR(info); } - - info = ninfo; } if (!info) @@ -1287,154 +1281,132 @@ static int edma_probe(struct platform_device *pdev) return ret; } - for (j = 0; j < EDMA_MAX_CC; j++) { - if (!info[j]) { - if (!found) - return -ENODEV; - break; - } - if (node) { - ret = of_address_to_resource(node, j, &res[j]); - if (!ret) - r[j] = &res[j]; - } else { - sprintf(res_name, "edma_cc%d", j); - r[j] = platform_get_resource_byname(pdev, - IORESOURCE_MEM, - res_name); - } - if (!r[j]) { - if (found) - break; - else - return -ENODEV; - } else { - found = 1; + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma3_cc"); + if (!mem) { + dev_dbg(dev, "mem resource not found, using index 0\n"); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "no mem resource?\n"); + return -ENODEV; } + } - edmacc_regs_base[j] = devm_ioremap_resource(&pdev->dev, r[j]); - if (IS_ERR(edmacc_regs_base[j])) - return PTR_ERR(edmacc_regs_base[j]); + edmacc_regs_base[dev_id] = devm_ioremap_resource(dev, mem); + if (IS_ERR(edmacc_regs_base[dev_id])) + return PTR_ERR(edmacc_regs_base[dev_id]); - edma_cc[j] = devm_kzalloc(&pdev->dev, sizeof(struct edma), - GFP_KERNEL); - if (!edma_cc[j]) - return -ENOMEM; + edma_cc[dev_id] = devm_kzalloc(dev, sizeof(struct edma), GFP_KERNEL); + if (!edma_cc[dev_id]) + return -ENOMEM; - /* Get eDMA3 configuration from IP */ - ret = edma_setup_from_hw(dev, info[j], edma_cc[j], j); - if (ret) - return ret; + cc = edma_cc[dev_id]; + cc->dev = dev; + cc->id = dev_id; + dev_set_drvdata(dev, cc); - edma_cc[j]->default_queue = info[j]->default_queue; + /* Get eDMA3 configuration from IP */ + ret = edma_setup_from_hw(dev, info, cc, dev_id); + if (ret) + return ret; - dev_dbg(&pdev->dev, "DMA REG BASE ADDR=%p\n", - edmacc_regs_base[j]); + cc->default_queue = info->default_queue; - for (i = 0; i < edma_cc[j]->num_slots; i++) - memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i), - &dummy_paramset, PARM_SIZE); + dev_dbg(dev, "DMA REG BASE ADDR=%p\n", edmacc_regs_base[dev_id]); - /* Mark all channels as unused */ - memset(edma_cc[j]->edma_unused, 0xff, - sizeof(edma_cc[j]->edma_unused)); + for (i = 0; i < cc->num_slots; i++) + memcpy_toio(edmacc_regs_base[dev_id] + PARM_OFFSET(i), + &dummy_paramset, PARM_SIZE); - if (info[j]->rsv) { + /* Mark all channels as unused */ + memset(cc->edma_unused, 0xff, sizeof(cc->edma_unused)); - /* Clear the reserved channels in unused list */ - rsv_chans = info[j]->rsv->rsv_chans; - if (rsv_chans) { - for (i = 0; rsv_chans[i][0] != -1; i++) { - off = rsv_chans[i][0]; - ln = rsv_chans[i][1]; - clear_bits(off, ln, - edma_cc[j]->edma_unused); - } - } + if (info->rsv) { - /* Set the reserved slots in inuse list */ - rsv_slots = info[j]->rsv->rsv_slots; - if (rsv_slots) { - for (i = 0; rsv_slots[i][0] != -1; i++) { - off = rsv_slots[i][0]; - ln = rsv_slots[i][1]; - set_bits(off, ln, - edma_cc[j]->edma_inuse); - } + /* Clear the reserved channels in unused list */ + rsv_chans = info->rsv->rsv_chans; + if (rsv_chans) { + for (i = 0; rsv_chans[i][0] != -1; i++) { + off = rsv_chans[i][0]; + ln = rsv_chans[i][1]; + clear_bits(off, ln, cc->edma_unused); } } - /* Clear the xbar mapped channels in unused list */ - xbar_chans = info[j]->xbar_chans; - if (xbar_chans) { - for (i = 0; xbar_chans[i][1] != -1; i++) { - off = xbar_chans[i][1]; - clear_bits(off, 1, - edma_cc[j]->edma_unused); + /* Set the reserved slots in inuse list */ + rsv_slots = info->rsv->rsv_slots; + if (rsv_slots) { + for (i = 0; rsv_slots[i][0] != -1; i++) { + off = rsv_slots[i][0]; + ln = rsv_slots[i][1]; + set_bits(off, ln, cc->edma_inuse); } } + } - if (node) { - irq[j] = irq_of_parse_and_map(node, 0); - err_irq[j] = irq_of_parse_and_map(node, 2); - } else { - char irq_name[10]; - - sprintf(irq_name, "edma%d", j); - irq[j] = platform_get_irq_byname(pdev, irq_name); - - sprintf(irq_name, "edma%d_err", j); - err_irq[j] = platform_get_irq_byname(pdev, irq_name); - } - edma_cc[j]->irq_res_start = irq[j]; - edma_cc[j]->irq_res_end = err_irq[j]; - - status = devm_request_irq(dev, irq[j], dma_irq_handler, 0, - "edma", dev); - if (status < 0) { - dev_dbg(&pdev->dev, - "devm_request_irq %d failed --> %d\n", - irq[j], status); - return status; + /* Clear the xbar mapped channels in unused list */ + xbar_chans = info->xbar_chans; + if (xbar_chans) { + for (i = 0; xbar_chans[i][1] != -1; i++) { + off = xbar_chans[i][1]; + clear_bits(off, 1, cc->edma_unused); } + } - status = devm_request_irq(dev, err_irq[j], dma_ccerr_handler, 0, - "edma_error", dev); - if (status < 0) { - dev_dbg(&pdev->dev, - "devm_request_irq %d failed --> %d\n", - err_irq[j], status); - return status; + irq = platform_get_irq_byname(pdev, "edma3_ccint"); + if (irq < 0 && node) + irq = irq_of_parse_and_map(node, 0); + + if (irq >= 0) { + irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint", + dev_name(dev)); + ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name, + cc); + if (ret) { + dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret); + return ret; } + } - for (i = 0; i < edma_cc[j]->num_channels; i++) - map_dmach_queue(j, i, info[j]->default_queue); + irq = platform_get_irq_byname(pdev, "edma3_ccerrint"); + if (irq < 0 && node) + irq = irq_of_parse_and_map(node, 2); + + if (irq >= 0) { + irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint", + dev_name(dev)); + ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name, + cc); + if (ret) { + dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret); + return ret; + } + } - queue_priority_mapping = info[j]->queue_priority_mapping; + for (i = 0; i < cc->num_channels; i++) + map_dmach_queue(dev_id, i, info->default_queue); - /* Event queue priority mapping */ - for (i = 0; queue_priority_mapping[i][0] != -1; i++) - assign_priority_to_queue(j, - queue_priority_mapping[i][0], - queue_priority_mapping[i][1]); + queue_priority_mapping = info->queue_priority_mapping; - /* Map the channel to param entry if channel mapping logic - * exist - */ - if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST) - map_dmach_param(j); + /* Event queue priority mapping */ + for (i = 0; queue_priority_mapping[i][0] != -1; i++) + assign_priority_to_queue(dev_id, queue_priority_mapping[i][0], + queue_priority_mapping[i][1]); - for (i = 0; i < edma_cc[j]->num_region; i++) { - edma_write_array2(j, EDMA_DRAE, i, 0, 0x0); - edma_write_array2(j, EDMA_DRAE, i, 1, 0x0); - edma_write_array(j, EDMA_QRAE, i, 0x0); - } - edma_cc[j]->info = info[j]; - arch_num_cc++; + /* Map the channel to param entry if channel mapping logic exist */ + if (edma_read(dev_id, EDMA_CCCFG) & CHMAP_EXIST) + map_dmach_param(dev_id); - edma_dev_info.id = j; - platform_device_register_full(&edma_dev_info); + for (i = 0; i < cc->num_region; i++) { + edma_write_array2(dev_id, EDMA_DRAE, i, 0, 0x0); + edma_write_array2(dev_id, EDMA_DRAE, i, 1, 0x0); + edma_write_array(dev_id, EDMA_QRAE, i, 0x0); } + cc->info = info; + arch_num_cc++; + + edma_dev_info.id = dev_id; + + platform_device_register_full(&edma_dev_info); return 0; } @@ -1442,38 +1414,30 @@ static int edma_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int edma_pm_resume(struct device *dev) { - int i, j; + struct edma *cc = dev_get_drvdata(dev); + int i; + s8 (*queue_priority_mapping)[2]; - for (j = 0; j < arch_num_cc; j++) { - struct edma *cc = edma_cc[j]; + queue_priority_mapping = cc->info->queue_priority_mapping; - s8 (*queue_priority_mapping)[2]; + /* Event queue priority mapping */ + for (i = 0; queue_priority_mapping[i][0] != -1; i++) + assign_priority_to_queue(cc->id, queue_priority_mapping[i][0], + queue_priority_mapping[i][1]); - queue_priority_mapping = cc->info->queue_priority_mapping; + /* Map the channel to param entry if channel mapping logic */ + if (edma_read(cc->id, EDMA_CCCFG) & CHMAP_EXIST) + map_dmach_param(cc->id); - /* Event queue priority mapping */ - for (i = 0; queue_priority_mapping[i][0] != -1; i++) - assign_priority_to_queue(j, - queue_priority_mapping[i][0], - queue_priority_mapping[i][1]); + for (i = 0; i < cc->num_channels; i++) { + if (test_bit(i, cc->edma_inuse)) { + /* ensure access through shadow region 0 */ + edma_or_array2(cc->id, EDMA_DRAE, 0, i >> 5, + BIT(i & 0x1f)); - /* - * Map the channel to param entry if channel mapping logic - * exist - */ - if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST) - map_dmach_param(j); - - for (i = 0; i < cc->num_channels; i++) { - if (test_bit(i, cc->edma_inuse)) { - /* ensure access through shadow region 0 */ - edma_or_array2(j, EDMA_DRAE, 0, i >> 5, - BIT(i & 0x1f)); - - setup_dma_interrupt(i, - cc->intr_data[i].callback, - cc->intr_data[i].data); - } + setup_dma_interrupt(EDMA_CTLR_CHAN(cc->id, i), + cc->intr_data[i].callback, + cc->intr_data[i].data); } } |