1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28e6152bcSZhangfei Gao /*
3a7e08fa6SAndy Green * Copyright (c) 2013 - 2015 Linaro Ltd.
4*1b6216a6SHao Fang * Copyright (c) 2013 HiSilicon Limited.
58e6152bcSZhangfei Gao */
68e6152bcSZhangfei Gao #include <linux/sched.h>
78e6152bcSZhangfei Gao #include <linux/device.h>
8b77f262aSJohn Stultz #include <linux/dma-mapping.h>
9b77f262aSJohn Stultz #include <linux/dmapool.h>
108e6152bcSZhangfei Gao #include <linux/dmaengine.h>
118e6152bcSZhangfei Gao #include <linux/init.h>
128e6152bcSZhangfei Gao #include <linux/interrupt.h>
138e6152bcSZhangfei Gao #include <linux/kernel.h>
148e6152bcSZhangfei Gao #include <linux/module.h>
158e6152bcSZhangfei Gao #include <linux/platform_device.h>
168e6152bcSZhangfei Gao #include <linux/slab.h>
178e6152bcSZhangfei Gao #include <linux/spinlock.h>
188e6152bcSZhangfei Gao #include <linux/of_device.h>
198e6152bcSZhangfei Gao #include <linux/of.h>
208e6152bcSZhangfei Gao #include <linux/clk.h>
218e6152bcSZhangfei Gao #include <linux/of_dma.h>
228e6152bcSZhangfei Gao
238e6152bcSZhangfei Gao #include "virt-dma.h"
248e6152bcSZhangfei Gao
258e6152bcSZhangfei Gao #define DRIVER_NAME "k3-dma"
268e6152bcSZhangfei Gao #define DMA_MAX_SIZE 0x1ffc
27a7e08fa6SAndy Green #define DMA_CYCLIC_MAX_PERIOD 0x1000
28b77f262aSJohn Stultz #define LLI_BLOCK_SIZE (4 * PAGE_SIZE)
298e6152bcSZhangfei Gao
308e6152bcSZhangfei Gao #define INT_STAT 0x00
318e6152bcSZhangfei Gao #define INT_TC1 0x04
32a7e08fa6SAndy Green #define INT_TC2 0x08
338e6152bcSZhangfei Gao #define INT_ERR1 0x0c
348e6152bcSZhangfei Gao #define INT_ERR2 0x10
358e6152bcSZhangfei Gao #define INT_TC1_MASK 0x18
36a7e08fa6SAndy Green #define INT_TC2_MASK 0x1c
378e6152bcSZhangfei Gao #define INT_ERR1_MASK 0x20
388e6152bcSZhangfei Gao #define INT_ERR2_MASK 0x24
398e6152bcSZhangfei Gao #define INT_TC1_RAW 0x600
40a7e08fa6SAndy Green #define INT_TC2_RAW 0x608
41aceaaa17SAndy Green #define INT_ERR1_RAW 0x610
42aceaaa17SAndy Green #define INT_ERR2_RAW 0x618
438e6152bcSZhangfei Gao #define CH_PRI 0x688
448e6152bcSZhangfei Gao #define CH_STAT 0x690
458e6152bcSZhangfei Gao #define CX_CUR_CNT 0x704
468e6152bcSZhangfei Gao #define CX_LLI 0x800
47a7e08fa6SAndy Green #define CX_CNT1 0x80c
48a7e08fa6SAndy Green #define CX_CNT0 0x810
498e6152bcSZhangfei Gao #define CX_SRC 0x814
508e6152bcSZhangfei Gao #define CX_DST 0x818
518e6152bcSZhangfei Gao #define CX_CFG 0x81c
528e6152bcSZhangfei Gao
538e6152bcSZhangfei Gao #define CX_LLI_CHAIN_EN 0x2
548e6152bcSZhangfei Gao #define CX_CFG_EN 0x1
55a7e08fa6SAndy Green #define CX_CFG_NODEIRQ BIT(1)
568e6152bcSZhangfei Gao #define CX_CFG_MEM2PER (0x1 << 2)
578e6152bcSZhangfei Gao #define CX_CFG_PER2MEM (0x2 << 2)
588e6152bcSZhangfei Gao #define CX_CFG_SRCINCR (0x1 << 31)
598e6152bcSZhangfei Gao #define CX_CFG_DSTINCR (0x1 << 30)
608e6152bcSZhangfei Gao
618e6152bcSZhangfei Gao struct k3_desc_hw {
628e6152bcSZhangfei Gao u32 lli;
638e6152bcSZhangfei Gao u32 reserved[3];
648e6152bcSZhangfei Gao u32 count;
658e6152bcSZhangfei Gao u32 saddr;
668e6152bcSZhangfei Gao u32 daddr;
678e6152bcSZhangfei Gao u32 config;
688e6152bcSZhangfei Gao } __aligned(32);
698e6152bcSZhangfei Gao
708e6152bcSZhangfei Gao struct k3_dma_desc_sw {
718e6152bcSZhangfei Gao struct virt_dma_desc vd;
728e6152bcSZhangfei Gao dma_addr_t desc_hw_lli;
738e6152bcSZhangfei Gao size_t desc_num;
748e6152bcSZhangfei Gao size_t size;
75b77f262aSJohn Stultz struct k3_desc_hw *desc_hw;
768e6152bcSZhangfei Gao };
778e6152bcSZhangfei Gao
788e6152bcSZhangfei Gao struct k3_dma_phy;
798e6152bcSZhangfei Gao
808e6152bcSZhangfei Gao struct k3_dma_chan {
818e6152bcSZhangfei Gao u32 ccfg;
828e6152bcSZhangfei Gao struct virt_dma_chan vc;
838e6152bcSZhangfei Gao struct k3_dma_phy *phy;
848e6152bcSZhangfei Gao struct list_head node;
858e6152bcSZhangfei Gao dma_addr_t dev_addr;
868e6152bcSZhangfei Gao enum dma_status status;
87a7e08fa6SAndy Green bool cyclic;
882ae1a237SVinod Koul struct dma_slave_config slave_config;
898e6152bcSZhangfei Gao };
908e6152bcSZhangfei Gao
918e6152bcSZhangfei Gao struct k3_dma_phy {
928e6152bcSZhangfei Gao u32 idx;
938e6152bcSZhangfei Gao void __iomem *base;
948e6152bcSZhangfei Gao struct k3_dma_chan *vchan;
958e6152bcSZhangfei Gao struct k3_dma_desc_sw *ds_run;
968e6152bcSZhangfei Gao struct k3_dma_desc_sw *ds_done;
978e6152bcSZhangfei Gao };
988e6152bcSZhangfei Gao
998e6152bcSZhangfei Gao struct k3_dma_dev {
1008e6152bcSZhangfei Gao struct dma_device slave;
1018e6152bcSZhangfei Gao void __iomem *base;
1028e6152bcSZhangfei Gao struct tasklet_struct task;
1038e6152bcSZhangfei Gao spinlock_t lock;
1048e6152bcSZhangfei Gao struct list_head chan_pending;
1058e6152bcSZhangfei Gao struct k3_dma_phy *phy;
1068e6152bcSZhangfei Gao struct k3_dma_chan *chans;
1078e6152bcSZhangfei Gao struct clk *clk;
108b77f262aSJohn Stultz struct dma_pool *pool;
1098e6152bcSZhangfei Gao u32 dma_channels;
1108e6152bcSZhangfei Gao u32 dma_requests;
111c4994a98SLi Yu u32 dma_channel_mask;
112486b10a2SVinod Koul unsigned int irq;
1138e6152bcSZhangfei Gao };
1148e6152bcSZhangfei Gao
115d4bdc39fSYoulin Wang
116d4bdc39fSYoulin Wang #define K3_FLAG_NOCLK BIT(1)
117d4bdc39fSYoulin Wang
118d4bdc39fSYoulin Wang struct k3dma_soc_data {
119d4bdc39fSYoulin Wang unsigned long flags;
120d4bdc39fSYoulin Wang };
121d4bdc39fSYoulin Wang
122d4bdc39fSYoulin Wang
1238e6152bcSZhangfei Gao #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
1248e6152bcSZhangfei Gao
1252ae1a237SVinod Koul static int k3_dma_config_write(struct dma_chan *chan,
1262ae1a237SVinod Koul enum dma_transfer_direction dir,
1272ae1a237SVinod Koul struct dma_slave_config *cfg);
1282ae1a237SVinod Koul
to_k3_chan(struct dma_chan * chan)1298e6152bcSZhangfei Gao static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan)
1308e6152bcSZhangfei Gao {
1318e6152bcSZhangfei Gao return container_of(chan, struct k3_dma_chan, vc.chan);
1328e6152bcSZhangfei Gao }
1338e6152bcSZhangfei Gao
k3_dma_pause_dma(struct k3_dma_phy * phy,bool on)1348e6152bcSZhangfei Gao static void k3_dma_pause_dma(struct k3_dma_phy *phy, bool on)
1358e6152bcSZhangfei Gao {
1368e6152bcSZhangfei Gao u32 val = 0;
1378e6152bcSZhangfei Gao
1388e6152bcSZhangfei Gao if (on) {
1398e6152bcSZhangfei Gao val = readl_relaxed(phy->base + CX_CFG);
1408e6152bcSZhangfei Gao val |= CX_CFG_EN;
1418e6152bcSZhangfei Gao writel_relaxed(val, phy->base + CX_CFG);
1428e6152bcSZhangfei Gao } else {
1438e6152bcSZhangfei Gao val = readl_relaxed(phy->base + CX_CFG);
1448e6152bcSZhangfei Gao val &= ~CX_CFG_EN;
1458e6152bcSZhangfei Gao writel_relaxed(val, phy->base + CX_CFG);
1468e6152bcSZhangfei Gao }
1478e6152bcSZhangfei Gao }
1488e6152bcSZhangfei Gao
k3_dma_terminate_chan(struct k3_dma_phy * phy,struct k3_dma_dev * d)1498e6152bcSZhangfei Gao static void k3_dma_terminate_chan(struct k3_dma_phy *phy, struct k3_dma_dev *d)
1508e6152bcSZhangfei Gao {
1518e6152bcSZhangfei Gao u32 val = 0;
1528e6152bcSZhangfei Gao
1538e6152bcSZhangfei Gao k3_dma_pause_dma(phy, false);
1548e6152bcSZhangfei Gao
1558e6152bcSZhangfei Gao val = 0x1 << phy->idx;
1568e6152bcSZhangfei Gao writel_relaxed(val, d->base + INT_TC1_RAW);
157a7e08fa6SAndy Green writel_relaxed(val, d->base + INT_TC2_RAW);
1588e6152bcSZhangfei Gao writel_relaxed(val, d->base + INT_ERR1_RAW);
1598e6152bcSZhangfei Gao writel_relaxed(val, d->base + INT_ERR2_RAW);
1608e6152bcSZhangfei Gao }
1618e6152bcSZhangfei Gao
k3_dma_set_desc(struct k3_dma_phy * phy,struct k3_desc_hw * hw)1628e6152bcSZhangfei Gao static void k3_dma_set_desc(struct k3_dma_phy *phy, struct k3_desc_hw *hw)
1638e6152bcSZhangfei Gao {
1648e6152bcSZhangfei Gao writel_relaxed(hw->lli, phy->base + CX_LLI);
165a7e08fa6SAndy Green writel_relaxed(hw->count, phy->base + CX_CNT0);
1668e6152bcSZhangfei Gao writel_relaxed(hw->saddr, phy->base + CX_SRC);
1678e6152bcSZhangfei Gao writel_relaxed(hw->daddr, phy->base + CX_DST);
1688e6152bcSZhangfei Gao writel_relaxed(hw->config, phy->base + CX_CFG);
1698e6152bcSZhangfei Gao }
1708e6152bcSZhangfei Gao
k3_dma_get_curr_cnt(struct k3_dma_dev * d,struct k3_dma_phy * phy)1718e6152bcSZhangfei Gao static u32 k3_dma_get_curr_cnt(struct k3_dma_dev *d, struct k3_dma_phy *phy)
1728e6152bcSZhangfei Gao {
1738e6152bcSZhangfei Gao u32 cnt = 0;
1748e6152bcSZhangfei Gao
1758e6152bcSZhangfei Gao cnt = readl_relaxed(d->base + CX_CUR_CNT + phy->idx * 0x10);
1768e6152bcSZhangfei Gao cnt &= 0xffff;
1778e6152bcSZhangfei Gao return cnt;
1788e6152bcSZhangfei Gao }
1798e6152bcSZhangfei Gao
k3_dma_get_curr_lli(struct k3_dma_phy * phy)1808e6152bcSZhangfei Gao static u32 k3_dma_get_curr_lli(struct k3_dma_phy *phy)
1818e6152bcSZhangfei Gao {
1828e6152bcSZhangfei Gao return readl_relaxed(phy->base + CX_LLI);
1838e6152bcSZhangfei Gao }
1848e6152bcSZhangfei Gao
k3_dma_get_chan_stat(struct k3_dma_dev * d)1858e6152bcSZhangfei Gao static u32 k3_dma_get_chan_stat(struct k3_dma_dev *d)
1868e6152bcSZhangfei Gao {
1878e6152bcSZhangfei Gao return readl_relaxed(d->base + CH_STAT);
1888e6152bcSZhangfei Gao }
1898e6152bcSZhangfei Gao
k3_dma_enable_dma(struct k3_dma_dev * d,bool on)1908e6152bcSZhangfei Gao static void k3_dma_enable_dma(struct k3_dma_dev *d, bool on)
1918e6152bcSZhangfei Gao {
1928e6152bcSZhangfei Gao if (on) {
1938e6152bcSZhangfei Gao /* set same priority */
1948e6152bcSZhangfei Gao writel_relaxed(0x0, d->base + CH_PRI);
1958e6152bcSZhangfei Gao
1968e6152bcSZhangfei Gao /* unmask irq */
1978e6152bcSZhangfei Gao writel_relaxed(0xffff, d->base + INT_TC1_MASK);
198a7e08fa6SAndy Green writel_relaxed(0xffff, d->base + INT_TC2_MASK);
1998e6152bcSZhangfei Gao writel_relaxed(0xffff, d->base + INT_ERR1_MASK);
2008e6152bcSZhangfei Gao writel_relaxed(0xffff, d->base + INT_ERR2_MASK);
2018e6152bcSZhangfei Gao } else {
2028e6152bcSZhangfei Gao /* mask irq */
2038e6152bcSZhangfei Gao writel_relaxed(0x0, d->base + INT_TC1_MASK);
204a7e08fa6SAndy Green writel_relaxed(0x0, d->base + INT_TC2_MASK);
2058e6152bcSZhangfei Gao writel_relaxed(0x0, d->base + INT_ERR1_MASK);
2068e6152bcSZhangfei Gao writel_relaxed(0x0, d->base + INT_ERR2_MASK);
2078e6152bcSZhangfei Gao }
2088e6152bcSZhangfei Gao }
2098e6152bcSZhangfei Gao
k3_dma_int_handler(int irq,void * dev_id)2108e6152bcSZhangfei Gao static irqreturn_t k3_dma_int_handler(int irq, void *dev_id)
2118e6152bcSZhangfei Gao {
2128e6152bcSZhangfei Gao struct k3_dma_dev *d = (struct k3_dma_dev *)dev_id;
2138e6152bcSZhangfei Gao struct k3_dma_phy *p;
2148e6152bcSZhangfei Gao struct k3_dma_chan *c;
2158e6152bcSZhangfei Gao u32 stat = readl_relaxed(d->base + INT_STAT);
2168e6152bcSZhangfei Gao u32 tc1 = readl_relaxed(d->base + INT_TC1);
217a7e08fa6SAndy Green u32 tc2 = readl_relaxed(d->base + INT_TC2);
2188e6152bcSZhangfei Gao u32 err1 = readl_relaxed(d->base + INT_ERR1);
2198e6152bcSZhangfei Gao u32 err2 = readl_relaxed(d->base + INT_ERR2);
2208e6152bcSZhangfei Gao u32 i, irq_chan = 0;
2218e6152bcSZhangfei Gao
2228e6152bcSZhangfei Gao while (stat) {
2238e6152bcSZhangfei Gao i = __ffs(stat);
224a7e08fa6SAndy Green stat &= ~BIT(i);
225a7e08fa6SAndy Green if (likely(tc1 & BIT(i)) || (tc2 & BIT(i))) {
2268e6152bcSZhangfei Gao
227a7e08fa6SAndy Green p = &d->phy[i];
228a7e08fa6SAndy Green c = p->vchan;
229a7e08fa6SAndy Green if (c && (tc1 & BIT(i))) {
2301ff20656SBarry Song spin_lock(&c->vc.lock);
2312f42e05bSJohn Stultz if (p->ds_run != NULL) {
2328e6152bcSZhangfei Gao vchan_cookie_complete(&p->ds_run->vd);
2338e6152bcSZhangfei Gao p->ds_done = p->ds_run;
23436387a2bSJohn Stultz p->ds_run = NULL;
2352f42e05bSJohn Stultz }
2361ff20656SBarry Song spin_unlock(&c->vc.lock);
2378e6152bcSZhangfei Gao }
238a7e08fa6SAndy Green if (c && (tc2 & BIT(i))) {
2391ff20656SBarry Song spin_lock(&c->vc.lock);
240a7e08fa6SAndy Green if (p->ds_run != NULL)
241a7e08fa6SAndy Green vchan_cyclic_callback(&p->ds_run->vd);
2421ff20656SBarry Song spin_unlock(&c->vc.lock);
243a7e08fa6SAndy Green }
2448e6152bcSZhangfei Gao irq_chan |= BIT(i);
2458e6152bcSZhangfei Gao }
2468e6152bcSZhangfei Gao if (unlikely((err1 & BIT(i)) || (err2 & BIT(i))))
2478e6152bcSZhangfei Gao dev_warn(d->slave.dev, "DMA ERR\n");
2488e6152bcSZhangfei Gao }
2498e6152bcSZhangfei Gao
2508e6152bcSZhangfei Gao writel_relaxed(irq_chan, d->base + INT_TC1_RAW);
251a7e08fa6SAndy Green writel_relaxed(irq_chan, d->base + INT_TC2_RAW);
2528e6152bcSZhangfei Gao writel_relaxed(err1, d->base + INT_ERR1_RAW);
2538e6152bcSZhangfei Gao writel_relaxed(err2, d->base + INT_ERR2_RAW);
2548e6152bcSZhangfei Gao
2550173c895SAndy Green if (irq_chan)
2568e6152bcSZhangfei Gao tasklet_schedule(&d->task);
2570173c895SAndy Green
2580173c895SAndy Green if (irq_chan || err1 || err2)
2598e6152bcSZhangfei Gao return IRQ_HANDLED;
2600173c895SAndy Green
2618e6152bcSZhangfei Gao return IRQ_NONE;
2628e6152bcSZhangfei Gao }
2638e6152bcSZhangfei Gao
k3_dma_start_txd(struct k3_dma_chan * c)2648e6152bcSZhangfei Gao static int k3_dma_start_txd(struct k3_dma_chan *c)
2658e6152bcSZhangfei Gao {
2668e6152bcSZhangfei Gao struct k3_dma_dev *d = to_k3_dma(c->vc.chan.device);
2678e6152bcSZhangfei Gao struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
2688e6152bcSZhangfei Gao
2698e6152bcSZhangfei Gao if (!c->phy)
2708e6152bcSZhangfei Gao return -EAGAIN;
2718e6152bcSZhangfei Gao
2728e6152bcSZhangfei Gao if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d))
2738e6152bcSZhangfei Gao return -EAGAIN;
2748e6152bcSZhangfei Gao
2752f42e05bSJohn Stultz /* Avoid losing track of ds_run if a transaction is in flight */
2762f42e05bSJohn Stultz if (c->phy->ds_run)
2772f42e05bSJohn Stultz return -EAGAIN;
2782f42e05bSJohn Stultz
2798e6152bcSZhangfei Gao if (vd) {
2808e6152bcSZhangfei Gao struct k3_dma_desc_sw *ds =
2818e6152bcSZhangfei Gao container_of(vd, struct k3_dma_desc_sw, vd);
2828e6152bcSZhangfei Gao /*
2838e6152bcSZhangfei Gao * fetch and remove request from vc->desc_issued
2848e6152bcSZhangfei Gao * so vc->desc_issued only contains desc pending
2858e6152bcSZhangfei Gao */
2868e6152bcSZhangfei Gao list_del(&ds->vd.node);
28736387a2bSJohn Stultz
2888e6152bcSZhangfei Gao c->phy->ds_run = ds;
289626c4e85SAntonio Borneo c->phy->ds_done = NULL;
2908e6152bcSZhangfei Gao /* start dma */
2918e6152bcSZhangfei Gao k3_dma_set_desc(c->phy, &ds->desc_hw[0]);
2928e6152bcSZhangfei Gao return 0;
2938e6152bcSZhangfei Gao }
294626c4e85SAntonio Borneo c->phy->ds_run = NULL;
295626c4e85SAntonio Borneo c->phy->ds_done = NULL;
2968e6152bcSZhangfei Gao return -EAGAIN;
2978e6152bcSZhangfei Gao }
2988e6152bcSZhangfei Gao
k3_dma_tasklet(struct tasklet_struct * t)299881bd142SAllen Pais static void k3_dma_tasklet(struct tasklet_struct *t)
3008e6152bcSZhangfei Gao {
301881bd142SAllen Pais struct k3_dma_dev *d = from_tasklet(d, t, task);
3028e6152bcSZhangfei Gao struct k3_dma_phy *p;
3038e6152bcSZhangfei Gao struct k3_dma_chan *c, *cn;
3048e6152bcSZhangfei Gao unsigned pch, pch_alloc = 0;
3058e6152bcSZhangfei Gao
3068e6152bcSZhangfei Gao /* check new dma request of running channel in vc->desc_issued */
3078e6152bcSZhangfei Gao list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
3088e6152bcSZhangfei Gao spin_lock_irq(&c->vc.lock);
3098e6152bcSZhangfei Gao p = c->phy;
3108e6152bcSZhangfei Gao if (p && p->ds_done) {
3118e6152bcSZhangfei Gao if (k3_dma_start_txd(c)) {
3128e6152bcSZhangfei Gao /* No current txd associated with this channel */
3138e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx);
3148e6152bcSZhangfei Gao /* Mark this channel free */
3158e6152bcSZhangfei Gao c->phy = NULL;
3168e6152bcSZhangfei Gao p->vchan = NULL;
3178e6152bcSZhangfei Gao }
3188e6152bcSZhangfei Gao }
3198e6152bcSZhangfei Gao spin_unlock_irq(&c->vc.lock);
3208e6152bcSZhangfei Gao }
3218e6152bcSZhangfei Gao
3228e6152bcSZhangfei Gao /* check new channel request in d->chan_pending */
3238e6152bcSZhangfei Gao spin_lock_irq(&d->lock);
3248e6152bcSZhangfei Gao for (pch = 0; pch < d->dma_channels; pch++) {
325c4994a98SLi Yu if (!(d->dma_channel_mask & (1 << pch)))
326c4994a98SLi Yu continue;
327c4994a98SLi Yu
3288e6152bcSZhangfei Gao p = &d->phy[pch];
3298e6152bcSZhangfei Gao
3308e6152bcSZhangfei Gao if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
3318e6152bcSZhangfei Gao c = list_first_entry(&d->chan_pending,
3328e6152bcSZhangfei Gao struct k3_dma_chan, node);
3338e6152bcSZhangfei Gao /* remove from d->chan_pending */
3348e6152bcSZhangfei Gao list_del_init(&c->node);
3358e6152bcSZhangfei Gao pch_alloc |= 1 << pch;
3368e6152bcSZhangfei Gao /* Mark this channel allocated */
3378e6152bcSZhangfei Gao p->vchan = c;
3388e6152bcSZhangfei Gao c->phy = p;
3398e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
3408e6152bcSZhangfei Gao }
3418e6152bcSZhangfei Gao }
3428e6152bcSZhangfei Gao spin_unlock_irq(&d->lock);
3438e6152bcSZhangfei Gao
3448e6152bcSZhangfei Gao for (pch = 0; pch < d->dma_channels; pch++) {
345c4994a98SLi Yu if (!(d->dma_channel_mask & (1 << pch)))
346c4994a98SLi Yu continue;
347c4994a98SLi Yu
3488e6152bcSZhangfei Gao if (pch_alloc & (1 << pch)) {
3498e6152bcSZhangfei Gao p = &d->phy[pch];
3508e6152bcSZhangfei Gao c = p->vchan;
3518e6152bcSZhangfei Gao if (c) {
3528e6152bcSZhangfei Gao spin_lock_irq(&c->vc.lock);
3538e6152bcSZhangfei Gao k3_dma_start_txd(c);
3548e6152bcSZhangfei Gao spin_unlock_irq(&c->vc.lock);
3558e6152bcSZhangfei Gao }
3568e6152bcSZhangfei Gao }
3578e6152bcSZhangfei Gao }
3588e6152bcSZhangfei Gao }
3598e6152bcSZhangfei Gao
k3_dma_free_chan_resources(struct dma_chan * chan)3608e6152bcSZhangfei Gao static void k3_dma_free_chan_resources(struct dma_chan *chan)
3618e6152bcSZhangfei Gao {
3628e6152bcSZhangfei Gao struct k3_dma_chan *c = to_k3_chan(chan);
3638e6152bcSZhangfei Gao struct k3_dma_dev *d = to_k3_dma(chan->device);
3648e6152bcSZhangfei Gao unsigned long flags;
3658e6152bcSZhangfei Gao
3668e6152bcSZhangfei Gao spin_lock_irqsave(&d->lock, flags);
3678e6152bcSZhangfei Gao list_del_init(&c->node);
3688e6152bcSZhangfei Gao spin_unlock_irqrestore(&d->lock, flags);
3698e6152bcSZhangfei Gao
3708e6152bcSZhangfei Gao vchan_free_chan_resources(&c->vc);
3718e6152bcSZhangfei Gao c->ccfg = 0;
3728e6152bcSZhangfei Gao }
3738e6152bcSZhangfei Gao
k3_dma_tx_status(struct dma_chan * chan,dma_cookie_t cookie,struct dma_tx_state * state)3748e6152bcSZhangfei Gao static enum dma_status k3_dma_tx_status(struct dma_chan *chan,
3758e6152bcSZhangfei Gao dma_cookie_t cookie, struct dma_tx_state *state)
3768e6152bcSZhangfei Gao {
3778e6152bcSZhangfei Gao struct k3_dma_chan *c = to_k3_chan(chan);
3788e6152bcSZhangfei Gao struct k3_dma_dev *d = to_k3_dma(chan->device);
3798e6152bcSZhangfei Gao struct k3_dma_phy *p;
3808e6152bcSZhangfei Gao struct virt_dma_desc *vd;
3818e6152bcSZhangfei Gao unsigned long flags;
3828e6152bcSZhangfei Gao enum dma_status ret;
3838e6152bcSZhangfei Gao size_t bytes = 0;
3848e6152bcSZhangfei Gao
3858e6152bcSZhangfei Gao ret = dma_cookie_status(&c->vc.chan, cookie, state);
386bd2c348eSVinod Koul if (ret == DMA_COMPLETE)
3878e6152bcSZhangfei Gao return ret;
3888e6152bcSZhangfei Gao
3898e6152bcSZhangfei Gao spin_lock_irqsave(&c->vc.lock, flags);
3908e6152bcSZhangfei Gao p = c->phy;
3918e6152bcSZhangfei Gao ret = c->status;
3928e6152bcSZhangfei Gao
3938e6152bcSZhangfei Gao /*
3948e6152bcSZhangfei Gao * If the cookie is on our issue queue, then the residue is
3958e6152bcSZhangfei Gao * its total size.
3968e6152bcSZhangfei Gao */
3978e6152bcSZhangfei Gao vd = vchan_find_desc(&c->vc, cookie);
398a7e08fa6SAndy Green if (vd && !c->cyclic) {
3998e6152bcSZhangfei Gao bytes = container_of(vd, struct k3_dma_desc_sw, vd)->size;
4008e6152bcSZhangfei Gao } else if ((!p) || (!p->ds_run)) {
4018e6152bcSZhangfei Gao bytes = 0;
4028e6152bcSZhangfei Gao } else {
4038e6152bcSZhangfei Gao struct k3_dma_desc_sw *ds = p->ds_run;
4048e6152bcSZhangfei Gao u32 clli = 0, index = 0;
4058e6152bcSZhangfei Gao
4068e6152bcSZhangfei Gao bytes = k3_dma_get_curr_cnt(d, p);
4078e6152bcSZhangfei Gao clli = k3_dma_get_curr_lli(p);
408a7e08fa6SAndy Green index = ((clli - ds->desc_hw_lli) /
409a7e08fa6SAndy Green sizeof(struct k3_desc_hw)) + 1;
4108e6152bcSZhangfei Gao for (; index < ds->desc_num; index++) {
4118e6152bcSZhangfei Gao bytes += ds->desc_hw[index].count;
4128e6152bcSZhangfei Gao /* end of lli */
4138e6152bcSZhangfei Gao if (!ds->desc_hw[index].lli)
4148e6152bcSZhangfei Gao break;
4158e6152bcSZhangfei Gao }
4168e6152bcSZhangfei Gao }
4178e6152bcSZhangfei Gao spin_unlock_irqrestore(&c->vc.lock, flags);
4188e6152bcSZhangfei Gao dma_set_residue(state, bytes);
4198e6152bcSZhangfei Gao return ret;
4208e6152bcSZhangfei Gao }
4218e6152bcSZhangfei Gao
k3_dma_issue_pending(struct dma_chan * chan)4228e6152bcSZhangfei Gao static void k3_dma_issue_pending(struct dma_chan *chan)
4238e6152bcSZhangfei Gao {
4248e6152bcSZhangfei Gao struct k3_dma_chan *c = to_k3_chan(chan);
4258e6152bcSZhangfei Gao struct k3_dma_dev *d = to_k3_dma(chan->device);
4268e6152bcSZhangfei Gao unsigned long flags;
4278e6152bcSZhangfei Gao
4288e6152bcSZhangfei Gao spin_lock_irqsave(&c->vc.lock, flags);
4298e6152bcSZhangfei Gao /* add request to vc->desc_issued */
4308e6152bcSZhangfei Gao if (vchan_issue_pending(&c->vc)) {
4318e6152bcSZhangfei Gao spin_lock(&d->lock);
4328e6152bcSZhangfei Gao if (!c->phy) {
4338e6152bcSZhangfei Gao if (list_empty(&c->node)) {
4348e6152bcSZhangfei Gao /* if new channel, add chan_pending */
4358e6152bcSZhangfei Gao list_add_tail(&c->node, &d->chan_pending);
4368e6152bcSZhangfei Gao /* check in tasklet */
4378e6152bcSZhangfei Gao tasklet_schedule(&d->task);
4388e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
4398e6152bcSZhangfei Gao }
4408e6152bcSZhangfei Gao }
4418e6152bcSZhangfei Gao spin_unlock(&d->lock);
4428e6152bcSZhangfei Gao } else
4438e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
4448e6152bcSZhangfei Gao spin_unlock_irqrestore(&c->vc.lock, flags);
4458e6152bcSZhangfei Gao }
4468e6152bcSZhangfei Gao
k3_dma_fill_desc(struct k3_dma_desc_sw * ds,dma_addr_t dst,dma_addr_t src,size_t len,u32 num,u32 ccfg)4478e6152bcSZhangfei Gao static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst,
4488e6152bcSZhangfei Gao dma_addr_t src, size_t len, u32 num, u32 ccfg)
4498e6152bcSZhangfei Gao {
450a7e08fa6SAndy Green if (num != ds->desc_num - 1)
4518e6152bcSZhangfei Gao ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
4528e6152bcSZhangfei Gao sizeof(struct k3_desc_hw);
453a7e08fa6SAndy Green
4548e6152bcSZhangfei Gao ds->desc_hw[num].lli |= CX_LLI_CHAIN_EN;
4558e6152bcSZhangfei Gao ds->desc_hw[num].count = len;
4568e6152bcSZhangfei Gao ds->desc_hw[num].saddr = src;
4578e6152bcSZhangfei Gao ds->desc_hw[num].daddr = dst;
4588e6152bcSZhangfei Gao ds->desc_hw[num].config = ccfg;
4598e6152bcSZhangfei Gao }
4608e6152bcSZhangfei Gao
k3_dma_alloc_desc_resource(int num,struct dma_chan * chan)461b77f262aSJohn Stultz static struct k3_dma_desc_sw *k3_dma_alloc_desc_resource(int num,
462b77f262aSJohn Stultz struct dma_chan *chan)
463b77f262aSJohn Stultz {
464b77f262aSJohn Stultz struct k3_dma_chan *c = to_k3_chan(chan);
465b77f262aSJohn Stultz struct k3_dma_desc_sw *ds;
466b77f262aSJohn Stultz struct k3_dma_dev *d = to_k3_dma(chan->device);
467b77f262aSJohn Stultz int lli_limit = LLI_BLOCK_SIZE / sizeof(struct k3_desc_hw);
468b77f262aSJohn Stultz
469b77f262aSJohn Stultz if (num > lli_limit) {
470b77f262aSJohn Stultz dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n",
471b77f262aSJohn Stultz &c->vc, num, lli_limit);
472b77f262aSJohn Stultz return NULL;
473b77f262aSJohn Stultz }
474b77f262aSJohn Stultz
475b77f262aSJohn Stultz ds = kzalloc(sizeof(*ds), GFP_NOWAIT);
476b77f262aSJohn Stultz if (!ds)
477b77f262aSJohn Stultz return NULL;
478b77f262aSJohn Stultz
479646b3b56SVinod Koul ds->desc_hw = dma_pool_zalloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli);
480b77f262aSJohn Stultz if (!ds->desc_hw) {
481b77f262aSJohn Stultz dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc);
482b77f262aSJohn Stultz kfree(ds);
483b77f262aSJohn Stultz return NULL;
484b77f262aSJohn Stultz }
485b77f262aSJohn Stultz ds->desc_num = num;
486b77f262aSJohn Stultz return ds;
487b77f262aSJohn Stultz }
488b77f262aSJohn Stultz
k3_dma_prep_memcpy(struct dma_chan * chan,dma_addr_t dst,dma_addr_t src,size_t len,unsigned long flags)4898e6152bcSZhangfei Gao static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
4908e6152bcSZhangfei Gao struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
4918e6152bcSZhangfei Gao size_t len, unsigned long flags)
4928e6152bcSZhangfei Gao {
4938e6152bcSZhangfei Gao struct k3_dma_chan *c = to_k3_chan(chan);
4948e6152bcSZhangfei Gao struct k3_dma_desc_sw *ds;
4958e6152bcSZhangfei Gao size_t copy = 0;
4968e6152bcSZhangfei Gao int num = 0;
4978e6152bcSZhangfei Gao
4988e6152bcSZhangfei Gao if (!len)
4998e6152bcSZhangfei Gao return NULL;
5008e6152bcSZhangfei Gao
5018e6152bcSZhangfei Gao num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
502b77f262aSJohn Stultz
503b77f262aSJohn Stultz ds = k3_dma_alloc_desc_resource(num, chan);
504aef94feaSPeter Griffin if (!ds)
5058e6152bcSZhangfei Gao return NULL;
506aef94feaSPeter Griffin
507a7e08fa6SAndy Green c->cyclic = 0;
5088e6152bcSZhangfei Gao ds->size = len;
5098e6152bcSZhangfei Gao num = 0;
5108e6152bcSZhangfei Gao
5118e6152bcSZhangfei Gao if (!c->ccfg) {
512db08425eSMaxime Ripard /* default is memtomem, without calling device_config */
5138e6152bcSZhangfei Gao c->ccfg = CX_CFG_SRCINCR | CX_CFG_DSTINCR | CX_CFG_EN;
5148e6152bcSZhangfei Gao c->ccfg |= (0xf << 20) | (0xf << 24); /* burst = 16 */
5158e6152bcSZhangfei Gao c->ccfg |= (0x3 << 12) | (0x3 << 16); /* width = 64 bit */
5168e6152bcSZhangfei Gao }
5178e6152bcSZhangfei Gao
5188e6152bcSZhangfei Gao do {
5198e6152bcSZhangfei Gao copy = min_t(size_t, len, DMA_MAX_SIZE);
5208e6152bcSZhangfei Gao k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
5218e6152bcSZhangfei Gao
5228e6152bcSZhangfei Gao src += copy;
5238e6152bcSZhangfei Gao dst += copy;
5248e6152bcSZhangfei Gao len -= copy;
5258e6152bcSZhangfei Gao } while (len);
5268e6152bcSZhangfei Gao
5278e6152bcSZhangfei Gao ds->desc_hw[num-1].lli = 0; /* end of link */
5288e6152bcSZhangfei Gao return vchan_tx_prep(&c->vc, &ds->vd, flags);
5298e6152bcSZhangfei Gao }
5308e6152bcSZhangfei Gao
k3_dma_prep_slave_sg(struct dma_chan * chan,struct scatterlist * sgl,unsigned int sglen,enum dma_transfer_direction dir,unsigned long flags,void * context)5318e6152bcSZhangfei Gao static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
5328e6152bcSZhangfei Gao struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen,
5338e6152bcSZhangfei Gao enum dma_transfer_direction dir, unsigned long flags, void *context)
5348e6152bcSZhangfei Gao {
5358e6152bcSZhangfei Gao struct k3_dma_chan *c = to_k3_chan(chan);
5368e6152bcSZhangfei Gao struct k3_dma_desc_sw *ds;
5378e6152bcSZhangfei Gao size_t len, avail, total = 0;
5388e6152bcSZhangfei Gao struct scatterlist *sg;
5398e6152bcSZhangfei Gao dma_addr_t addr, src = 0, dst = 0;
5408e6152bcSZhangfei Gao int num = sglen, i;
5418e6152bcSZhangfei Gao
542c61177c5SZhangfei Gao if (sgl == NULL)
5438e6152bcSZhangfei Gao return NULL;
5448e6152bcSZhangfei Gao
545a7e08fa6SAndy Green c->cyclic = 0;
546a7e08fa6SAndy Green
5478e6152bcSZhangfei Gao for_each_sg(sgl, sg, sglen, i) {
5488e6152bcSZhangfei Gao avail = sg_dma_len(sg);
5498e6152bcSZhangfei Gao if (avail > DMA_MAX_SIZE)
5508e6152bcSZhangfei Gao num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
5518e6152bcSZhangfei Gao }
5528e6152bcSZhangfei Gao
553b77f262aSJohn Stultz ds = k3_dma_alloc_desc_resource(num, chan);
554aef94feaSPeter Griffin if (!ds)
5558e6152bcSZhangfei Gao return NULL;
5568e6152bcSZhangfei Gao num = 0;
5572ae1a237SVinod Koul k3_dma_config_write(chan, dir, &c->slave_config);
5588e6152bcSZhangfei Gao
5598e6152bcSZhangfei Gao for_each_sg(sgl, sg, sglen, i) {
5608e6152bcSZhangfei Gao addr = sg_dma_address(sg);
5618e6152bcSZhangfei Gao avail = sg_dma_len(sg);
5628e6152bcSZhangfei Gao total += avail;
5638e6152bcSZhangfei Gao
5648e6152bcSZhangfei Gao do {
5658e6152bcSZhangfei Gao len = min_t(size_t, avail, DMA_MAX_SIZE);
5668e6152bcSZhangfei Gao
5678e6152bcSZhangfei Gao if (dir == DMA_MEM_TO_DEV) {
5688e6152bcSZhangfei Gao src = addr;
5698e6152bcSZhangfei Gao dst = c->dev_addr;
5708e6152bcSZhangfei Gao } else if (dir == DMA_DEV_TO_MEM) {
5718e6152bcSZhangfei Gao src = c->dev_addr;
5728e6152bcSZhangfei Gao dst = addr;
5738e6152bcSZhangfei Gao }
5748e6152bcSZhangfei Gao
5758e6152bcSZhangfei Gao k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg);
5768e6152bcSZhangfei Gao
5778e6152bcSZhangfei Gao addr += len;
5788e6152bcSZhangfei Gao avail -= len;
5798e6152bcSZhangfei Gao } while (avail);
5808e6152bcSZhangfei Gao }
5818e6152bcSZhangfei Gao
5828e6152bcSZhangfei Gao ds->desc_hw[num-1].lli = 0; /* end of link */
5838e6152bcSZhangfei Gao ds->size = total;
5848e6152bcSZhangfei Gao return vchan_tx_prep(&c->vc, &ds->vd, flags);
5858e6152bcSZhangfei Gao }
5868e6152bcSZhangfei Gao
587a7e08fa6SAndy Green static struct dma_async_tx_descriptor *
k3_dma_prep_dma_cyclic(struct dma_chan * chan,dma_addr_t buf_addr,size_t buf_len,size_t period_len,enum dma_transfer_direction dir,unsigned long flags)588a7e08fa6SAndy Green k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
589a7e08fa6SAndy Green size_t buf_len, size_t period_len,
590a7e08fa6SAndy Green enum dma_transfer_direction dir,
591a7e08fa6SAndy Green unsigned long flags)
592a7e08fa6SAndy Green {
593a7e08fa6SAndy Green struct k3_dma_chan *c = to_k3_chan(chan);
594a7e08fa6SAndy Green struct k3_dma_desc_sw *ds;
595a7e08fa6SAndy Green size_t len, avail, total = 0;
596a7e08fa6SAndy Green dma_addr_t addr, src = 0, dst = 0;
597a7e08fa6SAndy Green int num = 1, since = 0;
598a7e08fa6SAndy Green size_t modulo = DMA_CYCLIC_MAX_PERIOD;
599a7e08fa6SAndy Green u32 en_tc2 = 0;
600a7e08fa6SAndy Green
6015f03c399SArnd Bergmann dev_dbg(chan->device->dev, "%s: buf %pad, dst %pad, buf len %zu, period_len = %zu, dir %d\n",
6025f03c399SArnd Bergmann __func__, &buf_addr, &to_k3_chan(chan)->dev_addr,
6035f03c399SArnd Bergmann buf_len, period_len, (int)dir);
604a7e08fa6SAndy Green
605a7e08fa6SAndy Green avail = buf_len;
606a7e08fa6SAndy Green if (avail > modulo)
607a7e08fa6SAndy Green num += DIV_ROUND_UP(avail, modulo) - 1;
608a7e08fa6SAndy Green
609a7e08fa6SAndy Green ds = k3_dma_alloc_desc_resource(num, chan);
610a7e08fa6SAndy Green if (!ds)
611a7e08fa6SAndy Green return NULL;
612a7e08fa6SAndy Green
613a7e08fa6SAndy Green c->cyclic = 1;
614a7e08fa6SAndy Green addr = buf_addr;
615a7e08fa6SAndy Green avail = buf_len;
616a7e08fa6SAndy Green total = avail;
617a7e08fa6SAndy Green num = 0;
6182ae1a237SVinod Koul k3_dma_config_write(chan, dir, &c->slave_config);
619a7e08fa6SAndy Green
620a7e08fa6SAndy Green if (period_len < modulo)
621a7e08fa6SAndy Green modulo = period_len;
622a7e08fa6SAndy Green
623a7e08fa6SAndy Green do {
624a7e08fa6SAndy Green len = min_t(size_t, avail, modulo);
625a7e08fa6SAndy Green
626a7e08fa6SAndy Green if (dir == DMA_MEM_TO_DEV) {
627a7e08fa6SAndy Green src = addr;
628a7e08fa6SAndy Green dst = c->dev_addr;
629a7e08fa6SAndy Green } else if (dir == DMA_DEV_TO_MEM) {
630a7e08fa6SAndy Green src = c->dev_addr;
631a7e08fa6SAndy Green dst = addr;
632a7e08fa6SAndy Green }
633a7e08fa6SAndy Green since += len;
634a7e08fa6SAndy Green if (since >= period_len) {
635a7e08fa6SAndy Green /* descriptor asks for TC2 interrupt on completion */
636a7e08fa6SAndy Green en_tc2 = CX_CFG_NODEIRQ;
637a7e08fa6SAndy Green since -= period_len;
638a7e08fa6SAndy Green } else
639a7e08fa6SAndy Green en_tc2 = 0;
640a7e08fa6SAndy Green
641a7e08fa6SAndy Green k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg | en_tc2);
642a7e08fa6SAndy Green
643a7e08fa6SAndy Green addr += len;
644a7e08fa6SAndy Green avail -= len;
645a7e08fa6SAndy Green } while (avail);
646a7e08fa6SAndy Green
647a7e08fa6SAndy Green /* "Cyclic" == end of link points back to start of link */
648a7e08fa6SAndy Green ds->desc_hw[num - 1].lli |= ds->desc_hw_lli;
649a7e08fa6SAndy Green
650a7e08fa6SAndy Green ds->size = total;
651a7e08fa6SAndy Green
652a7e08fa6SAndy Green return vchan_tx_prep(&c->vc, &ds->vd, flags);
653a7e08fa6SAndy Green }
654a7e08fa6SAndy Green
k3_dma_config(struct dma_chan * chan,struct dma_slave_config * cfg)655db08425eSMaxime Ripard static int k3_dma_config(struct dma_chan *chan,
656db08425eSMaxime Ripard struct dma_slave_config *cfg)
6578e6152bcSZhangfei Gao {
6588e6152bcSZhangfei Gao struct k3_dma_chan *c = to_k3_chan(chan);
6592ae1a237SVinod Koul
6602ae1a237SVinod Koul memcpy(&c->slave_config, cfg, sizeof(*cfg));
6612ae1a237SVinod Koul
6622ae1a237SVinod Koul return 0;
6632ae1a237SVinod Koul }
6642ae1a237SVinod Koul
k3_dma_config_write(struct dma_chan * chan,enum dma_transfer_direction dir,struct dma_slave_config * cfg)6652ae1a237SVinod Koul static int k3_dma_config_write(struct dma_chan *chan,
6662ae1a237SVinod Koul enum dma_transfer_direction dir,
6672ae1a237SVinod Koul struct dma_slave_config *cfg)
6682ae1a237SVinod Koul {
6692ae1a237SVinod Koul struct k3_dma_chan *c = to_k3_chan(chan);
6708e6152bcSZhangfei Gao u32 maxburst = 0, val = 0;
6718e6152bcSZhangfei Gao enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
6728e6152bcSZhangfei Gao
6732ae1a237SVinod Koul if (dir == DMA_DEV_TO_MEM) {
6748e6152bcSZhangfei Gao c->ccfg = CX_CFG_DSTINCR;
6758e6152bcSZhangfei Gao c->dev_addr = cfg->src_addr;
6768e6152bcSZhangfei Gao maxburst = cfg->src_maxburst;
6778e6152bcSZhangfei Gao width = cfg->src_addr_width;
6782ae1a237SVinod Koul } else if (dir == DMA_MEM_TO_DEV) {
6798e6152bcSZhangfei Gao c->ccfg = CX_CFG_SRCINCR;
6808e6152bcSZhangfei Gao c->dev_addr = cfg->dst_addr;
6818e6152bcSZhangfei Gao maxburst = cfg->dst_maxburst;
6828e6152bcSZhangfei Gao width = cfg->dst_addr_width;
6838e6152bcSZhangfei Gao }
6848e6152bcSZhangfei Gao switch (width) {
6858e6152bcSZhangfei Gao case DMA_SLAVE_BUSWIDTH_1_BYTE:
6868e6152bcSZhangfei Gao case DMA_SLAVE_BUSWIDTH_2_BYTES:
6878e6152bcSZhangfei Gao case DMA_SLAVE_BUSWIDTH_4_BYTES:
6888e6152bcSZhangfei Gao case DMA_SLAVE_BUSWIDTH_8_BYTES:
6898e6152bcSZhangfei Gao val = __ffs(width);
6908e6152bcSZhangfei Gao break;
6918e6152bcSZhangfei Gao default:
6928e6152bcSZhangfei Gao val = 3;
6938e6152bcSZhangfei Gao break;
6948e6152bcSZhangfei Gao }
6958e6152bcSZhangfei Gao c->ccfg |= (val << 12) | (val << 16);
6968e6152bcSZhangfei Gao
6978e6152bcSZhangfei Gao if ((maxburst == 0) || (maxburst > 16))
6986c28a90fSAndy Green val = 15;
6998e6152bcSZhangfei Gao else
7008e6152bcSZhangfei Gao val = maxburst - 1;
7018e6152bcSZhangfei Gao c->ccfg |= (val << 20) | (val << 24);
7028e6152bcSZhangfei Gao c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;
7038e6152bcSZhangfei Gao
7048e6152bcSZhangfei Gao /* specific request line */
7058e6152bcSZhangfei Gao c->ccfg |= c->vc.chan.chan_id << 4;
7068e6152bcSZhangfei Gao
707db08425eSMaxime Ripard return 0;
708db08425eSMaxime Ripard }
709db08425eSMaxime Ripard
k3_dma_free_desc(struct virt_dma_desc * vd)71036387a2bSJohn Stultz static void k3_dma_free_desc(struct virt_dma_desc *vd)
71136387a2bSJohn Stultz {
71236387a2bSJohn Stultz struct k3_dma_desc_sw *ds =
71336387a2bSJohn Stultz container_of(vd, struct k3_dma_desc_sw, vd);
71436387a2bSJohn Stultz struct k3_dma_dev *d = to_k3_dma(vd->tx.chan->device);
71536387a2bSJohn Stultz
71636387a2bSJohn Stultz dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli);
71736387a2bSJohn Stultz kfree(ds);
71836387a2bSJohn Stultz }
71936387a2bSJohn Stultz
k3_dma_terminate_all(struct dma_chan * chan)720db08425eSMaxime Ripard static int k3_dma_terminate_all(struct dma_chan *chan)
721db08425eSMaxime Ripard {
722db08425eSMaxime Ripard struct k3_dma_chan *c = to_k3_chan(chan);
723db08425eSMaxime Ripard struct k3_dma_dev *d = to_k3_dma(chan->device);
724db08425eSMaxime Ripard struct k3_dma_phy *p = c->phy;
725db08425eSMaxime Ripard unsigned long flags;
726db08425eSMaxime Ripard LIST_HEAD(head);
727db08425eSMaxime Ripard
7288e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
7298e6152bcSZhangfei Gao
7308e6152bcSZhangfei Gao /* Prevent this channel being scheduled */
7318e6152bcSZhangfei Gao spin_lock(&d->lock);
7328e6152bcSZhangfei Gao list_del_init(&c->node);
7338e6152bcSZhangfei Gao spin_unlock(&d->lock);
7348e6152bcSZhangfei Gao
7358e6152bcSZhangfei Gao /* Clear the tx descriptor lists */
7368e6152bcSZhangfei Gao spin_lock_irqsave(&c->vc.lock, flags);
7378e6152bcSZhangfei Gao vchan_get_all_descriptors(&c->vc, &head);
7388e6152bcSZhangfei Gao if (p) {
7398e6152bcSZhangfei Gao /* vchan is assigned to a pchan - stop the channel */
7408e6152bcSZhangfei Gao k3_dma_terminate_chan(p, d);
7418e6152bcSZhangfei Gao c->phy = NULL;
7428e6152bcSZhangfei Gao p->vchan = NULL;
74336387a2bSJohn Stultz if (p->ds_run) {
7443ee7e42fSPeter Ujfalusi vchan_terminate_vdesc(&p->ds_run->vd);
74536387a2bSJohn Stultz p->ds_run = NULL;
74636387a2bSJohn Stultz }
74736387a2bSJohn Stultz p->ds_done = NULL;
74836387a2bSJohn Stultz }
7498e6152bcSZhangfei Gao spin_unlock_irqrestore(&c->vc.lock, flags);
7508e6152bcSZhangfei Gao vchan_dma_desc_free_list(&c->vc, &head);
7518e6152bcSZhangfei Gao
752db08425eSMaxime Ripard return 0;
753db08425eSMaxime Ripard }
754db08425eSMaxime Ripard
k3_dma_synchronize(struct dma_chan * chan)7553ee7e42fSPeter Ujfalusi static void k3_dma_synchronize(struct dma_chan *chan)
7563ee7e42fSPeter Ujfalusi {
7573ee7e42fSPeter Ujfalusi struct k3_dma_chan *c = to_k3_chan(chan);
7583ee7e42fSPeter Ujfalusi
7593ee7e42fSPeter Ujfalusi vchan_synchronize(&c->vc);
7603ee7e42fSPeter Ujfalusi }
7613ee7e42fSPeter Ujfalusi
k3_dma_transfer_pause(struct dma_chan * chan)762a1a9becbSKrzysztof Kozlowski static int k3_dma_transfer_pause(struct dma_chan *chan)
763db08425eSMaxime Ripard {
764db08425eSMaxime Ripard struct k3_dma_chan *c = to_k3_chan(chan);
765db08425eSMaxime Ripard struct k3_dma_dev *d = to_k3_dma(chan->device);
766db08425eSMaxime Ripard struct k3_dma_phy *p = c->phy;
767db08425eSMaxime Ripard
7688e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
7698e6152bcSZhangfei Gao if (c->status == DMA_IN_PROGRESS) {
7708e6152bcSZhangfei Gao c->status = DMA_PAUSED;
7718e6152bcSZhangfei Gao if (p) {
7728e6152bcSZhangfei Gao k3_dma_pause_dma(p, false);
7738e6152bcSZhangfei Gao } else {
7748e6152bcSZhangfei Gao spin_lock(&d->lock);
7758e6152bcSZhangfei Gao list_del_init(&c->node);
7768e6152bcSZhangfei Gao spin_unlock(&d->lock);
7778e6152bcSZhangfei Gao }
7788e6152bcSZhangfei Gao }
7798e6152bcSZhangfei Gao
780db08425eSMaxime Ripard return 0;
781db08425eSMaxime Ripard }
782db08425eSMaxime Ripard
k3_dma_transfer_resume(struct dma_chan * chan)783a1a9becbSKrzysztof Kozlowski static int k3_dma_transfer_resume(struct dma_chan *chan)
784db08425eSMaxime Ripard {
785db08425eSMaxime Ripard struct k3_dma_chan *c = to_k3_chan(chan);
786db08425eSMaxime Ripard struct k3_dma_dev *d = to_k3_dma(chan->device);
787db08425eSMaxime Ripard struct k3_dma_phy *p = c->phy;
788db08425eSMaxime Ripard unsigned long flags;
789db08425eSMaxime Ripard
7908e6152bcSZhangfei Gao dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
7918e6152bcSZhangfei Gao spin_lock_irqsave(&c->vc.lock, flags);
7928e6152bcSZhangfei Gao if (c->status == DMA_PAUSED) {
7938e6152bcSZhangfei Gao c->status = DMA_IN_PROGRESS;
7948e6152bcSZhangfei Gao if (p) {
7958e6152bcSZhangfei Gao k3_dma_pause_dma(p, true);
7968e6152bcSZhangfei Gao } else if (!list_empty(&c->vc.desc_issued)) {
7978e6152bcSZhangfei Gao spin_lock(&d->lock);
7988e6152bcSZhangfei Gao list_add_tail(&c->node, &d->chan_pending);
7998e6152bcSZhangfei Gao spin_unlock(&d->lock);
8008e6152bcSZhangfei Gao }
8018e6152bcSZhangfei Gao }
8028e6152bcSZhangfei Gao spin_unlock_irqrestore(&c->vc.lock, flags);
803db08425eSMaxime Ripard
8048e6152bcSZhangfei Gao return 0;
8058e6152bcSZhangfei Gao }
8068e6152bcSZhangfei Gao
807d4bdc39fSYoulin Wang static const struct k3dma_soc_data k3_v1_dma_data = {
808d4bdc39fSYoulin Wang .flags = 0,
809d4bdc39fSYoulin Wang };
810d4bdc39fSYoulin Wang
811d4bdc39fSYoulin Wang static const struct k3dma_soc_data asp_v1_dma_data = {
812d4bdc39fSYoulin Wang .flags = K3_FLAG_NOCLK,
813d4bdc39fSYoulin Wang };
814d4bdc39fSYoulin Wang
81557c03422SFabian Frederick static const struct of_device_id k3_pdma_dt_ids[] = {
816d4bdc39fSYoulin Wang { .compatible = "hisilicon,k3-dma-1.0",
817d4bdc39fSYoulin Wang .data = &k3_v1_dma_data
818d4bdc39fSYoulin Wang },
819d4bdc39fSYoulin Wang { .compatible = "hisilicon,hisi-pcm-asp-dma-1.0",
820d4bdc39fSYoulin Wang .data = &asp_v1_dma_data
821d4bdc39fSYoulin Wang },
8228e6152bcSZhangfei Gao {}
8238e6152bcSZhangfei Gao };
8248e6152bcSZhangfei Gao MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids);
8258e6152bcSZhangfei Gao
k3_of_dma_simple_xlate(struct of_phandle_args * dma_spec,struct of_dma * ofdma)8268e6152bcSZhangfei Gao static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
8278e6152bcSZhangfei Gao struct of_dma *ofdma)
8288e6152bcSZhangfei Gao {
8298e6152bcSZhangfei Gao struct k3_dma_dev *d = ofdma->of_dma_data;
8308e6152bcSZhangfei Gao unsigned int request = dma_spec->args[0];
8318e6152bcSZhangfei Gao
832c4c2b764SDan Carpenter if (request >= d->dma_requests)
8338e6152bcSZhangfei Gao return NULL;
8348e6152bcSZhangfei Gao
8358e6152bcSZhangfei Gao return dma_get_slave_channel(&(d->chans[request].vc.chan));
8368e6152bcSZhangfei Gao }
8378e6152bcSZhangfei Gao
k3_dma_probe(struct platform_device * op)8388e6152bcSZhangfei Gao static int k3_dma_probe(struct platform_device *op)
8398e6152bcSZhangfei Gao {
840d4bdc39fSYoulin Wang const struct k3dma_soc_data *soc_data;
8418e6152bcSZhangfei Gao struct k3_dma_dev *d;
8428e6152bcSZhangfei Gao const struct of_device_id *of_id;
8438e6152bcSZhangfei Gao int i, ret, irq = 0;
8448e6152bcSZhangfei Gao
8458e6152bcSZhangfei Gao d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
8468e6152bcSZhangfei Gao if (!d)
8478e6152bcSZhangfei Gao return -ENOMEM;
8488e6152bcSZhangfei Gao
849d4bdc39fSYoulin Wang soc_data = device_get_match_data(&op->dev);
850d4bdc39fSYoulin Wang if (!soc_data)
851d4bdc39fSYoulin Wang return -EINVAL;
852d4bdc39fSYoulin Wang
8533d4d6c27SMarkus Elfring d->base = devm_platform_ioremap_resource(op, 0);
854a576b7feSJingoo Han if (IS_ERR(d->base))
855a576b7feSJingoo Han return PTR_ERR(d->base);
8568e6152bcSZhangfei Gao
8578e6152bcSZhangfei Gao of_id = of_match_device(k3_pdma_dt_ids, &op->dev);
8588e6152bcSZhangfei Gao if (of_id) {
8598e6152bcSZhangfei Gao of_property_read_u32((&op->dev)->of_node,
8608e6152bcSZhangfei Gao "dma-channels", &d->dma_channels);
8618e6152bcSZhangfei Gao of_property_read_u32((&op->dev)->of_node,
8628e6152bcSZhangfei Gao "dma-requests", &d->dma_requests);
863c4994a98SLi Yu ret = of_property_read_u32((&op->dev)->of_node,
864c4994a98SLi Yu "dma-channel-mask", &d->dma_channel_mask);
865c4994a98SLi Yu if (ret) {
866c4994a98SLi Yu dev_warn(&op->dev,
867c4994a98SLi Yu "dma-channel-mask doesn't exist, considering all as available.\n");
868c4994a98SLi Yu d->dma_channel_mask = (u32)~0UL;
869c4994a98SLi Yu }
8708e6152bcSZhangfei Gao }
8718e6152bcSZhangfei Gao
872d4bdc39fSYoulin Wang if (!(soc_data->flags & K3_FLAG_NOCLK)) {
8738e6152bcSZhangfei Gao d->clk = devm_clk_get(&op->dev, NULL);
8748e6152bcSZhangfei Gao if (IS_ERR(d->clk)) {
8758e6152bcSZhangfei Gao dev_err(&op->dev, "no dma clk\n");
8768e6152bcSZhangfei Gao return PTR_ERR(d->clk);
8778e6152bcSZhangfei Gao }
878d4bdc39fSYoulin Wang }
8798e6152bcSZhangfei Gao
8808e6152bcSZhangfei Gao irq = platform_get_irq(op, 0);
8818e6152bcSZhangfei Gao ret = devm_request_irq(&op->dev, irq,
882174b537aSMichael Opdenacker k3_dma_int_handler, 0, DRIVER_NAME, d);
8838e6152bcSZhangfei Gao if (ret)
8848e6152bcSZhangfei Gao return ret;
8858e6152bcSZhangfei Gao
886486b10a2SVinod Koul d->irq = irq;
887486b10a2SVinod Koul
888b77f262aSJohn Stultz /* A DMA memory pool for LLIs, align on 32-byte boundary */
889b77f262aSJohn Stultz d->pool = dmam_pool_create(DRIVER_NAME, &op->dev,
890b77f262aSJohn Stultz LLI_BLOCK_SIZE, 32, 0);
891b77f262aSJohn Stultz if (!d->pool)
892b77f262aSJohn Stultz return -ENOMEM;
893b77f262aSJohn Stultz
8948e6152bcSZhangfei Gao /* init phy channel */
895a86854d0SKees Cook d->phy = devm_kcalloc(&op->dev,
896a86854d0SKees Cook d->dma_channels, sizeof(struct k3_dma_phy), GFP_KERNEL);
8978e6152bcSZhangfei Gao if (d->phy == NULL)
8988e6152bcSZhangfei Gao return -ENOMEM;
8998e6152bcSZhangfei Gao
9008e6152bcSZhangfei Gao for (i = 0; i < d->dma_channels; i++) {
901c4994a98SLi Yu struct k3_dma_phy *p;
9028e6152bcSZhangfei Gao
903c4994a98SLi Yu if (!(d->dma_channel_mask & BIT(i)))
904c4994a98SLi Yu continue;
905c4994a98SLi Yu
906c4994a98SLi Yu p = &d->phy[i];
9078e6152bcSZhangfei Gao p->idx = i;
9088e6152bcSZhangfei Gao p->base = d->base + i * 0x40;
9098e6152bcSZhangfei Gao }
9108e6152bcSZhangfei Gao
9118e6152bcSZhangfei Gao INIT_LIST_HEAD(&d->slave.channels);
9128e6152bcSZhangfei Gao dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
9138e6152bcSZhangfei Gao dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
914a7e08fa6SAndy Green dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
9158e6152bcSZhangfei Gao d->slave.dev = &op->dev;
9168e6152bcSZhangfei Gao d->slave.device_free_chan_resources = k3_dma_free_chan_resources;
9178e6152bcSZhangfei Gao d->slave.device_tx_status = k3_dma_tx_status;
9188e6152bcSZhangfei Gao d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
9198e6152bcSZhangfei Gao d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
920a7e08fa6SAndy Green d->slave.device_prep_dma_cyclic = k3_dma_prep_dma_cyclic;
9218e6152bcSZhangfei Gao d->slave.device_issue_pending = k3_dma_issue_pending;
922db08425eSMaxime Ripard d->slave.device_config = k3_dma_config;
923a1a9becbSKrzysztof Kozlowski d->slave.device_pause = k3_dma_transfer_pause;
924a1a9becbSKrzysztof Kozlowski d->slave.device_resume = k3_dma_transfer_resume;
925db08425eSMaxime Ripard d->slave.device_terminate_all = k3_dma_terminate_all;
9263ee7e42fSPeter Ujfalusi d->slave.device_synchronize = k3_dma_synchronize;
92777a68e56SMaxime Ripard d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES;
9288e6152bcSZhangfei Gao
9298e6152bcSZhangfei Gao /* init virtual channel */
930a86854d0SKees Cook d->chans = devm_kcalloc(&op->dev,
931a86854d0SKees Cook d->dma_requests, sizeof(struct k3_dma_chan), GFP_KERNEL);
9328e6152bcSZhangfei Gao if (d->chans == NULL)
9338e6152bcSZhangfei Gao return -ENOMEM;
9348e6152bcSZhangfei Gao
9358e6152bcSZhangfei Gao for (i = 0; i < d->dma_requests; i++) {
9368e6152bcSZhangfei Gao struct k3_dma_chan *c = &d->chans[i];
9378e6152bcSZhangfei Gao
9388e6152bcSZhangfei Gao c->status = DMA_IN_PROGRESS;
9398e6152bcSZhangfei Gao INIT_LIST_HEAD(&c->node);
9408e6152bcSZhangfei Gao c->vc.desc_free = k3_dma_free_desc;
9418e6152bcSZhangfei Gao vchan_init(&c->vc, &d->slave);
9428e6152bcSZhangfei Gao }
9438e6152bcSZhangfei Gao
9448e6152bcSZhangfei Gao /* Enable clock before accessing registers */
9458e6152bcSZhangfei Gao ret = clk_prepare_enable(d->clk);
9468e6152bcSZhangfei Gao if (ret < 0) {
9478e6152bcSZhangfei Gao dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
9488e6152bcSZhangfei Gao return ret;
9498e6152bcSZhangfei Gao }
9508e6152bcSZhangfei Gao
9518e6152bcSZhangfei Gao k3_dma_enable_dma(d, true);
9528e6152bcSZhangfei Gao
9538e6152bcSZhangfei Gao ret = dma_async_device_register(&d->slave);
9548e6152bcSZhangfei Gao if (ret)
95589b90c09SWei Yongjun goto dma_async_register_fail;
9568e6152bcSZhangfei Gao
9578e6152bcSZhangfei Gao ret = of_dma_controller_register((&op->dev)->of_node,
9588e6152bcSZhangfei Gao k3_of_dma_simple_xlate, d);
9598e6152bcSZhangfei Gao if (ret)
9608e6152bcSZhangfei Gao goto of_dma_register_fail;
9618e6152bcSZhangfei Gao
9628e6152bcSZhangfei Gao spin_lock_init(&d->lock);
9638e6152bcSZhangfei Gao INIT_LIST_HEAD(&d->chan_pending);
964881bd142SAllen Pais tasklet_setup(&d->task, k3_dma_tasklet);
9658e6152bcSZhangfei Gao platform_set_drvdata(op, d);
9668e6152bcSZhangfei Gao dev_info(&op->dev, "initialized\n");
9678e6152bcSZhangfei Gao
9688e6152bcSZhangfei Gao return 0;
9698e6152bcSZhangfei Gao
9708e6152bcSZhangfei Gao of_dma_register_fail:
9718e6152bcSZhangfei Gao dma_async_device_unregister(&d->slave);
97289b90c09SWei Yongjun dma_async_register_fail:
97389b90c09SWei Yongjun clk_disable_unprepare(d->clk);
9748e6152bcSZhangfei Gao return ret;
9758e6152bcSZhangfei Gao }
9768e6152bcSZhangfei Gao
k3_dma_remove(struct platform_device * op)9778e6152bcSZhangfei Gao static int k3_dma_remove(struct platform_device *op)
9788e6152bcSZhangfei Gao {
9798e6152bcSZhangfei Gao struct k3_dma_chan *c, *cn;
9808e6152bcSZhangfei Gao struct k3_dma_dev *d = platform_get_drvdata(op);
9818e6152bcSZhangfei Gao
9828e6152bcSZhangfei Gao dma_async_device_unregister(&d->slave);
9838e6152bcSZhangfei Gao of_dma_controller_free((&op->dev)->of_node);
9848e6152bcSZhangfei Gao
985486b10a2SVinod Koul devm_free_irq(&op->dev, d->irq, d);
986486b10a2SVinod Koul
9878e6152bcSZhangfei Gao list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
9888e6152bcSZhangfei Gao list_del(&c->vc.chan.device_node);
9898e6152bcSZhangfei Gao tasklet_kill(&c->vc.task);
9908e6152bcSZhangfei Gao }
9918e6152bcSZhangfei Gao tasklet_kill(&d->task);
9928e6152bcSZhangfei Gao clk_disable_unprepare(d->clk);
9938e6152bcSZhangfei Gao return 0;
9948e6152bcSZhangfei Gao }
9958e6152bcSZhangfei Gao
996af2d3139SJingoo Han #ifdef CONFIG_PM_SLEEP
k3_dma_suspend_dev(struct device * dev)99710b3e223SArnd Bergmann static int k3_dma_suspend_dev(struct device *dev)
9988e6152bcSZhangfei Gao {
9998e6152bcSZhangfei Gao struct k3_dma_dev *d = dev_get_drvdata(dev);
10008e6152bcSZhangfei Gao u32 stat = 0;
10018e6152bcSZhangfei Gao
10028e6152bcSZhangfei Gao stat = k3_dma_get_chan_stat(d);
10038e6152bcSZhangfei Gao if (stat) {
10048e6152bcSZhangfei Gao dev_warn(d->slave.dev,
10058e6152bcSZhangfei Gao "chan %d is running fail to suspend\n", stat);
10068e6152bcSZhangfei Gao return -1;
10078e6152bcSZhangfei Gao }
10088e6152bcSZhangfei Gao k3_dma_enable_dma(d, false);
10098e6152bcSZhangfei Gao clk_disable_unprepare(d->clk);
10108e6152bcSZhangfei Gao return 0;
10118e6152bcSZhangfei Gao }
10128e6152bcSZhangfei Gao
k3_dma_resume_dev(struct device * dev)101310b3e223SArnd Bergmann static int k3_dma_resume_dev(struct device *dev)
10148e6152bcSZhangfei Gao {
10158e6152bcSZhangfei Gao struct k3_dma_dev *d = dev_get_drvdata(dev);
10168e6152bcSZhangfei Gao int ret = 0;
10178e6152bcSZhangfei Gao
10188e6152bcSZhangfei Gao ret = clk_prepare_enable(d->clk);
10198e6152bcSZhangfei Gao if (ret < 0) {
10208e6152bcSZhangfei Gao dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret);
10218e6152bcSZhangfei Gao return ret;
10228e6152bcSZhangfei Gao }
10238e6152bcSZhangfei Gao k3_dma_enable_dma(d, true);
10248e6152bcSZhangfei Gao return 0;
10258e6152bcSZhangfei Gao }
1026af2d3139SJingoo Han #endif
10278e6152bcSZhangfei Gao
102810b3e223SArnd Bergmann static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend_dev, k3_dma_resume_dev);
10298e6152bcSZhangfei Gao
10308e6152bcSZhangfei Gao static struct platform_driver k3_pdma_driver = {
10318e6152bcSZhangfei Gao .driver = {
10328e6152bcSZhangfei Gao .name = DRIVER_NAME,
10338e6152bcSZhangfei Gao .pm = &k3_dma_pmops,
10348e6152bcSZhangfei Gao .of_match_table = k3_pdma_dt_ids,
10358e6152bcSZhangfei Gao },
10368e6152bcSZhangfei Gao .probe = k3_dma_probe,
10378e6152bcSZhangfei Gao .remove = k3_dma_remove,
10388e6152bcSZhangfei Gao };
10398e6152bcSZhangfei Gao
10408e6152bcSZhangfei Gao module_platform_driver(k3_pdma_driver);
10418e6152bcSZhangfei Gao
1042*1b6216a6SHao Fang MODULE_DESCRIPTION("HiSilicon k3 DMA Driver");
10438e6152bcSZhangfei Gao MODULE_ALIAS("platform:k3dma");
10448e6152bcSZhangfei Gao MODULE_LICENSE("GPL v2");
1045