--- zzzz-none-000/linux-3.10.107/drivers/dma/coh901318.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/dma/coh901318.c 2021-02-04 17:41:59.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include "coh901318.h" #include "dmaengine.h" @@ -1338,15 +1339,14 @@ { u64 started_channels = debugfs_dma_base->pm.started_channels; int pool_count = debugfs_dma_base->pool.debugfs_pool_counter; - int i; - int ret = 0; char *dev_buf; char *tmp; - int dev_size; + int ret; + int i; dev_buf = kmalloc(4*1024, GFP_KERNEL); if (dev_buf == NULL) - goto err_kmalloc; + return -ENOMEM; tmp = dev_buf; tmp += sprintf(tmp, "DMA -- enabled dma channels\n"); @@ -1356,26 +1356,11 @@ tmp += sprintf(tmp, "channel %d\n", i); tmp += sprintf(tmp, "Pool alloc nbr %d\n", pool_count); - dev_size = tmp - dev_buf; - /* No more to read if offset != 0 */ - if (*f_pos > dev_size) - goto out; - - if (count > dev_size - *f_pos) - count = dev_size - *f_pos; - - if (copy_to_user(buf, dev_buf + *f_pos, count)) - ret = -EINVAL; - ret = count; - *f_pos += count; - - out: + ret = simple_read_from_buffer(buf, count, f_pos, dev_buf, + tmp - dev_buf); kfree(dev_buf); return ret; - - err_kmalloc: - return 0; } static const struct file_operations coh901318_debugfs_status_operations = { @@ -1705,7 +1690,7 @@ * Pauses a transfer without losing data. Enables power save. * Use this function in conjunction with coh901318_resume. */ -static void coh901318_pause(struct dma_chan *chan) +static int coh901318_pause(struct dma_chan *chan) { u32 val; unsigned long flags; @@ -1745,12 +1730,13 @@ enable_powersave(cohc); spin_unlock_irqrestore(&cohc->lock, flags); + return 0; } /* Resumes a transfer that has been stopped via 300_dma_stop(..). Power save is handled. */ -static void coh901318_resume(struct dma_chan *chan) +static int coh901318_resume(struct dma_chan *chan) { u32 val; unsigned long flags; @@ -1775,6 +1761,7 @@ } spin_unlock_irqrestore(&cohc->lock, flags); + return 0; } bool coh901318_filter_id(struct dma_chan *chan, void *chan_id) @@ -1788,6 +1775,35 @@ } EXPORT_SYMBOL(coh901318_filter_id); +struct coh901318_filter_args { + struct coh901318_base *base; + unsigned int ch_nr; +}; + +static bool coh901318_filter_base_and_id(struct dma_chan *chan, void *data) +{ + struct coh901318_filter_args *args = data; + + if (&args->base->dma_slave == chan->device && + args->ch_nr == to_coh901318_chan(chan)->id) + return true; + + return false; +} + +static struct dma_chan *coh901318_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct coh901318_filter_args args = { + .base = ofdma->of_dma_data, + .ch_nr = dma_spec->args[0], + }; + dma_cap_mask_t cap; + dma_cap_zero(cap); + dma_cap_set(DMA_SLAVE, cap); + + return dma_request_channel(cap, coh901318_filter_base_and_id, &args); +} /* * DMA channel allocation */ @@ -2100,6 +2116,57 @@ return IRQ_HANDLED; } +static int coh901318_terminate_all(struct dma_chan *chan) +{ + unsigned long flags; + struct coh901318_chan *cohc = to_coh901318_chan(chan); + struct coh901318_desc *cohd; + void __iomem *virtbase = cohc->base->virtbase; + + /* The remainder of this function terminates the transfer */ + coh901318_pause(chan); + spin_lock_irqsave(&cohc->lock, flags); + + /* Clear any pending BE or TC interrupt */ + if (cohc->id < 32) { + writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1); + writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1); + } else { + writel(1 << (cohc->id - 32), virtbase + + COH901318_BE_INT_CLEAR2); + writel(1 << (cohc->id - 32), virtbase + + COH901318_TC_INT_CLEAR2); + } + + enable_powersave(cohc); + + while ((cohd = coh901318_first_active_get(cohc))) { + /* release the lli allocation*/ + coh901318_lli_free(&cohc->base->pool, &cohd->lli); + + /* return desc to free-list */ + coh901318_desc_remove(cohd); + coh901318_desc_free(cohc, cohd); + } + + while ((cohd = coh901318_first_queued(cohc))) { + /* release the lli allocation*/ + coh901318_lli_free(&cohc->base->pool, &cohd->lli); + + /* return desc to free-list */ + coh901318_desc_remove(cohd); + coh901318_desc_free(cohc, cohd); + } + + + cohc->nbr_active_done = 0; + cohc->busy = 0; + + spin_unlock_irqrestore(&cohc->lock, flags); + + return 0; +} + static int coh901318_alloc_chan_resources(struct dma_chan *chan) { struct coh901318_chan *cohc = to_coh901318_chan(chan); @@ -2142,7 +2209,7 @@ spin_unlock_irqrestore(&cohc->lock, flags); - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + coh901318_terminate_all(chan); } @@ -2355,7 +2422,7 @@ enum dma_status ret; ret = dma_cookie_status(chan, cookie, txstate); - if (ret == DMA_SUCCESS) + if (ret == DMA_COMPLETE) return ret; dma_set_residue(txstate, coh901318_get_bytes_left(chan)); @@ -2447,8 +2514,8 @@ }, }; -static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan, - struct dma_slave_config *config) +static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan, + struct dma_slave_config *config) { struct coh901318_chan *cohc = to_coh901318_chan(chan); dma_addr_t addr; @@ -2468,7 +2535,7 @@ maxburst = config->dst_maxburst; } else { dev_err(COHC_2_DEV(cohc), "illegal channel mode\n"); - return; + return -EINVAL; } dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n", @@ -2514,7 +2581,7 @@ default: dev_err(COHC_2_DEV(cohc), "bad runtimeconfig: alien address width\n"); - return; + return -EINVAL; } ctrl |= burst_sizes[i].reg; @@ -2524,84 +2591,12 @@ cohc->addr = addr; cohc->ctrl = ctrl; -} - -static int -coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, - unsigned long arg) -{ - unsigned long flags; - struct coh901318_chan *cohc = to_coh901318_chan(chan); - struct coh901318_desc *cohd; - void __iomem *virtbase = cohc->base->virtbase; - - if (cmd == DMA_SLAVE_CONFIG) { - struct dma_slave_config *config = - (struct dma_slave_config *) arg; - - coh901318_dma_set_runtimeconfig(chan, config); - return 0; - } - - if (cmd == DMA_PAUSE) { - coh901318_pause(chan); - return 0; - } - - if (cmd == DMA_RESUME) { - coh901318_resume(chan); - return 0; - } - - if (cmd != DMA_TERMINATE_ALL) - return -ENXIO; - - /* The remainder of this function terminates the transfer */ - coh901318_pause(chan); - spin_lock_irqsave(&cohc->lock, flags); - - /* Clear any pending BE or TC interrupt */ - if (cohc->id < 32) { - writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1); - writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1); - } else { - writel(1 << (cohc->id - 32), virtbase + - COH901318_BE_INT_CLEAR2); - writel(1 << (cohc->id - 32), virtbase + - COH901318_TC_INT_CLEAR2); - } - - enable_powersave(cohc); - - while ((cohd = coh901318_first_active_get(cohc))) { - /* release the lli allocation*/ - coh901318_lli_free(&cohc->base->pool, &cohd->lli); - - /* return desc to free-list */ - coh901318_desc_remove(cohd); - coh901318_desc_free(cohc, cohd); - } - - while ((cohd = coh901318_first_queued(cohc))) { - /* release the lli allocation*/ - coh901318_lli_free(&cohc->base->pool, &cohd->lli); - - /* return desc to free-list */ - coh901318_desc_remove(cohd); - coh901318_desc_free(cohc, cohd); - } - - - cohc->nbr_active_done = 0; - cohc->busy = 0; - - spin_unlock_irqrestore(&cohc->lock, flags); return 0; } -void coh901318_base_init(struct dma_device *dma, const int *pick_chans, - struct coh901318_base *base) +static void coh901318_base_init(struct dma_device *dma, const int *pick_chans, + struct coh901318_base *base) { int chans_i; int i = 0; @@ -2680,7 +2675,7 @@ if (irq < 0) return irq; - err = devm_request_irq(&pdev->dev, irq, dma_irq_handler, IRQF_DISABLED, + err = devm_request_irq(&pdev->dev, irq, dma_irq_handler, 0, "coh901318", base); if (err) return err; @@ -2703,7 +2698,10 @@ base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; base->dma_slave.device_tx_status = coh901318_tx_status; base->dma_slave.device_issue_pending = coh901318_issue_pending; - base->dma_slave.device_control = coh901318_control; + base->dma_slave.device_config = coh901318_dma_set_runtimeconfig; + base->dma_slave.device_pause = coh901318_pause; + base->dma_slave.device_resume = coh901318_resume; + base->dma_slave.device_terminate_all = coh901318_terminate_all; base->dma_slave.dev = &pdev->dev; err = dma_async_device_register(&base->dma_slave); @@ -2723,24 +2721,34 @@ base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; base->dma_memcpy.device_tx_status = coh901318_tx_status; base->dma_memcpy.device_issue_pending = coh901318_issue_pending; - base->dma_memcpy.device_control = coh901318_control; + base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig; + base->dma_memcpy.device_pause = coh901318_pause; + base->dma_memcpy.device_resume = coh901318_resume; + base->dma_memcpy.device_terminate_all = coh901318_terminate_all; base->dma_memcpy.dev = &pdev->dev; /* * This controller can only access address at even 32bit boundaries, * i.e. 2^2 */ - base->dma_memcpy.copy_align = 2; + base->dma_memcpy.copy_align = DMAENGINE_ALIGN_4_BYTES; err = dma_async_device_register(&base->dma_memcpy); if (err) goto err_register_memcpy; + err = of_dma_controller_register(pdev->dev.of_node, coh901318_xlate, + base); + if (err) + goto err_register_of_dma; + platform_set_drvdata(pdev, base); dev_info(&pdev->dev, "Initialized COH901318 DMA on virtual base 0x%08x\n", (u32) base->virtbase); return err; + err_register_of_dma: + dma_async_device_unregister(&base->dma_memcpy); err_register_memcpy: dma_async_device_unregister(&base->dma_slave); err_register_slave: @@ -2752,17 +2760,23 @@ { struct coh901318_base *base = platform_get_drvdata(pdev); + of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&base->dma_memcpy); dma_async_device_unregister(&base->dma_slave); coh901318_pool_destroy(&base->pool); return 0; } +static const struct of_device_id coh901318_dt_match[] = { + { .compatible = "stericsson,coh901318" }, + {}, +}; static struct platform_driver coh901318_driver = { .remove = coh901318_remove, .driver = { .name = "coh901318", + .of_match_table = coh901318_dt_match, }, };