diff options
Diffstat (limited to 'drivers/dma/k3dma.c')
| -rw-r--r-- | drivers/dma/k3dma.c | 119 |
1 files changed, 76 insertions, 43 deletions
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index fdec2b6cfbb0..0f9cd7815f88 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013 - 2015 Linaro Ltd. - * Copyright (c) 2013 Hisilicon Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * Copyright (c) 2013 HiSilicon Limited. */ #include <linux/sched.h> #include <linux/device.h> @@ -18,7 +15,6 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/of_device.h> #include <linux/of.h> #include <linux/clk.h> #include <linux/of_dma.h> @@ -52,8 +48,6 @@ #define CX_SRC 0x814 #define CX_DST 0x818 #define CX_CFG 0x81c -#define AXI_CFG 0x820 -#define AXI_CFG_DEFAULT 0x201201 #define CX_LLI_CHAIN_EN 0x2 #define CX_CFG_EN 0x1 @@ -113,9 +107,18 @@ struct k3_dma_dev { struct dma_pool *pool; u32 dma_channels; u32 dma_requests; + u32 dma_channel_mask; unsigned int irq; }; + +#define K3_FLAG_NOCLK BIT(1) + +struct k3dma_soc_data { + unsigned long flags; +}; + + #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave) static int k3_dma_config_write(struct dma_chan *chan, @@ -161,7 +164,6 @@ static void k3_dma_set_desc(struct k3_dma_phy *phy, struct k3_desc_hw *hw) writel_relaxed(hw->count, phy->base + CX_CNT0); writel_relaxed(hw->saddr, phy->base + CX_SRC); writel_relaxed(hw->daddr, phy->base + CX_DST); - writel_relaxed(AXI_CFG_DEFAULT, phy->base + AXI_CFG); writel_relaxed(hw->config, phy->base + CX_CFG); } @@ -220,22 +222,23 @@ static irqreturn_t k3_dma_int_handler(int irq, void *dev_id) i = __ffs(stat); stat &= ~BIT(i); if (likely(tc1 & BIT(i)) || (tc2 & BIT(i))) { - unsigned long flags; p = &d->phy[i]; c = p->vchan; if (c && (tc1 & BIT(i))) { - spin_lock_irqsave(&c->vc.lock, flags); - vchan_cookie_complete(&p->ds_run->vd); - p->ds_done = p->ds_run; - p->ds_run = NULL; - spin_unlock_irqrestore(&c->vc.lock, flags); + spin_lock(&c->vc.lock); + if (p->ds_run != NULL) { + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + p->ds_run = NULL; + } + spin_unlock(&c->vc.lock); } if (c && (tc2 & BIT(i))) { - spin_lock_irqsave(&c->vc.lock, flags); + spin_lock(&c->vc.lock); if (p->ds_run != NULL) vchan_cyclic_callback(&p->ds_run->vd); - spin_unlock_irqrestore(&c->vc.lock, flags); + spin_unlock(&c->vc.lock); } irq_chan |= BIT(i); } @@ -268,6 +271,10 @@ static int k3_dma_start_txd(struct k3_dma_chan *c) if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d)) return -EAGAIN; + /* Avoid losing track of ds_run if a transaction is in flight */ + if (c->phy->ds_run) + return -EAGAIN; + if (vd) { struct k3_dma_desc_sw *ds = container_of(vd, struct k3_dma_desc_sw, vd); @@ -288,9 +295,9 @@ static int k3_dma_start_txd(struct k3_dma_chan *c) return -EAGAIN; } -static void k3_dma_tasklet(unsigned long arg) +static void k3_dma_tasklet(struct tasklet_struct *t) { - struct k3_dma_dev *d = (struct k3_dma_dev *)arg; + struct k3_dma_dev *d = from_tasklet(d, t, task); struct k3_dma_phy *p; struct k3_dma_chan *c, *cn; unsigned pch, pch_alloc = 0; @@ -314,6 +321,9 @@ static void k3_dma_tasklet(unsigned long arg) /* check new channel request in d->chan_pending */ spin_lock_irq(&d->lock); for (pch = 0; pch < d->dma_channels; pch++) { + if (!(d->dma_channel_mask & (1 << pch))) + continue; + p = &d->phy[pch]; if (p->vchan == NULL && !list_empty(&d->chan_pending)) { @@ -331,6 +341,9 @@ static void k3_dma_tasklet(unsigned long arg) spin_unlock_irq(&d->lock); for (pch = 0; pch < d->dma_channels; pch++) { + if (!(d->dma_channel_mask & (1 << pch))) + continue; + if (pch_alloc & (1 << pch)) { p = &d->phy[pch]; c = p->vchan; @@ -790,8 +803,21 @@ static int k3_dma_transfer_resume(struct dma_chan *chan) return 0; } +static const struct k3dma_soc_data k3_v1_dma_data = { + .flags = 0, +}; + +static const struct k3dma_soc_data asp_v1_dma_data = { + .flags = K3_FLAG_NOCLK, +}; + static const struct of_device_id k3_pdma_dt_ids[] = { - { .compatible = "hisilicon,k3-dma-1.0", }, + { .compatible = "hisilicon,k3-dma-1.0", + .data = &k3_v1_dma_data + }, + { .compatible = "hisilicon,hisi-pcm-asp-dma-1.0", + .data = &asp_v1_dma_data + }, {} }; MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids); @@ -810,35 +836,40 @@ static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec, static int k3_dma_probe(struct platform_device *op) { + const struct k3dma_soc_data *soc_data; struct k3_dma_dev *d; - const struct of_device_id *of_id; - struct resource *iores; int i, ret, irq = 0; - iores = platform_get_resource(op, IORESOURCE_MEM, 0); - if (!iores) - return -EINVAL; - d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM; - d->base = devm_ioremap_resource(&op->dev, iores); + soc_data = device_get_match_data(&op->dev); + if (!soc_data) + return -EINVAL; + + d->base = devm_platform_ioremap_resource(op, 0); if (IS_ERR(d->base)) return PTR_ERR(d->base); - of_id = of_match_device(k3_pdma_dt_ids, &op->dev); - if (of_id) { - of_property_read_u32((&op->dev)->of_node, - "dma-channels", &d->dma_channels); - of_property_read_u32((&op->dev)->of_node, - "dma-requests", &d->dma_requests); + of_property_read_u32((&op->dev)->of_node, + "dma-channels", &d->dma_channels); + of_property_read_u32((&op->dev)->of_node, + "dma-requests", &d->dma_requests); + ret = of_property_read_u32((&op->dev)->of_node, + "dma-channel-mask", &d->dma_channel_mask); + if (ret) { + dev_warn(&op->dev, + "dma-channel-mask doesn't exist, considering all as available.\n"); + d->dma_channel_mask = (u32)~0UL; } - d->clk = devm_clk_get(&op->dev, NULL); - if (IS_ERR(d->clk)) { - dev_err(&op->dev, "no dma clk\n"); - return PTR_ERR(d->clk); + if (!(soc_data->flags & K3_FLAG_NOCLK)) { + d->clk = devm_clk_get(&op->dev, NULL); + if (IS_ERR(d->clk)) { + dev_err(&op->dev, "no dma clk\n"); + return PTR_ERR(d->clk); + } } irq = platform_get_irq(op, 0); @@ -862,8 +893,12 @@ static int k3_dma_probe(struct platform_device *op) return -ENOMEM; for (i = 0; i < d->dma_channels; i++) { - struct k3_dma_phy *p = &d->phy[i]; + struct k3_dma_phy *p; + if (!(d->dma_channel_mask & BIT(i))) + continue; + + p = &d->phy[i]; p->idx = i; p->base = d->base + i * 0x40; } @@ -921,7 +956,7 @@ static int k3_dma_probe(struct platform_device *op) spin_lock_init(&d->lock); INIT_LIST_HEAD(&d->chan_pending); - tasklet_init(&d->task, k3_dma_tasklet, (unsigned long)d); + tasklet_setup(&d->task, k3_dma_tasklet); platform_set_drvdata(op, d); dev_info(&op->dev, "initialized\n"); @@ -934,7 +969,7 @@ dma_async_register_fail: return ret; } -static int k3_dma_remove(struct platform_device *op) +static void k3_dma_remove(struct platform_device *op) { struct k3_dma_chan *c, *cn; struct k3_dma_dev *d = platform_get_drvdata(op); @@ -950,7 +985,6 @@ static int k3_dma_remove(struct platform_device *op) } tasklet_kill(&d->task); clk_disable_unprepare(d->clk); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -999,6 +1033,5 @@ static struct platform_driver k3_pdma_driver = { module_platform_driver(k3_pdma_driver); -MODULE_DESCRIPTION("Hisilicon k3 DMA Driver"); -MODULE_ALIAS("platform:k3dma"); +MODULE_DESCRIPTION("HiSilicon k3 DMA Driver"); MODULE_LICENSE("GPL v2"); |
