diff options
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); } } |