18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Core driver for the Synopsys DesignWare DMA Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2007-2008 Atmel Corporation
68c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 ST Microelectronics
78c2ecf20Sopenharmony_ci * Copyright (C) 2013 Intel Corporation
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/bitops.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
148c2ecf20Sopenharmony_ci#include <linux/dmapool.h>
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci#include <linux/mm.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "../dmaengine.h"
258c2ecf20Sopenharmony_ci#include "internal.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * This supports the Synopsys "DesignWare AHB Central DMA Controller",
298c2ecf20Sopenharmony_ci * (DW_ahb_dmac) which is used with various AMBA 2.0 systems (not all
308c2ecf20Sopenharmony_ci * of which use ARM any more).  See the "Databook" from Synopsys for
318c2ecf20Sopenharmony_ci * information beyond what licensees probably provide.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * The driver has been tested with the Atmel AT32AP7000, which does not
348c2ecf20Sopenharmony_ci * support descriptor writeback.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* The set of bus widths supported by the DMA controller */
388c2ecf20Sopenharmony_ci#define DW_DMA_BUSWIDTHS			  \
398c2ecf20Sopenharmony_ci	BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED)	| \
408c2ecf20Sopenharmony_ci	BIT(DMA_SLAVE_BUSWIDTH_1_BYTE)		| \
418c2ecf20Sopenharmony_ci	BIT(DMA_SLAVE_BUSWIDTH_2_BYTES)		| \
428c2ecf20Sopenharmony_ci	BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic struct device *chan2dev(struct dma_chan *chan)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	return &chan->dev->device;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	return to_dw_desc(dwc->active_list.next);
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct dw_desc		*desc = txd_to_dw_desc(tx);
598c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(tx->chan);
608c2ecf20Sopenharmony_ci	dma_cookie_t		cookie;
618c2ecf20Sopenharmony_ci	unsigned long		flags;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
648c2ecf20Sopenharmony_ci	cookie = dma_cookie_assign(tx);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * REVISIT: We should attempt to chain as many descriptors as
688c2ecf20Sopenharmony_ci	 * possible, perhaps even appending to those already submitted
698c2ecf20Sopenharmony_ci	 * for DMA. But this is hard to do in a race-free manner.
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	list_add_tail(&desc->desc_node, &dwc->queue);
738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
748c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(tx->chan), "%s: queued %u\n",
758c2ecf20Sopenharmony_ci		 __func__, desc->txd.cookie);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return cookie;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
838c2ecf20Sopenharmony_ci	struct dw_desc *desc;
848c2ecf20Sopenharmony_ci	dma_addr_t phys;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	desc = dma_pool_zalloc(dw->desc_pool, GFP_ATOMIC, &phys);
878c2ecf20Sopenharmony_ci	if (!desc)
888c2ecf20Sopenharmony_ci		return NULL;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	dwc->descs_allocated++;
918c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&desc->tx_list);
928c2ecf20Sopenharmony_ci	dma_async_tx_descriptor_init(&desc->txd, &dwc->chan);
938c2ecf20Sopenharmony_ci	desc->txd.tx_submit = dwc_tx_submit;
948c2ecf20Sopenharmony_ci	desc->txd.flags = DMA_CTRL_ACK;
958c2ecf20Sopenharmony_ci	desc->txd.phys = phys;
968c2ecf20Sopenharmony_ci	return desc;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
1028c2ecf20Sopenharmony_ci	struct dw_desc *child, *_next;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (unlikely(!desc))
1058c2ecf20Sopenharmony_ci		return;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	list_for_each_entry_safe(child, _next, &desc->tx_list, desc_node) {
1088c2ecf20Sopenharmony_ci		list_del(&child->desc_node);
1098c2ecf20Sopenharmony_ci		dma_pool_free(dw->desc_pool, child, child->txd.phys);
1108c2ecf20Sopenharmony_ci		dwc->descs_allocated--;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	dma_pool_free(dw->desc_pool, desc, desc->txd.phys);
1148c2ecf20Sopenharmony_ci	dwc->descs_allocated--;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void dwc_initialize(struct dw_dma_chan *dwc)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	dw->initialize_chan(dwc);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Enable interrupts */
1248c2ecf20Sopenharmony_ci	channel_set_bit(dw, MASK.XFER, dwc->mask);
1258c2ecf20Sopenharmony_ci	channel_set_bit(dw, MASK.ERROR, dwc->mask);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	dev_err(chan2dev(&dwc->chan),
1338c2ecf20Sopenharmony_ci		"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
1348c2ecf20Sopenharmony_ci		channel_readl(dwc, SAR),
1358c2ecf20Sopenharmony_ci		channel_readl(dwc, DAR),
1368c2ecf20Sopenharmony_ci		channel_readl(dwc, LLP),
1378c2ecf20Sopenharmony_ci		channel_readl(dwc, CTL_HI),
1388c2ecf20Sopenharmony_ci		channel_readl(dwc, CTL_LO));
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	channel_clear_bit(dw, CH_EN, dwc->mask);
1448c2ecf20Sopenharmony_ci	while (dma_readl(dw, CH_EN) & dwc->mask)
1458c2ecf20Sopenharmony_ci		cpu_relax();
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Perform single block transfer */
1518c2ecf20Sopenharmony_cistatic inline void dwc_do_single_block(struct dw_dma_chan *dwc,
1528c2ecf20Sopenharmony_ci				       struct dw_desc *desc)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
1558c2ecf20Sopenharmony_ci	u32		ctllo;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/*
1588c2ecf20Sopenharmony_ci	 * Software emulation of LLP mode relies on interrupts to continue
1598c2ecf20Sopenharmony_ci	 * multi block transfer.
1608c2ecf20Sopenharmony_ci	 */
1618c2ecf20Sopenharmony_ci	ctllo = lli_read(desc, ctllo) | DWC_CTLL_INT_EN;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	channel_writel(dwc, SAR, lli_read(desc, sar));
1648c2ecf20Sopenharmony_ci	channel_writel(dwc, DAR, lli_read(desc, dar));
1658c2ecf20Sopenharmony_ci	channel_writel(dwc, CTL_LO, ctllo);
1668c2ecf20Sopenharmony_ci	channel_writel(dwc, CTL_HI, lli_read(desc, ctlhi));
1678c2ecf20Sopenharmony_ci	channel_set_bit(dw, CH_EN, dwc->mask);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* Move pointer to next descriptor */
1708c2ecf20Sopenharmony_ci	dwc->tx_node_active = dwc->tx_node_active->next;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/* Called with dwc->lock held and bh disabled */
1748c2ecf20Sopenharmony_cistatic void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
1778c2ecf20Sopenharmony_ci	u8		lms = DWC_LLP_LMS(dwc->dws.m_master);
1788c2ecf20Sopenharmony_ci	unsigned long	was_soft_llp;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* ASSERT:  channel is idle */
1818c2ecf20Sopenharmony_ci	if (dma_readl(dw, CH_EN) & dwc->mask) {
1828c2ecf20Sopenharmony_ci		dev_err(chan2dev(&dwc->chan),
1838c2ecf20Sopenharmony_ci			"%s: BUG: Attempted to start non-idle channel\n",
1848c2ecf20Sopenharmony_ci			__func__);
1858c2ecf20Sopenharmony_ci		dwc_dump_chan_regs(dwc);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		/* The tasklet will hopefully advance the queue... */
1888c2ecf20Sopenharmony_ci		return;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (dwc->nollp) {
1928c2ecf20Sopenharmony_ci		was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP,
1938c2ecf20Sopenharmony_ci						&dwc->flags);
1948c2ecf20Sopenharmony_ci		if (was_soft_llp) {
1958c2ecf20Sopenharmony_ci			dev_err(chan2dev(&dwc->chan),
1968c2ecf20Sopenharmony_ci				"BUG: Attempted to start new LLP transfer inside ongoing one\n");
1978c2ecf20Sopenharmony_ci			return;
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		dwc_initialize(dwc);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		first->residue = first->total_len;
2038c2ecf20Sopenharmony_ci		dwc->tx_node_active = &first->tx_list;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		/* Submit first block */
2068c2ecf20Sopenharmony_ci		dwc_do_single_block(dwc, first);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		return;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	dwc_initialize(dwc);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	channel_writel(dwc, LLP, first->txd.phys | lms);
2148c2ecf20Sopenharmony_ci	channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
2158c2ecf20Sopenharmony_ci	channel_writel(dwc, CTL_HI, 0);
2168c2ecf20Sopenharmony_ci	channel_set_bit(dw, CH_EN, dwc->mask);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void dwc_dostart_first_queued(struct dw_dma_chan *dwc)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct dw_desc *desc;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (list_empty(&dwc->queue))
2248c2ecf20Sopenharmony_ci		return;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	list_move(dwc->queue.next, &dwc->active_list);
2278c2ecf20Sopenharmony_ci	desc = dwc_first_active(dwc);
2288c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(&dwc->chan), "%s: started %u\n", __func__, desc->txd.cookie);
2298c2ecf20Sopenharmony_ci	dwc_dostart(dwc, desc);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic void
2358c2ecf20Sopenharmony_cidwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
2368c2ecf20Sopenharmony_ci		bool callback_required)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor	*txd = &desc->txd;
2398c2ecf20Sopenharmony_ci	struct dw_desc			*child;
2408c2ecf20Sopenharmony_ci	unsigned long			flags;
2418c2ecf20Sopenharmony_ci	struct dmaengine_desc_callback	cb;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
2468c2ecf20Sopenharmony_ci	dma_cookie_complete(txd);
2478c2ecf20Sopenharmony_ci	if (callback_required)
2488c2ecf20Sopenharmony_ci		dmaengine_desc_get_callback(txd, &cb);
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci		memset(&cb, 0, sizeof(cb));
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* async_tx_ack */
2538c2ecf20Sopenharmony_ci	list_for_each_entry(child, &desc->tx_list, desc_node)
2548c2ecf20Sopenharmony_ci		async_tx_ack(&child->txd);
2558c2ecf20Sopenharmony_ci	async_tx_ack(&desc->txd);
2568c2ecf20Sopenharmony_ci	dwc_desc_put(dwc, desc);
2578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	dmaengine_desc_callback_invoke(&cb, NULL);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct dw_desc *desc, *_desc;
2658c2ecf20Sopenharmony_ci	LIST_HEAD(list);
2668c2ecf20Sopenharmony_ci	unsigned long flags;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
2698c2ecf20Sopenharmony_ci	if (dma_readl(dw, CH_EN) & dwc->mask) {
2708c2ecf20Sopenharmony_ci		dev_err(chan2dev(&dwc->chan),
2718c2ecf20Sopenharmony_ci			"BUG: XFER bit set, but channel not idle!\n");
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		/* Try to continue after resetting the channel... */
2748c2ecf20Sopenharmony_ci		dwc_chan_disable(dw, dwc);
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/*
2788c2ecf20Sopenharmony_ci	 * Submit queued descriptors ASAP, i.e. before we go through
2798c2ecf20Sopenharmony_ci	 * the completed ones.
2808c2ecf20Sopenharmony_ci	 */
2818c2ecf20Sopenharmony_ci	list_splice_init(&dwc->active_list, &list);
2828c2ecf20Sopenharmony_ci	dwc_dostart_first_queued(dwc);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	list_for_each_entry_safe(desc, _desc, &list, desc_node)
2878c2ecf20Sopenharmony_ci		dwc_descriptor_complete(dwc, desc, true);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* Returns how many bytes were already received from source */
2918c2ecf20Sopenharmony_cistatic inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
2948c2ecf20Sopenharmony_ci	u32 ctlhi = channel_readl(dwc, CTL_HI);
2958c2ecf20Sopenharmony_ci	u32 ctllo = channel_readl(dwc, CTL_LO);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	dma_addr_t llp;
3038c2ecf20Sopenharmony_ci	struct dw_desc *desc, *_desc;
3048c2ecf20Sopenharmony_ci	struct dw_desc *child;
3058c2ecf20Sopenharmony_ci	u32 status_xfer;
3068c2ecf20Sopenharmony_ci	unsigned long flags;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
3098c2ecf20Sopenharmony_ci	llp = channel_readl(dwc, LLP);
3108c2ecf20Sopenharmony_ci	status_xfer = dma_readl(dw, RAW.XFER);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (status_xfer & dwc->mask) {
3138c2ecf20Sopenharmony_ci		/* Everything we've submitted is done */
3148c2ecf20Sopenharmony_ci		dma_writel(dw, CLEAR.XFER, dwc->mask);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
3178c2ecf20Sopenharmony_ci			struct list_head *head, *active = dwc->tx_node_active;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			/*
3208c2ecf20Sopenharmony_ci			 * We are inside first active descriptor.
3218c2ecf20Sopenharmony_ci			 * Otherwise something is really wrong.
3228c2ecf20Sopenharmony_ci			 */
3238c2ecf20Sopenharmony_ci			desc = dwc_first_active(dwc);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci			head = &desc->tx_list;
3268c2ecf20Sopenharmony_ci			if (active != head) {
3278c2ecf20Sopenharmony_ci				/* Update residue to reflect last sent descriptor */
3288c2ecf20Sopenharmony_ci				if (active == head->next)
3298c2ecf20Sopenharmony_ci					desc->residue -= desc->len;
3308c2ecf20Sopenharmony_ci				else
3318c2ecf20Sopenharmony_ci					desc->residue -= to_dw_desc(active->prev)->len;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci				child = to_dw_desc(active);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci				/* Submit next block */
3368c2ecf20Sopenharmony_ci				dwc_do_single_block(dwc, child);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&dwc->lock, flags);
3398c2ecf20Sopenharmony_ci				return;
3408c2ecf20Sopenharmony_ci			}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci			/* We are done here */
3438c2ecf20Sopenharmony_ci			clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dwc->lock, flags);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		dwc_complete_all(dw, dwc);
3498c2ecf20Sopenharmony_ci		return;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (list_empty(&dwc->active_list)) {
3538c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dwc->lock, flags);
3548c2ecf20Sopenharmony_ci		return;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
3588c2ecf20Sopenharmony_ci		dev_vdbg(chan2dev(&dwc->chan), "%s: soft LLP mode\n", __func__);
3598c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dwc->lock, flags);
3608c2ecf20Sopenharmony_ci		return;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
3668c2ecf20Sopenharmony_ci		/* Initial residue value */
3678c2ecf20Sopenharmony_ci		desc->residue = desc->total_len;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		/* Check first descriptors addr */
3708c2ecf20Sopenharmony_ci		if (desc->txd.phys == DWC_LLP_LOC(llp)) {
3718c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&dwc->lock, flags);
3728c2ecf20Sopenharmony_ci			return;
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci		/* Check first descriptors llp */
3768c2ecf20Sopenharmony_ci		if (lli_read(desc, llp) == llp) {
3778c2ecf20Sopenharmony_ci			/* This one is currently in progress */
3788c2ecf20Sopenharmony_ci			desc->residue -= dwc_get_sent(dwc);
3798c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&dwc->lock, flags);
3808c2ecf20Sopenharmony_ci			return;
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		desc->residue -= desc->len;
3848c2ecf20Sopenharmony_ci		list_for_each_entry(child, &desc->tx_list, desc_node) {
3858c2ecf20Sopenharmony_ci			if (lli_read(child, llp) == llp) {
3868c2ecf20Sopenharmony_ci				/* Currently in progress */
3878c2ecf20Sopenharmony_ci				desc->residue -= dwc_get_sent(dwc);
3888c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&dwc->lock, flags);
3898c2ecf20Sopenharmony_ci				return;
3908c2ecf20Sopenharmony_ci			}
3918c2ecf20Sopenharmony_ci			desc->residue -= child->len;
3928c2ecf20Sopenharmony_ci		}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		/*
3958c2ecf20Sopenharmony_ci		 * No descriptors so far seem to be in progress, i.e.
3968c2ecf20Sopenharmony_ci		 * this one must be done.
3978c2ecf20Sopenharmony_ci		 */
3988c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dwc->lock, flags);
3998c2ecf20Sopenharmony_ci		dwc_descriptor_complete(dwc, desc, true);
4008c2ecf20Sopenharmony_ci		spin_lock_irqsave(&dwc->lock, flags);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	dev_err(chan2dev(&dwc->chan),
4048c2ecf20Sopenharmony_ci		"BUG: All descriptors done, but channel not idle!\n");
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* Try to continue after resetting the channel... */
4078c2ecf20Sopenharmony_ci	dwc_chan_disable(dw, dwc);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	dwc_dostart_first_queued(dwc);
4108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic inline void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_desc *desc)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	dev_crit(chan2dev(&dwc->chan), "  desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
4168c2ecf20Sopenharmony_ci		 lli_read(desc, sar),
4178c2ecf20Sopenharmony_ci		 lli_read(desc, dar),
4188c2ecf20Sopenharmony_ci		 lli_read(desc, llp),
4198c2ecf20Sopenharmony_ci		 lli_read(desc, ctlhi),
4208c2ecf20Sopenharmony_ci		 lli_read(desc, ctllo));
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct dw_desc *bad_desc;
4268c2ecf20Sopenharmony_ci	struct dw_desc *child;
4278c2ecf20Sopenharmony_ci	unsigned long flags;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	dwc_scan_descriptors(dw, dwc);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/*
4348c2ecf20Sopenharmony_ci	 * The descriptor currently at the head of the active list is
4358c2ecf20Sopenharmony_ci	 * borked. Since we don't have any way to report errors, we'll
4368c2ecf20Sopenharmony_ci	 * just have to scream loudly and try to carry on.
4378c2ecf20Sopenharmony_ci	 */
4388c2ecf20Sopenharmony_ci	bad_desc = dwc_first_active(dwc);
4398c2ecf20Sopenharmony_ci	list_del_init(&bad_desc->desc_node);
4408c2ecf20Sopenharmony_ci	list_move(dwc->queue.next, dwc->active_list.prev);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/* Clear the error flag and try to restart the controller */
4438c2ecf20Sopenharmony_ci	dma_writel(dw, CLEAR.ERROR, dwc->mask);
4448c2ecf20Sopenharmony_ci	if (!list_empty(&dwc->active_list))
4458c2ecf20Sopenharmony_ci		dwc_dostart(dwc, dwc_first_active(dwc));
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/*
4488c2ecf20Sopenharmony_ci	 * WARN may seem harsh, but since this only happens
4498c2ecf20Sopenharmony_ci	 * when someone submits a bad physical address in a
4508c2ecf20Sopenharmony_ci	 * descriptor, we should consider ourselves lucky that the
4518c2ecf20Sopenharmony_ci	 * controller flagged an error instead of scribbling over
4528c2ecf20Sopenharmony_ci	 * random memory locations.
4538c2ecf20Sopenharmony_ci	 */
4548c2ecf20Sopenharmony_ci	dev_WARN(chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"
4558c2ecf20Sopenharmony_ci				       "  cookie: %d\n", bad_desc->txd.cookie);
4568c2ecf20Sopenharmony_ci	dwc_dump_lli(dwc, bad_desc);
4578c2ecf20Sopenharmony_ci	list_for_each_entry(child, &bad_desc->tx_list, desc_node)
4588c2ecf20Sopenharmony_ci		dwc_dump_lli(dwc, child);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* Pretend the descriptor completed successfully */
4638c2ecf20Sopenharmony_ci	dwc_descriptor_complete(dwc, bad_desc, true);
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic void dw_dma_tasklet(struct tasklet_struct *t)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	struct dw_dma *dw = from_tasklet(dw, t, tasklet);
4698c2ecf20Sopenharmony_ci	struct dw_dma_chan *dwc;
4708c2ecf20Sopenharmony_ci	u32 status_xfer;
4718c2ecf20Sopenharmony_ci	u32 status_err;
4728c2ecf20Sopenharmony_ci	unsigned int i;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	status_xfer = dma_readl(dw, RAW.XFER);
4758c2ecf20Sopenharmony_ci	status_err = dma_readl(dw, RAW.ERROR);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	dev_vdbg(dw->dma.dev, "%s: status_err=%x\n", __func__, status_err);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	for (i = 0; i < dw->dma.chancnt; i++) {
4808c2ecf20Sopenharmony_ci		dwc = &dw->chan[i];
4818c2ecf20Sopenharmony_ci		if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
4828c2ecf20Sopenharmony_ci			dev_vdbg(dw->dma.dev, "Cyclic xfer is not implemented\n");
4838c2ecf20Sopenharmony_ci		else if (status_err & (1 << i))
4848c2ecf20Sopenharmony_ci			dwc_handle_error(dw, dwc);
4858c2ecf20Sopenharmony_ci		else if (status_xfer & (1 << i))
4868c2ecf20Sopenharmony_ci			dwc_scan_descriptors(dw, dwc);
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* Re-enable interrupts */
4908c2ecf20Sopenharmony_ci	channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
4918c2ecf20Sopenharmony_ci	channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct dw_dma *dw = dev_id;
4978c2ecf20Sopenharmony_ci	u32 status;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/* Check if we have any interrupt from the DMAC which is not in use */
5008c2ecf20Sopenharmony_ci	if (!dw->in_use)
5018c2ecf20Sopenharmony_ci		return IRQ_NONE;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	status = dma_readl(dw, STATUS_INT);
5048c2ecf20Sopenharmony_ci	dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	/* Check if we have any interrupt from the DMAC */
5078c2ecf20Sopenharmony_ci	if (!status)
5088c2ecf20Sopenharmony_ci		return IRQ_NONE;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/*
5118c2ecf20Sopenharmony_ci	 * Just disable the interrupts. We'll turn them back on in the
5128c2ecf20Sopenharmony_ci	 * softirq handler.
5138c2ecf20Sopenharmony_ci	 */
5148c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
5158c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
5168c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	status = dma_readl(dw, STATUS_INT);
5198c2ecf20Sopenharmony_ci	if (status) {
5208c2ecf20Sopenharmony_ci		dev_err(dw->dma.dev,
5218c2ecf20Sopenharmony_ci			"BUG: Unexpected interrupts pending: 0x%x\n",
5228c2ecf20Sopenharmony_ci			status);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		/* Try to recover */
5258c2ecf20Sopenharmony_ci		channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1);
5268c2ecf20Sopenharmony_ci		channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1);
5278c2ecf20Sopenharmony_ci		channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1);
5288c2ecf20Sopenharmony_ci		channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1);
5298c2ecf20Sopenharmony_ci		channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1);
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	tasklet_schedule(&dw->tasklet);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *
5408c2ecf20Sopenharmony_cidwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
5418c2ecf20Sopenharmony_ci		size_t len, unsigned long flags)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
5448c2ecf20Sopenharmony_ci	struct dw_dma		*dw = to_dw_dma(chan->device);
5458c2ecf20Sopenharmony_ci	struct dw_desc		*desc;
5468c2ecf20Sopenharmony_ci	struct dw_desc		*first;
5478c2ecf20Sopenharmony_ci	struct dw_desc		*prev;
5488c2ecf20Sopenharmony_ci	size_t			xfer_count;
5498c2ecf20Sopenharmony_ci	size_t			offset;
5508c2ecf20Sopenharmony_ci	u8			m_master = dwc->dws.m_master;
5518c2ecf20Sopenharmony_ci	unsigned int		src_width;
5528c2ecf20Sopenharmony_ci	unsigned int		dst_width;
5538c2ecf20Sopenharmony_ci	unsigned int		data_width = dw->pdata->data_width[m_master];
5548c2ecf20Sopenharmony_ci	u32			ctllo, ctlhi;
5558c2ecf20Sopenharmony_ci	u8			lms = DWC_LLP_LMS(m_master);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(chan),
5588c2ecf20Sopenharmony_ci			"%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
5598c2ecf20Sopenharmony_ci			&dest, &src, len, flags);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (unlikely(!len)) {
5628c2ecf20Sopenharmony_ci		dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
5638c2ecf20Sopenharmony_ci		return NULL;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	dwc->direction = DMA_MEM_TO_MEM;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	src_width = dst_width = __ffs(data_width | src | dest | len);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	ctllo = dw->prepare_ctllo(dwc)
5718c2ecf20Sopenharmony_ci			| DWC_CTLL_DST_WIDTH(dst_width)
5728c2ecf20Sopenharmony_ci			| DWC_CTLL_SRC_WIDTH(src_width)
5738c2ecf20Sopenharmony_ci			| DWC_CTLL_DST_INC
5748c2ecf20Sopenharmony_ci			| DWC_CTLL_SRC_INC
5758c2ecf20Sopenharmony_ci			| DWC_CTLL_FC_M2M;
5768c2ecf20Sopenharmony_ci	prev = first = NULL;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	for (offset = 0; offset < len; offset += xfer_count) {
5798c2ecf20Sopenharmony_ci		desc = dwc_desc_get(dwc);
5808c2ecf20Sopenharmony_ci		if (!desc)
5818c2ecf20Sopenharmony_ci			goto err_desc_get;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		ctlhi = dw->bytes2block(dwc, len - offset, src_width, &xfer_count);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		lli_write(desc, sar, src + offset);
5868c2ecf20Sopenharmony_ci		lli_write(desc, dar, dest + offset);
5878c2ecf20Sopenharmony_ci		lli_write(desc, ctllo, ctllo);
5888c2ecf20Sopenharmony_ci		lli_write(desc, ctlhi, ctlhi);
5898c2ecf20Sopenharmony_ci		desc->len = xfer_count;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		if (!first) {
5928c2ecf20Sopenharmony_ci			first = desc;
5938c2ecf20Sopenharmony_ci		} else {
5948c2ecf20Sopenharmony_ci			lli_write(prev, llp, desc->txd.phys | lms);
5958c2ecf20Sopenharmony_ci			list_add_tail(&desc->desc_node, &first->tx_list);
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci		prev = desc;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (flags & DMA_PREP_INTERRUPT)
6018c2ecf20Sopenharmony_ci		/* Trigger interrupt after last block */
6028c2ecf20Sopenharmony_ci		lli_set(prev, ctllo, DWC_CTLL_INT_EN);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	prev->lli.llp = 0;
6058c2ecf20Sopenharmony_ci	lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
6068c2ecf20Sopenharmony_ci	first->txd.flags = flags;
6078c2ecf20Sopenharmony_ci	first->total_len = len;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	return &first->txd;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cierr_desc_get:
6128c2ecf20Sopenharmony_ci	dwc_desc_put(dwc, first);
6138c2ecf20Sopenharmony_ci	return NULL;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *
6178c2ecf20Sopenharmony_cidwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
6188c2ecf20Sopenharmony_ci		unsigned int sg_len, enum dma_transfer_direction direction,
6198c2ecf20Sopenharmony_ci		unsigned long flags, void *context)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
6228c2ecf20Sopenharmony_ci	struct dw_dma		*dw = to_dw_dma(chan->device);
6238c2ecf20Sopenharmony_ci	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
6248c2ecf20Sopenharmony_ci	struct dw_desc		*prev;
6258c2ecf20Sopenharmony_ci	struct dw_desc		*first;
6268c2ecf20Sopenharmony_ci	u32			ctllo, ctlhi;
6278c2ecf20Sopenharmony_ci	u8			m_master = dwc->dws.m_master;
6288c2ecf20Sopenharmony_ci	u8			lms = DWC_LLP_LMS(m_master);
6298c2ecf20Sopenharmony_ci	dma_addr_t		reg;
6308c2ecf20Sopenharmony_ci	unsigned int		reg_width;
6318c2ecf20Sopenharmony_ci	unsigned int		mem_width;
6328c2ecf20Sopenharmony_ci	unsigned int		data_width = dw->pdata->data_width[m_master];
6338c2ecf20Sopenharmony_ci	unsigned int		i;
6348c2ecf20Sopenharmony_ci	struct scatterlist	*sg;
6358c2ecf20Sopenharmony_ci	size_t			total_len = 0;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(chan), "%s\n", __func__);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (unlikely(!is_slave_direction(direction) || !sg_len))
6408c2ecf20Sopenharmony_ci		return NULL;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	dwc->direction = direction;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	prev = first = NULL;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	switch (direction) {
6478c2ecf20Sopenharmony_ci	case DMA_MEM_TO_DEV:
6488c2ecf20Sopenharmony_ci		reg_width = __ffs(sconfig->dst_addr_width);
6498c2ecf20Sopenharmony_ci		reg = sconfig->dst_addr;
6508c2ecf20Sopenharmony_ci		ctllo = dw->prepare_ctllo(dwc)
6518c2ecf20Sopenharmony_ci				| DWC_CTLL_DST_WIDTH(reg_width)
6528c2ecf20Sopenharmony_ci				| DWC_CTLL_DST_FIX
6538c2ecf20Sopenharmony_ci				| DWC_CTLL_SRC_INC;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
6568c2ecf20Sopenharmony_ci			DWC_CTLL_FC(DW_DMA_FC_D_M2P);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci		for_each_sg(sgl, sg, sg_len, i) {
6598c2ecf20Sopenharmony_ci			struct dw_desc	*desc;
6608c2ecf20Sopenharmony_ci			u32		len, mem;
6618c2ecf20Sopenharmony_ci			size_t		dlen;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci			mem = sg_dma_address(sg);
6648c2ecf20Sopenharmony_ci			len = sg_dma_len(sg);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci			mem_width = __ffs(data_width | mem | len);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cislave_sg_todev_fill_desc:
6698c2ecf20Sopenharmony_ci			desc = dwc_desc_get(dwc);
6708c2ecf20Sopenharmony_ci			if (!desc)
6718c2ecf20Sopenharmony_ci				goto err_desc_get;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci			ctlhi = dw->bytes2block(dwc, len, mem_width, &dlen);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci			lli_write(desc, sar, mem);
6768c2ecf20Sopenharmony_ci			lli_write(desc, dar, reg);
6778c2ecf20Sopenharmony_ci			lli_write(desc, ctlhi, ctlhi);
6788c2ecf20Sopenharmony_ci			lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
6798c2ecf20Sopenharmony_ci			desc->len = dlen;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci			if (!first) {
6828c2ecf20Sopenharmony_ci				first = desc;
6838c2ecf20Sopenharmony_ci			} else {
6848c2ecf20Sopenharmony_ci				lli_write(prev, llp, desc->txd.phys | lms);
6858c2ecf20Sopenharmony_ci				list_add_tail(&desc->desc_node, &first->tx_list);
6868c2ecf20Sopenharmony_ci			}
6878c2ecf20Sopenharmony_ci			prev = desc;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci			mem += dlen;
6908c2ecf20Sopenharmony_ci			len -= dlen;
6918c2ecf20Sopenharmony_ci			total_len += dlen;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci			if (len)
6948c2ecf20Sopenharmony_ci				goto slave_sg_todev_fill_desc;
6958c2ecf20Sopenharmony_ci		}
6968c2ecf20Sopenharmony_ci		break;
6978c2ecf20Sopenharmony_ci	case DMA_DEV_TO_MEM:
6988c2ecf20Sopenharmony_ci		reg_width = __ffs(sconfig->src_addr_width);
6998c2ecf20Sopenharmony_ci		reg = sconfig->src_addr;
7008c2ecf20Sopenharmony_ci		ctllo = dw->prepare_ctllo(dwc)
7018c2ecf20Sopenharmony_ci				| DWC_CTLL_SRC_WIDTH(reg_width)
7028c2ecf20Sopenharmony_ci				| DWC_CTLL_DST_INC
7038c2ecf20Sopenharmony_ci				| DWC_CTLL_SRC_FIX;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
7068c2ecf20Sopenharmony_ci			DWC_CTLL_FC(DW_DMA_FC_D_P2M);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci		for_each_sg(sgl, sg, sg_len, i) {
7098c2ecf20Sopenharmony_ci			struct dw_desc	*desc;
7108c2ecf20Sopenharmony_ci			u32		len, mem;
7118c2ecf20Sopenharmony_ci			size_t		dlen;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci			mem = sg_dma_address(sg);
7148c2ecf20Sopenharmony_ci			len = sg_dma_len(sg);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cislave_sg_fromdev_fill_desc:
7178c2ecf20Sopenharmony_ci			desc = dwc_desc_get(dwc);
7188c2ecf20Sopenharmony_ci			if (!desc)
7198c2ecf20Sopenharmony_ci				goto err_desc_get;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci			ctlhi = dw->bytes2block(dwc, len, reg_width, &dlen);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci			lli_write(desc, sar, reg);
7248c2ecf20Sopenharmony_ci			lli_write(desc, dar, mem);
7258c2ecf20Sopenharmony_ci			lli_write(desc, ctlhi, ctlhi);
7268c2ecf20Sopenharmony_ci			mem_width = __ffs(data_width | mem);
7278c2ecf20Sopenharmony_ci			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
7288c2ecf20Sopenharmony_ci			desc->len = dlen;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci			if (!first) {
7318c2ecf20Sopenharmony_ci				first = desc;
7328c2ecf20Sopenharmony_ci			} else {
7338c2ecf20Sopenharmony_ci				lli_write(prev, llp, desc->txd.phys | lms);
7348c2ecf20Sopenharmony_ci				list_add_tail(&desc->desc_node, &first->tx_list);
7358c2ecf20Sopenharmony_ci			}
7368c2ecf20Sopenharmony_ci			prev = desc;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci			mem += dlen;
7398c2ecf20Sopenharmony_ci			len -= dlen;
7408c2ecf20Sopenharmony_ci			total_len += dlen;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci			if (len)
7438c2ecf20Sopenharmony_ci				goto slave_sg_fromdev_fill_desc;
7448c2ecf20Sopenharmony_ci		}
7458c2ecf20Sopenharmony_ci		break;
7468c2ecf20Sopenharmony_ci	default:
7478c2ecf20Sopenharmony_ci		return NULL;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	if (flags & DMA_PREP_INTERRUPT)
7518c2ecf20Sopenharmony_ci		/* Trigger interrupt after last block */
7528c2ecf20Sopenharmony_ci		lli_set(prev, ctllo, DWC_CTLL_INT_EN);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	prev->lli.llp = 0;
7558c2ecf20Sopenharmony_ci	lli_clear(prev, ctllo, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN);
7568c2ecf20Sopenharmony_ci	first->total_len = total_len;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return &first->txd;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cierr_desc_get:
7618c2ecf20Sopenharmony_ci	dev_err(chan2dev(chan),
7628c2ecf20Sopenharmony_ci		"not enough descriptors available. Direction %d\n", direction);
7638c2ecf20Sopenharmony_ci	dwc_desc_put(dwc, first);
7648c2ecf20Sopenharmony_ci	return NULL;
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_cibool dw_dma_filter(struct dma_chan *chan, void *param)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
7708c2ecf20Sopenharmony_ci	struct dw_dma_slave *dws = param;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	if (dws->dma_dev != chan->device->dev)
7738c2ecf20Sopenharmony_ci		return false;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/* permit channels in accordance with the channels mask */
7768c2ecf20Sopenharmony_ci	if (dws->channels && !(dws->channels & dwc->mask))
7778c2ecf20Sopenharmony_ci		return false;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/* We have to copy data since dws can be temporary storage */
7808c2ecf20Sopenharmony_ci	memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave));
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	return true;
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_dma_filter);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
7898c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(chan->device);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	dwc->dma_sconfig.src_maxburst =
7948c2ecf20Sopenharmony_ci		clamp(dwc->dma_sconfig.src_maxburst, 0U, dwc->max_burst);
7958c2ecf20Sopenharmony_ci	dwc->dma_sconfig.dst_maxburst =
7968c2ecf20Sopenharmony_ci		clamp(dwc->dma_sconfig.dst_maxburst, 0U, dwc->max_burst);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
7998c2ecf20Sopenharmony_ci	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	return 0;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
8078c2ecf20Sopenharmony_ci	unsigned int		count = 20;	/* timeout iterations */
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	dw->suspend_chan(dwc, drain);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
8128c2ecf20Sopenharmony_ci		udelay(2);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	set_bit(DW_DMA_IS_PAUSED, &dwc->flags);
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic int dwc_pause(struct dma_chan *chan)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
8208c2ecf20Sopenharmony_ci	unsigned long		flags;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
8238c2ecf20Sopenharmony_ci	dwc_chan_pause(dwc, false);
8248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	return 0;
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic inline void dwc_chan_resume(struct dw_dma_chan *dwc, bool drain)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	dw->resume_chan(dwc, drain);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	clear_bit(DW_DMA_IS_PAUSED, &dwc->flags);
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic int dwc_resume(struct dma_chan *chan)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
8418c2ecf20Sopenharmony_ci	unsigned long		flags;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags))
8468c2ecf20Sopenharmony_ci		dwc_chan_resume(dwc, false);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	return 0;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic int dwc_terminate_all(struct dma_chan *chan)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
8568c2ecf20Sopenharmony_ci	struct dw_dma		*dw = to_dw_dma(chan->device);
8578c2ecf20Sopenharmony_ci	struct dw_desc		*desc, *_desc;
8588c2ecf20Sopenharmony_ci	unsigned long		flags;
8598c2ecf20Sopenharmony_ci	LIST_HEAD(list);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	dwc_chan_pause(dwc, true);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	dwc_chan_disable(dw, dwc);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	dwc_chan_resume(dwc, true);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* active_list entries will end up before queued entries */
8728c2ecf20Sopenharmony_ci	list_splice_init(&dwc->queue, &list);
8738c2ecf20Sopenharmony_ci	list_splice_init(&dwc->active_list, &list);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* Flush all pending and queued descriptors */
8788c2ecf20Sopenharmony_ci	list_for_each_entry_safe(desc, _desc, &list, desc_node)
8798c2ecf20Sopenharmony_ci		dwc_descriptor_complete(dwc, desc, false);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return 0;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct dw_desc *desc;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	list_for_each_entry(desc, &dwc->active_list, desc_node)
8898c2ecf20Sopenharmony_ci		if (desc->txd.cookie == c)
8908c2ecf20Sopenharmony_ci			return desc;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	return NULL;
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_cistatic u32 dwc_get_residue(struct dw_dma_chan *dwc, dma_cookie_t cookie)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	struct dw_desc *desc;
8988c2ecf20Sopenharmony_ci	unsigned long flags;
8998c2ecf20Sopenharmony_ci	u32 residue;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	desc = dwc_find_desc(dwc, cookie);
9048c2ecf20Sopenharmony_ci	if (desc) {
9058c2ecf20Sopenharmony_ci		if (desc == dwc_first_active(dwc)) {
9068c2ecf20Sopenharmony_ci			residue = desc->residue;
9078c2ecf20Sopenharmony_ci			if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue)
9088c2ecf20Sopenharmony_ci				residue -= dwc_get_sent(dwc);
9098c2ecf20Sopenharmony_ci		} else {
9108c2ecf20Sopenharmony_ci			residue = desc->total_len;
9118c2ecf20Sopenharmony_ci		}
9128c2ecf20Sopenharmony_ci	} else {
9138c2ecf20Sopenharmony_ci		residue = 0;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
9178c2ecf20Sopenharmony_ci	return residue;
9188c2ecf20Sopenharmony_ci}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_cistatic enum dma_status
9218c2ecf20Sopenharmony_cidwc_tx_status(struct dma_chan *chan,
9228c2ecf20Sopenharmony_ci	      dma_cookie_t cookie,
9238c2ecf20Sopenharmony_ci	      struct dma_tx_state *txstate)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
9268c2ecf20Sopenharmony_ci	enum dma_status		ret;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	ret = dma_cookie_status(chan, cookie, txstate);
9298c2ecf20Sopenharmony_ci	if (ret == DMA_COMPLETE)
9308c2ecf20Sopenharmony_ci		return ret;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	ret = dma_cookie_status(chan, cookie, txstate);
9358c2ecf20Sopenharmony_ci	if (ret == DMA_COMPLETE)
9368c2ecf20Sopenharmony_ci		return ret;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	dma_set_residue(txstate, dwc_get_residue(dwc, cookie));
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags) && ret == DMA_IN_PROGRESS)
9418c2ecf20Sopenharmony_ci		return DMA_PAUSED;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return ret;
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic void dwc_issue_pending(struct dma_chan *chan)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
9498c2ecf20Sopenharmony_ci	unsigned long		flags;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
9528c2ecf20Sopenharmony_ci	if (list_empty(&dwc->active_list))
9538c2ecf20Sopenharmony_ci		dwc_dostart_first_queued(dwc);
9548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_civoid do_dw_dma_off(struct dw_dma *dw)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	dma_writel(dw, CFG, 0);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask);
9648c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
9658c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask);
9668c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask);
9678c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	while (dma_readl(dw, CFG) & DW_CFG_DMA_EN)
9708c2ecf20Sopenharmony_ci		cpu_relax();
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_civoid do_dw_dma_on(struct dw_dma *dw)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	dma_writel(dw, CFG, DW_CFG_DMA_EN);
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_cistatic int dwc_alloc_chan_resources(struct dma_chan *chan)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
9818c2ecf20Sopenharmony_ci	struct dw_dma		*dw = to_dw_dma(chan->device);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(chan), "%s\n", __func__);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	/* ASSERT:  channel is idle */
9868c2ecf20Sopenharmony_ci	if (dma_readl(dw, CH_EN) & dwc->mask) {
9878c2ecf20Sopenharmony_ci		dev_dbg(chan2dev(chan), "DMA channel not idle?\n");
9888c2ecf20Sopenharmony_ci		return -EIO;
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	dma_cookie_init(chan);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	/*
9948c2ecf20Sopenharmony_ci	 * NOTE: some controllers may have additional features that we
9958c2ecf20Sopenharmony_ci	 * need to initialize here, like "scatter-gather" (which
9968c2ecf20Sopenharmony_ci	 * doesn't mean what you think it means), and status writeback.
9978c2ecf20Sopenharmony_ci	 */
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/*
10008c2ecf20Sopenharmony_ci	 * We need controller-specific data to set up slave transfers.
10018c2ecf20Sopenharmony_ci	 */
10028c2ecf20Sopenharmony_ci	if (chan->private && !dw_dma_filter(chan, chan->private)) {
10038c2ecf20Sopenharmony_ci		dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
10048c2ecf20Sopenharmony_ci		return -EINVAL;
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/* Enable controller here if needed */
10088c2ecf20Sopenharmony_ci	if (!dw->in_use)
10098c2ecf20Sopenharmony_ci		do_dw_dma_on(dw);
10108c2ecf20Sopenharmony_ci	dw->in_use |= dwc->mask;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	return 0;
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cistatic void dwc_free_chan_resources(struct dma_chan *chan)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
10188c2ecf20Sopenharmony_ci	struct dw_dma		*dw = to_dw_dma(chan->device);
10198c2ecf20Sopenharmony_ci	unsigned long		flags;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	dev_dbg(chan2dev(chan), "%s: descs allocated=%u\n", __func__,
10228c2ecf20Sopenharmony_ci			dwc->descs_allocated);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	/* ASSERT:  channel is idle */
10258c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&dwc->active_list));
10268c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&dwc->queue));
10278c2ecf20Sopenharmony_ci	BUG_ON(dma_readl(to_dw_dma(chan->device), CH_EN) & dwc->mask);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dwc->lock, flags);
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	/* Clear custom channel configuration */
10328c2ecf20Sopenharmony_ci	memset(&dwc->dws, 0, sizeof(struct dw_dma_slave));
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	/* Disable interrupts */
10358c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.XFER, dwc->mask);
10368c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.BLOCK, dwc->mask);
10378c2ecf20Sopenharmony_ci	channel_clear_bit(dw, MASK.ERROR, dwc->mask);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dwc->lock, flags);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* Disable controller in case it was a last user */
10428c2ecf20Sopenharmony_ci	dw->in_use &= ~dwc->mask;
10438c2ecf20Sopenharmony_ci	if (!dw->in_use)
10448c2ecf20Sopenharmony_ci		do_dw_dma_off(dw);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_cistatic void dwc_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	caps->max_burst = dwc->max_burst;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/*
10568c2ecf20Sopenharmony_ci	 * It might be crucial for some devices to have the hardware
10578c2ecf20Sopenharmony_ci	 * accelerated multi-block transfers supported, aka LLPs in DW DMAC
10588c2ecf20Sopenharmony_ci	 * notation. So if LLPs are supported then max_sg_burst is set to
10598c2ecf20Sopenharmony_ci	 * zero which means unlimited number of SG entries can be handled in a
10608c2ecf20Sopenharmony_ci	 * single DMA transaction, otherwise it's just one SG entry.
10618c2ecf20Sopenharmony_ci	 */
10628c2ecf20Sopenharmony_ci	if (dwc->nollp)
10638c2ecf20Sopenharmony_ci		caps->max_sg_burst = 1;
10648c2ecf20Sopenharmony_ci	else
10658c2ecf20Sopenharmony_ci		caps->max_sg_burst = 0;
10668c2ecf20Sopenharmony_ci}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ciint do_dma_probe(struct dw_dma_chip *chip)
10698c2ecf20Sopenharmony_ci{
10708c2ecf20Sopenharmony_ci	struct dw_dma *dw = chip->dw;
10718c2ecf20Sopenharmony_ci	struct dw_dma_platform_data *pdata;
10728c2ecf20Sopenharmony_ci	bool			autocfg = false;
10738c2ecf20Sopenharmony_ci	unsigned int		dw_params;
10748c2ecf20Sopenharmony_ci	unsigned int		i;
10758c2ecf20Sopenharmony_ci	int			err;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
10788c2ecf20Sopenharmony_ci	if (!dw->pdata)
10798c2ecf20Sopenharmony_ci		return -ENOMEM;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	dw->regs = chip->regs;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	pm_runtime_get_sync(chip->dev);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (!chip->pdata) {
10868c2ecf20Sopenharmony_ci		dw_params = dma_readl(dw, DW_PARAMS);
10878c2ecf20Sopenharmony_ci		dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci		autocfg = dw_params >> DW_PARAMS_EN & 1;
10908c2ecf20Sopenharmony_ci		if (!autocfg) {
10918c2ecf20Sopenharmony_ci			err = -EINVAL;
10928c2ecf20Sopenharmony_ci			goto err_pdata;
10938c2ecf20Sopenharmony_ci		}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci		/* Reassign the platform data pointer */
10968c2ecf20Sopenharmony_ci		pdata = dw->pdata;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		/* Get hardware configuration parameters */
10998c2ecf20Sopenharmony_ci		pdata->nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 7) + 1;
11008c2ecf20Sopenharmony_ci		pdata->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
11018c2ecf20Sopenharmony_ci		for (i = 0; i < pdata->nr_masters; i++) {
11028c2ecf20Sopenharmony_ci			pdata->data_width[i] =
11038c2ecf20Sopenharmony_ci				4 << (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3);
11048c2ecf20Sopenharmony_ci		}
11058c2ecf20Sopenharmony_ci		pdata->block_size = dma_readl(dw, MAX_BLK_SIZE);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci		/* Fill platform data with the default values */
11088c2ecf20Sopenharmony_ci		pdata->chan_allocation_order = CHAN_ALLOCATION_ASCENDING;
11098c2ecf20Sopenharmony_ci		pdata->chan_priority = CHAN_PRIORITY_ASCENDING;
11108c2ecf20Sopenharmony_ci	} else if (chip->pdata->nr_channels > DW_DMA_MAX_NR_CHANNELS) {
11118c2ecf20Sopenharmony_ci		err = -EINVAL;
11128c2ecf20Sopenharmony_ci		goto err_pdata;
11138c2ecf20Sopenharmony_ci	} else {
11148c2ecf20Sopenharmony_ci		memcpy(dw->pdata, chip->pdata, sizeof(*dw->pdata));
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci		/* Reassign the platform data pointer */
11178c2ecf20Sopenharmony_ci		pdata = dw->pdata;
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	dw->chan = devm_kcalloc(chip->dev, pdata->nr_channels, sizeof(*dw->chan),
11218c2ecf20Sopenharmony_ci				GFP_KERNEL);
11228c2ecf20Sopenharmony_ci	if (!dw->chan) {
11238c2ecf20Sopenharmony_ci		err = -ENOMEM;
11248c2ecf20Sopenharmony_ci		goto err_pdata;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	/* Calculate all channel mask before DMA setup */
11288c2ecf20Sopenharmony_ci	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	/* Force dma off, just in case */
11318c2ecf20Sopenharmony_ci	dw->disable(dw);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	/* Device and instance ID for IRQ and DMA pool */
11348c2ecf20Sopenharmony_ci	dw->set_device_name(dw, chip->id);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	/* Create a pool of consistent memory blocks for hardware descriptors */
11378c2ecf20Sopenharmony_ci	dw->desc_pool = dmam_pool_create(dw->name, chip->dev,
11388c2ecf20Sopenharmony_ci					 sizeof(struct dw_desc), 4, 0);
11398c2ecf20Sopenharmony_ci	if (!dw->desc_pool) {
11408c2ecf20Sopenharmony_ci		dev_err(chip->dev, "No memory for descriptors dma pool\n");
11418c2ecf20Sopenharmony_ci		err = -ENOMEM;
11428c2ecf20Sopenharmony_ci		goto err_pdata;
11438c2ecf20Sopenharmony_ci	}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	tasklet_setup(&dw->tasklet, dw_dma_tasklet);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED,
11488c2ecf20Sopenharmony_ci			  dw->name, dw);
11498c2ecf20Sopenharmony_ci	if (err)
11508c2ecf20Sopenharmony_ci		goto err_pdata;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dw->dma.channels);
11538c2ecf20Sopenharmony_ci	for (i = 0; i < pdata->nr_channels; i++) {
11548c2ecf20Sopenharmony_ci		struct dw_dma_chan	*dwc = &dw->chan[i];
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci		dwc->chan.device = &dw->dma;
11578c2ecf20Sopenharmony_ci		dma_cookie_init(&dwc->chan);
11588c2ecf20Sopenharmony_ci		if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING)
11598c2ecf20Sopenharmony_ci			list_add_tail(&dwc->chan.device_node,
11608c2ecf20Sopenharmony_ci					&dw->dma.channels);
11618c2ecf20Sopenharmony_ci		else
11628c2ecf20Sopenharmony_ci			list_add(&dwc->chan.device_node, &dw->dma.channels);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci		/* 7 is highest priority & 0 is lowest. */
11658c2ecf20Sopenharmony_ci		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
11668c2ecf20Sopenharmony_ci			dwc->priority = pdata->nr_channels - i - 1;
11678c2ecf20Sopenharmony_ci		else
11688c2ecf20Sopenharmony_ci			dwc->priority = i;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci		dwc->ch_regs = &__dw_regs(dw)->CHAN[i];
11718c2ecf20Sopenharmony_ci		spin_lock_init(&dwc->lock);
11728c2ecf20Sopenharmony_ci		dwc->mask = 1 << i;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dwc->active_list);
11758c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dwc->queue);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci		channel_clear_bit(dw, CH_EN, dwc->mask);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci		dwc->direction = DMA_TRANS_NONE;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci		/* Hardware configuration */
11828c2ecf20Sopenharmony_ci		if (autocfg) {
11838c2ecf20Sopenharmony_ci			unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1;
11848c2ecf20Sopenharmony_ci			void __iomem *addr = &__dw_regs(dw)->DWC_PARAMS[r];
11858c2ecf20Sopenharmony_ci			unsigned int dwc_params = readl(addr);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci			dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
11888c2ecf20Sopenharmony_ci					   dwc_params);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci			/*
11918c2ecf20Sopenharmony_ci			 * Decode maximum block size for given channel. The
11928c2ecf20Sopenharmony_ci			 * stored 4 bit value represents blocks from 0x00 for 3
11938c2ecf20Sopenharmony_ci			 * up to 0x0a for 4095.
11948c2ecf20Sopenharmony_ci			 */
11958c2ecf20Sopenharmony_ci			dwc->block_size =
11968c2ecf20Sopenharmony_ci				(4 << ((pdata->block_size >> 4 * i) & 0xf)) - 1;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci			/*
11998c2ecf20Sopenharmony_ci			 * According to the DW DMA databook the true scatter-
12008c2ecf20Sopenharmony_ci			 * gether LLPs aren't available if either multi-block
12018c2ecf20Sopenharmony_ci			 * config is disabled (CHx_MULTI_BLK_EN == 0) or the
12028c2ecf20Sopenharmony_ci			 * LLP register is hard-coded to zeros
12038c2ecf20Sopenharmony_ci			 * (CHx_HC_LLP == 1).
12048c2ecf20Sopenharmony_ci			 */
12058c2ecf20Sopenharmony_ci			dwc->nollp =
12068c2ecf20Sopenharmony_ci				(dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0 ||
12078c2ecf20Sopenharmony_ci				(dwc_params >> DWC_PARAMS_HC_LLP & 0x1) == 1;
12088c2ecf20Sopenharmony_ci			dwc->max_burst =
12098c2ecf20Sopenharmony_ci				(0x4 << (dwc_params >> DWC_PARAMS_MSIZE & 0x7));
12108c2ecf20Sopenharmony_ci		} else {
12118c2ecf20Sopenharmony_ci			dwc->block_size = pdata->block_size;
12128c2ecf20Sopenharmony_ci			dwc->nollp = !pdata->multi_block[i];
12138c2ecf20Sopenharmony_ci			dwc->max_burst = pdata->max_burst[i] ?: DW_DMA_MAX_BURST;
12148c2ecf20Sopenharmony_ci		}
12158c2ecf20Sopenharmony_ci	}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	/* Clear all interrupts on all channels. */
12188c2ecf20Sopenharmony_ci	dma_writel(dw, CLEAR.XFER, dw->all_chan_mask);
12198c2ecf20Sopenharmony_ci	dma_writel(dw, CLEAR.BLOCK, dw->all_chan_mask);
12208c2ecf20Sopenharmony_ci	dma_writel(dw, CLEAR.SRC_TRAN, dw->all_chan_mask);
12218c2ecf20Sopenharmony_ci	dma_writel(dw, CLEAR.DST_TRAN, dw->all_chan_mask);
12228c2ecf20Sopenharmony_ci	dma_writel(dw, CLEAR.ERROR, dw->all_chan_mask);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	/* Set capabilities */
12258c2ecf20Sopenharmony_ci	dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
12268c2ecf20Sopenharmony_ci	dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask);
12278c2ecf20Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	dw->dma.dev = chip->dev;
12308c2ecf20Sopenharmony_ci	dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources;
12318c2ecf20Sopenharmony_ci	dw->dma.device_free_chan_resources = dwc_free_chan_resources;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy;
12348c2ecf20Sopenharmony_ci	dw->dma.device_prep_slave_sg = dwc_prep_slave_sg;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	dw->dma.device_caps = dwc_caps;
12378c2ecf20Sopenharmony_ci	dw->dma.device_config = dwc_config;
12388c2ecf20Sopenharmony_ci	dw->dma.device_pause = dwc_pause;
12398c2ecf20Sopenharmony_ci	dw->dma.device_resume = dwc_resume;
12408c2ecf20Sopenharmony_ci	dw->dma.device_terminate_all = dwc_terminate_all;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	dw->dma.device_tx_status = dwc_tx_status;
12438c2ecf20Sopenharmony_ci	dw->dma.device_issue_pending = dwc_issue_pending;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	/* DMA capabilities */
12468c2ecf20Sopenharmony_ci	dw->dma.min_burst = DW_DMA_MIN_BURST;
12478c2ecf20Sopenharmony_ci	dw->dma.max_burst = DW_DMA_MAX_BURST;
12488c2ecf20Sopenharmony_ci	dw->dma.src_addr_widths = DW_DMA_BUSWIDTHS;
12498c2ecf20Sopenharmony_ci	dw->dma.dst_addr_widths = DW_DMA_BUSWIDTHS;
12508c2ecf20Sopenharmony_ci	dw->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
12518c2ecf20Sopenharmony_ci			     BIT(DMA_MEM_TO_MEM);
12528c2ecf20Sopenharmony_ci	dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	/*
12558c2ecf20Sopenharmony_ci	 * For now there is no hardware with non uniform maximum block size
12568c2ecf20Sopenharmony_ci	 * across all of the device channels, so we set the maximum segment
12578c2ecf20Sopenharmony_ci	 * size as the block size found for the very first channel.
12588c2ecf20Sopenharmony_ci	 */
12598c2ecf20Sopenharmony_ci	dma_set_max_seg_size(dw->dma.dev, dw->chan[0].block_size);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	err = dma_async_device_register(&dw->dma);
12628c2ecf20Sopenharmony_ci	if (err)
12638c2ecf20Sopenharmony_ci		goto err_dma_register;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
12668c2ecf20Sopenharmony_ci		 pdata->nr_channels);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	pm_runtime_put_sync_suspend(chip->dev);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	return 0;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cierr_dma_register:
12738c2ecf20Sopenharmony_ci	free_irq(chip->irq, dw);
12748c2ecf20Sopenharmony_cierr_pdata:
12758c2ecf20Sopenharmony_ci	pm_runtime_put_sync_suspend(chip->dev);
12768c2ecf20Sopenharmony_ci	return err;
12778c2ecf20Sopenharmony_ci}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ciint do_dma_remove(struct dw_dma_chip *chip)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	struct dw_dma		*dw = chip->dw;
12828c2ecf20Sopenharmony_ci	struct dw_dma_chan	*dwc, *_dwc;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	pm_runtime_get_sync(chip->dev);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	do_dw_dma_off(dw);
12878c2ecf20Sopenharmony_ci	dma_async_device_unregister(&dw->dma);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	free_irq(chip->irq, dw);
12908c2ecf20Sopenharmony_ci	tasklet_kill(&dw->tasklet);
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels,
12938c2ecf20Sopenharmony_ci			chan.device_node) {
12948c2ecf20Sopenharmony_ci		list_del(&dwc->chan.device_node);
12958c2ecf20Sopenharmony_ci		channel_clear_bit(dw, CH_EN, dwc->mask);
12968c2ecf20Sopenharmony_ci	}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	pm_runtime_put_sync_suspend(chip->dev);
12998c2ecf20Sopenharmony_ci	return 0;
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ciint do_dw_dma_disable(struct dw_dma_chip *chip)
13038c2ecf20Sopenharmony_ci{
13048c2ecf20Sopenharmony_ci	struct dw_dma *dw = chip->dw;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	dw->disable(dw);
13078c2ecf20Sopenharmony_ci	return 0;
13088c2ecf20Sopenharmony_ci}
13098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(do_dw_dma_disable);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ciint do_dw_dma_enable(struct dw_dma_chip *chip)
13128c2ecf20Sopenharmony_ci{
13138c2ecf20Sopenharmony_ci	struct dw_dma *dw = chip->dw;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	dw->enable(dw);
13168c2ecf20Sopenharmony_ci	return 0;
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(do_dw_dma_enable);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
13218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
13228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
13238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
1324