162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Core driver for the Synopsys DesignWare DMA Controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007-2008 Atmel Corporation 662306a36Sopenharmony_ci * Copyright (C) 2010-2011 ST Microelectronics 762306a36Sopenharmony_ci * Copyright (C) 2013 Intel Corporation 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/dmaengine.h> 1362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1462306a36Sopenharmony_ci#include <linux/dmapool.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "../dmaengine.h" 2562306a36Sopenharmony_ci#include "internal.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * This supports the Synopsys "DesignWare AHB Central DMA Controller", 2962306a36Sopenharmony_ci * (DW_ahb_dmac) which is used with various AMBA 2.0 systems (not all 3062306a36Sopenharmony_ci * of which use ARM any more). See the "Databook" from Synopsys for 3162306a36Sopenharmony_ci * information beyond what licensees probably provide. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* The set of bus widths supported by the DMA controller */ 3562306a36Sopenharmony_ci#define DW_DMA_BUSWIDTHS \ 3662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ 3762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ 3862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ 3962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic struct device *chan2dev(struct dma_chan *chan) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return &chan->dev->device; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci return to_dw_desc(dwc->active_list.next); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct dw_desc *desc = txd_to_dw_desc(tx); 5662306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(tx->chan); 5762306a36Sopenharmony_ci dma_cookie_t cookie; 5862306a36Sopenharmony_ci unsigned long flags; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 6162306a36Sopenharmony_ci cookie = dma_cookie_assign(tx); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* 6462306a36Sopenharmony_ci * REVISIT: We should attempt to chain as many descriptors as 6562306a36Sopenharmony_ci * possible, perhaps even appending to those already submitted 6662306a36Sopenharmony_ci * for DMA. But this is hard to do in a race-free manner. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci list_add_tail(&desc->desc_node, &dwc->queue); 7062306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 7162306a36Sopenharmony_ci dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n", 7262306a36Sopenharmony_ci __func__, desc->txd.cookie); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return cookie; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 8062306a36Sopenharmony_ci struct dw_desc *desc; 8162306a36Sopenharmony_ci dma_addr_t phys; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci desc = dma_pool_zalloc(dw->desc_pool, GFP_ATOMIC, &phys); 8462306a36Sopenharmony_ci if (!desc) 8562306a36Sopenharmony_ci return NULL; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci dwc->descs_allocated++; 8862306a36Sopenharmony_ci INIT_LIST_HEAD(&desc->tx_list); 8962306a36Sopenharmony_ci dma_async_tx_descriptor_init(&desc->txd, &dwc->chan); 9062306a36Sopenharmony_ci desc->txd.tx_submit = dwc_tx_submit; 9162306a36Sopenharmony_ci desc->txd.flags = DMA_CTRL_ACK; 9262306a36Sopenharmony_ci desc->txd.phys = phys; 9362306a36Sopenharmony_ci return desc; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 9962306a36Sopenharmony_ci struct dw_desc *child, *_next; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (unlikely(!desc)) 10262306a36Sopenharmony_ci return; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci list_for_each_entry_safe(child, _next, &desc->tx_list, desc_node) { 10562306a36Sopenharmony_ci list_del(&child->desc_node); 10662306a36Sopenharmony_ci dma_pool_free(dw->desc_pool, child, child->txd.phys); 10762306a36Sopenharmony_ci dwc->descs_allocated--; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci dma_pool_free(dw->desc_pool, desc, desc->txd.phys); 11162306a36Sopenharmony_ci dwc->descs_allocated--; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void dwc_initialize(struct dw_dma_chan *dwc) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci dw->initialize_chan(dwc); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Enable interrupts */ 12162306a36Sopenharmony_ci channel_set_bit(dw, MASK.XFER, dwc->mask); 12262306a36Sopenharmony_ci channel_set_bit(dw, MASK.ERROR, dwc->mask); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci dev_err(chan2dev(&dwc->chan), 13062306a36Sopenharmony_ci " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", 13162306a36Sopenharmony_ci channel_readl(dwc, SAR), 13262306a36Sopenharmony_ci channel_readl(dwc, DAR), 13362306a36Sopenharmony_ci channel_readl(dwc, LLP), 13462306a36Sopenharmony_ci channel_readl(dwc, CTL_HI), 13562306a36Sopenharmony_ci channel_readl(dwc, CTL_LO)); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci channel_clear_bit(dw, CH_EN, dwc->mask); 14162306a36Sopenharmony_ci while (dma_readl(dw, CH_EN) & dwc->mask) 14262306a36Sopenharmony_ci cpu_relax(); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* Perform single block transfer */ 14862306a36Sopenharmony_cistatic inline void dwc_do_single_block(struct dw_dma_chan *dwc, 14962306a36Sopenharmony_ci struct dw_desc *desc) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 15262306a36Sopenharmony_ci u32 ctllo; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* 15562306a36Sopenharmony_ci * Software emulation of LLP mode relies on interrupts to continue 15662306a36Sopenharmony_ci * multi block transfer. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci ctllo = lli_read(desc, ctllo) | DWC_CTLL_INT_EN; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci channel_writel(dwc, SAR, lli_read(desc, sar)); 16162306a36Sopenharmony_ci channel_writel(dwc, DAR, lli_read(desc, dar)); 16262306a36Sopenharmony_ci channel_writel(dwc, CTL_LO, ctllo); 16362306a36Sopenharmony_ci channel_writel(dwc, CTL_HI, lli_read(desc, ctlhi)); 16462306a36Sopenharmony_ci channel_set_bit(dw, CH_EN, dwc->mask); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Move pointer to next descriptor */ 16762306a36Sopenharmony_ci dwc->tx_node_active = dwc->tx_node_active->next; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Called with dwc->lock held and bh disabled */ 17162306a36Sopenharmony_cistatic void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 17462306a36Sopenharmony_ci u8 lms = DWC_LLP_LMS(dwc->dws.m_master); 17562306a36Sopenharmony_ci unsigned long was_soft_llp; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* ASSERT: channel is idle */ 17862306a36Sopenharmony_ci if (dma_readl(dw, CH_EN) & dwc->mask) { 17962306a36Sopenharmony_ci dev_err(chan2dev(&dwc->chan), 18062306a36Sopenharmony_ci "%s: BUG: Attempted to start non-idle channel\n", 18162306a36Sopenharmony_ci __func__); 18262306a36Sopenharmony_ci dwc_dump_chan_regs(dwc); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* The tasklet will hopefully advance the queue... */ 18562306a36Sopenharmony_ci return; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (dwc->nollp) { 18962306a36Sopenharmony_ci was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP, 19062306a36Sopenharmony_ci &dwc->flags); 19162306a36Sopenharmony_ci if (was_soft_llp) { 19262306a36Sopenharmony_ci dev_err(chan2dev(&dwc->chan), 19362306a36Sopenharmony_ci "BUG: Attempted to start new LLP transfer inside ongoing one\n"); 19462306a36Sopenharmony_ci return; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci dwc_initialize(dwc); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci first->residue = first->total_len; 20062306a36Sopenharmony_ci dwc->tx_node_active = &first->tx_list; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Submit first block */ 20362306a36Sopenharmony_ci dwc_do_single_block(dwc, first); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci dwc_initialize(dwc); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci channel_writel(dwc, LLP, first->txd.phys | lms); 21162306a36Sopenharmony_ci channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN); 21262306a36Sopenharmony_ci channel_writel(dwc, CTL_HI, 0); 21362306a36Sopenharmony_ci channel_set_bit(dw, CH_EN, dwc->mask); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void dwc_dostart_first_queued(struct dw_dma_chan *dwc) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct dw_desc *desc; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (list_empty(&dwc->queue)) 22162306a36Sopenharmony_ci return; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci list_move(dwc->queue.next, &dwc->active_list); 22462306a36Sopenharmony_ci desc = dwc_first_active(dwc); 22562306a36Sopenharmony_ci dev_vdbg(chan2dev(&dwc->chan), "%s: started %u\n", __func__, desc->txd.cookie); 22662306a36Sopenharmony_ci dwc_dostart(dwc, desc); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void 23262306a36Sopenharmony_cidwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc, 23362306a36Sopenharmony_ci bool callback_required) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct dma_async_tx_descriptor *txd = &desc->txd; 23662306a36Sopenharmony_ci struct dw_desc *child; 23762306a36Sopenharmony_ci unsigned long flags; 23862306a36Sopenharmony_ci struct dmaengine_desc_callback cb; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 24362306a36Sopenharmony_ci dma_cookie_complete(txd); 24462306a36Sopenharmony_ci if (callback_required) 24562306a36Sopenharmony_ci dmaengine_desc_get_callback(txd, &cb); 24662306a36Sopenharmony_ci else 24762306a36Sopenharmony_ci memset(&cb, 0, sizeof(cb)); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* async_tx_ack */ 25062306a36Sopenharmony_ci list_for_each_entry(child, &desc->tx_list, desc_node) 25162306a36Sopenharmony_ci async_tx_ack(&child->txd); 25262306a36Sopenharmony_ci async_tx_ack(&desc->txd); 25362306a36Sopenharmony_ci dwc_desc_put(dwc, desc); 25462306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dmaengine_desc_callback_invoke(&cb, NULL); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct dw_desc *desc, *_desc; 26262306a36Sopenharmony_ci LIST_HEAD(list); 26362306a36Sopenharmony_ci unsigned long flags; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 26662306a36Sopenharmony_ci if (dma_readl(dw, CH_EN) & dwc->mask) { 26762306a36Sopenharmony_ci dev_err(chan2dev(&dwc->chan), 26862306a36Sopenharmony_ci "BUG: XFER bit set, but channel not idle!\n"); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Try to continue after resetting the channel... */ 27162306a36Sopenharmony_ci dwc_chan_disable(dw, dwc); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* 27562306a36Sopenharmony_ci * Submit queued descriptors ASAP, i.e. before we go through 27662306a36Sopenharmony_ci * the completed ones. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci list_splice_init(&dwc->active_list, &list); 27962306a36Sopenharmony_ci dwc_dostart_first_queued(dwc); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci list_for_each_entry_safe(desc, _desc, &list, desc_node) 28462306a36Sopenharmony_ci dwc_descriptor_complete(dwc, desc, true); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* Returns how many bytes were already received from source */ 28862306a36Sopenharmony_cistatic inline u32 dwc_get_sent(struct dw_dma_chan *dwc) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 29162306a36Sopenharmony_ci u32 ctlhi = channel_readl(dwc, CTL_HI); 29262306a36Sopenharmony_ci u32 ctllo = channel_readl(dwc, CTL_LO); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci dma_addr_t llp; 30062306a36Sopenharmony_ci struct dw_desc *desc, *_desc; 30162306a36Sopenharmony_ci struct dw_desc *child; 30262306a36Sopenharmony_ci u32 status_xfer; 30362306a36Sopenharmony_ci unsigned long flags; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 30662306a36Sopenharmony_ci llp = channel_readl(dwc, LLP); 30762306a36Sopenharmony_ci status_xfer = dma_readl(dw, RAW.XFER); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (status_xfer & dwc->mask) { 31062306a36Sopenharmony_ci /* Everything we've submitted is done */ 31162306a36Sopenharmony_ci dma_writel(dw, CLEAR.XFER, dwc->mask); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) { 31462306a36Sopenharmony_ci struct list_head *head, *active = dwc->tx_node_active; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * We are inside first active descriptor. 31862306a36Sopenharmony_ci * Otherwise something is really wrong. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci desc = dwc_first_active(dwc); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci head = &desc->tx_list; 32362306a36Sopenharmony_ci if (active != head) { 32462306a36Sopenharmony_ci /* Update residue to reflect last sent descriptor */ 32562306a36Sopenharmony_ci if (active == head->next) 32662306a36Sopenharmony_ci desc->residue -= desc->len; 32762306a36Sopenharmony_ci else 32862306a36Sopenharmony_ci desc->residue -= to_dw_desc(active->prev)->len; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci child = to_dw_desc(active); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Submit next block */ 33362306a36Sopenharmony_ci dwc_do_single_block(dwc, child); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 33662306a36Sopenharmony_ci return; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* We are done here */ 34062306a36Sopenharmony_ci clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci dwc_complete_all(dw, dwc); 34662306a36Sopenharmony_ci return; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (list_empty(&dwc->active_list)) { 35062306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 35162306a36Sopenharmony_ci return; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) { 35562306a36Sopenharmony_ci dev_vdbg(chan2dev(&dwc->chan), "%s: soft LLP mode\n", __func__); 35662306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 35762306a36Sopenharmony_ci return; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci dev_vdbg(chan2dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { 36362306a36Sopenharmony_ci /* Initial residue value */ 36462306a36Sopenharmony_ci desc->residue = desc->total_len; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Check first descriptors addr */ 36762306a36Sopenharmony_ci if (desc->txd.phys == DWC_LLP_LOC(llp)) { 36862306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 36962306a36Sopenharmony_ci return; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Check first descriptors llp */ 37362306a36Sopenharmony_ci if (lli_read(desc, llp) == llp) { 37462306a36Sopenharmony_ci /* This one is currently in progress */ 37562306a36Sopenharmony_ci desc->residue -= dwc_get_sent(dwc); 37662306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 37762306a36Sopenharmony_ci return; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci desc->residue -= desc->len; 38162306a36Sopenharmony_ci list_for_each_entry(child, &desc->tx_list, desc_node) { 38262306a36Sopenharmony_ci if (lli_read(child, llp) == llp) { 38362306a36Sopenharmony_ci /* Currently in progress */ 38462306a36Sopenharmony_ci desc->residue -= dwc_get_sent(dwc); 38562306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 38662306a36Sopenharmony_ci return; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci desc->residue -= child->len; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * No descriptors so far seem to be in progress, i.e. 39362306a36Sopenharmony_ci * this one must be done. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 39662306a36Sopenharmony_ci dwc_descriptor_complete(dwc, desc, true); 39762306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci dev_err(chan2dev(&dwc->chan), 40162306a36Sopenharmony_ci "BUG: All descriptors done, but channel not idle!\n"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Try to continue after resetting the channel... */ 40462306a36Sopenharmony_ci dwc_chan_disable(dw, dwc); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci dwc_dostart_first_queued(dwc); 40762306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_desc *desc) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci dev_crit(chan2dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n", 41362306a36Sopenharmony_ci lli_read(desc, sar), 41462306a36Sopenharmony_ci lli_read(desc, dar), 41562306a36Sopenharmony_ci lli_read(desc, llp), 41662306a36Sopenharmony_ci lli_read(desc, ctlhi), 41762306a36Sopenharmony_ci lli_read(desc, ctllo)); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct dw_desc *bad_desc; 42362306a36Sopenharmony_ci struct dw_desc *child; 42462306a36Sopenharmony_ci unsigned long flags; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci dwc_scan_descriptors(dw, dwc); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* 43162306a36Sopenharmony_ci * The descriptor currently at the head of the active list is 43262306a36Sopenharmony_ci * borked. Since we don't have any way to report errors, we'll 43362306a36Sopenharmony_ci * just have to scream loudly and try to carry on. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci bad_desc = dwc_first_active(dwc); 43662306a36Sopenharmony_ci list_del_init(&bad_desc->desc_node); 43762306a36Sopenharmony_ci list_move(dwc->queue.next, dwc->active_list.prev); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Clear the error flag and try to restart the controller */ 44062306a36Sopenharmony_ci dma_writel(dw, CLEAR.ERROR, dwc->mask); 44162306a36Sopenharmony_ci if (!list_empty(&dwc->active_list)) 44262306a36Sopenharmony_ci dwc_dostart(dwc, dwc_first_active(dwc)); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * WARN may seem harsh, but since this only happens 44662306a36Sopenharmony_ci * when someone submits a bad physical address in a 44762306a36Sopenharmony_ci * descriptor, we should consider ourselves lucky that the 44862306a36Sopenharmony_ci * controller flagged an error instead of scribbling over 44962306a36Sopenharmony_ci * random memory locations. 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_ci dev_WARN(chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n" 45262306a36Sopenharmony_ci " cookie: %d\n", bad_desc->txd.cookie); 45362306a36Sopenharmony_ci dwc_dump_lli(dwc, bad_desc); 45462306a36Sopenharmony_ci list_for_each_entry(child, &bad_desc->tx_list, desc_node) 45562306a36Sopenharmony_ci dwc_dump_lli(dwc, child); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Pretend the descriptor completed successfully */ 46062306a36Sopenharmony_ci dwc_descriptor_complete(dwc, bad_desc, true); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic void dw_dma_tasklet(struct tasklet_struct *t) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct dw_dma *dw = from_tasklet(dw, t, tasklet); 46662306a36Sopenharmony_ci struct dw_dma_chan *dwc; 46762306a36Sopenharmony_ci u32 status_xfer; 46862306a36Sopenharmony_ci u32 status_err; 46962306a36Sopenharmony_ci unsigned int i; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci status_xfer = dma_readl(dw, RAW.XFER); 47262306a36Sopenharmony_ci status_err = dma_readl(dw, RAW.ERROR); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci for (i = 0; i < dw->dma.chancnt; i++) { 47762306a36Sopenharmony_ci dwc = &dw->chan[i]; 47862306a36Sopenharmony_ci if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) 47962306a36Sopenharmony_ci dev_vdbg(dw->dma.dev, "Cyclic xfer is not implemented\n"); 48062306a36Sopenharmony_ci else if (status_err & (1 << i)) 48162306a36Sopenharmony_ci dwc_handle_error(dw, dwc); 48262306a36Sopenharmony_ci else if (status_xfer & (1 << i)) 48362306a36Sopenharmony_ci dwc_scan_descriptors(dw, dwc); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Re-enable interrupts */ 48762306a36Sopenharmony_ci channel_set_bit(dw, MASK.XFER, dw->all_chan_mask); 48862306a36Sopenharmony_ci channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask); 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic irqreturn_t dw_dma_interrupt(int irq, void *dev_id) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct dw_dma *dw = dev_id; 49462306a36Sopenharmony_ci u32 status; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* Check if we have any interrupt from the DMAC which is not in use */ 49762306a36Sopenharmony_ci if (!dw->in_use) 49862306a36Sopenharmony_ci return IRQ_NONE; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci status = dma_readl(dw, STATUS_INT); 50162306a36Sopenharmony_ci dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Check if we have any interrupt from the DMAC */ 50462306a36Sopenharmony_ci if (!status) 50562306a36Sopenharmony_ci return IRQ_NONE; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* 50862306a36Sopenharmony_ci * Just disable the interrupts. We'll turn them back on in the 50962306a36Sopenharmony_ci * softirq handler. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); 51262306a36Sopenharmony_ci channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); 51362306a36Sopenharmony_ci channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci status = dma_readl(dw, STATUS_INT); 51662306a36Sopenharmony_ci if (status) { 51762306a36Sopenharmony_ci dev_err(dw->dma.dev, 51862306a36Sopenharmony_ci "BUG: Unexpected interrupts pending: 0x%x\n", 51962306a36Sopenharmony_ci status); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Try to recover */ 52262306a36Sopenharmony_ci channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1); 52362306a36Sopenharmony_ci channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1); 52462306a36Sopenharmony_ci channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1); 52562306a36Sopenharmony_ci channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1); 52662306a36Sopenharmony_ci channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci tasklet_schedule(&dw->tasklet); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return IRQ_HANDLED; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 53762306a36Sopenharmony_cidwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, 53862306a36Sopenharmony_ci size_t len, unsigned long flags) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 54162306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(chan->device); 54262306a36Sopenharmony_ci struct dw_desc *desc; 54362306a36Sopenharmony_ci struct dw_desc *first; 54462306a36Sopenharmony_ci struct dw_desc *prev; 54562306a36Sopenharmony_ci size_t xfer_count; 54662306a36Sopenharmony_ci size_t offset; 54762306a36Sopenharmony_ci u8 m_master = dwc->dws.m_master; 54862306a36Sopenharmony_ci unsigned int src_width; 54962306a36Sopenharmony_ci unsigned int dst_width; 55062306a36Sopenharmony_ci unsigned int data_width = dw->pdata->data_width[m_master]; 55162306a36Sopenharmony_ci u32 ctllo, ctlhi; 55262306a36Sopenharmony_ci u8 lms = DWC_LLP_LMS(m_master); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci dev_vdbg(chan2dev(chan), 55562306a36Sopenharmony_ci "%s: d%pad s%pad l0x%zx f0x%lx\n", __func__, 55662306a36Sopenharmony_ci &dest, &src, len, flags); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (unlikely(!len)) { 55962306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); 56062306a36Sopenharmony_ci return NULL; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci dwc->direction = DMA_MEM_TO_MEM; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci src_width = dst_width = __ffs(data_width | src | dest | len); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci ctllo = dw->prepare_ctllo(dwc) 56862306a36Sopenharmony_ci | DWC_CTLL_DST_WIDTH(dst_width) 56962306a36Sopenharmony_ci | DWC_CTLL_SRC_WIDTH(src_width) 57062306a36Sopenharmony_ci | DWC_CTLL_DST_INC 57162306a36Sopenharmony_ci | DWC_CTLL_SRC_INC 57262306a36Sopenharmony_ci | DWC_CTLL_FC_M2M; 57362306a36Sopenharmony_ci prev = first = NULL; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci for (offset = 0; offset < len; offset += xfer_count) { 57662306a36Sopenharmony_ci desc = dwc_desc_get(dwc); 57762306a36Sopenharmony_ci if (!desc) 57862306a36Sopenharmony_ci goto err_desc_get; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci ctlhi = dw->bytes2block(dwc, len - offset, src_width, &xfer_count); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci lli_write(desc, sar, src + offset); 58362306a36Sopenharmony_ci lli_write(desc, dar, dest + offset); 58462306a36Sopenharmony_ci lli_write(desc, ctllo, ctllo); 58562306a36Sopenharmony_ci lli_write(desc, ctlhi, ctlhi); 58662306a36Sopenharmony_ci desc->len = xfer_count; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (!first) { 58962306a36Sopenharmony_ci first = desc; 59062306a36Sopenharmony_ci } else { 59162306a36Sopenharmony_ci lli_write(prev, llp, desc->txd.phys | lms); 59262306a36Sopenharmony_ci list_add_tail(&desc->desc_node, &first->tx_list); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci prev = desc; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (flags & DMA_PREP_INTERRUPT) 59862306a36Sopenharmony_ci /* Trigger interrupt after last block */ 59962306a36Sopenharmony_ci lli_set(prev, ctllo, DWC_CTLL_INT_EN); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci prev->lli.llp = 0; 60262306a36Sopenharmony_ci lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN); 60362306a36Sopenharmony_ci first->txd.flags = flags; 60462306a36Sopenharmony_ci first->total_len = len; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci return &first->txd; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cierr_desc_get: 60962306a36Sopenharmony_ci dwc_desc_put(dwc, first); 61062306a36Sopenharmony_ci return NULL; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 61462306a36Sopenharmony_cidwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, 61562306a36Sopenharmony_ci unsigned int sg_len, enum dma_transfer_direction direction, 61662306a36Sopenharmony_ci unsigned long flags, void *context) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 61962306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(chan->device); 62062306a36Sopenharmony_ci struct dma_slave_config *sconfig = &dwc->dma_sconfig; 62162306a36Sopenharmony_ci struct dw_desc *prev; 62262306a36Sopenharmony_ci struct dw_desc *first; 62362306a36Sopenharmony_ci u32 ctllo, ctlhi; 62462306a36Sopenharmony_ci u8 m_master = dwc->dws.m_master; 62562306a36Sopenharmony_ci u8 lms = DWC_LLP_LMS(m_master); 62662306a36Sopenharmony_ci dma_addr_t reg; 62762306a36Sopenharmony_ci unsigned int reg_width; 62862306a36Sopenharmony_ci unsigned int mem_width; 62962306a36Sopenharmony_ci unsigned int data_width = dw->pdata->data_width[m_master]; 63062306a36Sopenharmony_ci unsigned int i; 63162306a36Sopenharmony_ci struct scatterlist *sg; 63262306a36Sopenharmony_ci size_t total_len = 0; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci dev_vdbg(chan2dev(chan), "%s\n", __func__); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (unlikely(!is_slave_direction(direction) || !sg_len)) 63762306a36Sopenharmony_ci return NULL; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci dwc->direction = direction; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci prev = first = NULL; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci switch (direction) { 64462306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 64562306a36Sopenharmony_ci reg_width = __ffs(sconfig->dst_addr_width); 64662306a36Sopenharmony_ci reg = sconfig->dst_addr; 64762306a36Sopenharmony_ci ctllo = dw->prepare_ctllo(dwc) 64862306a36Sopenharmony_ci | DWC_CTLL_DST_WIDTH(reg_width) 64962306a36Sopenharmony_ci | DWC_CTLL_DST_FIX 65062306a36Sopenharmony_ci | DWC_CTLL_SRC_INC; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) : 65362306a36Sopenharmony_ci DWC_CTLL_FC(DW_DMA_FC_D_M2P); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 65662306a36Sopenharmony_ci struct dw_desc *desc; 65762306a36Sopenharmony_ci u32 len, mem; 65862306a36Sopenharmony_ci size_t dlen; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci mem = sg_dma_address(sg); 66162306a36Sopenharmony_ci len = sg_dma_len(sg); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci mem_width = __ffs(data_width | mem | len); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cislave_sg_todev_fill_desc: 66662306a36Sopenharmony_ci desc = dwc_desc_get(dwc); 66762306a36Sopenharmony_ci if (!desc) 66862306a36Sopenharmony_ci goto err_desc_get; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci ctlhi = dw->bytes2block(dwc, len, mem_width, &dlen); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci lli_write(desc, sar, mem); 67362306a36Sopenharmony_ci lli_write(desc, dar, reg); 67462306a36Sopenharmony_ci lli_write(desc, ctlhi, ctlhi); 67562306a36Sopenharmony_ci lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width)); 67662306a36Sopenharmony_ci desc->len = dlen; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (!first) { 67962306a36Sopenharmony_ci first = desc; 68062306a36Sopenharmony_ci } else { 68162306a36Sopenharmony_ci lli_write(prev, llp, desc->txd.phys | lms); 68262306a36Sopenharmony_ci list_add_tail(&desc->desc_node, &first->tx_list); 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci prev = desc; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci mem += dlen; 68762306a36Sopenharmony_ci len -= dlen; 68862306a36Sopenharmony_ci total_len += dlen; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (len) 69162306a36Sopenharmony_ci goto slave_sg_todev_fill_desc; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 69562306a36Sopenharmony_ci reg_width = __ffs(sconfig->src_addr_width); 69662306a36Sopenharmony_ci reg = sconfig->src_addr; 69762306a36Sopenharmony_ci ctllo = dw->prepare_ctllo(dwc) 69862306a36Sopenharmony_ci | DWC_CTLL_SRC_WIDTH(reg_width) 69962306a36Sopenharmony_ci | DWC_CTLL_DST_INC 70062306a36Sopenharmony_ci | DWC_CTLL_SRC_FIX; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) : 70362306a36Sopenharmony_ci DWC_CTLL_FC(DW_DMA_FC_D_P2M); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 70662306a36Sopenharmony_ci struct dw_desc *desc; 70762306a36Sopenharmony_ci u32 len, mem; 70862306a36Sopenharmony_ci size_t dlen; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci mem = sg_dma_address(sg); 71162306a36Sopenharmony_ci len = sg_dma_len(sg); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cislave_sg_fromdev_fill_desc: 71462306a36Sopenharmony_ci desc = dwc_desc_get(dwc); 71562306a36Sopenharmony_ci if (!desc) 71662306a36Sopenharmony_ci goto err_desc_get; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ctlhi = dw->bytes2block(dwc, len, reg_width, &dlen); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci lli_write(desc, sar, reg); 72162306a36Sopenharmony_ci lli_write(desc, dar, mem); 72262306a36Sopenharmony_ci lli_write(desc, ctlhi, ctlhi); 72362306a36Sopenharmony_ci mem_width = __ffs(data_width | mem); 72462306a36Sopenharmony_ci lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width)); 72562306a36Sopenharmony_ci desc->len = dlen; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (!first) { 72862306a36Sopenharmony_ci first = desc; 72962306a36Sopenharmony_ci } else { 73062306a36Sopenharmony_ci lli_write(prev, llp, desc->txd.phys | lms); 73162306a36Sopenharmony_ci list_add_tail(&desc->desc_node, &first->tx_list); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci prev = desc; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci mem += dlen; 73662306a36Sopenharmony_ci len -= dlen; 73762306a36Sopenharmony_ci total_len += dlen; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (len) 74062306a36Sopenharmony_ci goto slave_sg_fromdev_fill_desc; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci break; 74362306a36Sopenharmony_ci default: 74462306a36Sopenharmony_ci return NULL; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (flags & DMA_PREP_INTERRUPT) 74862306a36Sopenharmony_ci /* Trigger interrupt after last block */ 74962306a36Sopenharmony_ci lli_set(prev, ctllo, DWC_CTLL_INT_EN); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci prev->lli.llp = 0; 75262306a36Sopenharmony_ci lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN); 75362306a36Sopenharmony_ci first->total_len = total_len; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return &first->txd; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cierr_desc_get: 75862306a36Sopenharmony_ci dev_err(chan2dev(chan), 75962306a36Sopenharmony_ci "not enough descriptors available. Direction %d\n", direction); 76062306a36Sopenharmony_ci dwc_desc_put(dwc, first); 76162306a36Sopenharmony_ci return NULL; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cibool dw_dma_filter(struct dma_chan *chan, void *param) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 76762306a36Sopenharmony_ci struct dw_dma_slave *dws = param; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (dws->dma_dev != chan->device->dev) 77062306a36Sopenharmony_ci return false; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* permit channels in accordance with the channels mask */ 77362306a36Sopenharmony_ci if (dws->channels && !(dws->channels & dwc->mask)) 77462306a36Sopenharmony_ci return false; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* We have to copy data since dws can be temporary storage */ 77762306a36Sopenharmony_ci memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave)); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return true; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_dma_filter); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 78662306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(chan->device); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci dwc->dma_sconfig.src_maxburst = 79162306a36Sopenharmony_ci clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst); 79262306a36Sopenharmony_ci dwc->dma_sconfig.dst_maxburst = 79362306a36Sopenharmony_ci clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst); 79662306a36Sopenharmony_ci dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 80462306a36Sopenharmony_ci unsigned int count = 20; /* timeout iterations */ 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci dw->suspend_chan(dwc, drain); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--) 80962306a36Sopenharmony_ci udelay(2); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci set_bit(DW_DMA_IS_PAUSED, &dwc->flags); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int dwc_pause(struct dma_chan *chan) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 81762306a36Sopenharmony_ci unsigned long flags; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 82062306a36Sopenharmony_ci dwc_chan_pause(dwc, false); 82162306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return 0; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic inline void dwc_chan_resume(struct dw_dma_chan *dwc, bool drain) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(dwc->chan.device); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci dw->resume_chan(dwc, drain); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci clear_bit(DW_DMA_IS_PAUSED, &dwc->flags); 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic int dwc_resume(struct dma_chan *chan) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 83862306a36Sopenharmony_ci unsigned long flags; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags)) 84362306a36Sopenharmony_ci dwc_chan_resume(dwc, false); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int dwc_terminate_all(struct dma_chan *chan) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 85362306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(chan->device); 85462306a36Sopenharmony_ci struct dw_desc *desc, *_desc; 85562306a36Sopenharmony_ci unsigned long flags; 85662306a36Sopenharmony_ci LIST_HEAD(list); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci dwc_chan_pause(dwc, true); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci dwc_chan_disable(dw, dwc); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci dwc_chan_resume(dwc, true); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* active_list entries will end up before queued entries */ 86962306a36Sopenharmony_ci list_splice_init(&dwc->queue, &list); 87062306a36Sopenharmony_ci list_splice_init(&dwc->active_list, &list); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* Flush all pending and queued descriptors */ 87562306a36Sopenharmony_ci list_for_each_entry_safe(desc, _desc, &list, desc_node) 87662306a36Sopenharmony_ci dwc_descriptor_complete(dwc, desc, false); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct dw_desc *desc; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci list_for_each_entry(desc, &dwc->active_list, desc_node) 88662306a36Sopenharmony_ci if (desc->txd.cookie == c) 88762306a36Sopenharmony_ci return desc; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return NULL; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic u32 dwc_get_residue_and_status(struct dw_dma_chan *dwc, dma_cookie_t cookie, 89362306a36Sopenharmony_ci enum dma_status *status) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct dw_desc *desc; 89662306a36Sopenharmony_ci unsigned long flags; 89762306a36Sopenharmony_ci u32 residue; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci desc = dwc_find_desc(dwc, cookie); 90262306a36Sopenharmony_ci if (desc) { 90362306a36Sopenharmony_ci if (desc == dwc_first_active(dwc)) { 90462306a36Sopenharmony_ci residue = desc->residue; 90562306a36Sopenharmony_ci if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue) 90662306a36Sopenharmony_ci residue -= dwc_get_sent(dwc); 90762306a36Sopenharmony_ci if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags)) 90862306a36Sopenharmony_ci *status = DMA_PAUSED; 90962306a36Sopenharmony_ci } else { 91062306a36Sopenharmony_ci residue = desc->total_len; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci } else { 91362306a36Sopenharmony_ci residue = 0; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 91762306a36Sopenharmony_ci return residue; 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic enum dma_status 92162306a36Sopenharmony_cidwc_tx_status(struct dma_chan *chan, 92262306a36Sopenharmony_ci dma_cookie_t cookie, 92362306a36Sopenharmony_ci struct dma_tx_state *txstate) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 92662306a36Sopenharmony_ci enum dma_status ret; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci ret = dma_cookie_status(chan, cookie, txstate); 92962306a36Sopenharmony_ci if (ret == DMA_COMPLETE) 93062306a36Sopenharmony_ci return ret; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci dwc_scan_descriptors(to_dw_dma(chan->device), dwc); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci ret = dma_cookie_status(chan, cookie, txstate); 93562306a36Sopenharmony_ci if (ret == DMA_COMPLETE) 93662306a36Sopenharmony_ci return ret; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci dma_set_residue(txstate, dwc_get_residue_and_status(dwc, cookie, &ret)); 93962306a36Sopenharmony_ci return ret; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic void dwc_issue_pending(struct dma_chan *chan) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 94562306a36Sopenharmony_ci unsigned long flags; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 94862306a36Sopenharmony_ci if (list_empty(&dwc->active_list)) 94962306a36Sopenharmony_ci dwc_dostart_first_queued(dwc); 95062306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci/*----------------------------------------------------------------------*/ 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_civoid do_dw_dma_off(struct dw_dma *dw) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci dma_writel(dw, CFG, 0); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); 96062306a36Sopenharmony_ci channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); 96162306a36Sopenharmony_ci channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask); 96262306a36Sopenharmony_ci channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask); 96362306a36Sopenharmony_ci channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci while (dma_readl(dw, CFG) & DW_CFG_DMA_EN) 96662306a36Sopenharmony_ci cpu_relax(); 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_civoid do_dw_dma_on(struct dw_dma *dw) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci dma_writel(dw, CFG, DW_CFG_DMA_EN); 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic int dwc_alloc_chan_resources(struct dma_chan *chan) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 97762306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(chan->device); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci dev_vdbg(chan2dev(chan), "%s\n", __func__); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* ASSERT: channel is idle */ 98262306a36Sopenharmony_ci if (dma_readl(dw, CH_EN) & dwc->mask) { 98362306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "DMA channel not idle?\n"); 98462306a36Sopenharmony_ci return -EIO; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci dma_cookie_init(chan); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* 99062306a36Sopenharmony_ci * NOTE: some controllers may have additional features that we 99162306a36Sopenharmony_ci * need to initialize here, like "scatter-gather" (which 99262306a36Sopenharmony_ci * doesn't mean what you think it means), and status writeback. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* 99662306a36Sopenharmony_ci * We need controller-specific data to set up slave transfers. 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_ci if (chan->private && !dw_dma_filter(chan, chan->private)) { 99962306a36Sopenharmony_ci dev_warn(chan2dev(chan), "Wrong controller-specific data\n"); 100062306a36Sopenharmony_ci return -EINVAL; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Enable controller here if needed */ 100462306a36Sopenharmony_ci if (!dw->in_use) 100562306a36Sopenharmony_ci do_dw_dma_on(dw); 100662306a36Sopenharmony_ci dw->in_use |= dwc->mask; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci return 0; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic void dwc_free_chan_resources(struct dma_chan *chan) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 101462306a36Sopenharmony_ci struct dw_dma *dw = to_dw_dma(chan->device); 101562306a36Sopenharmony_ci unsigned long flags; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__, 101862306a36Sopenharmony_ci dwc->descs_allocated); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* ASSERT: channel is idle */ 102162306a36Sopenharmony_ci BUG_ON(!list_empty(&dwc->active_list)); 102262306a36Sopenharmony_ci BUG_ON(!list_empty(&dwc->queue)); 102362306a36Sopenharmony_ci BUG_ON(dma_readl(to_dw_dma(chan->device), CH_EN) & dwc->mask); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci spin_lock_irqsave(&dwc->lock, flags); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* Clear custom channel configuration */ 102862306a36Sopenharmony_ci memset(&dwc->dws, 0, sizeof(struct dw_dma_slave)); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* Disable interrupts */ 103162306a36Sopenharmony_ci channel_clear_bit(dw, MASK.XFER, dwc->mask); 103262306a36Sopenharmony_ci channel_clear_bit(dw, MASK.BLOCK, dwc->mask); 103362306a36Sopenharmony_ci channel_clear_bit(dw, MASK.ERROR, dwc->mask); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci spin_unlock_irqrestore(&dwc->lock, flags); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* Disable controller in case it was a last user */ 103862306a36Sopenharmony_ci dw->in_use &= ~dwc->mask; 103962306a36Sopenharmony_ci if (!dw->in_use) 104062306a36Sopenharmony_ci do_dw_dma_off(dw); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci dev_vdbg(chan2dev(chan), "%s: done\n", __func__); 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic void dwc_caps(struct dma_chan *chan, struct dma_slave_caps *caps) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct dw_dma_chan *dwc = to_dw_dma_chan(chan); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci caps->max_burst = dwc->max_burst; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* 105262306a36Sopenharmony_ci * It might be crucial for some devices to have the hardware 105362306a36Sopenharmony_ci * accelerated multi-block transfers supported, aka LLPs in DW DMAC 105462306a36Sopenharmony_ci * notation. So if LLPs are supported then max_sg_burst is set to 105562306a36Sopenharmony_ci * zero which means unlimited number of SG entries can be handled in a 105662306a36Sopenharmony_ci * single DMA transaction, otherwise it's just one SG entry. 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ci if (dwc->nollp) 105962306a36Sopenharmony_ci caps->max_sg_burst = 1; 106062306a36Sopenharmony_ci else 106162306a36Sopenharmony_ci caps->max_sg_burst = 0; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ciint do_dma_probe(struct dw_dma_chip *chip) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci struct dw_dma *dw = chip->dw; 106762306a36Sopenharmony_ci struct dw_dma_platform_data *pdata; 106862306a36Sopenharmony_ci bool autocfg = false; 106962306a36Sopenharmony_ci unsigned int dw_params; 107062306a36Sopenharmony_ci unsigned int i; 107162306a36Sopenharmony_ci int err; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL); 107462306a36Sopenharmony_ci if (!dw->pdata) 107562306a36Sopenharmony_ci return -ENOMEM; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci dw->regs = chip->regs; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci pm_runtime_get_sync(chip->dev); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (!chip->pdata) { 108262306a36Sopenharmony_ci dw_params = dma_readl(dw, DW_PARAMS); 108362306a36Sopenharmony_ci dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci autocfg = dw_params >> DW_PARAMS_EN & 1; 108662306a36Sopenharmony_ci if (!autocfg) { 108762306a36Sopenharmony_ci err = -EINVAL; 108862306a36Sopenharmony_ci goto err_pdata; 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* Reassign the platform data pointer */ 109262306a36Sopenharmony_ci pdata = dw->pdata; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* Get hardware configuration parameters */ 109562306a36Sopenharmony_ci pdata->nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 7) + 1; 109662306a36Sopenharmony_ci pdata->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1; 109762306a36Sopenharmony_ci for (i = 0; i < pdata->nr_masters; i++) { 109862306a36Sopenharmony_ci pdata->data_width[i] = 109962306a36Sopenharmony_ci 4 << (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci pdata->block_size = dma_readl(dw, MAX_BLK_SIZE); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* Fill platform data with the default values */ 110462306a36Sopenharmony_ci pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING; 110562306a36Sopenharmony_ci pdata->chan_priority = CHAN_PRIORITY_ASCENDING; 110662306a36Sopenharmony_ci } else if (chip->pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) { 110762306a36Sopenharmony_ci err = -EINVAL; 110862306a36Sopenharmony_ci goto err_pdata; 110962306a36Sopenharmony_ci } else { 111062306a36Sopenharmony_ci memcpy(dw->pdata, chip->pdata, sizeof(*dw->pdata)); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* Reassign the platform data pointer */ 111362306a36Sopenharmony_ci pdata = dw->pdata; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci dw->chan = devm_kcalloc(chip->dev, pdata->nr_channels, sizeof(*dw->chan), 111762306a36Sopenharmony_ci GFP_KERNEL); 111862306a36Sopenharmony_ci if (!dw->chan) { 111962306a36Sopenharmony_ci err = -ENOMEM; 112062306a36Sopenharmony_ci goto err_pdata; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* Calculate all channel mask before DMA setup */ 112462306a36Sopenharmony_ci dw->all_chan_mask = (1 << pdata->nr_channels) - 1; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci /* Force dma off, just in case */ 112762306a36Sopenharmony_ci dw->disable(dw); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci /* Device and instance ID for IRQ and DMA pool */ 113062306a36Sopenharmony_ci dw->set_device_name(dw, chip->id); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* Create a pool of consistent memory blocks for hardware descriptors */ 113362306a36Sopenharmony_ci dw->desc_pool = dmam_pool_create(dw->name, chip->dev, 113462306a36Sopenharmony_ci sizeof(struct dw_desc), 4, 0); 113562306a36Sopenharmony_ci if (!dw->desc_pool) { 113662306a36Sopenharmony_ci dev_err(chip->dev, "No memory for descriptors dma pool\n"); 113762306a36Sopenharmony_ci err = -ENOMEM; 113862306a36Sopenharmony_ci goto err_pdata; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci tasklet_setup(&dw->tasklet, dw_dma_tasklet); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED, 114462306a36Sopenharmony_ci dw->name, dw); 114562306a36Sopenharmony_ci if (err) 114662306a36Sopenharmony_ci goto err_pdata; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci INIT_LIST_HEAD(&dw->dma.channels); 114962306a36Sopenharmony_ci for (i = 0; i < pdata->nr_channels; i++) { 115062306a36Sopenharmony_ci struct dw_dma_chan *dwc = &dw->chan[i]; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci dwc->chan.device = &dw->dma; 115362306a36Sopenharmony_ci dma_cookie_init(&dwc->chan); 115462306a36Sopenharmony_ci if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING) 115562306a36Sopenharmony_ci list_add_tail(&dwc->chan.device_node, 115662306a36Sopenharmony_ci &dw->dma.channels); 115762306a36Sopenharmony_ci else 115862306a36Sopenharmony_ci list_add(&dwc->chan.device_node, &dw->dma.channels); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* 7 is highest priority & 0 is lowest. */ 116162306a36Sopenharmony_ci if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING) 116262306a36Sopenharmony_ci dwc->priority = pdata->nr_channels - i - 1; 116362306a36Sopenharmony_ci else 116462306a36Sopenharmony_ci dwc->priority = i; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci dwc->ch_regs = &__dw_regs(dw)->CHAN[i]; 116762306a36Sopenharmony_ci spin_lock_init(&dwc->lock); 116862306a36Sopenharmony_ci dwc->mask = 1 << i; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci INIT_LIST_HEAD(&dwc->active_list); 117162306a36Sopenharmony_ci INIT_LIST_HEAD(&dwc->queue); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci channel_clear_bit(dw, CH_EN, dwc->mask); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci dwc->direction = DMA_TRANS_NONE; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* Hardware configuration */ 117862306a36Sopenharmony_ci if (autocfg) { 117962306a36Sopenharmony_ci unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1; 118062306a36Sopenharmony_ci void __iomem *addr = &__dw_regs(dw)->DWC_PARAMS[r]; 118162306a36Sopenharmony_ci unsigned int dwc_params = readl(addr); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i, 118462306a36Sopenharmony_ci dwc_params); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci /* 118762306a36Sopenharmony_ci * Decode maximum block size for given channel. The 118862306a36Sopenharmony_ci * stored 4 bit value represents blocks from 0x00 for 3 118962306a36Sopenharmony_ci * up to 0x0a for 4095. 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci dwc->block_size = 119262306a36Sopenharmony_ci (4 << ((pdata->block_size >> 4 * i) & 0xf)) - 1; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* 119562306a36Sopenharmony_ci * According to the DW DMA databook the true scatter- 119662306a36Sopenharmony_ci * gether LLPs aren't available if either multi-block 119762306a36Sopenharmony_ci * config is disabled (CHx_MULTI_BLK_EN == 0) or the 119862306a36Sopenharmony_ci * LLP register is hard-coded to zeros 119962306a36Sopenharmony_ci * (CHx_HC_LLP == 1). 120062306a36Sopenharmony_ci */ 120162306a36Sopenharmony_ci dwc->nollp = 120262306a36Sopenharmony_ci (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0 || 120362306a36Sopenharmony_ci (dwc_params >> DWC_PARAMS_HC_LLP & 0x1) == 1; 120462306a36Sopenharmony_ci dwc->max_burst = 120562306a36Sopenharmony_ci (0x4 << (dwc_params >> DWC_PARAMS_MSIZE & 0x7)); 120662306a36Sopenharmony_ci } else { 120762306a36Sopenharmony_ci dwc->block_size = pdata->block_size; 120862306a36Sopenharmony_ci dwc->nollp = !pdata->multi_block[i]; 120962306a36Sopenharmony_ci dwc->max_burst = pdata->max_burst[i] ?: DW_DMA_MAX_BURST; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* Clear all interrupts on all channels. */ 121462306a36Sopenharmony_ci dma_writel(dw, CLEAR.XFER, dw->all_chan_mask); 121562306a36Sopenharmony_ci dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask); 121662306a36Sopenharmony_ci dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask); 121762306a36Sopenharmony_ci dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask); 121862306a36Sopenharmony_ci dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* Set capabilities */ 122162306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, dw->dma.cap_mask); 122262306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask); 122362306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci dw->dma.dev = chip->dev; 122662306a36Sopenharmony_ci dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources; 122762306a36Sopenharmony_ci dw->dma.device_free_chan_resources = dwc_free_chan_resources; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy; 123062306a36Sopenharmony_ci dw->dma.device_prep_slave_sg = dwc_prep_slave_sg; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci dw->dma.device_caps = dwc_caps; 123362306a36Sopenharmony_ci dw->dma.device_config = dwc_config; 123462306a36Sopenharmony_ci dw->dma.device_pause = dwc_pause; 123562306a36Sopenharmony_ci dw->dma.device_resume = dwc_resume; 123662306a36Sopenharmony_ci dw->dma.device_terminate_all = dwc_terminate_all; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci dw->dma.device_tx_status = dwc_tx_status; 123962306a36Sopenharmony_ci dw->dma.device_issue_pending = dwc_issue_pending; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci /* DMA capabilities */ 124262306a36Sopenharmony_ci dw->dma.min_burst = DW_DMA_MIN_BURST; 124362306a36Sopenharmony_ci dw->dma.max_burst = DW_DMA_MAX_BURST; 124462306a36Sopenharmony_ci dw->dma.src_addr_widths = DW_DMA_BUSWIDTHS; 124562306a36Sopenharmony_ci dw->dma.dst_addr_widths = DW_DMA_BUSWIDTHS; 124662306a36Sopenharmony_ci dw->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | 124762306a36Sopenharmony_ci BIT(DMA_MEM_TO_MEM); 124862306a36Sopenharmony_ci dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci /* 125162306a36Sopenharmony_ci * For now there is no hardware with non uniform maximum block size 125262306a36Sopenharmony_ci * across all of the device channels, so we set the maximum segment 125362306a36Sopenharmony_ci * size as the block size found for the very first channel. 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci dma_set_max_seg_size(dw->dma.dev, dw->chan[0].block_size); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci err = dma_async_device_register(&dw->dma); 125862306a36Sopenharmony_ci if (err) 125962306a36Sopenharmony_ci goto err_dma_register; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n", 126262306a36Sopenharmony_ci pdata->nr_channels); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci pm_runtime_put_sync_suspend(chip->dev); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return 0; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cierr_dma_register: 126962306a36Sopenharmony_ci free_irq(chip->irq, dw); 127062306a36Sopenharmony_cierr_pdata: 127162306a36Sopenharmony_ci pm_runtime_put_sync_suspend(chip->dev); 127262306a36Sopenharmony_ci return err; 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ciint do_dma_remove(struct dw_dma_chip *chip) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci struct dw_dma *dw = chip->dw; 127862306a36Sopenharmony_ci struct dw_dma_chan *dwc, *_dwc; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci pm_runtime_get_sync(chip->dev); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci do_dw_dma_off(dw); 128362306a36Sopenharmony_ci dma_async_device_unregister(&dw->dma); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci free_irq(chip->irq, dw); 128662306a36Sopenharmony_ci tasklet_kill(&dw->tasklet); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels, 128962306a36Sopenharmony_ci chan.device_node) { 129062306a36Sopenharmony_ci list_del(&dwc->chan.device_node); 129162306a36Sopenharmony_ci channel_clear_bit(dw, CH_EN, dwc->mask); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci pm_runtime_put_sync_suspend(chip->dev); 129562306a36Sopenharmony_ci return 0; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ciint do_dw_dma_disable(struct dw_dma_chip *chip) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci struct dw_dma *dw = chip->dw; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci dw->disable(dw); 130362306a36Sopenharmony_ci return 0; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(do_dw_dma_disable); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ciint do_dw_dma_enable(struct dw_dma_chip *chip) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci struct dw_dma *dw = chip->dw; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci dw->enable(dw); 131262306a36Sopenharmony_ci return 0; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(do_dw_dma_enable); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 131762306a36Sopenharmony_ciMODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver"); 131862306a36Sopenharmony_ciMODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); 131962306a36Sopenharmony_ciMODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>"); 1320