diff options
Diffstat (limited to 'drivers/dma/fsldma.c')
-rw-r--r-- | drivers/dma/fsldma.c | 259 |
1 files changed, 132 insertions, 127 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index c2db754..507b297 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -40,7 +40,7 @@ static void dma_init(struct fsldma_chan *fsl_chan) { /* Reset the channel */ - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, 0, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, 0, 32); switch (fsl_chan->feature & FSL_DMA_IP_MASK) { case FSL_DMA_IP_85XX: @@ -49,7 +49,7 @@ static void dma_init(struct fsldma_chan *fsl_chan) * EOSIE - End of segments interrupt enable (basic mode) * EOLNIE - End of links interrupt enable */ - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EIE + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32); break; case FSL_DMA_IP_83XX: @@ -57,7 +57,7 @@ static void dma_init(struct fsldma_chan *fsl_chan) * EOTIE - End-of-transfer interrupt enable * PRC_RM - PCI read multiple */ - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, FSL_DMA_MR_EOTIE | FSL_DMA_MR_PRC_RM, 32); break; } @@ -66,12 +66,12 @@ static void dma_init(struct fsldma_chan *fsl_chan) static void set_sr(struct fsldma_chan *fsl_chan, u32 val) { - DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->sr, val, 32); } static u32 get_sr(struct fsldma_chan *fsl_chan) { - return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32); + return DMA_IN(fsl_chan, &fsl_chan->regs->sr, 32); } static void set_desc_cnt(struct fsldma_chan *fsl_chan, @@ -112,27 +112,27 @@ static void set_desc_next(struct fsldma_chan *fsl_chan, static void set_cdar(struct fsldma_chan *fsl_chan, dma_addr_t addr) { - DMA_OUT(fsl_chan, &fsl_chan->reg_base->cdar, addr | FSL_DMA_SNEN, 64); + DMA_OUT(fsl_chan, &fsl_chan->regs->cdar, addr | FSL_DMA_SNEN, 64); } static dma_addr_t get_cdar(struct fsldma_chan *fsl_chan) { - return DMA_IN(fsl_chan, &fsl_chan->reg_base->cdar, 64) & ~FSL_DMA_SNEN; + return DMA_IN(fsl_chan, &fsl_chan->regs->cdar, 64) & ~FSL_DMA_SNEN; } static void set_ndar(struct fsldma_chan *fsl_chan, dma_addr_t addr) { - DMA_OUT(fsl_chan, &fsl_chan->reg_base->ndar, addr, 64); + DMA_OUT(fsl_chan, &fsl_chan->regs->ndar, addr, 64); } static dma_addr_t get_ndar(struct fsldma_chan *fsl_chan) { - return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64); + return DMA_IN(fsl_chan, &fsl_chan->regs->ndar, 64); } static u32 get_bcr(struct fsldma_chan *fsl_chan) { - return DMA_IN(fsl_chan, &fsl_chan->reg_base->bcr, 32); + return DMA_IN(fsl_chan, &fsl_chan->regs->bcr, 32); } static int dma_is_idle(struct fsldma_chan *fsl_chan) @@ -145,11 +145,11 @@ static void dma_start(struct fsldma_chan *fsl_chan) { u32 mode; - mode = DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32); + mode = DMA_IN(fsl_chan, &fsl_chan->regs->mr, 32); if ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { if (fsl_chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { - DMA_OUT(fsl_chan, &fsl_chan->reg_base->bcr, 0, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->bcr, 0, 32); mode |= FSL_DMA_MR_EMP_EN; } else { mode &= ~FSL_DMA_MR_EMP_EN; @@ -161,7 +161,7 @@ static void dma_start(struct fsldma_chan *fsl_chan) else mode |= FSL_DMA_MR_CS; - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, mode, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, mode, 32); } static void dma_halt(struct fsldma_chan *fsl_chan) @@ -169,12 +169,12 @@ static void dma_halt(struct fsldma_chan *fsl_chan) u32 mode; int i; - mode = DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32); + mode = DMA_IN(fsl_chan, &fsl_chan->regs->mr, 32); mode |= FSL_DMA_MR_CA; - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, mode, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, mode, 32); mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA); - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, mode, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, mode, 32); for (i = 0; i < 100; i++) { if (dma_is_idle(fsl_chan)) @@ -235,7 +235,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *fsl_chan, int size) { u32 mode; - mode = DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32); + mode = DMA_IN(fsl_chan, &fsl_chan->regs->mr, 32); switch (size) { case 0: @@ -249,7 +249,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *fsl_chan, int size) break; } - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, mode, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, mode, 32); } /** @@ -267,7 +267,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *fsl_chan, int size) { u32 mode; - mode = DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32); + mode = DMA_IN(fsl_chan, &fsl_chan->regs->mr, 32); switch (size) { case 0: @@ -281,7 +281,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *fsl_chan, int size) break; } - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, mode, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, mode, 32); } /** @@ -302,10 +302,10 @@ static void fsl_chan_set_request_count(struct fsldma_chan *fsl_chan, int size) BUG_ON(size > 1024); - mode = DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32); + mode = DMA_IN(fsl_chan, &fsl_chan->regs->mr, 32); mode |= (__ilog2(size) << 24) & 0x0f000000; - DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, mode, 32); + DMA_OUT(fsl_chan, &fsl_chan->regs->mr, mode, 32); } /** @@ -967,7 +967,7 @@ static enum dma_status fsl_dma_is_complete(struct dma_chan *chan, return dma_async_is_complete(cookie, last_complete, last_used); } -static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) +static irqreturn_t fsldma_chan_irq(int irq, void *data) { struct fsldma_chan *fsl_chan = data; u32 stat; @@ -1048,17 +1048,17 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t fsl_dma_do_interrupt(int irq, void *data) +static irqreturn_t fsldma_irq(int irq, void *data) { struct fsldma_device *fdev = data; int ch_nr; u32 gsr; - gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->reg_base) - : in_le32(fdev->reg_base); + gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs) + : in_le32(fdev->regs); ch_nr = (32 - ffs(gsr)) / 8; - return fdev->chan[ch_nr] ? fsl_dma_chan_do_interrupt(irq, + return fdev->chan[ch_nr] ? fsldma_chan_irq(irq, fdev->chan[ch_nr]) : IRQ_NONE; } @@ -1075,140 +1075,142 @@ static void dma_do_tasklet(unsigned long data) static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev, struct device_node *node, u32 feature, const char *compatible) { - struct fsldma_chan *new_fsl_chan; + struct fsldma_chan *fchan; struct resource res; int err; /* alloc channel */ - new_fsl_chan = kzalloc(sizeof(*new_fsl_chan), GFP_KERNEL); - if (!new_fsl_chan) { - dev_err(fdev->dev, "No free memory for allocating " - "dma channels!\n"); - return -ENOMEM; + fchan = kzalloc(sizeof(*fchan), GFP_KERNEL); + if (!fchan) { + dev_err(fdev->dev, "no free memory for DMA channels!\n"); + err = -ENOMEM; + goto out_return; + } + + /* ioremap registers for use */ + fchan->regs = of_iomap(node, 0); + if (!fchan->regs) { + dev_err(fdev->dev, "unable to ioremap registers\n"); + err = -ENOMEM; + goto out_free_fchan; } - /* get dma channel register base */ err = of_address_to_resource(node, 0, &res); if (err) { - dev_err(fdev->dev, "Can't get %s property 'reg'\n", - node->full_name); - goto err_no_reg; + dev_err(fdev->dev, "unable to find 'reg' property\n"); + goto out_iounmap_regs; } - new_fsl_chan->feature = feature; - + fchan->feature = feature; if (!fdev->feature) - fdev->feature = new_fsl_chan->feature; + fdev->feature = fchan->feature; - /* If the DMA device's feature is different than its channels', - * report the bug. + /* + * If the DMA device's feature is different than the feature + * of its channels, report the bug */ - WARN_ON(fdev->feature != new_fsl_chan->feature); - - new_fsl_chan->dev = fdev->dev; - new_fsl_chan->reg_base = ioremap(res.start, resource_size(&res)); - new_fsl_chan->id = ((res.start - 0x100) & 0xfff) >> 7; - if (new_fsl_chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) { - dev_err(fdev->dev, "There is no %d channel!\n", - new_fsl_chan->id); + WARN_ON(fdev->feature != fchan->feature); + + fchan->dev = fdev->dev; + fchan->id = ((res.start - 0x100) & 0xfff) >> 7; + if (fchan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) { + dev_err(fdev->dev, "too many channels for device\n"); err = -EINVAL; - goto err_no_chan; + goto out_iounmap_regs; } - fdev->chan[new_fsl_chan->id] = new_fsl_chan; - tasklet_init(&new_fsl_chan->tasklet, dma_do_tasklet, - (unsigned long)new_fsl_chan); - /* Init the channel */ - dma_init(new_fsl_chan); + fdev->chan[fchan->id] = fchan; + tasklet_init(&fchan->tasklet, dma_do_tasklet, (unsigned long)fchan); + + /* Initialize the channel */ + dma_init(fchan); /* Clear cdar registers */ - set_cdar(new_fsl_chan, 0); + set_cdar(fchan, 0); - switch (new_fsl_chan->feature & FSL_DMA_IP_MASK) { + switch (fchan->feature & FSL_DMA_IP_MASK) { case FSL_DMA_IP_85XX: - new_fsl_chan->toggle_ext_pause = fsl_chan_toggle_ext_pause; + fchan->toggle_ext_pause = fsl_chan_toggle_ext_pause; case FSL_DMA_IP_83XX: - new_fsl_chan->toggle_ext_start = fsl_chan_toggle_ext_start; - new_fsl_chan->set_src_loop_size = fsl_chan_set_src_loop_size; - new_fsl_chan->set_dst_loop_size = fsl_chan_set_dst_loop_size; - new_fsl_chan->set_request_count = fsl_chan_set_request_count; + fchan->toggle_ext_start = fsl_chan_toggle_ext_start; + fchan->set_src_loop_size = fsl_chan_set_src_loop_size; + fchan->set_dst_loop_size = fsl_chan_set_dst_loop_size; + fchan->set_request_count = fsl_chan_set_request_count; } - spin_lock_init(&new_fsl_chan->desc_lock); - INIT_LIST_HEAD(&new_fsl_chan->ld_queue); + spin_lock_init(&fchan->desc_lock); + INIT_LIST_HEAD(&fchan->ld_queue); - new_fsl_chan->common.device = &fdev->common; + fchan->common.device = &fdev->common; /* Add the channel to DMA device channel list */ - list_add_tail(&new_fsl_chan->common.device_node, - &fdev->common.channels); + list_add_tail(&fchan->common.device_node, &fdev->common.channels); fdev->common.chancnt++; - new_fsl_chan->irq = irq_of_parse_and_map(node, 0); - if (new_fsl_chan->irq != NO_IRQ) { - err = request_irq(new_fsl_chan->irq, - &fsl_dma_chan_do_interrupt, IRQF_SHARED, - "fsldma-channel", new_fsl_chan); + fchan->irq = irq_of_parse_and_map(node, 0); + if (fchan->irq != NO_IRQ) { + err = request_irq(fchan->irq, &fsldma_chan_irq, + IRQF_SHARED, "fsldma-channel", fchan); if (err) { - dev_err(fdev->dev, "DMA channel %s request_irq error " - "with return %d\n", node->full_name, err); - goto err_no_irq; + dev_err(fdev->dev, "unable to request IRQ " + "for channel %d\n", fchan->id); + goto out_list_del; } } - dev_info(fdev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id, - compatible, - new_fsl_chan->irq != NO_IRQ ? new_fsl_chan->irq : fdev->irq); + dev_info(fdev->dev, "#%d (%s), irq %d\n", fchan->id, compatible, + fchan->irq != NO_IRQ ? fchan->irq : fdev->irq); return 0; -err_no_irq: - list_del(&new_fsl_chan->common.device_node); -err_no_chan: - iounmap(new_fsl_chan->reg_base); -err_no_reg: - kfree(new_fsl_chan); +out_list_del: + irq_dispose_mapping(fchan->irq); + list_del_init(&fchan->common.device_node); +out_iounmap_regs: + iounmap(fchan->regs); +out_free_fchan: + kfree(fchan); +out_return: return err; } static void fsl_dma_chan_remove(struct fsldma_chan *fchan) { - if (fchan->irq != NO_IRQ) + if (fchan->irq != NO_IRQ) { free_irq(fchan->irq, fchan); + irq_dispose_mapping(fchan->irq); + } + list_del(&fchan->common.device_node); - iounmap(fchan->reg_base); + iounmap(fchan->regs); kfree(fchan); } -static int __devinit fsldma_of_probe(struct of_device *dev, +static int __devinit fsldma_of_probe(struct of_device *op, const struct of_device_id *match) { - int err; struct fsldma_device *fdev; struct device_node *child; - struct resource res; + int err; fdev = kzalloc(sizeof(*fdev), GFP_KERNEL); if (!fdev) { - dev_err(&dev->dev, "No enough memory for 'priv'\n"); - return -ENOMEM; + dev_err(&op->dev, "No enough memory for 'priv'\n"); + err = -ENOMEM; + goto out_return; } - fdev->dev = &dev->dev; + + fdev->dev = &op->dev; INIT_LIST_HEAD(&fdev->common.channels); - /* get DMA controller register base */ - err = of_address_to_resource(dev->node, 0, &res); - if (err) { - dev_err(&dev->dev, "Can't get %s property 'reg'\n", - dev->node->full_name); - goto err_no_reg; + /* ioremap the registers for use */ + fdev->regs = of_iomap(op->node, 0); + if (!fdev->regs) { + dev_err(&op->dev, "unable to ioremap registers\n"); + err = -ENOMEM; + goto out_free_fdev; } - dev_info(&dev->dev, "Probe the Freescale DMA driver for %s " - "controller at 0x%llx...\n", - match->compatible, (unsigned long long)res.start); - fdev->reg_base = ioremap(res.start, resource_size(&res)); - dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); @@ -1220,66 +1222,69 @@ static int __devinit fsldma_of_probe(struct of_device *dev, fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; fdev->common.device_terminate_all = fsl_dma_device_terminate_all; - fdev->common.dev = &dev->dev; + fdev->common.dev = &op->dev; - fdev->irq = irq_of_parse_and_map(dev->node, 0); + fdev->irq = irq_of_parse_and_map(op->node, 0); if (fdev->irq != NO_IRQ) { - err = request_irq(fdev->irq, &fsl_dma_do_interrupt, IRQF_SHARED, - "fsldma-device", fdev); + err = request_irq(fdev->irq, &fsldma_irq, IRQF_SHARED, + "fsldma-device", fdev); if (err) { - dev_err(&dev->dev, "DMA device request_irq error " - "with return %d\n", err); - goto err; + dev_err(&op->dev, "unable to request IRQ\n"); + goto out_iounmap_regs; } } - dev_set_drvdata(&(dev->dev), fdev); + dev_set_drvdata(&op->dev, fdev); - /* We cannot use of_platform_bus_probe() because there is no - * of_platform_bus_remove. Instead, we manually instantiate every DMA + /* + * We cannot use of_platform_bus_probe() because there is no + * of_platform_bus_remove(). Instead, we manually instantiate every DMA * channel object. */ - for_each_child_of_node(dev->node, child) { - if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) + for_each_child_of_node(op->node, child) { + if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) { fsl_dma_chan_probe(fdev, child, FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN, "fsl,eloplus-dma-channel"); - if (of_device_is_compatible(child, "fsl,elo-dma-channel")) + } + + if (of_device_is_compatible(child, "fsl,elo-dma-channel")) { fsl_dma_chan_probe(fdev, child, FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN, "fsl,elo-dma-channel"); + } } dma_async_device_register(&fdev->common); return 0; -err: - iounmap(fdev->reg_base); -err_no_reg: +out_iounmap_regs: + iounmap(fdev->regs); +out_free_fdev: kfree(fdev); +out_return: return err; } -static int fsldma_of_remove(struct of_device *of_dev) +static int fsldma_of_remove(struct of_device *op) { struct fsldma_device *fdev; unsigned int i; - fdev = dev_get_drvdata(&of_dev->dev); - + fdev = dev_get_drvdata(&op->dev); dma_async_device_unregister(&fdev->common); - for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) + for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { if (fdev->chan[i]) fsl_dma_chan_remove(fdev->chan[i]); + } if (fdev->irq != NO_IRQ) free_irq(fdev->irq, fdev); - iounmap(fdev->reg_base); - + iounmap(fdev->regs); + dev_set_drvdata(&op->dev, NULL); kfree(fdev); - dev_set_drvdata(&of_dev->dev, NULL); return 0; } |