1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 26365beadSRussell King /* 36365beadSRussell King * SA11x0 DMAengine support 46365beadSRussell King * 56365beadSRussell King * Copyright (C) 2012 Russell King 66365beadSRussell King * Derived in part from arch/arm/mach-sa1100/dma.c, 76365beadSRussell King * Copyright (C) 2000, 2001 by Nicolas Pitre 86365beadSRussell King */ 96365beadSRussell King #include <linux/sched.h> 106365beadSRussell King #include <linux/device.h> 116365beadSRussell King #include <linux/dmaengine.h> 126365beadSRussell King #include <linux/init.h> 136365beadSRussell King #include <linux/interrupt.h> 146365beadSRussell King #include <linux/kernel.h> 156365beadSRussell King #include <linux/module.h> 166365beadSRussell King #include <linux/platform_device.h> 176365beadSRussell King #include <linux/slab.h> 186365beadSRussell King #include <linux/spinlock.h> 196365beadSRussell King 2050437bffSRussell King #include "virt-dma.h" 2150437bffSRussell King 226365beadSRussell King #define NR_PHY_CHAN 6 236365beadSRussell King #define DMA_ALIGN 3 246365beadSRussell King #define DMA_MAX_SIZE 0x1fff 256365beadSRussell King #define DMA_CHUNK_SIZE 0x1000 266365beadSRussell King 276365beadSRussell King #define DMA_DDAR 0x00 286365beadSRussell King #define DMA_DCSR_S 0x04 296365beadSRussell King #define DMA_DCSR_C 0x08 306365beadSRussell King #define DMA_DCSR_R 0x0c 316365beadSRussell King #define DMA_DBSA 0x10 326365beadSRussell King #define DMA_DBTA 0x14 336365beadSRussell King #define DMA_DBSB 0x18 346365beadSRussell King #define DMA_DBTB 0x1c 356365beadSRussell King #define DMA_SIZE 0x20 366365beadSRussell King 376365beadSRussell King #define DCSR_RUN (1 << 0) 386365beadSRussell King #define DCSR_IE (1 << 1) 396365beadSRussell King #define DCSR_ERROR (1 << 2) 406365beadSRussell King #define DCSR_DONEA (1 << 3) 416365beadSRussell King #define DCSR_STRTA (1 << 4) 426365beadSRussell King #define DCSR_DONEB (1 << 5) 436365beadSRussell King #define DCSR_STRTB (1 << 6) 446365beadSRussell King #define DCSR_BIU (1 << 7) 456365beadSRussell King 466365beadSRussell King #define DDAR_RW (1 << 0) /* 0 = W, 1 = R */ 476365beadSRussell King #define DDAR_E (1 << 1) /* 0 = LE, 1 = BE */ 486365beadSRussell King #define DDAR_BS (1 << 2) /* 0 = BS4, 1 = BS8 */ 496365beadSRussell King #define DDAR_DW (1 << 3) /* 0 = 8b, 1 = 16b */ 506365beadSRussell King #define DDAR_Ser0UDCTr (0x0 << 4) 516365beadSRussell King #define DDAR_Ser0UDCRc (0x1 << 4) 526365beadSRussell King #define DDAR_Ser1SDLCTr (0x2 << 4) 536365beadSRussell King #define DDAR_Ser1SDLCRc (0x3 << 4) 546365beadSRussell King #define DDAR_Ser1UARTTr (0x4 << 4) 556365beadSRussell King #define DDAR_Ser1UARTRc (0x5 << 4) 566365beadSRussell King #define DDAR_Ser2ICPTr (0x6 << 4) 576365beadSRussell King #define DDAR_Ser2ICPRc (0x7 << 4) 586365beadSRussell King #define DDAR_Ser3UARTTr (0x8 << 4) 596365beadSRussell King #define DDAR_Ser3UARTRc (0x9 << 4) 606365beadSRussell King #define DDAR_Ser4MCP0Tr (0xa << 4) 616365beadSRussell King #define DDAR_Ser4MCP0Rc (0xb << 4) 626365beadSRussell King #define DDAR_Ser4MCP1Tr (0xc << 4) 636365beadSRussell King #define DDAR_Ser4MCP1Rc (0xd << 4) 646365beadSRussell King #define DDAR_Ser4SSPTr (0xe << 4) 656365beadSRussell King #define DDAR_Ser4SSPRc (0xf << 4) 666365beadSRussell King 676365beadSRussell King struct sa11x0_dma_sg { 686365beadSRussell King u32 addr; 696365beadSRussell King u32 len; 706365beadSRussell King }; 716365beadSRussell King 726365beadSRussell King struct sa11x0_dma_desc { 7350437bffSRussell King struct virt_dma_desc vd; 7450437bffSRussell King 756365beadSRussell King u32 ddar; 766365beadSRussell King size_t size; 77d9444325SRussell King unsigned period; 78d9444325SRussell King bool cyclic; 796365beadSRussell King 806365beadSRussell King unsigned sglen; 81bfb59d4aSGustavo A. R. Silva struct sa11x0_dma_sg sg[]; 826365beadSRussell King }; 836365beadSRussell King 846365beadSRussell King struct sa11x0_dma_phy; 856365beadSRussell King 866365beadSRussell King struct sa11x0_dma_chan { 8750437bffSRussell King struct virt_dma_chan vc; 886365beadSRussell King 8950437bffSRussell King /* protected by c->vc.lock */ 906365beadSRussell King struct sa11x0_dma_phy *phy; 916365beadSRussell King enum dma_status status; 926365beadSRussell King 936365beadSRussell King /* protected by d->lock */ 946365beadSRussell King struct list_head node; 956365beadSRussell King 966365beadSRussell King u32 ddar; 976365beadSRussell King const char *name; 986365beadSRussell King }; 996365beadSRussell King 1006365beadSRussell King struct sa11x0_dma_phy { 1016365beadSRussell King void __iomem *base; 1026365beadSRussell King struct sa11x0_dma_dev *dev; 1036365beadSRussell King unsigned num; 1046365beadSRussell King 1056365beadSRussell King struct sa11x0_dma_chan *vchan; 1066365beadSRussell King 10750437bffSRussell King /* Protected by c->vc.lock */ 1086365beadSRussell King unsigned sg_load; 1096365beadSRussell King struct sa11x0_dma_desc *txd_load; 1106365beadSRussell King unsigned sg_done; 1116365beadSRussell King struct sa11x0_dma_desc *txd_done; 1126365beadSRussell King u32 dbs[2]; 1136365beadSRussell King u32 dbt[2]; 1146365beadSRussell King u32 dcsr; 1156365beadSRussell King }; 1166365beadSRussell King 1176365beadSRussell King struct sa11x0_dma_dev { 1186365beadSRussell King struct dma_device slave; 1196365beadSRussell King void __iomem *base; 1206365beadSRussell King spinlock_t lock; 1216365beadSRussell King struct tasklet_struct task; 1226365beadSRussell King struct list_head chan_pending; 1236365beadSRussell King struct sa11x0_dma_phy phy[NR_PHY_CHAN]; 1246365beadSRussell King }; 1256365beadSRussell King 1266365beadSRussell King static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan) 1276365beadSRussell King { 12850437bffSRussell King return container_of(chan, struct sa11x0_dma_chan, vc.chan); 1296365beadSRussell King } 1306365beadSRussell King 1316365beadSRussell King static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev) 1326365beadSRussell King { 1336365beadSRussell King return container_of(dmadev, struct sa11x0_dma_dev, slave); 1346365beadSRussell King } 1356365beadSRussell King 1366365beadSRussell King static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c) 1376365beadSRussell King { 13850437bffSRussell King struct virt_dma_desc *vd = vchan_next_desc(&c->vc); 1396365beadSRussell King 14050437bffSRussell King return vd ? container_of(vd, struct sa11x0_dma_desc, vd) : NULL; 14150437bffSRussell King } 14250437bffSRussell King 14350437bffSRussell King static void sa11x0_dma_free_desc(struct virt_dma_desc *vd) 14450437bffSRussell King { 14550437bffSRussell King kfree(container_of(vd, struct sa11x0_dma_desc, vd)); 1466365beadSRussell King } 1476365beadSRussell King 1486365beadSRussell King static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd) 1496365beadSRussell King { 15050437bffSRussell King list_del(&txd->vd.node); 1516365beadSRussell King p->txd_load = txd; 1526365beadSRussell King p->sg_load = 0; 1536365beadSRussell King 1546365beadSRussell King dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n", 15550437bffSRussell King p->num, &txd->vd, txd->vd.tx.cookie, txd->ddar); 1566365beadSRussell King } 1576365beadSRussell King 1586365beadSRussell King static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p, 1596365beadSRussell King struct sa11x0_dma_chan *c) 1606365beadSRussell King { 1616365beadSRussell King struct sa11x0_dma_desc *txd = p->txd_load; 1626365beadSRussell King struct sa11x0_dma_sg *sg; 1636365beadSRussell King void __iomem *base = p->base; 1646365beadSRussell King unsigned dbsx, dbtx; 1656365beadSRussell King u32 dcsr; 1666365beadSRussell King 1676365beadSRussell King if (!txd) 1686365beadSRussell King return; 1696365beadSRussell King 1706365beadSRussell King dcsr = readl_relaxed(base + DMA_DCSR_R); 1716365beadSRussell King 1726365beadSRussell King /* Don't try to load the next transfer if both buffers are started */ 1736365beadSRussell King if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) 1746365beadSRussell King return; 1756365beadSRussell King 1766365beadSRussell King if (p->sg_load == txd->sglen) { 177d9444325SRussell King if (!txd->cyclic) { 1786365beadSRussell King struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c); 1796365beadSRussell King 1806365beadSRussell King /* 1816365beadSRussell King * We have reached the end of the current descriptor. 1826365beadSRussell King * Peek at the next descriptor, and if compatible with 1836365beadSRussell King * the current, start processing it. 1846365beadSRussell King */ 1856365beadSRussell King if (txn && txn->ddar == txd->ddar) { 1866365beadSRussell King txd = txn; 1876365beadSRussell King sa11x0_dma_start_desc(p, txn); 1886365beadSRussell King } else { 1896365beadSRussell King p->txd_load = NULL; 1906365beadSRussell King return; 1916365beadSRussell King } 192d9444325SRussell King } else { 193d9444325SRussell King /* Cyclic: reset back to beginning */ 194d9444325SRussell King p->sg_load = 0; 195d9444325SRussell King } 1966365beadSRussell King } 1976365beadSRussell King 1986365beadSRussell King sg = &txd->sg[p->sg_load++]; 1996365beadSRussell King 2006365beadSRussell King /* Select buffer to load according to channel status */ 2016365beadSRussell King if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) || 2026365beadSRussell King ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) { 2036365beadSRussell King dbsx = DMA_DBSA; 2046365beadSRussell King dbtx = DMA_DBTA; 2056365beadSRussell King dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN; 2066365beadSRussell King } else { 2076365beadSRussell King dbsx = DMA_DBSB; 2086365beadSRussell King dbtx = DMA_DBTB; 2096365beadSRussell King dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN; 2106365beadSRussell King } 2116365beadSRussell King 2126365beadSRussell King writel_relaxed(sg->addr, base + dbsx); 2136365beadSRussell King writel_relaxed(sg->len, base + dbtx); 2146365beadSRussell King writel(dcsr, base + DMA_DCSR_S); 2156365beadSRussell King 2166365beadSRussell King dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n", 2176365beadSRussell King p->num, dcsr, 2186365beadSRussell King 'A' + (dbsx == DMA_DBSB), sg->addr, 2196365beadSRussell King 'A' + (dbtx == DMA_DBTB), sg->len); 2206365beadSRussell King } 2216365beadSRussell King 2226365beadSRussell King static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p, 2236365beadSRussell King struct sa11x0_dma_chan *c) 2246365beadSRussell King { 2256365beadSRussell King struct sa11x0_dma_desc *txd = p->txd_done; 2266365beadSRussell King 2276365beadSRussell King if (++p->sg_done == txd->sglen) { 228d9444325SRussell King if (!txd->cyclic) { 22950437bffSRussell King vchan_cookie_complete(&txd->vd); 2306365beadSRussell King 2316365beadSRussell King p->sg_done = 0; 2326365beadSRussell King p->txd_done = p->txd_load; 2336365beadSRussell King 23450437bffSRussell King if (!p->txd_done) 23550437bffSRussell King tasklet_schedule(&p->dev->task); 236d9444325SRussell King } else { 237d9444325SRussell King if ((p->sg_done % txd->period) == 0) 238d9444325SRussell King vchan_cyclic_callback(&txd->vd); 239d9444325SRussell King 240d9444325SRussell King /* Cyclic: reset back to beginning */ 241d9444325SRussell King p->sg_done = 0; 242d9444325SRussell King } 2436365beadSRussell King } 2446365beadSRussell King 2456365beadSRussell King sa11x0_dma_start_sg(p, c); 2466365beadSRussell King } 2476365beadSRussell King 2486365beadSRussell King static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id) 2496365beadSRussell King { 2506365beadSRussell King struct sa11x0_dma_phy *p = dev_id; 2516365beadSRussell King struct sa11x0_dma_dev *d = p->dev; 2526365beadSRussell King struct sa11x0_dma_chan *c; 2536365beadSRussell King u32 dcsr; 2546365beadSRussell King 2556365beadSRussell King dcsr = readl_relaxed(p->base + DMA_DCSR_R); 2566365beadSRussell King if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB))) 2576365beadSRussell King return IRQ_NONE; 2586365beadSRussell King 2596365beadSRussell King /* Clear reported status bits */ 2606365beadSRussell King writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB), 2616365beadSRussell King p->base + DMA_DCSR_C); 2626365beadSRussell King 2636365beadSRussell King dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr); 2646365beadSRussell King 2656365beadSRussell King if (dcsr & DCSR_ERROR) { 2666365beadSRussell King dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n", 2676365beadSRussell King p->num, dcsr, 2686365beadSRussell King readl_relaxed(p->base + DMA_DDAR), 2696365beadSRussell King readl_relaxed(p->base + DMA_DBSA), 2706365beadSRussell King readl_relaxed(p->base + DMA_DBTA), 2716365beadSRussell King readl_relaxed(p->base + DMA_DBSB), 2726365beadSRussell King readl_relaxed(p->base + DMA_DBTB)); 2736365beadSRussell King } 2746365beadSRussell King 2756365beadSRussell King c = p->vchan; 2766365beadSRussell King if (c) { 2776365beadSRussell King unsigned long flags; 2786365beadSRussell King 27950437bffSRussell King spin_lock_irqsave(&c->vc.lock, flags); 2806365beadSRussell King /* 2816365beadSRussell King * Now that we're holding the lock, check that the vchan 2826365beadSRussell King * really is associated with this pchan before touching the 2836365beadSRussell King * hardware. This should always succeed, because we won't 2846365beadSRussell King * change p->vchan or c->phy while the channel is actively 2856365beadSRussell King * transferring. 2866365beadSRussell King */ 2876365beadSRussell King if (c->phy == p) { 2886365beadSRussell King if (dcsr & DCSR_DONEA) 2896365beadSRussell King sa11x0_dma_complete(p, c); 2906365beadSRussell King if (dcsr & DCSR_DONEB) 2916365beadSRussell King sa11x0_dma_complete(p, c); 2926365beadSRussell King } 29350437bffSRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 2946365beadSRussell King } 2956365beadSRussell King 2966365beadSRussell King return IRQ_HANDLED; 2976365beadSRussell King } 2986365beadSRussell King 2996365beadSRussell King static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c) 3006365beadSRussell King { 3016365beadSRussell King struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c); 3026365beadSRussell King 3036365beadSRussell King /* If the issued list is empty, we have no further txds to process */ 3046365beadSRussell King if (txd) { 3056365beadSRussell King struct sa11x0_dma_phy *p = c->phy; 3066365beadSRussell King 3076365beadSRussell King sa11x0_dma_start_desc(p, txd); 3086365beadSRussell King p->txd_done = txd; 3096365beadSRussell King p->sg_done = 0; 3106365beadSRussell King 3116365beadSRussell King /* The channel should not have any transfers started */ 3126365beadSRussell King WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) & 3136365beadSRussell King (DCSR_STRTA | DCSR_STRTB)); 3146365beadSRussell King 3156365beadSRussell King /* Clear the run and start bits before changing DDAR */ 3166365beadSRussell King writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB, 3176365beadSRussell King p->base + DMA_DCSR_C); 3186365beadSRussell King writel_relaxed(txd->ddar, p->base + DMA_DDAR); 3196365beadSRussell King 3206365beadSRussell King /* Try to start both buffers */ 3216365beadSRussell King sa11x0_dma_start_sg(p, c); 3226365beadSRussell King sa11x0_dma_start_sg(p, c); 3236365beadSRussell King } 3246365beadSRussell King } 3256365beadSRussell King 326*8a536883SAllen Pais static void sa11x0_dma_tasklet(struct tasklet_struct *t) 3276365beadSRussell King { 328*8a536883SAllen Pais struct sa11x0_dma_dev *d = from_tasklet(d, t, task); 3296365beadSRussell King struct sa11x0_dma_phy *p; 3306365beadSRussell King struct sa11x0_dma_chan *c; 3316365beadSRussell King unsigned pch, pch_alloc = 0; 3326365beadSRussell King 3336365beadSRussell King dev_dbg(d->slave.dev, "tasklet enter\n"); 3346365beadSRussell King 33550437bffSRussell King list_for_each_entry(c, &d->slave.channels, vc.chan.device_node) { 33650437bffSRussell King spin_lock_irq(&c->vc.lock); 3376365beadSRussell King p = c->phy; 33850437bffSRussell King if (p && !p->txd_done) { 3396365beadSRussell King sa11x0_dma_start_txd(c); 3406365beadSRussell King if (!p->txd_done) { 3416365beadSRussell King /* No current txd associated with this channel */ 3426365beadSRussell King dev_dbg(d->slave.dev, "pchan %u: free\n", p->num); 3436365beadSRussell King 3446365beadSRussell King /* Mark this channel free */ 3456365beadSRussell King c->phy = NULL; 3466365beadSRussell King p->vchan = NULL; 3476365beadSRussell King } 3486365beadSRussell King } 34950437bffSRussell King spin_unlock_irq(&c->vc.lock); 3506365beadSRussell King } 3516365beadSRussell King 3526365beadSRussell King spin_lock_irq(&d->lock); 3536365beadSRussell King for (pch = 0; pch < NR_PHY_CHAN; pch++) { 3546365beadSRussell King p = &d->phy[pch]; 3556365beadSRussell King 3566365beadSRussell King if (p->vchan == NULL && !list_empty(&d->chan_pending)) { 3576365beadSRussell King c = list_first_entry(&d->chan_pending, 3586365beadSRussell King struct sa11x0_dma_chan, node); 3596365beadSRussell King list_del_init(&c->node); 3606365beadSRussell King 3616365beadSRussell King pch_alloc |= 1 << pch; 3626365beadSRussell King 3636365beadSRussell King /* Mark this channel allocated */ 3646365beadSRussell King p->vchan = c; 3656365beadSRussell King 36650437bffSRussell King dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc); 3676365beadSRussell King } 3686365beadSRussell King } 3696365beadSRussell King spin_unlock_irq(&d->lock); 3706365beadSRussell King 3716365beadSRussell King for (pch = 0; pch < NR_PHY_CHAN; pch++) { 3726365beadSRussell King if (pch_alloc & (1 << pch)) { 3736365beadSRussell King p = &d->phy[pch]; 3746365beadSRussell King c = p->vchan; 3756365beadSRussell King 37650437bffSRussell King spin_lock_irq(&c->vc.lock); 3776365beadSRussell King c->phy = p; 3786365beadSRussell King 3796365beadSRussell King sa11x0_dma_start_txd(c); 38050437bffSRussell King spin_unlock_irq(&c->vc.lock); 3816365beadSRussell King } 3826365beadSRussell King } 3836365beadSRussell King 3846365beadSRussell King dev_dbg(d->slave.dev, "tasklet exit\n"); 3856365beadSRussell King } 3866365beadSRussell King 3876365beadSRussell King 3886365beadSRussell King static void sa11x0_dma_free_chan_resources(struct dma_chan *chan) 3896365beadSRussell King { 3906365beadSRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 3916365beadSRussell King struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 3926365beadSRussell King unsigned long flags; 3936365beadSRussell King 39450437bffSRussell King spin_lock_irqsave(&d->lock, flags); 3956365beadSRussell King list_del_init(&c->node); 39650437bffSRussell King spin_unlock_irqrestore(&d->lock, flags); 3976365beadSRussell King 39850437bffSRussell King vchan_free_chan_resources(&c->vc); 3996365beadSRussell King } 4006365beadSRussell King 4016365beadSRussell King static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p) 4026365beadSRussell King { 4036365beadSRussell King unsigned reg; 4046365beadSRussell King u32 dcsr; 4056365beadSRussell King 4066365beadSRussell King dcsr = readl_relaxed(p->base + DMA_DCSR_R); 4076365beadSRussell King 4086365beadSRussell King if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA || 4096365beadSRussell King (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU) 4106365beadSRussell King reg = DMA_DBSA; 4116365beadSRussell King else 4126365beadSRussell King reg = DMA_DBSB; 4136365beadSRussell King 4146365beadSRussell King return readl_relaxed(p->base + reg); 4156365beadSRussell King } 4166365beadSRussell King 4176365beadSRussell King static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan, 4186365beadSRussell King dma_cookie_t cookie, struct dma_tx_state *state) 4196365beadSRussell King { 4206365beadSRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 4216365beadSRussell King struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 4226365beadSRussell King struct sa11x0_dma_phy *p; 42363fe23c3SRussell King struct virt_dma_desc *vd; 4246365beadSRussell King unsigned long flags; 4256365beadSRussell King enum dma_status ret; 4266365beadSRussell King 42750437bffSRussell King ret = dma_cookie_status(&c->vc.chan, cookie, state); 428fdebb768SVinod Koul if (ret == DMA_COMPLETE) 4296365beadSRussell King return ret; 4306365beadSRussell King 43163fe23c3SRussell King if (!state) 43263fe23c3SRussell King return c->status; 43363fe23c3SRussell King 43450437bffSRussell King spin_lock_irqsave(&c->vc.lock, flags); 4356365beadSRussell King p = c->phy; 43663fe23c3SRussell King 43763fe23c3SRussell King /* 43863fe23c3SRussell King * If the cookie is on our issue queue, then the residue is 43963fe23c3SRussell King * its total size. 44063fe23c3SRussell King */ 44163fe23c3SRussell King vd = vchan_find_desc(&c->vc, cookie); 44263fe23c3SRussell King if (vd) { 44363fe23c3SRussell King state->residue = container_of(vd, struct sa11x0_dma_desc, vd)->size; 44463fe23c3SRussell King } else if (!p) { 44563fe23c3SRussell King state->residue = 0; 44663fe23c3SRussell King } else { 44763fe23c3SRussell King struct sa11x0_dma_desc *txd; 44863fe23c3SRussell King size_t bytes = 0; 44963fe23c3SRussell King 45063fe23c3SRussell King if (p->txd_done && p->txd_done->vd.tx.cookie == cookie) 45163fe23c3SRussell King txd = p->txd_done; 45263fe23c3SRussell King else if (p->txd_load && p->txd_load->vd.tx.cookie == cookie) 45363fe23c3SRussell King txd = p->txd_load; 45463fe23c3SRussell King else 45563fe23c3SRussell King txd = NULL; 45663fe23c3SRussell King 4576365beadSRussell King ret = c->status; 45863fe23c3SRussell King if (txd) { 4596365beadSRussell King dma_addr_t addr = sa11x0_dma_pos(p); 46063fe23c3SRussell King unsigned i; 4616365beadSRussell King 462f92e934dSVinod Koul dev_vdbg(d->slave.dev, "tx_status: addr:%pad\n", &addr); 4636365beadSRussell King 4646365beadSRussell King for (i = 0; i < txd->sglen; i++) { 4656365beadSRussell King dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n", 4666365beadSRussell King i, txd->sg[i].addr, txd->sg[i].len); 4676365beadSRussell King if (addr >= txd->sg[i].addr && 4686365beadSRussell King addr < txd->sg[i].addr + txd->sg[i].len) { 4696365beadSRussell King unsigned len; 4706365beadSRussell King 4716365beadSRussell King len = txd->sg[i].len - 4726365beadSRussell King (addr - txd->sg[i].addr); 4736365beadSRussell King dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n", 4746365beadSRussell King i, len); 4756365beadSRussell King bytes += len; 4766365beadSRussell King i++; 4776365beadSRussell King break; 4786365beadSRussell King } 4796365beadSRussell King } 4806365beadSRussell King for (; i < txd->sglen; i++) { 4816365beadSRussell King dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n", 4826365beadSRussell King i, txd->sg[i].addr, txd->sg[i].len); 4836365beadSRussell King bytes += txd->sg[i].len; 4846365beadSRussell King } 4856365beadSRussell King } 48663fe23c3SRussell King state->residue = bytes; 4876365beadSRussell King } 48850437bffSRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 4896365beadSRussell King 490872b4af4SVinod Koul dev_vdbg(d->slave.dev, "tx_status: bytes 0x%x\n", state->residue); 4916365beadSRussell King 4926365beadSRussell King return ret; 4936365beadSRussell King } 4946365beadSRussell King 4956365beadSRussell King /* 4966365beadSRussell King * Move pending txds to the issued list, and re-init pending list. 4976365beadSRussell King * If not already pending, add this channel to the list of pending 4986365beadSRussell King * channels and trigger the tasklet to run. 4996365beadSRussell King */ 5006365beadSRussell King static void sa11x0_dma_issue_pending(struct dma_chan *chan) 5016365beadSRussell King { 5026365beadSRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 5036365beadSRussell King struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 5046365beadSRussell King unsigned long flags; 5056365beadSRussell King 50650437bffSRussell King spin_lock_irqsave(&c->vc.lock, flags); 50750437bffSRussell King if (vchan_issue_pending(&c->vc)) { 50850437bffSRussell King if (!c->phy) { 5096365beadSRussell King spin_lock(&d->lock); 51050437bffSRussell King if (list_empty(&c->node)) { 5116365beadSRussell King list_add_tail(&c->node, &d->chan_pending); 5126365beadSRussell King tasklet_schedule(&d->task); 51350437bffSRussell King dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc); 5146365beadSRussell King } 5156365beadSRussell King spin_unlock(&d->lock); 5166365beadSRussell King } 51750437bffSRussell King } else 51850437bffSRussell King dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc); 51950437bffSRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 5206365beadSRussell King } 5216365beadSRussell King 5226365beadSRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( 5236365beadSRussell King struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen, 524d9d54540SRussell King enum dma_transfer_direction dir, unsigned long flags, void *context) 5256365beadSRussell King { 5266365beadSRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 5276365beadSRussell King struct sa11x0_dma_desc *txd; 5286365beadSRussell King struct scatterlist *sgent; 5296365beadSRussell King unsigned i, j = sglen; 5306365beadSRussell King size_t size = 0; 5316365beadSRussell King 5326365beadSRussell King /* SA11x0 channels can only operate in their native direction */ 5336365beadSRussell King if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) { 5346365beadSRussell King dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n", 53550437bffSRussell King &c->vc, c->ddar, dir); 5366365beadSRussell King return NULL; 5376365beadSRussell King } 5386365beadSRussell King 5396365beadSRussell King /* Do not allow zero-sized txds */ 5406365beadSRussell King if (sglen == 0) 5416365beadSRussell King return NULL; 5426365beadSRussell King 5436365beadSRussell King for_each_sg(sg, sgent, sglen, i) { 5446365beadSRussell King dma_addr_t addr = sg_dma_address(sgent); 5456365beadSRussell King unsigned int len = sg_dma_len(sgent); 5466365beadSRussell King 5476365beadSRussell King if (len > DMA_MAX_SIZE) 5486365beadSRussell King j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1; 5496365beadSRussell King if (addr & DMA_ALIGN) { 550f92e934dSVinod Koul dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %pad\n", 551f92e934dSVinod Koul &c->vc, &addr); 5526365beadSRussell King return NULL; 5536365beadSRussell King } 5546365beadSRussell King } 5556365beadSRussell King 556acafe7e3SKees Cook txd = kzalloc(struct_size(txd, sg, j), GFP_ATOMIC); 5576365beadSRussell King if (!txd) { 55850437bffSRussell King dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc); 5596365beadSRussell King return NULL; 5606365beadSRussell King } 5616365beadSRussell King 5626365beadSRussell King j = 0; 5636365beadSRussell King for_each_sg(sg, sgent, sglen, i) { 5646365beadSRussell King dma_addr_t addr = sg_dma_address(sgent); 5656365beadSRussell King unsigned len = sg_dma_len(sgent); 5666365beadSRussell King 5676365beadSRussell King size += len; 5686365beadSRussell King 5696365beadSRussell King do { 5706365beadSRussell King unsigned tlen = len; 5716365beadSRussell King 5726365beadSRussell King /* 5736365beadSRussell King * Check whether the transfer will fit. If not, try 5746365beadSRussell King * to split the transfer up such that we end up with 5756365beadSRussell King * equal chunks - but make sure that we preserve the 5766365beadSRussell King * alignment. This avoids small segments. 5776365beadSRussell King */ 5786365beadSRussell King if (tlen > DMA_MAX_SIZE) { 5796365beadSRussell King unsigned mult = DIV_ROUND_UP(tlen, 5806365beadSRussell King DMA_MAX_SIZE & ~DMA_ALIGN); 5816365beadSRussell King 5826365beadSRussell King tlen = (tlen / mult) & ~DMA_ALIGN; 5836365beadSRussell King } 5846365beadSRussell King 5856365beadSRussell King txd->sg[j].addr = addr; 5866365beadSRussell King txd->sg[j].len = tlen; 5876365beadSRussell King 5886365beadSRussell King addr += tlen; 5896365beadSRussell King len -= tlen; 5906365beadSRussell King j++; 5916365beadSRussell King } while (len); 5926365beadSRussell King } 5936365beadSRussell King 5946365beadSRussell King txd->ddar = c->ddar; 5956365beadSRussell King txd->size = size; 5966365beadSRussell King txd->sglen = j; 5976365beadSRussell King 598762ff31dSVinod Koul dev_dbg(chan->device->dev, "vchan %p: txd %p: size %zu nr %u\n", 59950437bffSRussell King &c->vc, &txd->vd, txd->size, txd->sglen); 6006365beadSRussell King 60150437bffSRussell King return vchan_tx_prep(&c->vc, &txd->vd, flags); 6026365beadSRussell King } 6036365beadSRussell King 604d9444325SRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic( 605d9444325SRussell King struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period, 60631c1e5a1SLaurent Pinchart enum dma_transfer_direction dir, unsigned long flags) 607d9444325SRussell King { 608d9444325SRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 609d9444325SRussell King struct sa11x0_dma_desc *txd; 610d9444325SRussell King unsigned i, j, k, sglen, sgperiod; 611d9444325SRussell King 612d9444325SRussell King /* SA11x0 channels can only operate in their native direction */ 613d9444325SRussell King if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) { 614d9444325SRussell King dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n", 615d9444325SRussell King &c->vc, c->ddar, dir); 616d9444325SRussell King return NULL; 617d9444325SRussell King } 618d9444325SRussell King 619d9444325SRussell King sgperiod = DIV_ROUND_UP(period, DMA_MAX_SIZE & ~DMA_ALIGN); 620d9444325SRussell King sglen = size * sgperiod / period; 621d9444325SRussell King 622d9444325SRussell King /* Do not allow zero-sized txds */ 623d9444325SRussell King if (sglen == 0) 624d9444325SRussell King return NULL; 625d9444325SRussell King 626acafe7e3SKees Cook txd = kzalloc(struct_size(txd, sg, sglen), GFP_ATOMIC); 627d9444325SRussell King if (!txd) { 628d9444325SRussell King dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc); 629d9444325SRussell King return NULL; 630d9444325SRussell King } 631d9444325SRussell King 632d9444325SRussell King for (i = k = 0; i < size / period; i++) { 633d9444325SRussell King size_t tlen, len = period; 634d9444325SRussell King 635d9444325SRussell King for (j = 0; j < sgperiod; j++, k++) { 636d9444325SRussell King tlen = len; 637d9444325SRussell King 638d9444325SRussell King if (tlen > DMA_MAX_SIZE) { 639d9444325SRussell King unsigned mult = DIV_ROUND_UP(tlen, DMA_MAX_SIZE & ~DMA_ALIGN); 640d9444325SRussell King tlen = (tlen / mult) & ~DMA_ALIGN; 641d9444325SRussell King } 642d9444325SRussell King 643d9444325SRussell King txd->sg[k].addr = addr; 644d9444325SRussell King txd->sg[k].len = tlen; 645d9444325SRussell King addr += tlen; 646d9444325SRussell King len -= tlen; 647d9444325SRussell King } 648d9444325SRussell King 649d9444325SRussell King WARN_ON(len != 0); 650d9444325SRussell King } 651d9444325SRussell King 652d9444325SRussell King WARN_ON(k != sglen); 653d9444325SRussell King 654d9444325SRussell King txd->ddar = c->ddar; 655d9444325SRussell King txd->size = size; 656d9444325SRussell King txd->sglen = sglen; 657d9444325SRussell King txd->cyclic = 1; 658d9444325SRussell King txd->period = sgperiod; 659d9444325SRussell King 660d9444325SRussell King return vchan_tx_prep(&c->vc, &txd->vd, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 661d9444325SRussell King } 662d9444325SRussell King 663a0a51a64SMaxime Ripard static int sa11x0_dma_device_config(struct dma_chan *chan, 6644a533218SMaxime Ripard struct dma_slave_config *cfg) 6656365beadSRussell King { 6664a533218SMaxime Ripard struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 6676365beadSRussell King u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW); 6686365beadSRussell King dma_addr_t addr; 6696365beadSRussell King enum dma_slave_buswidth width; 6706365beadSRussell King u32 maxburst; 6716365beadSRussell King 6726365beadSRussell King if (ddar & DDAR_RW) { 6736365beadSRussell King addr = cfg->src_addr; 6746365beadSRussell King width = cfg->src_addr_width; 6756365beadSRussell King maxburst = cfg->src_maxburst; 6766365beadSRussell King } else { 6776365beadSRussell King addr = cfg->dst_addr; 6786365beadSRussell King width = cfg->dst_addr_width; 6796365beadSRussell King maxburst = cfg->dst_maxburst; 6806365beadSRussell King } 6816365beadSRussell King 6826365beadSRussell King if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE && 6836365beadSRussell King width != DMA_SLAVE_BUSWIDTH_2_BYTES) || 6846365beadSRussell King (maxburst != 4 && maxburst != 8)) 6856365beadSRussell King return -EINVAL; 6866365beadSRussell King 6876365beadSRussell King if (width == DMA_SLAVE_BUSWIDTH_2_BYTES) 6886365beadSRussell King ddar |= DDAR_DW; 6896365beadSRussell King if (maxburst == 8) 6906365beadSRussell King ddar |= DDAR_BS; 6916365beadSRussell King 692f92e934dSVinod Koul dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %pad width %u burst %u\n", 693f92e934dSVinod Koul &c->vc, &addr, width, maxburst); 6946365beadSRussell King 6956365beadSRussell King c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6; 6966365beadSRussell King 6976365beadSRussell King return 0; 6986365beadSRussell King } 6996365beadSRussell King 700a0a51a64SMaxime Ripard static int sa11x0_dma_device_pause(struct dma_chan *chan) 7016365beadSRussell King { 7026365beadSRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 7036365beadSRussell King struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 7046365beadSRussell King struct sa11x0_dma_phy *p; 7056365beadSRussell King unsigned long flags; 7066365beadSRussell King 7074a533218SMaxime Ripard dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc); 7084a533218SMaxime Ripard spin_lock_irqsave(&c->vc.lock, flags); 7094a533218SMaxime Ripard if (c->status == DMA_IN_PROGRESS) { 7104a533218SMaxime Ripard c->status = DMA_PAUSED; 7116365beadSRussell King 7124a533218SMaxime Ripard p = c->phy; 7134a533218SMaxime Ripard if (p) { 7144a533218SMaxime Ripard writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C); 7154a533218SMaxime Ripard } else { 7164a533218SMaxime Ripard spin_lock(&d->lock); 7174a533218SMaxime Ripard list_del_init(&c->node); 7184a533218SMaxime Ripard spin_unlock(&d->lock); 7194a533218SMaxime Ripard } 7204a533218SMaxime Ripard } 7214a533218SMaxime Ripard spin_unlock_irqrestore(&c->vc.lock, flags); 7224a533218SMaxime Ripard 7234a533218SMaxime Ripard return 0; 7244a533218SMaxime Ripard } 7254a533218SMaxime Ripard 726a0a51a64SMaxime Ripard static int sa11x0_dma_device_resume(struct dma_chan *chan) 7274a533218SMaxime Ripard { 7284a533218SMaxime Ripard struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 7294a533218SMaxime Ripard struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 7304a533218SMaxime Ripard struct sa11x0_dma_phy *p; 7314a533218SMaxime Ripard unsigned long flags; 7324a533218SMaxime Ripard 7334a533218SMaxime Ripard dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc); 7344a533218SMaxime Ripard spin_lock_irqsave(&c->vc.lock, flags); 7354a533218SMaxime Ripard if (c->status == DMA_PAUSED) { 7364a533218SMaxime Ripard c->status = DMA_IN_PROGRESS; 7374a533218SMaxime Ripard 7384a533218SMaxime Ripard p = c->phy; 7394a533218SMaxime Ripard if (p) { 7404a533218SMaxime Ripard writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S); 7414a533218SMaxime Ripard } else if (!list_empty(&c->vc.desc_issued)) { 7424a533218SMaxime Ripard spin_lock(&d->lock); 7434a533218SMaxime Ripard list_add_tail(&c->node, &d->chan_pending); 7444a533218SMaxime Ripard spin_unlock(&d->lock); 7454a533218SMaxime Ripard } 7464a533218SMaxime Ripard } 7474a533218SMaxime Ripard spin_unlock_irqrestore(&c->vc.lock, flags); 7484a533218SMaxime Ripard 7494a533218SMaxime Ripard return 0; 7504a533218SMaxime Ripard } 7514a533218SMaxime Ripard 752a0a51a64SMaxime Ripard static int sa11x0_dma_device_terminate_all(struct dma_chan *chan) 7534a533218SMaxime Ripard { 7544a533218SMaxime Ripard struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 7554a533218SMaxime Ripard struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device); 7564a533218SMaxime Ripard struct sa11x0_dma_phy *p; 7574a533218SMaxime Ripard LIST_HEAD(head); 7584a533218SMaxime Ripard unsigned long flags; 7594a533218SMaxime Ripard 76050437bffSRussell King dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc); 7616365beadSRussell King /* Clear the tx descriptor lists */ 76250437bffSRussell King spin_lock_irqsave(&c->vc.lock, flags); 76350437bffSRussell King vchan_get_all_descriptors(&c->vc, &head); 7646365beadSRussell King 7656365beadSRussell King p = c->phy; 7666365beadSRussell King if (p) { 7676365beadSRussell King dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num); 7686365beadSRussell King /* vchan is assigned to a pchan - stop the channel */ 7696365beadSRussell King writel(DCSR_RUN | DCSR_IE | 7706365beadSRussell King DCSR_STRTA | DCSR_DONEA | 7716365beadSRussell King DCSR_STRTB | DCSR_DONEB, 7726365beadSRussell King p->base + DMA_DCSR_C); 7736365beadSRussell King 7746365beadSRussell King if (p->txd_load) { 7756365beadSRussell King if (p->txd_load != p->txd_done) 77650437bffSRussell King list_add_tail(&p->txd_load->vd.node, &head); 7776365beadSRussell King p->txd_load = NULL; 7786365beadSRussell King } 7796365beadSRussell King if (p->txd_done) { 78050437bffSRussell King list_add_tail(&p->txd_done->vd.node, &head); 7816365beadSRussell King p->txd_done = NULL; 7826365beadSRussell King } 7836365beadSRussell King c->phy = NULL; 7846365beadSRussell King spin_lock(&d->lock); 7856365beadSRussell King p->vchan = NULL; 7866365beadSRussell King spin_unlock(&d->lock); 7876365beadSRussell King tasklet_schedule(&d->task); 7886365beadSRussell King } 78950437bffSRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 79050437bffSRussell King vchan_dma_desc_free_list(&c->vc, &head); 7916365beadSRussell King 7924a533218SMaxime Ripard return 0; 7936365beadSRussell King } 7946365beadSRussell King 7956365beadSRussell King struct sa11x0_dma_channel_desc { 7966365beadSRussell King u32 ddar; 7976365beadSRussell King const char *name; 7986365beadSRussell King }; 7996365beadSRussell King 8006365beadSRussell King #define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 } 8016365beadSRussell King static const struct sa11x0_dma_channel_desc chan_desc[] = { 8026365beadSRussell King CD(Ser0UDCTr, 0), 8036365beadSRussell King CD(Ser0UDCRc, DDAR_RW), 8046365beadSRussell King CD(Ser1SDLCTr, 0), 8056365beadSRussell King CD(Ser1SDLCRc, DDAR_RW), 8066365beadSRussell King CD(Ser1UARTTr, 0), 8076365beadSRussell King CD(Ser1UARTRc, DDAR_RW), 8086365beadSRussell King CD(Ser2ICPTr, 0), 8096365beadSRussell King CD(Ser2ICPRc, DDAR_RW), 8106365beadSRussell King CD(Ser3UARTTr, 0), 8116365beadSRussell King CD(Ser3UARTRc, DDAR_RW), 8126365beadSRussell King CD(Ser4MCP0Tr, 0), 8136365beadSRussell King CD(Ser4MCP0Rc, DDAR_RW), 8146365beadSRussell King CD(Ser4MCP1Tr, 0), 8156365beadSRussell King CD(Ser4MCP1Rc, DDAR_RW), 8166365beadSRussell King CD(Ser4SSPTr, 0), 8176365beadSRussell King CD(Ser4SSPRc, DDAR_RW), 8186365beadSRussell King }; 8196365beadSRussell King 82073d2a3ceSRussell King static const struct dma_slave_map sa11x0_dma_map[] = { 82173d2a3ceSRussell King { "sa11x0-ir", "tx", "Ser2ICPTr" }, 82273d2a3ceSRussell King { "sa11x0-ir", "rx", "Ser2ICPRc" }, 82373d2a3ceSRussell King { "sa11x0-ssp", "tx", "Ser4SSPTr" }, 82473d2a3ceSRussell King { "sa11x0-ssp", "rx", "Ser4SSPRc" }, 82573d2a3ceSRussell King }; 82673d2a3ceSRussell King 827bc822e80SRussell King static bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param) 828bc822e80SRussell King { 829bc822e80SRussell King struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); 830bc822e80SRussell King const char *p = param; 831bc822e80SRussell King 832bc822e80SRussell King return !strcmp(c->name, p); 833bc822e80SRussell King } 834bc822e80SRussell King 835463a1f8bSBill Pemberton static int sa11x0_dma_init_dmadev(struct dma_device *dmadev, 8366365beadSRussell King struct device *dev) 8376365beadSRussell King { 8386365beadSRussell King unsigned i; 8396365beadSRussell King 8406365beadSRussell King INIT_LIST_HEAD(&dmadev->channels); 8416365beadSRussell King dmadev->dev = dev; 8426365beadSRussell King dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources; 843a0a51a64SMaxime Ripard dmadev->device_config = sa11x0_dma_device_config; 844a0a51a64SMaxime Ripard dmadev->device_pause = sa11x0_dma_device_pause; 845a0a51a64SMaxime Ripard dmadev->device_resume = sa11x0_dma_device_resume; 846a0a51a64SMaxime Ripard dmadev->device_terminate_all = sa11x0_dma_device_terminate_all; 8476365beadSRussell King dmadev->device_tx_status = sa11x0_dma_tx_status; 8486365beadSRussell King dmadev->device_issue_pending = sa11x0_dma_issue_pending; 8496365beadSRussell King 8509aa71711SMaxime Ripard for (i = 0; i < ARRAY_SIZE(chan_desc); i++) { 8516365beadSRussell King struct sa11x0_dma_chan *c; 8526365beadSRussell King 8536365beadSRussell King c = kzalloc(sizeof(*c), GFP_KERNEL); 8546365beadSRussell King if (!c) { 8556365beadSRussell King dev_err(dev, "no memory for channel %u\n", i); 8566365beadSRussell King return -ENOMEM; 8576365beadSRussell King } 8586365beadSRussell King 8596365beadSRussell King c->status = DMA_IN_PROGRESS; 8606365beadSRussell King c->ddar = chan_desc[i].ddar; 8616365beadSRussell King c->name = chan_desc[i].name; 8626365beadSRussell King INIT_LIST_HEAD(&c->node); 86350437bffSRussell King 86450437bffSRussell King c->vc.desc_free = sa11x0_dma_free_desc; 86550437bffSRussell King vchan_init(&c->vc, dmadev); 8666365beadSRussell King } 8676365beadSRussell King 8686365beadSRussell King return dma_async_device_register(dmadev); 8696365beadSRussell King } 8706365beadSRussell King 8716365beadSRussell King static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr, 8726365beadSRussell King void *data) 8736365beadSRussell King { 8746365beadSRussell King int irq = platform_get_irq(pdev, nr); 8756365beadSRussell King 8766365beadSRussell King if (irq <= 0) 8776365beadSRussell King return -ENXIO; 8786365beadSRussell King 8796365beadSRussell King return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data); 8806365beadSRussell King } 8816365beadSRussell King 8826365beadSRussell King static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr, 8836365beadSRussell King void *data) 8846365beadSRussell King { 8856365beadSRussell King int irq = platform_get_irq(pdev, nr); 8866365beadSRussell King if (irq > 0) 8876365beadSRussell King free_irq(irq, data); 8886365beadSRussell King } 8896365beadSRussell King 8906365beadSRussell King static void sa11x0_dma_free_channels(struct dma_device *dmadev) 8916365beadSRussell King { 8926365beadSRussell King struct sa11x0_dma_chan *c, *cn; 8936365beadSRussell King 89450437bffSRussell King list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) { 89550437bffSRussell King list_del(&c->vc.chan.device_node); 89650437bffSRussell King tasklet_kill(&c->vc.task); 8976365beadSRussell King kfree(c); 8986365beadSRussell King } 8996365beadSRussell King } 9006365beadSRussell King 901463a1f8bSBill Pemberton static int sa11x0_dma_probe(struct platform_device *pdev) 9026365beadSRussell King { 9036365beadSRussell King struct sa11x0_dma_dev *d; 9046365beadSRussell King struct resource *res; 9056365beadSRussell King unsigned i; 9066365beadSRussell King int ret; 9076365beadSRussell King 9086365beadSRussell King res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9096365beadSRussell King if (!res) 9106365beadSRussell King return -ENXIO; 9116365beadSRussell King 9126365beadSRussell King d = kzalloc(sizeof(*d), GFP_KERNEL); 9136365beadSRussell King if (!d) { 9146365beadSRussell King ret = -ENOMEM; 9156365beadSRussell King goto err_alloc; 9166365beadSRussell King } 9176365beadSRussell King 9186365beadSRussell King spin_lock_init(&d->lock); 9196365beadSRussell King INIT_LIST_HEAD(&d->chan_pending); 9206365beadSRussell King 92173d2a3ceSRussell King d->slave.filter.fn = sa11x0_dma_filter_fn; 92273d2a3ceSRussell King d->slave.filter.mapcnt = ARRAY_SIZE(sa11x0_dma_map); 92373d2a3ceSRussell King d->slave.filter.map = sa11x0_dma_map; 92473d2a3ceSRussell King 9256365beadSRussell King d->base = ioremap(res->start, resource_size(res)); 9266365beadSRussell King if (!d->base) { 9276365beadSRussell King ret = -ENOMEM; 9286365beadSRussell King goto err_ioremap; 9296365beadSRussell King } 9306365beadSRussell King 931*8a536883SAllen Pais tasklet_setup(&d->task, sa11x0_dma_tasklet); 9326365beadSRussell King 9336365beadSRussell King for (i = 0; i < NR_PHY_CHAN; i++) { 9346365beadSRussell King struct sa11x0_dma_phy *p = &d->phy[i]; 9356365beadSRussell King 9366365beadSRussell King p->dev = d; 9376365beadSRussell King p->num = i; 9386365beadSRussell King p->base = d->base + i * DMA_SIZE; 9396365beadSRussell King writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR | 9406365beadSRussell King DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB, 9416365beadSRussell King p->base + DMA_DCSR_C); 9426365beadSRussell King writel_relaxed(0, p->base + DMA_DDAR); 9436365beadSRussell King 9446365beadSRussell King ret = sa11x0_dma_request_irq(pdev, i, p); 9456365beadSRussell King if (ret) { 9466365beadSRussell King while (i) { 9476365beadSRussell King i--; 9486365beadSRussell King sa11x0_dma_free_irq(pdev, i, &d->phy[i]); 9496365beadSRussell King } 9506365beadSRussell King goto err_irq; 9516365beadSRussell King } 9526365beadSRussell King } 9536365beadSRussell King 9546365beadSRussell King dma_cap_set(DMA_SLAVE, d->slave.cap_mask); 955d9444325SRussell King dma_cap_set(DMA_CYCLIC, d->slave.cap_mask); 9566365beadSRussell King d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg; 957d9444325SRussell King d->slave.device_prep_dma_cyclic = sa11x0_dma_prep_dma_cyclic; 95828591dfdSDmitry Eremin-Solenikov d->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 95928591dfdSDmitry Eremin-Solenikov d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 96028591dfdSDmitry Eremin-Solenikov d->slave.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 96128591dfdSDmitry Eremin-Solenikov BIT(DMA_SLAVE_BUSWIDTH_2_BYTES); 96228591dfdSDmitry Eremin-Solenikov d->slave.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 96328591dfdSDmitry Eremin-Solenikov BIT(DMA_SLAVE_BUSWIDTH_2_BYTES); 9646365beadSRussell King ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev); 9656365beadSRussell King if (ret) { 9666365beadSRussell King dev_warn(d->slave.dev, "failed to register slave async device: %d\n", 9676365beadSRussell King ret); 9686365beadSRussell King goto err_slave_reg; 9696365beadSRussell King } 9706365beadSRussell King 9716365beadSRussell King platform_set_drvdata(pdev, d); 9726365beadSRussell King return 0; 9736365beadSRussell King 9746365beadSRussell King err_slave_reg: 9756365beadSRussell King sa11x0_dma_free_channels(&d->slave); 9766365beadSRussell King for (i = 0; i < NR_PHY_CHAN; i++) 9776365beadSRussell King sa11x0_dma_free_irq(pdev, i, &d->phy[i]); 9786365beadSRussell King err_irq: 9796365beadSRussell King tasklet_kill(&d->task); 9806365beadSRussell King iounmap(d->base); 9816365beadSRussell King err_ioremap: 9826365beadSRussell King kfree(d); 9836365beadSRussell King err_alloc: 9846365beadSRussell King return ret; 9856365beadSRussell King } 9866365beadSRussell King 9874bf27b8bSGreg Kroah-Hartman static int sa11x0_dma_remove(struct platform_device *pdev) 9886365beadSRussell King { 9896365beadSRussell King struct sa11x0_dma_dev *d = platform_get_drvdata(pdev); 9906365beadSRussell King unsigned pch; 9916365beadSRussell King 9926365beadSRussell King dma_async_device_unregister(&d->slave); 9936365beadSRussell King 9946365beadSRussell King sa11x0_dma_free_channels(&d->slave); 9956365beadSRussell King for (pch = 0; pch < NR_PHY_CHAN; pch++) 9966365beadSRussell King sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]); 9976365beadSRussell King tasklet_kill(&d->task); 9986365beadSRussell King iounmap(d->base); 9996365beadSRussell King kfree(d); 10006365beadSRussell King 10016365beadSRussell King return 0; 10026365beadSRussell King } 10036365beadSRussell King 10046365beadSRussell King static int sa11x0_dma_suspend(struct device *dev) 10056365beadSRussell King { 10066365beadSRussell King struct sa11x0_dma_dev *d = dev_get_drvdata(dev); 10076365beadSRussell King unsigned pch; 10086365beadSRussell King 10096365beadSRussell King for (pch = 0; pch < NR_PHY_CHAN; pch++) { 10106365beadSRussell King struct sa11x0_dma_phy *p = &d->phy[pch]; 10116365beadSRussell King u32 dcsr, saved_dcsr; 10126365beadSRussell King 10136365beadSRussell King dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R); 10146365beadSRussell King if (dcsr & DCSR_RUN) { 10156365beadSRussell King writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C); 10166365beadSRussell King dcsr = readl_relaxed(p->base + DMA_DCSR_R); 10176365beadSRussell King } 10186365beadSRussell King 10196365beadSRussell King saved_dcsr &= DCSR_RUN | DCSR_IE; 10206365beadSRussell King if (dcsr & DCSR_BIU) { 10216365beadSRussell King p->dbs[0] = readl_relaxed(p->base + DMA_DBSB); 10226365beadSRussell King p->dbt[0] = readl_relaxed(p->base + DMA_DBTB); 10236365beadSRussell King p->dbs[1] = readl_relaxed(p->base + DMA_DBSA); 10246365beadSRussell King p->dbt[1] = readl_relaxed(p->base + DMA_DBTA); 10256365beadSRussell King saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) | 10266365beadSRussell King (dcsr & DCSR_STRTB ? DCSR_STRTA : 0); 10276365beadSRussell King } else { 10286365beadSRussell King p->dbs[0] = readl_relaxed(p->base + DMA_DBSA); 10296365beadSRussell King p->dbt[0] = readl_relaxed(p->base + DMA_DBTA); 10306365beadSRussell King p->dbs[1] = readl_relaxed(p->base + DMA_DBSB); 10316365beadSRussell King p->dbt[1] = readl_relaxed(p->base + DMA_DBTB); 10326365beadSRussell King saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB); 10336365beadSRussell King } 10346365beadSRussell King p->dcsr = saved_dcsr; 10356365beadSRussell King 10366365beadSRussell King writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C); 10376365beadSRussell King } 10386365beadSRussell King 10396365beadSRussell King return 0; 10406365beadSRussell King } 10416365beadSRussell King 10426365beadSRussell King static int sa11x0_dma_resume(struct device *dev) 10436365beadSRussell King { 10446365beadSRussell King struct sa11x0_dma_dev *d = dev_get_drvdata(dev); 10456365beadSRussell King unsigned pch; 10466365beadSRussell King 10476365beadSRussell King for (pch = 0; pch < NR_PHY_CHAN; pch++) { 10486365beadSRussell King struct sa11x0_dma_phy *p = &d->phy[pch]; 10496365beadSRussell King struct sa11x0_dma_desc *txd = NULL; 10506365beadSRussell King u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R); 10516365beadSRussell King 10526365beadSRussell King WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN)); 10536365beadSRussell King 10546365beadSRussell King if (p->txd_done) 10556365beadSRussell King txd = p->txd_done; 10566365beadSRussell King else if (p->txd_load) 10576365beadSRussell King txd = p->txd_load; 10586365beadSRussell King 10596365beadSRussell King if (!txd) 10606365beadSRussell King continue; 10616365beadSRussell King 10626365beadSRussell King writel_relaxed(txd->ddar, p->base + DMA_DDAR); 10636365beadSRussell King 10646365beadSRussell King writel_relaxed(p->dbs[0], p->base + DMA_DBSA); 10656365beadSRussell King writel_relaxed(p->dbt[0], p->base + DMA_DBTA); 10666365beadSRussell King writel_relaxed(p->dbs[1], p->base + DMA_DBSB); 10676365beadSRussell King writel_relaxed(p->dbt[1], p->base + DMA_DBTB); 10686365beadSRussell King writel_relaxed(p->dcsr, p->base + DMA_DCSR_S); 10696365beadSRussell King } 10706365beadSRussell King 10716365beadSRussell King return 0; 10726365beadSRussell King } 10736365beadSRussell King 10746365beadSRussell King static const struct dev_pm_ops sa11x0_dma_pm_ops = { 10756365beadSRussell King .suspend_noirq = sa11x0_dma_suspend, 10766365beadSRussell King .resume_noirq = sa11x0_dma_resume, 10776365beadSRussell King .freeze_noirq = sa11x0_dma_suspend, 10786365beadSRussell King .thaw_noirq = sa11x0_dma_resume, 10796365beadSRussell King .poweroff_noirq = sa11x0_dma_suspend, 10806365beadSRussell King .restore_noirq = sa11x0_dma_resume, 10816365beadSRussell King }; 10826365beadSRussell King 10836365beadSRussell King static struct platform_driver sa11x0_dma_driver = { 10846365beadSRussell King .driver = { 10856365beadSRussell King .name = "sa11x0-dma", 10866365beadSRussell King .pm = &sa11x0_dma_pm_ops, 10876365beadSRussell King }, 10886365beadSRussell King .probe = sa11x0_dma_probe, 1089a7d6e3ecSBill Pemberton .remove = sa11x0_dma_remove, 10906365beadSRussell King }; 10916365beadSRussell King 10926365beadSRussell King static int __init sa11x0_dma_init(void) 10936365beadSRussell King { 10946365beadSRussell King return platform_driver_register(&sa11x0_dma_driver); 10956365beadSRussell King } 10966365beadSRussell King subsys_initcall(sa11x0_dma_init); 10976365beadSRussell King 10986365beadSRussell King static void __exit sa11x0_dma_exit(void) 10996365beadSRussell King { 11006365beadSRussell King platform_driver_unregister(&sa11x0_dma_driver); 11016365beadSRussell King } 11026365beadSRussell King module_exit(sa11x0_dma_exit); 11036365beadSRussell King 11046365beadSRussell King MODULE_AUTHOR("Russell King"); 11056365beadSRussell King MODULE_DESCRIPTION("SA-11x0 DMA driver"); 11066365beadSRussell King MODULE_LICENSE("GPL v2"); 11076365beadSRussell King MODULE_ALIAS("platform:sa11x0-dma"); 1108