18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Renesas R-Car Gen2/Gen3 DMA Controller Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2019 Renesas Electronics Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
128c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/list.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/mutex.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/of_dma.h>
198c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "../dmaengine.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * struct rcar_dmac_xfer_chunk - Descriptor for a hardware transfer
298c2ecf20Sopenharmony_ci * @node: entry in the parent's chunks list
308c2ecf20Sopenharmony_ci * @src_addr: device source address
318c2ecf20Sopenharmony_ci * @dst_addr: device destination address
328c2ecf20Sopenharmony_ci * @size: transfer size in bytes
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_cistruct rcar_dmac_xfer_chunk {
358c2ecf20Sopenharmony_ci	struct list_head node;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	dma_addr_t src_addr;
388c2ecf20Sopenharmony_ci	dma_addr_t dst_addr;
398c2ecf20Sopenharmony_ci	u32 size;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/*
438c2ecf20Sopenharmony_ci * struct rcar_dmac_hw_desc - Hardware descriptor for a transfer chunk
448c2ecf20Sopenharmony_ci * @sar: value of the SAR register (source address)
458c2ecf20Sopenharmony_ci * @dar: value of the DAR register (destination address)
468c2ecf20Sopenharmony_ci * @tcr: value of the TCR register (transfer count)
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistruct rcar_dmac_hw_desc {
498c2ecf20Sopenharmony_ci	u32 sar;
508c2ecf20Sopenharmony_ci	u32 dar;
518c2ecf20Sopenharmony_ci	u32 tcr;
528c2ecf20Sopenharmony_ci	u32 reserved;
538c2ecf20Sopenharmony_ci} __attribute__((__packed__));
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * struct rcar_dmac_desc - R-Car Gen2 DMA Transfer Descriptor
578c2ecf20Sopenharmony_ci * @async_tx: base DMA asynchronous transaction descriptor
588c2ecf20Sopenharmony_ci * @direction: direction of the DMA transfer
598c2ecf20Sopenharmony_ci * @xfer_shift: log2 of the transfer size
608c2ecf20Sopenharmony_ci * @chcr: value of the channel configuration register for this transfer
618c2ecf20Sopenharmony_ci * @node: entry in the channel's descriptors lists
628c2ecf20Sopenharmony_ci * @chunks: list of transfer chunks for this transfer
638c2ecf20Sopenharmony_ci * @running: the transfer chunk being currently processed
648c2ecf20Sopenharmony_ci * @nchunks: number of transfer chunks for this transfer
658c2ecf20Sopenharmony_ci * @hwdescs.use: whether the transfer descriptor uses hardware descriptors
668c2ecf20Sopenharmony_ci * @hwdescs.mem: hardware descriptors memory for the transfer
678c2ecf20Sopenharmony_ci * @hwdescs.dma: device address of the hardware descriptors memory
688c2ecf20Sopenharmony_ci * @hwdescs.size: size of the hardware descriptors in bytes
698c2ecf20Sopenharmony_ci * @size: transfer size in bytes
708c2ecf20Sopenharmony_ci * @cyclic: when set indicates that the DMA transfer is cyclic
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistruct rcar_dmac_desc {
738c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor async_tx;
748c2ecf20Sopenharmony_ci	enum dma_transfer_direction direction;
758c2ecf20Sopenharmony_ci	unsigned int xfer_shift;
768c2ecf20Sopenharmony_ci	u32 chcr;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	struct list_head node;
798c2ecf20Sopenharmony_ci	struct list_head chunks;
808c2ecf20Sopenharmony_ci	struct rcar_dmac_xfer_chunk *running;
818c2ecf20Sopenharmony_ci	unsigned int nchunks;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct {
848c2ecf20Sopenharmony_ci		bool use;
858c2ecf20Sopenharmony_ci		struct rcar_dmac_hw_desc *mem;
868c2ecf20Sopenharmony_ci		dma_addr_t dma;
878c2ecf20Sopenharmony_ci		size_t size;
888c2ecf20Sopenharmony_ci	} hwdescs;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	unsigned int size;
918c2ecf20Sopenharmony_ci	bool cyclic;
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci#define to_rcar_dmac_desc(d)	container_of(d, struct rcar_dmac_desc, async_tx)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/*
978c2ecf20Sopenharmony_ci * struct rcar_dmac_desc_page - One page worth of descriptors
988c2ecf20Sopenharmony_ci * @node: entry in the channel's pages list
998c2ecf20Sopenharmony_ci * @descs: array of DMA descriptors
1008c2ecf20Sopenharmony_ci * @chunks: array of transfer chunk descriptors
1018c2ecf20Sopenharmony_ci */
1028c2ecf20Sopenharmony_cistruct rcar_dmac_desc_page {
1038c2ecf20Sopenharmony_ci	struct list_head node;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	union {
1068c2ecf20Sopenharmony_ci		struct rcar_dmac_desc descs[0];
1078c2ecf20Sopenharmony_ci		struct rcar_dmac_xfer_chunk chunks[0];
1088c2ecf20Sopenharmony_ci	};
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#define RCAR_DMAC_DESCS_PER_PAGE					\
1128c2ecf20Sopenharmony_ci	((PAGE_SIZE - offsetof(struct rcar_dmac_desc_page, descs)) /	\
1138c2ecf20Sopenharmony_ci	sizeof(struct rcar_dmac_desc))
1148c2ecf20Sopenharmony_ci#define RCAR_DMAC_XFER_CHUNKS_PER_PAGE					\
1158c2ecf20Sopenharmony_ci	((PAGE_SIZE - offsetof(struct rcar_dmac_desc_page, chunks)) /	\
1168c2ecf20Sopenharmony_ci	sizeof(struct rcar_dmac_xfer_chunk))
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/*
1198c2ecf20Sopenharmony_ci * struct rcar_dmac_chan_slave - Slave configuration
1208c2ecf20Sopenharmony_ci * @slave_addr: slave memory address
1218c2ecf20Sopenharmony_ci * @xfer_size: size (in bytes) of hardware transfers
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_cistruct rcar_dmac_chan_slave {
1248c2ecf20Sopenharmony_ci	phys_addr_t slave_addr;
1258c2ecf20Sopenharmony_ci	unsigned int xfer_size;
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/*
1298c2ecf20Sopenharmony_ci * struct rcar_dmac_chan_map - Map of slave device phys to dma address
1308c2ecf20Sopenharmony_ci * @addr: slave dma address
1318c2ecf20Sopenharmony_ci * @dir: direction of mapping
1328c2ecf20Sopenharmony_ci * @slave: slave configuration that is mapped
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cistruct rcar_dmac_chan_map {
1358c2ecf20Sopenharmony_ci	dma_addr_t addr;
1368c2ecf20Sopenharmony_ci	enum dma_data_direction dir;
1378c2ecf20Sopenharmony_ci	struct rcar_dmac_chan_slave slave;
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/*
1418c2ecf20Sopenharmony_ci * struct rcar_dmac_chan - R-Car Gen2 DMA Controller Channel
1428c2ecf20Sopenharmony_ci * @chan: base DMA channel object
1438c2ecf20Sopenharmony_ci * @iomem: channel I/O memory base
1448c2ecf20Sopenharmony_ci * @index: index of this channel in the controller
1458c2ecf20Sopenharmony_ci * @irq: channel IRQ
1468c2ecf20Sopenharmony_ci * @src: slave memory address and size on the source side
1478c2ecf20Sopenharmony_ci * @dst: slave memory address and size on the destination side
1488c2ecf20Sopenharmony_ci * @mid_rid: hardware MID/RID for the DMA client using this channel
1498c2ecf20Sopenharmony_ci * @lock: protects the channel CHCR register and the desc members
1508c2ecf20Sopenharmony_ci * @desc.free: list of free descriptors
1518c2ecf20Sopenharmony_ci * @desc.pending: list of pending descriptors (submitted with tx_submit)
1528c2ecf20Sopenharmony_ci * @desc.active: list of active descriptors (activated with issue_pending)
1538c2ecf20Sopenharmony_ci * @desc.done: list of completed descriptors
1548c2ecf20Sopenharmony_ci * @desc.wait: list of descriptors waiting for an ack
1558c2ecf20Sopenharmony_ci * @desc.running: the descriptor being processed (a member of the active list)
1568c2ecf20Sopenharmony_ci * @desc.chunks_free: list of free transfer chunk descriptors
1578c2ecf20Sopenharmony_ci * @desc.pages: list of pages used by allocated descriptors
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistruct rcar_dmac_chan {
1608c2ecf20Sopenharmony_ci	struct dma_chan chan;
1618c2ecf20Sopenharmony_ci	void __iomem *iomem;
1628c2ecf20Sopenharmony_ci	unsigned int index;
1638c2ecf20Sopenharmony_ci	int irq;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	struct rcar_dmac_chan_slave src;
1668c2ecf20Sopenharmony_ci	struct rcar_dmac_chan_slave dst;
1678c2ecf20Sopenharmony_ci	struct rcar_dmac_chan_map map;
1688c2ecf20Sopenharmony_ci	int mid_rid;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	spinlock_t lock;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	struct {
1738c2ecf20Sopenharmony_ci		struct list_head free;
1748c2ecf20Sopenharmony_ci		struct list_head pending;
1758c2ecf20Sopenharmony_ci		struct list_head active;
1768c2ecf20Sopenharmony_ci		struct list_head done;
1778c2ecf20Sopenharmony_ci		struct list_head wait;
1788c2ecf20Sopenharmony_ci		struct rcar_dmac_desc *running;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		struct list_head chunks_free;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		struct list_head pages;
1838c2ecf20Sopenharmony_ci	} desc;
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci#define to_rcar_dmac_chan(c)	container_of(c, struct rcar_dmac_chan, chan)
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/*
1898c2ecf20Sopenharmony_ci * struct rcar_dmac - R-Car Gen2 DMA Controller
1908c2ecf20Sopenharmony_ci * @engine: base DMA engine object
1918c2ecf20Sopenharmony_ci * @dev: the hardware device
1928c2ecf20Sopenharmony_ci * @iomem: remapped I/O memory base
1938c2ecf20Sopenharmony_ci * @n_channels: number of available channels
1948c2ecf20Sopenharmony_ci * @channels: array of DMAC channels
1958c2ecf20Sopenharmony_ci * @channels_mask: bitfield of which DMA channels are managed by this driver
1968c2ecf20Sopenharmony_ci * @modules: bitmask of client modules in use
1978c2ecf20Sopenharmony_ci */
1988c2ecf20Sopenharmony_cistruct rcar_dmac {
1998c2ecf20Sopenharmony_ci	struct dma_device engine;
2008c2ecf20Sopenharmony_ci	struct device *dev;
2018c2ecf20Sopenharmony_ci	void __iomem *iomem;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	unsigned int n_channels;
2048c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *channels;
2058c2ecf20Sopenharmony_ci	u32 channels_mask;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	DECLARE_BITMAP(modules, 256);
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#define to_rcar_dmac(d)		container_of(d, struct rcar_dmac, engine)
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/*
2138c2ecf20Sopenharmony_ci * struct rcar_dmac_of_data - This driver's OF data
2148c2ecf20Sopenharmony_ci * @chan_offset_base: DMAC channels base offset
2158c2ecf20Sopenharmony_ci * @chan_offset_stride: DMAC channels offset stride
2168c2ecf20Sopenharmony_ci */
2178c2ecf20Sopenharmony_cistruct rcar_dmac_of_data {
2188c2ecf20Sopenharmony_ci	u32 chan_offset_base;
2198c2ecf20Sopenharmony_ci	u32 chan_offset_stride;
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
2238c2ecf20Sopenharmony_ci * Registers
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci#define RCAR_DMAISTA			0x0020
2278c2ecf20Sopenharmony_ci#define RCAR_DMASEC			0x0030
2288c2ecf20Sopenharmony_ci#define RCAR_DMAOR			0x0060
2298c2ecf20Sopenharmony_ci#define RCAR_DMAOR_PRI_FIXED		(0 << 8)
2308c2ecf20Sopenharmony_ci#define RCAR_DMAOR_PRI_ROUND_ROBIN	(3 << 8)
2318c2ecf20Sopenharmony_ci#define RCAR_DMAOR_AE			(1 << 2)
2328c2ecf20Sopenharmony_ci#define RCAR_DMAOR_DME			(1 << 0)
2338c2ecf20Sopenharmony_ci#define RCAR_DMACHCLR			0x0080
2348c2ecf20Sopenharmony_ci#define RCAR_DMADPSEC			0x00a0
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci#define RCAR_DMASAR			0x0000
2378c2ecf20Sopenharmony_ci#define RCAR_DMADAR			0x0004
2388c2ecf20Sopenharmony_ci#define RCAR_DMATCR			0x0008
2398c2ecf20Sopenharmony_ci#define RCAR_DMATCR_MASK		0x00ffffff
2408c2ecf20Sopenharmony_ci#define RCAR_DMATSR			0x0028
2418c2ecf20Sopenharmony_ci#define RCAR_DMACHCR			0x000c
2428c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_CAE		(1 << 31)
2438c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_CAIE		(1 << 30)
2448c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DPM_DISABLED	(0 << 28)
2458c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DPM_ENABLED	(1 << 28)
2468c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DPM_REPEAT		(2 << 28)
2478c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DPM_INFINITE	(3 << 28)
2488c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_RPT_SAR		(1 << 27)
2498c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_RPT_DAR		(1 << 26)
2508c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_RPT_TCR		(1 << 25)
2518c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DPB		(1 << 22)
2528c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DSE		(1 << 19)
2538c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DSIE		(1 << 18)
2548c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_1B		((0 << 20) | (0 << 3))
2558c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_2B		((0 << 20) | (1 << 3))
2568c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_4B		((0 << 20) | (2 << 3))
2578c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_16B		((0 << 20) | (3 << 3))
2588c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_32B		((1 << 20) | (0 << 3))
2598c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_64B		((1 << 20) | (1 << 3))
2608c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TS_8B		((1 << 20) | (3 << 3))
2618c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DM_FIXED		(0 << 14)
2628c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DM_INC		(1 << 14)
2638c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DM_DEC		(2 << 14)
2648c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_SM_FIXED		(0 << 12)
2658c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_SM_INC		(1 << 12)
2668c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_SM_DEC		(2 << 12)
2678c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_RS_AUTO		(4 << 8)
2688c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_RS_DMARS		(8 << 8)
2698c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_IE			(1 << 2)
2708c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_TE			(1 << 1)
2718c2ecf20Sopenharmony_ci#define RCAR_DMACHCR_DE			(1 << 0)
2728c2ecf20Sopenharmony_ci#define RCAR_DMATCRB			0x0018
2738c2ecf20Sopenharmony_ci#define RCAR_DMATSRB			0x0038
2748c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB			0x001c
2758c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_DCNT(n)		((n) << 24)
2768c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_DPTR_MASK		(0xff << 16)
2778c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_DPTR_SHIFT	16
2788c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_DRST		(1 << 15)
2798c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_DTS		(1 << 8)
2808c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_SLM_NORMAL	(0 << 4)
2818c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_SLM_CLK(n)	((8 | (n)) << 4)
2828c2ecf20Sopenharmony_ci#define RCAR_DMACHCRB_PRI(n)		((n) << 0)
2838c2ecf20Sopenharmony_ci#define RCAR_DMARS			0x0040
2848c2ecf20Sopenharmony_ci#define RCAR_DMABUFCR			0x0048
2858c2ecf20Sopenharmony_ci#define RCAR_DMABUFCR_MBU(n)		((n) << 16)
2868c2ecf20Sopenharmony_ci#define RCAR_DMABUFCR_ULB(n)		((n) << 0)
2878c2ecf20Sopenharmony_ci#define RCAR_DMADPBASE			0x0050
2888c2ecf20Sopenharmony_ci#define RCAR_DMADPBASE_MASK		0xfffffff0
2898c2ecf20Sopenharmony_ci#define RCAR_DMADPBASE_SEL		(1 << 0)
2908c2ecf20Sopenharmony_ci#define RCAR_DMADPCR			0x0054
2918c2ecf20Sopenharmony_ci#define RCAR_DMADPCR_DIPT(n)		((n) << 24)
2928c2ecf20Sopenharmony_ci#define RCAR_DMAFIXSAR			0x0010
2938c2ecf20Sopenharmony_ci#define RCAR_DMAFIXDAR			0x0014
2948c2ecf20Sopenharmony_ci#define RCAR_DMAFIXDPBASE		0x0060
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/* Hardcode the MEMCPY transfer size to 4 bytes. */
2978c2ecf20Sopenharmony_ci#define RCAR_DMAC_MEMCPY_XFER_SIZE	4
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
3008c2ecf20Sopenharmony_ci * Device access
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic void rcar_dmac_write(struct rcar_dmac *dmac, u32 reg, u32 data)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	if (reg == RCAR_DMAOR)
3068c2ecf20Sopenharmony_ci		writew(data, dmac->iomem + reg);
3078c2ecf20Sopenharmony_ci	else
3088c2ecf20Sopenharmony_ci		writel(data, dmac->iomem + reg);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic u32 rcar_dmac_read(struct rcar_dmac *dmac, u32 reg)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	if (reg == RCAR_DMAOR)
3148c2ecf20Sopenharmony_ci		return readw(dmac->iomem + reg);
3158c2ecf20Sopenharmony_ci	else
3168c2ecf20Sopenharmony_ci		return readl(dmac->iomem + reg);
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic u32 rcar_dmac_chan_read(struct rcar_dmac_chan *chan, u32 reg)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	if (reg == RCAR_DMARS)
3228c2ecf20Sopenharmony_ci		return readw(chan->iomem + reg);
3238c2ecf20Sopenharmony_ci	else
3248c2ecf20Sopenharmony_ci		return readl(chan->iomem + reg);
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic void rcar_dmac_chan_write(struct rcar_dmac_chan *chan, u32 reg, u32 data)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	if (reg == RCAR_DMARS)
3308c2ecf20Sopenharmony_ci		writew(data, chan->iomem + reg);
3318c2ecf20Sopenharmony_ci	else
3328c2ecf20Sopenharmony_ci		writel(data, chan->iomem + reg);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
3368c2ecf20Sopenharmony_ci * Initialization and configuration
3378c2ecf20Sopenharmony_ci */
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic bool rcar_dmac_chan_is_busy(struct rcar_dmac_chan *chan)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return !!(chcr & (RCAR_DMACHCR_DE | RCAR_DMACHCR_TE));
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc = chan->desc.running;
3498c2ecf20Sopenharmony_ci	u32 chcr = desc->chcr;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	WARN_ON_ONCE(rcar_dmac_chan_is_busy(chan));
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (chan->mid_rid >= 0)
3548c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMARS, chan->mid_rid);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (desc->hwdescs.use) {
3578c2ecf20Sopenharmony_ci		struct rcar_dmac_xfer_chunk *chunk =
3588c2ecf20Sopenharmony_ci			list_first_entry(&desc->chunks,
3598c2ecf20Sopenharmony_ci					 struct rcar_dmac_xfer_chunk, node);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		dev_dbg(chan->chan.device->dev,
3628c2ecf20Sopenharmony_ci			"chan%u: queue desc %p: %u@%pad\n",
3638c2ecf20Sopenharmony_ci			chan->index, desc, desc->nchunks, &desc->hwdescs.dma);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
3668c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMAFIXSAR,
3678c2ecf20Sopenharmony_ci				     chunk->src_addr >> 32);
3688c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMAFIXDAR,
3698c2ecf20Sopenharmony_ci				     chunk->dst_addr >> 32);
3708c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMAFIXDPBASE,
3718c2ecf20Sopenharmony_ci				     desc->hwdescs.dma >> 32);
3728c2ecf20Sopenharmony_ci#endif
3738c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMADPBASE,
3748c2ecf20Sopenharmony_ci				     (desc->hwdescs.dma & 0xfffffff0) |
3758c2ecf20Sopenharmony_ci				     RCAR_DMADPBASE_SEL);
3768c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMACHCRB,
3778c2ecf20Sopenharmony_ci				     RCAR_DMACHCRB_DCNT(desc->nchunks - 1) |
3788c2ecf20Sopenharmony_ci				     RCAR_DMACHCRB_DRST);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		/*
3818c2ecf20Sopenharmony_ci		 * Errata: When descriptor memory is accessed through an IOMMU
3828c2ecf20Sopenharmony_ci		 * the DMADAR register isn't initialized automatically from the
3838c2ecf20Sopenharmony_ci		 * first descriptor at beginning of transfer by the DMAC like it
3848c2ecf20Sopenharmony_ci		 * should. Initialize it manually with the destination address
3858c2ecf20Sopenharmony_ci		 * of the first chunk.
3868c2ecf20Sopenharmony_ci		 */
3878c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMADAR,
3888c2ecf20Sopenharmony_ci				     chunk->dst_addr & 0xffffffff);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		/*
3918c2ecf20Sopenharmony_ci		 * Program the descriptor stage interrupt to occur after the end
3928c2ecf20Sopenharmony_ci		 * of the first stage.
3938c2ecf20Sopenharmony_ci		 */
3948c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMADPCR, RCAR_DMADPCR_DIPT(1));
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		chcr |= RCAR_DMACHCR_RPT_SAR | RCAR_DMACHCR_RPT_DAR
3978c2ecf20Sopenharmony_ci		     |  RCAR_DMACHCR_RPT_TCR | RCAR_DMACHCR_DPB;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		/*
4008c2ecf20Sopenharmony_ci		 * If the descriptor isn't cyclic enable normal descriptor mode
4018c2ecf20Sopenharmony_ci		 * and the transfer completion interrupt.
4028c2ecf20Sopenharmony_ci		 */
4038c2ecf20Sopenharmony_ci		if (!desc->cyclic)
4048c2ecf20Sopenharmony_ci			chcr |= RCAR_DMACHCR_DPM_ENABLED | RCAR_DMACHCR_IE;
4058c2ecf20Sopenharmony_ci		/*
4068c2ecf20Sopenharmony_ci		 * If the descriptor is cyclic and has a callback enable the
4078c2ecf20Sopenharmony_ci		 * descriptor stage interrupt in infinite repeat mode.
4088c2ecf20Sopenharmony_ci		 */
4098c2ecf20Sopenharmony_ci		else if (desc->async_tx.callback)
4108c2ecf20Sopenharmony_ci			chcr |= RCAR_DMACHCR_DPM_INFINITE | RCAR_DMACHCR_DSIE;
4118c2ecf20Sopenharmony_ci		/*
4128c2ecf20Sopenharmony_ci		 * Otherwise just select infinite repeat mode without any
4138c2ecf20Sopenharmony_ci		 * interrupt.
4148c2ecf20Sopenharmony_ci		 */
4158c2ecf20Sopenharmony_ci		else
4168c2ecf20Sopenharmony_ci			chcr |= RCAR_DMACHCR_DPM_INFINITE;
4178c2ecf20Sopenharmony_ci	} else {
4188c2ecf20Sopenharmony_ci		struct rcar_dmac_xfer_chunk *chunk = desc->running;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci		dev_dbg(chan->chan.device->dev,
4218c2ecf20Sopenharmony_ci			"chan%u: queue chunk %p: %u@%pad -> %pad\n",
4228c2ecf20Sopenharmony_ci			chan->index, chunk, chunk->size, &chunk->src_addr,
4238c2ecf20Sopenharmony_ci			&chunk->dst_addr);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
4268c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMAFIXSAR,
4278c2ecf20Sopenharmony_ci				     chunk->src_addr >> 32);
4288c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMAFIXDAR,
4298c2ecf20Sopenharmony_ci				     chunk->dst_addr >> 32);
4308c2ecf20Sopenharmony_ci#endif
4318c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMASAR,
4328c2ecf20Sopenharmony_ci				     chunk->src_addr & 0xffffffff);
4338c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMADAR,
4348c2ecf20Sopenharmony_ci				     chunk->dst_addr & 0xffffffff);
4358c2ecf20Sopenharmony_ci		rcar_dmac_chan_write(chan, RCAR_DMATCR,
4368c2ecf20Sopenharmony_ci				     chunk->size >> desc->xfer_shift);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		chcr |= RCAR_DMACHCR_DPM_DISABLED | RCAR_DMACHCR_IE;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	rcar_dmac_chan_write(chan, RCAR_DMACHCR,
4428c2ecf20Sopenharmony_ci			     chcr | RCAR_DMACHCR_DE | RCAR_DMACHCR_CAIE);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic int rcar_dmac_init(struct rcar_dmac *dmac)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	u16 dmaor;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* Clear all channels and enable the DMAC globally. */
4508c2ecf20Sopenharmony_ci	rcar_dmac_write(dmac, RCAR_DMACHCLR, dmac->channels_mask);
4518c2ecf20Sopenharmony_ci	rcar_dmac_write(dmac, RCAR_DMAOR,
4528c2ecf20Sopenharmony_ci			RCAR_DMAOR_PRI_FIXED | RCAR_DMAOR_DME);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	dmaor = rcar_dmac_read(dmac, RCAR_DMAOR);
4558c2ecf20Sopenharmony_ci	if ((dmaor & (RCAR_DMAOR_AE | RCAR_DMAOR_DME)) != RCAR_DMAOR_DME) {
4568c2ecf20Sopenharmony_ci		dev_warn(dmac->dev, "DMAOR initialization failed.\n");
4578c2ecf20Sopenharmony_ci		return -EIO;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return 0;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
4648c2ecf20Sopenharmony_ci * Descriptors submission
4658c2ecf20Sopenharmony_ci */
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *chan = to_rcar_dmac_chan(tx->chan);
4708c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc = to_rcar_dmac_desc(tx);
4718c2ecf20Sopenharmony_ci	unsigned long flags;
4728c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	cookie = dma_cookie_assign(tx);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	dev_dbg(chan->chan.device->dev, "chan%u: submit #%d@%p\n",
4798c2ecf20Sopenharmony_ci		chan->index, tx->cookie, desc);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	list_add_tail(&desc->node, &chan->desc.pending);
4828c2ecf20Sopenharmony_ci	desc->running = list_first_entry(&desc->chunks,
4838c2ecf20Sopenharmony_ci					 struct rcar_dmac_xfer_chunk, node);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return cookie;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
4918c2ecf20Sopenharmony_ci * Descriptors allocation and free
4928c2ecf20Sopenharmony_ci */
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci/*
4958c2ecf20Sopenharmony_ci * rcar_dmac_desc_alloc - Allocate a page worth of DMA descriptors
4968c2ecf20Sopenharmony_ci * @chan: the DMA channel
4978c2ecf20Sopenharmony_ci * @gfp: allocation flags
4988c2ecf20Sopenharmony_ci */
4998c2ecf20Sopenharmony_cistatic int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct rcar_dmac_desc_page *page;
5028c2ecf20Sopenharmony_ci	unsigned long flags;
5038c2ecf20Sopenharmony_ci	LIST_HEAD(list);
5048c2ecf20Sopenharmony_ci	unsigned int i;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	page = (void *)get_zeroed_page(gfp);
5078c2ecf20Sopenharmony_ci	if (!page)
5088c2ecf20Sopenharmony_ci		return -ENOMEM;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	for (i = 0; i < RCAR_DMAC_DESCS_PER_PAGE; ++i) {
5118c2ecf20Sopenharmony_ci		struct rcar_dmac_desc *desc = &page->descs[i];
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		dma_async_tx_descriptor_init(&desc->async_tx, &chan->chan);
5148c2ecf20Sopenharmony_ci		desc->async_tx.tx_submit = rcar_dmac_tx_submit;
5158c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&desc->chunks);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		list_add_tail(&desc->node, &list);
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
5218c2ecf20Sopenharmony_ci	list_splice_tail(&list, &chan->desc.free);
5228c2ecf20Sopenharmony_ci	list_add_tail(&page->node, &chan->desc.pages);
5238c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return 0;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/*
5298c2ecf20Sopenharmony_ci * rcar_dmac_desc_put - Release a DMA transfer descriptor
5308c2ecf20Sopenharmony_ci * @chan: the DMA channel
5318c2ecf20Sopenharmony_ci * @desc: the descriptor
5328c2ecf20Sopenharmony_ci *
5338c2ecf20Sopenharmony_ci * Put the descriptor and its transfer chunk descriptors back in the channel's
5348c2ecf20Sopenharmony_ci * free descriptors lists. The descriptor's chunks list will be reinitialized to
5358c2ecf20Sopenharmony_ci * an empty list as a result.
5368c2ecf20Sopenharmony_ci *
5378c2ecf20Sopenharmony_ci * The descriptor must have been removed from the channel's lists before calling
5388c2ecf20Sopenharmony_ci * this function.
5398c2ecf20Sopenharmony_ci */
5408c2ecf20Sopenharmony_cistatic void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
5418c2ecf20Sopenharmony_ci			       struct rcar_dmac_desc *desc)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	unsigned long flags;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
5468c2ecf20Sopenharmony_ci	list_splice_tail_init(&desc->chunks, &chan->desc.chunks_free);
5478c2ecf20Sopenharmony_ci	list_add(&desc->node, &chan->desc.free);
5488c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc, *_desc;
5548c2ecf20Sopenharmony_ci	unsigned long flags;
5558c2ecf20Sopenharmony_ci	LIST_HEAD(list);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/*
5588c2ecf20Sopenharmony_ci	 * We have to temporarily move all descriptors from the wait list to a
5598c2ecf20Sopenharmony_ci	 * local list as iterating over the wait list, even with
5608c2ecf20Sopenharmony_ci	 * list_for_each_entry_safe, isn't safe if we release the channel lock
5618c2ecf20Sopenharmony_ci	 * around the rcar_dmac_desc_put() call.
5628c2ecf20Sopenharmony_ci	 */
5638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
5648c2ecf20Sopenharmony_ci	list_splice_init(&chan->desc.wait, &list);
5658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	list_for_each_entry_safe(desc, _desc, &list, node) {
5688c2ecf20Sopenharmony_ci		if (async_tx_test_ack(&desc->async_tx)) {
5698c2ecf20Sopenharmony_ci			list_del(&desc->node);
5708c2ecf20Sopenharmony_ci			rcar_dmac_desc_put(chan, desc);
5718c2ecf20Sopenharmony_ci		}
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	if (list_empty(&list))
5758c2ecf20Sopenharmony_ci		return;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* Put the remaining descriptors back in the wait list. */
5788c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
5798c2ecf20Sopenharmony_ci	list_splice(&list, &chan->desc.wait);
5808c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci/*
5848c2ecf20Sopenharmony_ci * rcar_dmac_desc_get - Allocate a descriptor for a DMA transfer
5858c2ecf20Sopenharmony_ci * @chan: the DMA channel
5868c2ecf20Sopenharmony_ci *
5878c2ecf20Sopenharmony_ci * Locking: This function must be called in a non-atomic context.
5888c2ecf20Sopenharmony_ci *
5898c2ecf20Sopenharmony_ci * Return: A pointer to the allocated descriptor or NULL if no descriptor can
5908c2ecf20Sopenharmony_ci * be allocated.
5918c2ecf20Sopenharmony_ci */
5928c2ecf20Sopenharmony_cistatic struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc;
5958c2ecf20Sopenharmony_ci	unsigned long flags;
5968c2ecf20Sopenharmony_ci	int ret;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* Recycle acked descriptors before attempting allocation. */
5998c2ecf20Sopenharmony_ci	rcar_dmac_desc_recycle_acked(chan);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	while (list_empty(&chan->desc.free)) {
6048c2ecf20Sopenharmony_ci		/*
6058c2ecf20Sopenharmony_ci		 * No free descriptors, allocate a page worth of them and try
6068c2ecf20Sopenharmony_ci		 * again, as someone else could race us to get the newly
6078c2ecf20Sopenharmony_ci		 * allocated descriptors. If the allocation fails return an
6088c2ecf20Sopenharmony_ci		 * error.
6098c2ecf20Sopenharmony_ci		 */
6108c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&chan->lock, flags);
6118c2ecf20Sopenharmony_ci		ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
6128c2ecf20Sopenharmony_ci		if (ret < 0)
6138c2ecf20Sopenharmony_ci			return NULL;
6148c2ecf20Sopenharmony_ci		spin_lock_irqsave(&chan->lock, flags);
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
6188c2ecf20Sopenharmony_ci	list_del(&desc->node);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	return desc;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/*
6268c2ecf20Sopenharmony_ci * rcar_dmac_xfer_chunk_alloc - Allocate a page worth of transfer chunks
6278c2ecf20Sopenharmony_ci * @chan: the DMA channel
6288c2ecf20Sopenharmony_ci * @gfp: allocation flags
6298c2ecf20Sopenharmony_ci */
6308c2ecf20Sopenharmony_cistatic int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct rcar_dmac_desc_page *page;
6338c2ecf20Sopenharmony_ci	unsigned long flags;
6348c2ecf20Sopenharmony_ci	LIST_HEAD(list);
6358c2ecf20Sopenharmony_ci	unsigned int i;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	page = (void *)get_zeroed_page(gfp);
6388c2ecf20Sopenharmony_ci	if (!page)
6398c2ecf20Sopenharmony_ci		return -ENOMEM;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	for (i = 0; i < RCAR_DMAC_XFER_CHUNKS_PER_PAGE; ++i) {
6428c2ecf20Sopenharmony_ci		struct rcar_dmac_xfer_chunk *chunk = &page->chunks[i];
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci		list_add_tail(&chunk->node, &list);
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
6488c2ecf20Sopenharmony_ci	list_splice_tail(&list, &chan->desc.chunks_free);
6498c2ecf20Sopenharmony_ci	list_add_tail(&page->node, &chan->desc.pages);
6508c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return 0;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci/*
6568c2ecf20Sopenharmony_ci * rcar_dmac_xfer_chunk_get - Allocate a transfer chunk for a DMA transfer
6578c2ecf20Sopenharmony_ci * @chan: the DMA channel
6588c2ecf20Sopenharmony_ci *
6598c2ecf20Sopenharmony_ci * Locking: This function must be called in a non-atomic context.
6608c2ecf20Sopenharmony_ci *
6618c2ecf20Sopenharmony_ci * Return: A pointer to the allocated transfer chunk descriptor or NULL if no
6628c2ecf20Sopenharmony_ci * descriptor can be allocated.
6638c2ecf20Sopenharmony_ci */
6648c2ecf20Sopenharmony_cistatic struct rcar_dmac_xfer_chunk *
6658c2ecf20Sopenharmony_circar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct rcar_dmac_xfer_chunk *chunk;
6688c2ecf20Sopenharmony_ci	unsigned long flags;
6698c2ecf20Sopenharmony_ci	int ret;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	while (list_empty(&chan->desc.chunks_free)) {
6748c2ecf20Sopenharmony_ci		/*
6758c2ecf20Sopenharmony_ci		 * No free descriptors, allocate a page worth of them and try
6768c2ecf20Sopenharmony_ci		 * again, as someone else could race us to get the newly
6778c2ecf20Sopenharmony_ci		 * allocated descriptors. If the allocation fails return an
6788c2ecf20Sopenharmony_ci		 * error.
6798c2ecf20Sopenharmony_ci		 */
6808c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&chan->lock, flags);
6818c2ecf20Sopenharmony_ci		ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
6828c2ecf20Sopenharmony_ci		if (ret < 0)
6838c2ecf20Sopenharmony_ci			return NULL;
6848c2ecf20Sopenharmony_ci		spin_lock_irqsave(&chan->lock, flags);
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	chunk = list_first_entry(&chan->desc.chunks_free,
6888c2ecf20Sopenharmony_ci				 struct rcar_dmac_xfer_chunk, node);
6898c2ecf20Sopenharmony_ci	list_del(&chunk->node);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	return chunk;
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_cistatic void rcar_dmac_realloc_hwdesc(struct rcar_dmac_chan *chan,
6978c2ecf20Sopenharmony_ci				     struct rcar_dmac_desc *desc, size_t size)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	/*
7008c2ecf20Sopenharmony_ci	 * dma_alloc_coherent() allocates memory in page size increments. To
7018c2ecf20Sopenharmony_ci	 * avoid reallocating the hardware descriptors when the allocated size
7028c2ecf20Sopenharmony_ci	 * wouldn't change align the requested size to a multiple of the page
7038c2ecf20Sopenharmony_ci	 * size.
7048c2ecf20Sopenharmony_ci	 */
7058c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(size);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (desc->hwdescs.size == size)
7088c2ecf20Sopenharmony_ci		return;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (desc->hwdescs.mem) {
7118c2ecf20Sopenharmony_ci		dma_free_coherent(chan->chan.device->dev, desc->hwdescs.size,
7128c2ecf20Sopenharmony_ci				  desc->hwdescs.mem, desc->hwdescs.dma);
7138c2ecf20Sopenharmony_ci		desc->hwdescs.mem = NULL;
7148c2ecf20Sopenharmony_ci		desc->hwdescs.size = 0;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (!size)
7188c2ecf20Sopenharmony_ci		return;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	desc->hwdescs.mem = dma_alloc_coherent(chan->chan.device->dev, size,
7218c2ecf20Sopenharmony_ci					       &desc->hwdescs.dma, GFP_NOWAIT);
7228c2ecf20Sopenharmony_ci	if (!desc->hwdescs.mem)
7238c2ecf20Sopenharmony_ci		return;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	desc->hwdescs.size = size;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int rcar_dmac_fill_hwdesc(struct rcar_dmac_chan *chan,
7298c2ecf20Sopenharmony_ci				 struct rcar_dmac_desc *desc)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	struct rcar_dmac_xfer_chunk *chunk;
7328c2ecf20Sopenharmony_ci	struct rcar_dmac_hw_desc *hwdesc;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	rcar_dmac_realloc_hwdesc(chan, desc, desc->nchunks * sizeof(*hwdesc));
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	hwdesc = desc->hwdescs.mem;
7378c2ecf20Sopenharmony_ci	if (!hwdesc)
7388c2ecf20Sopenharmony_ci		return -ENOMEM;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	list_for_each_entry(chunk, &desc->chunks, node) {
7418c2ecf20Sopenharmony_ci		hwdesc->sar = chunk->src_addr;
7428c2ecf20Sopenharmony_ci		hwdesc->dar = chunk->dst_addr;
7438c2ecf20Sopenharmony_ci		hwdesc->tcr = chunk->size >> desc->xfer_shift;
7448c2ecf20Sopenharmony_ci		hwdesc++;
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	return 0;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
7518c2ecf20Sopenharmony_ci * Stop and reset
7528c2ecf20Sopenharmony_ci */
7538c2ecf20Sopenharmony_cistatic void rcar_dmac_chcr_de_barrier(struct rcar_dmac_chan *chan)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	u32 chcr;
7568c2ecf20Sopenharmony_ci	unsigned int i;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	/*
7598c2ecf20Sopenharmony_ci	 * Ensure that the setting of the DE bit is actually 0 after
7608c2ecf20Sopenharmony_ci	 * clearing it.
7618c2ecf20Sopenharmony_ci	 */
7628c2ecf20Sopenharmony_ci	for (i = 0; i < 1024; i++) {
7638c2ecf20Sopenharmony_ci		chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
7648c2ecf20Sopenharmony_ci		if (!(chcr & RCAR_DMACHCR_DE))
7658c2ecf20Sopenharmony_ci			return;
7668c2ecf20Sopenharmony_ci		udelay(1);
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	dev_err(chan->chan.device->dev, "CHCR DE check error\n");
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic void rcar_dmac_clear_chcr_de(struct rcar_dmac_chan *chan)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* set DE=0 and flush remaining data */
7778c2ecf20Sopenharmony_ci	rcar_dmac_chan_write(chan, RCAR_DMACHCR, (chcr & ~RCAR_DMACHCR_DE));
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/* make sure all remaining data was flushed */
7808c2ecf20Sopenharmony_ci	rcar_dmac_chcr_de_barrier(chan);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE |
7888c2ecf20Sopenharmony_ci		  RCAR_DMACHCR_TE | RCAR_DMACHCR_DE |
7898c2ecf20Sopenharmony_ci		  RCAR_DMACHCR_CAE | RCAR_DMACHCR_CAIE);
7908c2ecf20Sopenharmony_ci	rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
7918c2ecf20Sopenharmony_ci	rcar_dmac_chcr_de_barrier(chan);
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_cistatic void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc, *_desc;
7978c2ecf20Sopenharmony_ci	unsigned long flags;
7988c2ecf20Sopenharmony_ci	LIST_HEAD(descs);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chan->lock, flags);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/* Move all non-free descriptors to the local lists. */
8038c2ecf20Sopenharmony_ci	list_splice_init(&chan->desc.pending, &descs);
8048c2ecf20Sopenharmony_ci	list_splice_init(&chan->desc.active, &descs);
8058c2ecf20Sopenharmony_ci	list_splice_init(&chan->desc.done, &descs);
8068c2ecf20Sopenharmony_ci	list_splice_init(&chan->desc.wait, &descs);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	chan->desc.running = NULL;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chan->lock, flags);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	list_for_each_entry_safe(desc, _desc, &descs, node) {
8138c2ecf20Sopenharmony_ci		list_del(&desc->node);
8148c2ecf20Sopenharmony_ci		rcar_dmac_desc_put(chan, desc);
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_cistatic void rcar_dmac_stop_all_chan(struct rcar_dmac *dmac)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	unsigned int i;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	/* Stop all channels. */
8238c2ecf20Sopenharmony_ci	for (i = 0; i < dmac->n_channels; ++i) {
8248c2ecf20Sopenharmony_ci		struct rcar_dmac_chan *chan = &dmac->channels[i];
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		if (!(dmac->channels_mask & BIT(i)))
8278c2ecf20Sopenharmony_ci			continue;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		/* Stop and reinitialize the channel. */
8308c2ecf20Sopenharmony_ci		spin_lock_irq(&chan->lock);
8318c2ecf20Sopenharmony_ci		rcar_dmac_chan_halt(chan);
8328c2ecf20Sopenharmony_ci		spin_unlock_irq(&chan->lock);
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic int rcar_dmac_chan_pause(struct dma_chan *chan)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	unsigned long flags;
8398c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rchan->lock, flags);
8428c2ecf20Sopenharmony_ci	rcar_dmac_clear_chcr_de(rchan);
8438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rchan->lock, flags);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	return 0;
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
8498c2ecf20Sopenharmony_ci * Descriptors preparation
8508c2ecf20Sopenharmony_ci */
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic void rcar_dmac_chan_configure_desc(struct rcar_dmac_chan *chan,
8538c2ecf20Sopenharmony_ci					  struct rcar_dmac_desc *desc)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	static const u32 chcr_ts[] = {
8568c2ecf20Sopenharmony_ci		RCAR_DMACHCR_TS_1B, RCAR_DMACHCR_TS_2B,
8578c2ecf20Sopenharmony_ci		RCAR_DMACHCR_TS_4B, RCAR_DMACHCR_TS_8B,
8588c2ecf20Sopenharmony_ci		RCAR_DMACHCR_TS_16B, RCAR_DMACHCR_TS_32B,
8598c2ecf20Sopenharmony_ci		RCAR_DMACHCR_TS_64B,
8608c2ecf20Sopenharmony_ci	};
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	unsigned int xfer_size;
8638c2ecf20Sopenharmony_ci	u32 chcr;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	switch (desc->direction) {
8668c2ecf20Sopenharmony_ci	case DMA_DEV_TO_MEM:
8678c2ecf20Sopenharmony_ci		chcr = RCAR_DMACHCR_DM_INC | RCAR_DMACHCR_SM_FIXED
8688c2ecf20Sopenharmony_ci		     | RCAR_DMACHCR_RS_DMARS;
8698c2ecf20Sopenharmony_ci		xfer_size = chan->src.xfer_size;
8708c2ecf20Sopenharmony_ci		break;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	case DMA_MEM_TO_DEV:
8738c2ecf20Sopenharmony_ci		chcr = RCAR_DMACHCR_DM_FIXED | RCAR_DMACHCR_SM_INC
8748c2ecf20Sopenharmony_ci		     | RCAR_DMACHCR_RS_DMARS;
8758c2ecf20Sopenharmony_ci		xfer_size = chan->dst.xfer_size;
8768c2ecf20Sopenharmony_ci		break;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	case DMA_MEM_TO_MEM:
8798c2ecf20Sopenharmony_ci	default:
8808c2ecf20Sopenharmony_ci		chcr = RCAR_DMACHCR_DM_INC | RCAR_DMACHCR_SM_INC
8818c2ecf20Sopenharmony_ci		     | RCAR_DMACHCR_RS_AUTO;
8828c2ecf20Sopenharmony_ci		xfer_size = RCAR_DMAC_MEMCPY_XFER_SIZE;
8838c2ecf20Sopenharmony_ci		break;
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	desc->xfer_shift = ilog2(xfer_size);
8878c2ecf20Sopenharmony_ci	desc->chcr = chcr | chcr_ts[desc->xfer_shift];
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci/*
8918c2ecf20Sopenharmony_ci * rcar_dmac_chan_prep_sg - prepare transfer descriptors from an SG list
8928c2ecf20Sopenharmony_ci *
8938c2ecf20Sopenharmony_ci * Common routine for public (MEMCPY) and slave DMA. The MEMCPY case is also
8948c2ecf20Sopenharmony_ci * converted to scatter-gather to guarantee consistent locking and a correct
8958c2ecf20Sopenharmony_ci * list manipulation. For slave DMA direction carries the usual meaning, and,
8968c2ecf20Sopenharmony_ci * logically, the SG list is RAM and the addr variable contains slave address,
8978c2ecf20Sopenharmony_ci * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_MEM_TO_MEM
8988c2ecf20Sopenharmony_ci * and the SG list contains only one element and points at the source buffer.
8998c2ecf20Sopenharmony_ci */
9008c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *
9018c2ecf20Sopenharmony_circar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl,
9028c2ecf20Sopenharmony_ci		       unsigned int sg_len, dma_addr_t dev_addr,
9038c2ecf20Sopenharmony_ci		       enum dma_transfer_direction dir, unsigned long dma_flags,
9048c2ecf20Sopenharmony_ci		       bool cyclic)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	struct rcar_dmac_xfer_chunk *chunk;
9078c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc;
9088c2ecf20Sopenharmony_ci	struct scatterlist *sg;
9098c2ecf20Sopenharmony_ci	unsigned int nchunks = 0;
9108c2ecf20Sopenharmony_ci	unsigned int max_chunk_size;
9118c2ecf20Sopenharmony_ci	unsigned int full_size = 0;
9128c2ecf20Sopenharmony_ci	bool cross_boundary = false;
9138c2ecf20Sopenharmony_ci	unsigned int i;
9148c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
9158c2ecf20Sopenharmony_ci	u32 high_dev_addr;
9168c2ecf20Sopenharmony_ci	u32 high_mem_addr;
9178c2ecf20Sopenharmony_ci#endif
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	desc = rcar_dmac_desc_get(chan);
9208c2ecf20Sopenharmony_ci	if (!desc)
9218c2ecf20Sopenharmony_ci		return NULL;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	desc->async_tx.flags = dma_flags;
9248c2ecf20Sopenharmony_ci	desc->async_tx.cookie = -EBUSY;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	desc->cyclic = cyclic;
9278c2ecf20Sopenharmony_ci	desc->direction = dir;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	rcar_dmac_chan_configure_desc(chan, desc);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	/*
9348c2ecf20Sopenharmony_ci	 * Allocate and fill the transfer chunk descriptors. We own the only
9358c2ecf20Sopenharmony_ci	 * reference to the DMA descriptor, there's no need for locking.
9368c2ecf20Sopenharmony_ci	 */
9378c2ecf20Sopenharmony_ci	for_each_sg(sgl, sg, sg_len, i) {
9388c2ecf20Sopenharmony_ci		dma_addr_t mem_addr = sg_dma_address(sg);
9398c2ecf20Sopenharmony_ci		unsigned int len = sg_dma_len(sg);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		full_size += len;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
9448c2ecf20Sopenharmony_ci		if (i == 0) {
9458c2ecf20Sopenharmony_ci			high_dev_addr = dev_addr >> 32;
9468c2ecf20Sopenharmony_ci			high_mem_addr = mem_addr >> 32;
9478c2ecf20Sopenharmony_ci		}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci		if ((dev_addr >> 32 != high_dev_addr) ||
9508c2ecf20Sopenharmony_ci		    (mem_addr >> 32 != high_mem_addr))
9518c2ecf20Sopenharmony_ci			cross_boundary = true;
9528c2ecf20Sopenharmony_ci#endif
9538c2ecf20Sopenharmony_ci		while (len) {
9548c2ecf20Sopenharmony_ci			unsigned int size = min(len, max_chunk_size);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
9578c2ecf20Sopenharmony_ci			/*
9588c2ecf20Sopenharmony_ci			 * Prevent individual transfers from crossing 4GB
9598c2ecf20Sopenharmony_ci			 * boundaries.
9608c2ecf20Sopenharmony_ci			 */
9618c2ecf20Sopenharmony_ci			if (dev_addr >> 32 != (dev_addr + size - 1) >> 32) {
9628c2ecf20Sopenharmony_ci				size = ALIGN(dev_addr, 1ULL << 32) - dev_addr;
9638c2ecf20Sopenharmony_ci				cross_boundary = true;
9648c2ecf20Sopenharmony_ci			}
9658c2ecf20Sopenharmony_ci			if (mem_addr >> 32 != (mem_addr + size - 1) >> 32) {
9668c2ecf20Sopenharmony_ci				size = ALIGN(mem_addr, 1ULL << 32) - mem_addr;
9678c2ecf20Sopenharmony_ci				cross_boundary = true;
9688c2ecf20Sopenharmony_ci			}
9698c2ecf20Sopenharmony_ci#endif
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci			chunk = rcar_dmac_xfer_chunk_get(chan);
9728c2ecf20Sopenharmony_ci			if (!chunk) {
9738c2ecf20Sopenharmony_ci				rcar_dmac_desc_put(chan, desc);
9748c2ecf20Sopenharmony_ci				return NULL;
9758c2ecf20Sopenharmony_ci			}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci			if (dir == DMA_DEV_TO_MEM) {
9788c2ecf20Sopenharmony_ci				chunk->src_addr = dev_addr;
9798c2ecf20Sopenharmony_ci				chunk->dst_addr = mem_addr;
9808c2ecf20Sopenharmony_ci			} else {
9818c2ecf20Sopenharmony_ci				chunk->src_addr = mem_addr;
9828c2ecf20Sopenharmony_ci				chunk->dst_addr = dev_addr;
9838c2ecf20Sopenharmony_ci			}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci			chunk->size = size;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci			dev_dbg(chan->chan.device->dev,
9888c2ecf20Sopenharmony_ci				"chan%u: chunk %p/%p sgl %u@%p, %u/%u %pad -> %pad\n",
9898c2ecf20Sopenharmony_ci				chan->index, chunk, desc, i, sg, size, len,
9908c2ecf20Sopenharmony_ci				&chunk->src_addr, &chunk->dst_addr);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci			mem_addr += size;
9938c2ecf20Sopenharmony_ci			if (dir == DMA_MEM_TO_MEM)
9948c2ecf20Sopenharmony_ci				dev_addr += size;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci			len -= size;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci			list_add_tail(&chunk->node, &desc->chunks);
9998c2ecf20Sopenharmony_ci			nchunks++;
10008c2ecf20Sopenharmony_ci		}
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	desc->nchunks = nchunks;
10048c2ecf20Sopenharmony_ci	desc->size = full_size;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	/*
10078c2ecf20Sopenharmony_ci	 * Use hardware descriptor lists if possible when more than one chunk
10088c2ecf20Sopenharmony_ci	 * needs to be transferred (otherwise they don't make much sense).
10098c2ecf20Sopenharmony_ci	 *
10108c2ecf20Sopenharmony_ci	 * Source/Destination address should be located in same 4GiB region
10118c2ecf20Sopenharmony_ci	 * in the 40bit address space when it uses Hardware descriptor,
10128c2ecf20Sopenharmony_ci	 * and cross_boundary is checking it.
10138c2ecf20Sopenharmony_ci	 */
10148c2ecf20Sopenharmony_ci	desc->hwdescs.use = !cross_boundary && nchunks > 1;
10158c2ecf20Sopenharmony_ci	if (desc->hwdescs.use) {
10168c2ecf20Sopenharmony_ci		if (rcar_dmac_fill_hwdesc(chan, desc) < 0)
10178c2ecf20Sopenharmony_ci			desc->hwdescs.use = false;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	return &desc->async_tx;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
10248c2ecf20Sopenharmony_ci * DMA engine operations
10258c2ecf20Sopenharmony_ci */
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_cistatic int rcar_dmac_alloc_chan_resources(struct dma_chan *chan)
10288c2ecf20Sopenharmony_ci{
10298c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
10308c2ecf20Sopenharmony_ci	int ret;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.chunks_free);
10338c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.pages);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	/* Preallocate descriptors. */
10368c2ecf20Sopenharmony_ci	ret = rcar_dmac_xfer_chunk_alloc(rchan, GFP_KERNEL);
10378c2ecf20Sopenharmony_ci	if (ret < 0)
10388c2ecf20Sopenharmony_ci		return -ENOMEM;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	ret = rcar_dmac_desc_alloc(rchan, GFP_KERNEL);
10418c2ecf20Sopenharmony_ci	if (ret < 0)
10428c2ecf20Sopenharmony_ci		return -ENOMEM;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	return pm_runtime_get_sync(chan->device->dev);
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_cistatic void rcar_dmac_free_chan_resources(struct dma_chan *chan)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
10508c2ecf20Sopenharmony_ci	struct rcar_dmac *dmac = to_rcar_dmac(chan->device);
10518c2ecf20Sopenharmony_ci	struct rcar_dmac_chan_map *map = &rchan->map;
10528c2ecf20Sopenharmony_ci	struct rcar_dmac_desc_page *page, *_page;
10538c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc;
10548c2ecf20Sopenharmony_ci	LIST_HEAD(list);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	/* Protect against ISR */
10578c2ecf20Sopenharmony_ci	spin_lock_irq(&rchan->lock);
10588c2ecf20Sopenharmony_ci	rcar_dmac_chan_halt(rchan);
10598c2ecf20Sopenharmony_ci	spin_unlock_irq(&rchan->lock);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	/*
10628c2ecf20Sopenharmony_ci	 * Now no new interrupts will occur, but one might already be
10638c2ecf20Sopenharmony_ci	 * running. Wait for it to finish before freeing resources.
10648c2ecf20Sopenharmony_ci	 */
10658c2ecf20Sopenharmony_ci	synchronize_irq(rchan->irq);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (rchan->mid_rid >= 0) {
10688c2ecf20Sopenharmony_ci		/* The caller is holding dma_list_mutex */
10698c2ecf20Sopenharmony_ci		clear_bit(rchan->mid_rid, dmac->modules);
10708c2ecf20Sopenharmony_ci		rchan->mid_rid = -EINVAL;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	list_splice_init(&rchan->desc.free, &list);
10748c2ecf20Sopenharmony_ci	list_splice_init(&rchan->desc.pending, &list);
10758c2ecf20Sopenharmony_ci	list_splice_init(&rchan->desc.active, &list);
10768c2ecf20Sopenharmony_ci	list_splice_init(&rchan->desc.done, &list);
10778c2ecf20Sopenharmony_ci	list_splice_init(&rchan->desc.wait, &list);
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	rchan->desc.running = NULL;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	list_for_each_entry(desc, &list, node)
10828c2ecf20Sopenharmony_ci		rcar_dmac_realloc_hwdesc(rchan, desc, 0);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	list_for_each_entry_safe(page, _page, &rchan->desc.pages, node) {
10858c2ecf20Sopenharmony_ci		list_del(&page->node);
10868c2ecf20Sopenharmony_ci		free_page((unsigned long)page);
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	/* Remove slave mapping if present. */
10908c2ecf20Sopenharmony_ci	if (map->slave.xfer_size) {
10918c2ecf20Sopenharmony_ci		dma_unmap_resource(chan->device->dev, map->addr,
10928c2ecf20Sopenharmony_ci				   map->slave.xfer_size, map->dir, 0);
10938c2ecf20Sopenharmony_ci		map->slave.xfer_size = 0;
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	pm_runtime_put(chan->device->dev);
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *
11008c2ecf20Sopenharmony_circar_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
11018c2ecf20Sopenharmony_ci			  dma_addr_t dma_src, size_t len, unsigned long flags)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
11048c2ecf20Sopenharmony_ci	struct scatterlist sgl;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	if (!len)
11078c2ecf20Sopenharmony_ci		return NULL;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	sg_init_table(&sgl, 1);
11108c2ecf20Sopenharmony_ci	sg_set_page(&sgl, pfn_to_page(PFN_DOWN(dma_src)), len,
11118c2ecf20Sopenharmony_ci		    offset_in_page(dma_src));
11128c2ecf20Sopenharmony_ci	sg_dma_address(&sgl) = dma_src;
11138c2ecf20Sopenharmony_ci	sg_dma_len(&sgl) = len;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	return rcar_dmac_chan_prep_sg(rchan, &sgl, 1, dma_dest,
11168c2ecf20Sopenharmony_ci				      DMA_MEM_TO_MEM, flags, false);
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic int rcar_dmac_map_slave_addr(struct dma_chan *chan,
11208c2ecf20Sopenharmony_ci				    enum dma_transfer_direction dir)
11218c2ecf20Sopenharmony_ci{
11228c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
11238c2ecf20Sopenharmony_ci	struct rcar_dmac_chan_map *map = &rchan->map;
11248c2ecf20Sopenharmony_ci	phys_addr_t dev_addr;
11258c2ecf20Sopenharmony_ci	size_t dev_size;
11268c2ecf20Sopenharmony_ci	enum dma_data_direction dev_dir;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM) {
11298c2ecf20Sopenharmony_ci		dev_addr = rchan->src.slave_addr;
11308c2ecf20Sopenharmony_ci		dev_size = rchan->src.xfer_size;
11318c2ecf20Sopenharmony_ci		dev_dir = DMA_TO_DEVICE;
11328c2ecf20Sopenharmony_ci	} else {
11338c2ecf20Sopenharmony_ci		dev_addr = rchan->dst.slave_addr;
11348c2ecf20Sopenharmony_ci		dev_size = rchan->dst.xfer_size;
11358c2ecf20Sopenharmony_ci		dev_dir = DMA_FROM_DEVICE;
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	/* Reuse current map if possible. */
11398c2ecf20Sopenharmony_ci	if (dev_addr == map->slave.slave_addr &&
11408c2ecf20Sopenharmony_ci	    dev_size == map->slave.xfer_size &&
11418c2ecf20Sopenharmony_ci	    dev_dir == map->dir)
11428c2ecf20Sopenharmony_ci		return 0;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/* Remove old mapping if present. */
11458c2ecf20Sopenharmony_ci	if (map->slave.xfer_size)
11468c2ecf20Sopenharmony_ci		dma_unmap_resource(chan->device->dev, map->addr,
11478c2ecf20Sopenharmony_ci				   map->slave.xfer_size, map->dir, 0);
11488c2ecf20Sopenharmony_ci	map->slave.xfer_size = 0;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	/* Create new slave address map. */
11518c2ecf20Sopenharmony_ci	map->addr = dma_map_resource(chan->device->dev, dev_addr, dev_size,
11528c2ecf20Sopenharmony_ci				     dev_dir, 0);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (dma_mapping_error(chan->device->dev, map->addr)) {
11558c2ecf20Sopenharmony_ci		dev_err(chan->device->dev,
11568c2ecf20Sopenharmony_ci			"chan%u: failed to map %zx@%pap", rchan->index,
11578c2ecf20Sopenharmony_ci			dev_size, &dev_addr);
11588c2ecf20Sopenharmony_ci		return -EIO;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	dev_dbg(chan->device->dev, "chan%u: map %zx@%pap to %pad dir: %s\n",
11628c2ecf20Sopenharmony_ci		rchan->index, dev_size, &dev_addr, &map->addr,
11638c2ecf20Sopenharmony_ci		dev_dir == DMA_TO_DEVICE ? "DMA_TO_DEVICE" : "DMA_FROM_DEVICE");
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	map->slave.slave_addr = dev_addr;
11668c2ecf20Sopenharmony_ci	map->slave.xfer_size = dev_size;
11678c2ecf20Sopenharmony_ci	map->dir = dev_dir;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	return 0;
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *
11738c2ecf20Sopenharmony_circar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
11748c2ecf20Sopenharmony_ci			unsigned int sg_len, enum dma_transfer_direction dir,
11758c2ecf20Sopenharmony_ci			unsigned long flags, void *context)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	/* Someone calling slave DMA on a generic channel? */
11808c2ecf20Sopenharmony_ci	if (rchan->mid_rid < 0 || !sg_len || !sg_dma_len(sgl)) {
11818c2ecf20Sopenharmony_ci		dev_warn(chan->device->dev,
11828c2ecf20Sopenharmony_ci			 "%s: bad parameter: len=%d, id=%d\n",
11838c2ecf20Sopenharmony_ci			 __func__, sg_len, rchan->mid_rid);
11848c2ecf20Sopenharmony_ci		return NULL;
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	if (rcar_dmac_map_slave_addr(chan, dir))
11888c2ecf20Sopenharmony_ci		return NULL;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	return rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, rchan->map.addr,
11918c2ecf20Sopenharmony_ci				      dir, flags, false);
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci#define RCAR_DMAC_MAX_SG_LEN	32
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *
11978c2ecf20Sopenharmony_circar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
11988c2ecf20Sopenharmony_ci			  size_t buf_len, size_t period_len,
11998c2ecf20Sopenharmony_ci			  enum dma_transfer_direction dir, unsigned long flags)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
12028c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
12038c2ecf20Sopenharmony_ci	struct scatterlist *sgl;
12048c2ecf20Sopenharmony_ci	unsigned int sg_len;
12058c2ecf20Sopenharmony_ci	unsigned int i;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	/* Someone calling slave DMA on a generic channel? */
12088c2ecf20Sopenharmony_ci	if (rchan->mid_rid < 0 || buf_len < period_len) {
12098c2ecf20Sopenharmony_ci		dev_warn(chan->device->dev,
12108c2ecf20Sopenharmony_ci			"%s: bad parameter: buf_len=%zu, period_len=%zu, id=%d\n",
12118c2ecf20Sopenharmony_ci			__func__, buf_len, period_len, rchan->mid_rid);
12128c2ecf20Sopenharmony_ci		return NULL;
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	if (rcar_dmac_map_slave_addr(chan, dir))
12168c2ecf20Sopenharmony_ci		return NULL;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	sg_len = buf_len / period_len;
12198c2ecf20Sopenharmony_ci	if (sg_len > RCAR_DMAC_MAX_SG_LEN) {
12208c2ecf20Sopenharmony_ci		dev_err(chan->device->dev,
12218c2ecf20Sopenharmony_ci			"chan%u: sg length %d exceeds limit %d",
12228c2ecf20Sopenharmony_ci			rchan->index, sg_len, RCAR_DMAC_MAX_SG_LEN);
12238c2ecf20Sopenharmony_ci		return NULL;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	/*
12278c2ecf20Sopenharmony_ci	 * Allocate the sg list dynamically as it would consume too much stack
12288c2ecf20Sopenharmony_ci	 * space.
12298c2ecf20Sopenharmony_ci	 */
12308c2ecf20Sopenharmony_ci	sgl = kmalloc_array(sg_len, sizeof(*sgl), GFP_NOWAIT);
12318c2ecf20Sopenharmony_ci	if (!sgl)
12328c2ecf20Sopenharmony_ci		return NULL;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	sg_init_table(sgl, sg_len);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	for (i = 0; i < sg_len; ++i) {
12378c2ecf20Sopenharmony_ci		dma_addr_t src = buf_addr + (period_len * i);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci		sg_set_page(&sgl[i], pfn_to_page(PFN_DOWN(src)), period_len,
12408c2ecf20Sopenharmony_ci			    offset_in_page(src));
12418c2ecf20Sopenharmony_ci		sg_dma_address(&sgl[i]) = src;
12428c2ecf20Sopenharmony_ci		sg_dma_len(&sgl[i]) = period_len;
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	desc = rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, rchan->map.addr,
12468c2ecf20Sopenharmony_ci				      dir, flags, true);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	kfree(sgl);
12498c2ecf20Sopenharmony_ci	return desc;
12508c2ecf20Sopenharmony_ci}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_cistatic int rcar_dmac_device_config(struct dma_chan *chan,
12538c2ecf20Sopenharmony_ci				   struct dma_slave_config *cfg)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	/*
12588c2ecf20Sopenharmony_ci	 * We could lock this, but you shouldn't be configuring the
12598c2ecf20Sopenharmony_ci	 * channel, while using it...
12608c2ecf20Sopenharmony_ci	 */
12618c2ecf20Sopenharmony_ci	rchan->src.slave_addr = cfg->src_addr;
12628c2ecf20Sopenharmony_ci	rchan->dst.slave_addr = cfg->dst_addr;
12638c2ecf20Sopenharmony_ci	rchan->src.xfer_size = cfg->src_addr_width;
12648c2ecf20Sopenharmony_ci	rchan->dst.xfer_size = cfg->dst_addr_width;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	return 0;
12678c2ecf20Sopenharmony_ci}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_cistatic int rcar_dmac_chan_terminate_all(struct dma_chan *chan)
12708c2ecf20Sopenharmony_ci{
12718c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
12728c2ecf20Sopenharmony_ci	unsigned long flags;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rchan->lock, flags);
12758c2ecf20Sopenharmony_ci	rcar_dmac_chan_halt(rchan);
12768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rchan->lock, flags);
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	/*
12798c2ecf20Sopenharmony_ci	 * FIXME: No new interrupt can occur now, but the IRQ thread might still
12808c2ecf20Sopenharmony_ci	 * be running.
12818c2ecf20Sopenharmony_ci	 */
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	rcar_dmac_chan_reinit(rchan);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	return 0;
12868c2ecf20Sopenharmony_ci}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_cistatic unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
12898c2ecf20Sopenharmony_ci					       dma_cookie_t cookie)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc = chan->desc.running;
12928c2ecf20Sopenharmony_ci	struct rcar_dmac_xfer_chunk *running = NULL;
12938c2ecf20Sopenharmony_ci	struct rcar_dmac_xfer_chunk *chunk;
12948c2ecf20Sopenharmony_ci	enum dma_status status;
12958c2ecf20Sopenharmony_ci	unsigned int residue = 0;
12968c2ecf20Sopenharmony_ci	unsigned int dptr = 0;
12978c2ecf20Sopenharmony_ci	unsigned int chcrb;
12988c2ecf20Sopenharmony_ci	unsigned int tcrb;
12998c2ecf20Sopenharmony_ci	unsigned int i;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	if (!desc)
13028c2ecf20Sopenharmony_ci		return 0;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	/*
13058c2ecf20Sopenharmony_ci	 * If the cookie corresponds to a descriptor that has been completed
13068c2ecf20Sopenharmony_ci	 * there is no residue. The same check has already been performed by the
13078c2ecf20Sopenharmony_ci	 * caller but without holding the channel lock, so the descriptor could
13088c2ecf20Sopenharmony_ci	 * now be complete.
13098c2ecf20Sopenharmony_ci	 */
13108c2ecf20Sopenharmony_ci	status = dma_cookie_status(&chan->chan, cookie, NULL);
13118c2ecf20Sopenharmony_ci	if (status == DMA_COMPLETE)
13128c2ecf20Sopenharmony_ci		return 0;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	/*
13158c2ecf20Sopenharmony_ci	 * If the cookie doesn't correspond to the currently running transfer
13168c2ecf20Sopenharmony_ci	 * then the descriptor hasn't been processed yet, and the residue is
13178c2ecf20Sopenharmony_ci	 * equal to the full descriptor size.
13188c2ecf20Sopenharmony_ci	 * Also, a client driver is possible to call this function before
13198c2ecf20Sopenharmony_ci	 * rcar_dmac_isr_channel_thread() runs. In this case, the "desc.running"
13208c2ecf20Sopenharmony_ci	 * will be the next descriptor, and the done list will appear. So, if
13218c2ecf20Sopenharmony_ci	 * the argument cookie matches the done list's cookie, we can assume
13228c2ecf20Sopenharmony_ci	 * the residue is zero.
13238c2ecf20Sopenharmony_ci	 */
13248c2ecf20Sopenharmony_ci	if (cookie != desc->async_tx.cookie) {
13258c2ecf20Sopenharmony_ci		list_for_each_entry(desc, &chan->desc.done, node) {
13268c2ecf20Sopenharmony_ci			if (cookie == desc->async_tx.cookie)
13278c2ecf20Sopenharmony_ci				return 0;
13288c2ecf20Sopenharmony_ci		}
13298c2ecf20Sopenharmony_ci		list_for_each_entry(desc, &chan->desc.pending, node) {
13308c2ecf20Sopenharmony_ci			if (cookie == desc->async_tx.cookie)
13318c2ecf20Sopenharmony_ci				return desc->size;
13328c2ecf20Sopenharmony_ci		}
13338c2ecf20Sopenharmony_ci		list_for_each_entry(desc, &chan->desc.active, node) {
13348c2ecf20Sopenharmony_ci			if (cookie == desc->async_tx.cookie)
13358c2ecf20Sopenharmony_ci				return desc->size;
13368c2ecf20Sopenharmony_ci		}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci		/*
13398c2ecf20Sopenharmony_ci		 * No descriptor found for the cookie, there's thus no residue.
13408c2ecf20Sopenharmony_ci		 * This shouldn't happen if the calling driver passes a correct
13418c2ecf20Sopenharmony_ci		 * cookie value.
13428c2ecf20Sopenharmony_ci		 */
13438c2ecf20Sopenharmony_ci		WARN(1, "No descriptor for cookie!");
13448c2ecf20Sopenharmony_ci		return 0;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	/*
13488c2ecf20Sopenharmony_ci	 * We need to read two registers.
13498c2ecf20Sopenharmony_ci	 * Make sure the control register does not skip to next chunk
13508c2ecf20Sopenharmony_ci	 * while reading the counter.
13518c2ecf20Sopenharmony_ci	 * Trying it 3 times should be enough: Initial read, retry, retry
13528c2ecf20Sopenharmony_ci	 * for the paranoid.
13538c2ecf20Sopenharmony_ci	 */
13548c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
13558c2ecf20Sopenharmony_ci		chcrb = rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
13568c2ecf20Sopenharmony_ci					    RCAR_DMACHCRB_DPTR_MASK;
13578c2ecf20Sopenharmony_ci		tcrb = rcar_dmac_chan_read(chan, RCAR_DMATCRB);
13588c2ecf20Sopenharmony_ci		/* Still the same? */
13598c2ecf20Sopenharmony_ci		if (chcrb == (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
13608c2ecf20Sopenharmony_ci			      RCAR_DMACHCRB_DPTR_MASK))
13618c2ecf20Sopenharmony_ci			break;
13628c2ecf20Sopenharmony_ci	}
13638c2ecf20Sopenharmony_ci	WARN_ONCE(i >= 3, "residue might be not continuous!");
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	/*
13668c2ecf20Sopenharmony_ci	 * In descriptor mode the descriptor running pointer is not maintained
13678c2ecf20Sopenharmony_ci	 * by the interrupt handler, find the running descriptor from the
13688c2ecf20Sopenharmony_ci	 * descriptor pointer field in the CHCRB register. In non-descriptor
13698c2ecf20Sopenharmony_ci	 * mode just use the running descriptor pointer.
13708c2ecf20Sopenharmony_ci	 */
13718c2ecf20Sopenharmony_ci	if (desc->hwdescs.use) {
13728c2ecf20Sopenharmony_ci		dptr = chcrb >> RCAR_DMACHCRB_DPTR_SHIFT;
13738c2ecf20Sopenharmony_ci		if (dptr == 0)
13748c2ecf20Sopenharmony_ci			dptr = desc->nchunks;
13758c2ecf20Sopenharmony_ci		dptr--;
13768c2ecf20Sopenharmony_ci		WARN_ON(dptr >= desc->nchunks);
13778c2ecf20Sopenharmony_ci	} else {
13788c2ecf20Sopenharmony_ci		running = desc->running;
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	/* Compute the size of all chunks still to be transferred. */
13828c2ecf20Sopenharmony_ci	list_for_each_entry_reverse(chunk, &desc->chunks, node) {
13838c2ecf20Sopenharmony_ci		if (chunk == running || ++dptr == desc->nchunks)
13848c2ecf20Sopenharmony_ci			break;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		residue += chunk->size;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* Add the residue for the current chunk. */
13908c2ecf20Sopenharmony_ci	residue += tcrb << desc->xfer_shift;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	return residue;
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_cistatic enum dma_status rcar_dmac_tx_status(struct dma_chan *chan,
13968c2ecf20Sopenharmony_ci					   dma_cookie_t cookie,
13978c2ecf20Sopenharmony_ci					   struct dma_tx_state *txstate)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
14008c2ecf20Sopenharmony_ci	enum dma_status status;
14018c2ecf20Sopenharmony_ci	unsigned long flags;
14028c2ecf20Sopenharmony_ci	unsigned int residue;
14038c2ecf20Sopenharmony_ci	bool cyclic;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	status = dma_cookie_status(chan, cookie, txstate);
14068c2ecf20Sopenharmony_ci	if (status == DMA_COMPLETE || !txstate)
14078c2ecf20Sopenharmony_ci		return status;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rchan->lock, flags);
14108c2ecf20Sopenharmony_ci	residue = rcar_dmac_chan_get_residue(rchan, cookie);
14118c2ecf20Sopenharmony_ci	cyclic = rchan->desc.running ? rchan->desc.running->cyclic : false;
14128c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rchan->lock, flags);
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	/* if there's no residue, the cookie is complete */
14158c2ecf20Sopenharmony_ci	if (!residue && !cyclic)
14168c2ecf20Sopenharmony_ci		return DMA_COMPLETE;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	dma_set_residue(txstate, residue);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	return status;
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_cistatic void rcar_dmac_issue_pending(struct dma_chan *chan)
14248c2ecf20Sopenharmony_ci{
14258c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
14268c2ecf20Sopenharmony_ci	unsigned long flags;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&rchan->lock, flags);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (list_empty(&rchan->desc.pending))
14318c2ecf20Sopenharmony_ci		goto done;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	/* Append the pending list to the active list. */
14348c2ecf20Sopenharmony_ci	list_splice_tail_init(&rchan->desc.pending, &rchan->desc.active);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/*
14378c2ecf20Sopenharmony_ci	 * If no transfer is running pick the first descriptor from the active
14388c2ecf20Sopenharmony_ci	 * list and start the transfer.
14398c2ecf20Sopenharmony_ci	 */
14408c2ecf20Sopenharmony_ci	if (!rchan->desc.running) {
14418c2ecf20Sopenharmony_ci		struct rcar_dmac_desc *desc;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci		desc = list_first_entry(&rchan->desc.active,
14448c2ecf20Sopenharmony_ci					struct rcar_dmac_desc, node);
14458c2ecf20Sopenharmony_ci		rchan->desc.running = desc;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci		rcar_dmac_chan_start_xfer(rchan);
14488c2ecf20Sopenharmony_ci	}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cidone:
14518c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&rchan->lock, flags);
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_cistatic void rcar_dmac_device_synchronize(struct dma_chan *chan)
14558c2ecf20Sopenharmony_ci{
14568c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	synchronize_irq(rchan->irq);
14598c2ecf20Sopenharmony_ci}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
14628c2ecf20Sopenharmony_ci * IRQ handling
14638c2ecf20Sopenharmony_ci */
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_cistatic irqreturn_t rcar_dmac_isr_desc_stage_end(struct rcar_dmac_chan *chan)
14668c2ecf20Sopenharmony_ci{
14678c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc = chan->desc.running;
14688c2ecf20Sopenharmony_ci	unsigned int stage;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if (WARN_ON(!desc || !desc->cyclic)) {
14718c2ecf20Sopenharmony_ci		/*
14728c2ecf20Sopenharmony_ci		 * This should never happen, there should always be a running
14738c2ecf20Sopenharmony_ci		 * cyclic descriptor when a descriptor stage end interrupt is
14748c2ecf20Sopenharmony_ci		 * triggered. Warn and return.
14758c2ecf20Sopenharmony_ci		 */
14768c2ecf20Sopenharmony_ci		return IRQ_NONE;
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	/* Program the interrupt pointer to the next stage. */
14808c2ecf20Sopenharmony_ci	stage = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
14818c2ecf20Sopenharmony_ci		 RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT;
14828c2ecf20Sopenharmony_ci	rcar_dmac_chan_write(chan, RCAR_DMADPCR, RCAR_DMADPCR_DIPT(stage));
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	return IRQ_WAKE_THREAD;
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_cistatic irqreturn_t rcar_dmac_isr_transfer_end(struct rcar_dmac_chan *chan)
14888c2ecf20Sopenharmony_ci{
14898c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc = chan->desc.running;
14908c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_WAKE_THREAD;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!desc)) {
14938c2ecf20Sopenharmony_ci		/*
14948c2ecf20Sopenharmony_ci		 * This should never happen, there should always be a running
14958c2ecf20Sopenharmony_ci		 * descriptor when a transfer end interrupt is triggered. Warn
14968c2ecf20Sopenharmony_ci		 * and return.
14978c2ecf20Sopenharmony_ci		 */
14988c2ecf20Sopenharmony_ci		return IRQ_NONE;
14998c2ecf20Sopenharmony_ci	}
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	/*
15028c2ecf20Sopenharmony_ci	 * The transfer end interrupt isn't generated for each chunk when using
15038c2ecf20Sopenharmony_ci	 * descriptor mode. Only update the running chunk pointer in
15048c2ecf20Sopenharmony_ci	 * non-descriptor mode.
15058c2ecf20Sopenharmony_ci	 */
15068c2ecf20Sopenharmony_ci	if (!desc->hwdescs.use) {
15078c2ecf20Sopenharmony_ci		/*
15088c2ecf20Sopenharmony_ci		 * If we haven't completed the last transfer chunk simply move
15098c2ecf20Sopenharmony_ci		 * to the next one. Only wake the IRQ thread if the transfer is
15108c2ecf20Sopenharmony_ci		 * cyclic.
15118c2ecf20Sopenharmony_ci		 */
15128c2ecf20Sopenharmony_ci		if (!list_is_last(&desc->running->node, &desc->chunks)) {
15138c2ecf20Sopenharmony_ci			desc->running = list_next_entry(desc->running, node);
15148c2ecf20Sopenharmony_ci			if (!desc->cyclic)
15158c2ecf20Sopenharmony_ci				ret = IRQ_HANDLED;
15168c2ecf20Sopenharmony_ci			goto done;
15178c2ecf20Sopenharmony_ci		}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci		/*
15208c2ecf20Sopenharmony_ci		 * We've completed the last transfer chunk. If the transfer is
15218c2ecf20Sopenharmony_ci		 * cyclic, move back to the first one.
15228c2ecf20Sopenharmony_ci		 */
15238c2ecf20Sopenharmony_ci		if (desc->cyclic) {
15248c2ecf20Sopenharmony_ci			desc->running =
15258c2ecf20Sopenharmony_ci				list_first_entry(&desc->chunks,
15268c2ecf20Sopenharmony_ci						 struct rcar_dmac_xfer_chunk,
15278c2ecf20Sopenharmony_ci						 node);
15288c2ecf20Sopenharmony_ci			goto done;
15298c2ecf20Sopenharmony_ci		}
15308c2ecf20Sopenharmony_ci	}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	/* The descriptor is complete, move it to the done list. */
15338c2ecf20Sopenharmony_ci	list_move_tail(&desc->node, &chan->desc.done);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	/* Queue the next descriptor, if any. */
15368c2ecf20Sopenharmony_ci	if (!list_empty(&chan->desc.active))
15378c2ecf20Sopenharmony_ci		chan->desc.running = list_first_entry(&chan->desc.active,
15388c2ecf20Sopenharmony_ci						      struct rcar_dmac_desc,
15398c2ecf20Sopenharmony_ci						      node);
15408c2ecf20Sopenharmony_ci	else
15418c2ecf20Sopenharmony_ci		chan->desc.running = NULL;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cidone:
15448c2ecf20Sopenharmony_ci	if (chan->desc.running)
15458c2ecf20Sopenharmony_ci		rcar_dmac_chan_start_xfer(chan);
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	return ret;
15488c2ecf20Sopenharmony_ci}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_cistatic irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	u32 mask = RCAR_DMACHCR_DSE | RCAR_DMACHCR_TE;
15538c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *chan = dev;
15548c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
15558c2ecf20Sopenharmony_ci	bool reinit = false;
15568c2ecf20Sopenharmony_ci	u32 chcr;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	spin_lock(&chan->lock);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
15618c2ecf20Sopenharmony_ci	if (chcr & RCAR_DMACHCR_CAE) {
15628c2ecf20Sopenharmony_ci		struct rcar_dmac *dmac = to_rcar_dmac(chan->chan.device);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci		/*
15658c2ecf20Sopenharmony_ci		 * We don't need to call rcar_dmac_chan_halt()
15668c2ecf20Sopenharmony_ci		 * because channel is already stopped in error case.
15678c2ecf20Sopenharmony_ci		 * We need to clear register and check DE bit as recovery.
15688c2ecf20Sopenharmony_ci		 */
15698c2ecf20Sopenharmony_ci		rcar_dmac_write(dmac, RCAR_DMACHCLR, 1 << chan->index);
15708c2ecf20Sopenharmony_ci		rcar_dmac_chcr_de_barrier(chan);
15718c2ecf20Sopenharmony_ci		reinit = true;
15728c2ecf20Sopenharmony_ci		goto spin_lock_end;
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	if (chcr & RCAR_DMACHCR_TE)
15768c2ecf20Sopenharmony_ci		mask |= RCAR_DMACHCR_DE;
15778c2ecf20Sopenharmony_ci	rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
15788c2ecf20Sopenharmony_ci	if (mask & RCAR_DMACHCR_DE)
15798c2ecf20Sopenharmony_ci		rcar_dmac_chcr_de_barrier(chan);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	if (chcr & RCAR_DMACHCR_DSE)
15828c2ecf20Sopenharmony_ci		ret |= rcar_dmac_isr_desc_stage_end(chan);
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	if (chcr & RCAR_DMACHCR_TE)
15858c2ecf20Sopenharmony_ci		ret |= rcar_dmac_isr_transfer_end(chan);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_cispin_lock_end:
15888c2ecf20Sopenharmony_ci	spin_unlock(&chan->lock);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	if (reinit) {
15918c2ecf20Sopenharmony_ci		dev_err(chan->chan.device->dev, "Channel Address Error\n");
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci		rcar_dmac_chan_reinit(chan);
15948c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	return ret;
15988c2ecf20Sopenharmony_ci}
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_cistatic irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *chan = dev;
16038c2ecf20Sopenharmony_ci	struct rcar_dmac_desc *desc;
16048c2ecf20Sopenharmony_ci	struct dmaengine_desc_callback cb;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	spin_lock_irq(&chan->lock);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	/* For cyclic transfers notify the user after every chunk. */
16098c2ecf20Sopenharmony_ci	if (chan->desc.running && chan->desc.running->cyclic) {
16108c2ecf20Sopenharmony_ci		desc = chan->desc.running;
16118c2ecf20Sopenharmony_ci		dmaengine_desc_get_callback(&desc->async_tx, &cb);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci		if (dmaengine_desc_callback_valid(&cb)) {
16148c2ecf20Sopenharmony_ci			spin_unlock_irq(&chan->lock);
16158c2ecf20Sopenharmony_ci			dmaengine_desc_callback_invoke(&cb, NULL);
16168c2ecf20Sopenharmony_ci			spin_lock_irq(&chan->lock);
16178c2ecf20Sopenharmony_ci		}
16188c2ecf20Sopenharmony_ci	}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	/*
16218c2ecf20Sopenharmony_ci	 * Call the callback function for all descriptors on the done list and
16228c2ecf20Sopenharmony_ci	 * move them to the ack wait list.
16238c2ecf20Sopenharmony_ci	 */
16248c2ecf20Sopenharmony_ci	while (!list_empty(&chan->desc.done)) {
16258c2ecf20Sopenharmony_ci		desc = list_first_entry(&chan->desc.done, struct rcar_dmac_desc,
16268c2ecf20Sopenharmony_ci					node);
16278c2ecf20Sopenharmony_ci		dma_cookie_complete(&desc->async_tx);
16288c2ecf20Sopenharmony_ci		list_del(&desc->node);
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci		dmaengine_desc_get_callback(&desc->async_tx, &cb);
16318c2ecf20Sopenharmony_ci		if (dmaengine_desc_callback_valid(&cb)) {
16328c2ecf20Sopenharmony_ci			spin_unlock_irq(&chan->lock);
16338c2ecf20Sopenharmony_ci			/*
16348c2ecf20Sopenharmony_ci			 * We own the only reference to this descriptor, we can
16358c2ecf20Sopenharmony_ci			 * safely dereference it without holding the channel
16368c2ecf20Sopenharmony_ci			 * lock.
16378c2ecf20Sopenharmony_ci			 */
16388c2ecf20Sopenharmony_ci			dmaengine_desc_callback_invoke(&cb, NULL);
16398c2ecf20Sopenharmony_ci			spin_lock_irq(&chan->lock);
16408c2ecf20Sopenharmony_ci		}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci		list_add_tail(&desc->node, &chan->desc.wait);
16438c2ecf20Sopenharmony_ci	}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	spin_unlock_irq(&chan->lock);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	/* Recycle all acked descriptors. */
16488c2ecf20Sopenharmony_ci	rcar_dmac_desc_recycle_acked(chan);
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
16518c2ecf20Sopenharmony_ci}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
16548c2ecf20Sopenharmony_ci * OF xlate and channel filter
16558c2ecf20Sopenharmony_ci */
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_cistatic bool rcar_dmac_chan_filter(struct dma_chan *chan, void *arg)
16588c2ecf20Sopenharmony_ci{
16598c2ecf20Sopenharmony_ci	struct rcar_dmac *dmac = to_rcar_dmac(chan->device);
16608c2ecf20Sopenharmony_ci	struct of_phandle_args *dma_spec = arg;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	/*
16638c2ecf20Sopenharmony_ci	 * FIXME: Using a filter on OF platforms is a nonsense. The OF xlate
16648c2ecf20Sopenharmony_ci	 * function knows from which device it wants to allocate a channel from,
16658c2ecf20Sopenharmony_ci	 * and would be perfectly capable of selecting the channel it wants.
16668c2ecf20Sopenharmony_ci	 * Forcing it to call dma_request_channel() and iterate through all
16678c2ecf20Sopenharmony_ci	 * channels from all controllers is just pointless.
16688c2ecf20Sopenharmony_ci	 */
16698c2ecf20Sopenharmony_ci	if (chan->device->device_config != rcar_dmac_device_config)
16708c2ecf20Sopenharmony_ci		return false;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	return !test_and_set_bit(dma_spec->args[0], dmac->modules);
16738c2ecf20Sopenharmony_ci}
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_cistatic struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
16768c2ecf20Sopenharmony_ci					   struct of_dma *ofdma)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	struct rcar_dmac_chan *rchan;
16798c2ecf20Sopenharmony_ci	struct dma_chan *chan;
16808c2ecf20Sopenharmony_ci	dma_cap_mask_t mask;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	if (dma_spec->args_count != 1)
16838c2ecf20Sopenharmony_ci		return NULL;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	/* Only slave DMA channels can be allocated via DT */
16868c2ecf20Sopenharmony_ci	dma_cap_zero(mask);
16878c2ecf20Sopenharmony_ci	dma_cap_set(DMA_SLAVE, mask);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	chan = __dma_request_channel(&mask, rcar_dmac_chan_filter, dma_spec,
16908c2ecf20Sopenharmony_ci				     ofdma->of_node);
16918c2ecf20Sopenharmony_ci	if (!chan)
16928c2ecf20Sopenharmony_ci		return NULL;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	rchan = to_rcar_dmac_chan(chan);
16958c2ecf20Sopenharmony_ci	rchan->mid_rid = dma_spec->args[0];
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	return chan;
16988c2ecf20Sopenharmony_ci}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
17018c2ecf20Sopenharmony_ci * Power management
17028c2ecf20Sopenharmony_ci */
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
17058c2ecf20Sopenharmony_cistatic int rcar_dmac_runtime_suspend(struct device *dev)
17068c2ecf20Sopenharmony_ci{
17078c2ecf20Sopenharmony_ci	return 0;
17088c2ecf20Sopenharmony_ci}
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_cistatic int rcar_dmac_runtime_resume(struct device *dev)
17118c2ecf20Sopenharmony_ci{
17128c2ecf20Sopenharmony_ci	struct rcar_dmac *dmac = dev_get_drvdata(dev);
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	return rcar_dmac_init(dmac);
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci#endif
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rcar_dmac_pm = {
17198c2ecf20Sopenharmony_ci	/*
17208c2ecf20Sopenharmony_ci	 * TODO for system sleep/resume:
17218c2ecf20Sopenharmony_ci	 *   - Wait for the current transfer to complete and stop the device,
17228c2ecf20Sopenharmony_ci	 *   - Resume transfers, if any.
17238c2ecf20Sopenharmony_ci	 */
17248c2ecf20Sopenharmony_ci	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
17258c2ecf20Sopenharmony_ci				      pm_runtime_force_resume)
17268c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(rcar_dmac_runtime_suspend, rcar_dmac_runtime_resume,
17278c2ecf20Sopenharmony_ci			   NULL)
17288c2ecf20Sopenharmony_ci};
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
17318c2ecf20Sopenharmony_ci * Probe and remove
17328c2ecf20Sopenharmony_ci */
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_cistatic int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
17358c2ecf20Sopenharmony_ci				struct rcar_dmac_chan *rchan,
17368c2ecf20Sopenharmony_ci				const struct rcar_dmac_of_data *data,
17378c2ecf20Sopenharmony_ci				unsigned int index)
17388c2ecf20Sopenharmony_ci{
17398c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dmac->dev);
17408c2ecf20Sopenharmony_ci	struct dma_chan *chan = &rchan->chan;
17418c2ecf20Sopenharmony_ci	char pdev_irqname[5];
17428c2ecf20Sopenharmony_ci	char *irqname;
17438c2ecf20Sopenharmony_ci	int ret;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	rchan->index = index;
17468c2ecf20Sopenharmony_ci	rchan->iomem = dmac->iomem + data->chan_offset_base +
17478c2ecf20Sopenharmony_ci		       data->chan_offset_stride * index;
17488c2ecf20Sopenharmony_ci	rchan->mid_rid = -EINVAL;
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	spin_lock_init(&rchan->lock);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.free);
17538c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.pending);
17548c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.active);
17558c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.done);
17568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rchan->desc.wait);
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	/* Request the channel interrupt. */
17598c2ecf20Sopenharmony_ci	sprintf(pdev_irqname, "ch%u", index);
17608c2ecf20Sopenharmony_ci	rchan->irq = platform_get_irq_byname(pdev, pdev_irqname);
17618c2ecf20Sopenharmony_ci	if (rchan->irq < 0)
17628c2ecf20Sopenharmony_ci		return -ENODEV;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
17658c2ecf20Sopenharmony_ci				 dev_name(dmac->dev), index);
17668c2ecf20Sopenharmony_ci	if (!irqname)
17678c2ecf20Sopenharmony_ci		return -ENOMEM;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	/*
17708c2ecf20Sopenharmony_ci	 * Initialize the DMA engine channel and add it to the DMA engine
17718c2ecf20Sopenharmony_ci	 * channels list.
17728c2ecf20Sopenharmony_ci	 */
17738c2ecf20Sopenharmony_ci	chan->device = &dmac->engine;
17748c2ecf20Sopenharmony_ci	dma_cookie_init(chan);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	list_add_tail(&chan->device_node, &dmac->engine.channels);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	ret = devm_request_threaded_irq(dmac->dev, rchan->irq,
17798c2ecf20Sopenharmony_ci					rcar_dmac_isr_channel,
17808c2ecf20Sopenharmony_ci					rcar_dmac_isr_channel_thread, 0,
17818c2ecf20Sopenharmony_ci					irqname, rchan);
17828c2ecf20Sopenharmony_ci	if (ret) {
17838c2ecf20Sopenharmony_ci		dev_err(dmac->dev, "failed to request IRQ %u (%d)\n",
17848c2ecf20Sopenharmony_ci			rchan->irq, ret);
17858c2ecf20Sopenharmony_ci		return ret;
17868c2ecf20Sopenharmony_ci	}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	return 0;
17898c2ecf20Sopenharmony_ci}
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci#define RCAR_DMAC_MAX_CHANNELS	32
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_cistatic int rcar_dmac_parse_of(struct device *dev, struct rcar_dmac *dmac)
17948c2ecf20Sopenharmony_ci{
17958c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
17968c2ecf20Sopenharmony_ci	int ret;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "dma-channels", &dmac->n_channels);
17998c2ecf20Sopenharmony_ci	if (ret < 0) {
18008c2ecf20Sopenharmony_ci		dev_err(dev, "unable to read dma-channels property\n");
18018c2ecf20Sopenharmony_ci		return ret;
18028c2ecf20Sopenharmony_ci	}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	/* The hardware and driver don't support more than 32 bits in CHCLR */
18058c2ecf20Sopenharmony_ci	if (dmac->n_channels <= 0 ||
18068c2ecf20Sopenharmony_ci	    dmac->n_channels >= RCAR_DMAC_MAX_CHANNELS) {
18078c2ecf20Sopenharmony_ci		dev_err(dev, "invalid number of channels %u\n",
18088c2ecf20Sopenharmony_ci			dmac->n_channels);
18098c2ecf20Sopenharmony_ci		return -EINVAL;
18108c2ecf20Sopenharmony_ci	}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	/*
18138c2ecf20Sopenharmony_ci	 * If the driver is unable to read dma-channel-mask property,
18148c2ecf20Sopenharmony_ci	 * the driver assumes that it can use all channels.
18158c2ecf20Sopenharmony_ci	 */
18168c2ecf20Sopenharmony_ci	dmac->channels_mask = GENMASK(dmac->n_channels - 1, 0);
18178c2ecf20Sopenharmony_ci	of_property_read_u32(np, "dma-channel-mask", &dmac->channels_mask);
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	/* If the property has out-of-channel mask, this driver clears it */
18208c2ecf20Sopenharmony_ci	dmac->channels_mask &= GENMASK(dmac->n_channels - 1, 0);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	return 0;
18238c2ecf20Sopenharmony_ci}
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_cistatic int rcar_dmac_probe(struct platform_device *pdev)
18268c2ecf20Sopenharmony_ci{
18278c2ecf20Sopenharmony_ci	const enum dma_slave_buswidth widths = DMA_SLAVE_BUSWIDTH_1_BYTE |
18288c2ecf20Sopenharmony_ci		DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES |
18298c2ecf20Sopenharmony_ci		DMA_SLAVE_BUSWIDTH_8_BYTES | DMA_SLAVE_BUSWIDTH_16_BYTES |
18308c2ecf20Sopenharmony_ci		DMA_SLAVE_BUSWIDTH_32_BYTES | DMA_SLAVE_BUSWIDTH_64_BYTES;
18318c2ecf20Sopenharmony_ci	struct dma_device *engine;
18328c2ecf20Sopenharmony_ci	struct rcar_dmac *dmac;
18338c2ecf20Sopenharmony_ci	const struct rcar_dmac_of_data *data;
18348c2ecf20Sopenharmony_ci	unsigned int i;
18358c2ecf20Sopenharmony_ci	int ret;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	data = of_device_get_match_data(&pdev->dev);
18388c2ecf20Sopenharmony_ci	if (!data)
18398c2ecf20Sopenharmony_ci		return -EINVAL;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
18428c2ecf20Sopenharmony_ci	if (!dmac)
18438c2ecf20Sopenharmony_ci		return -ENOMEM;
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	dmac->dev = &pdev->dev;
18468c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, dmac);
18478c2ecf20Sopenharmony_ci	ret = dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK);
18488c2ecf20Sopenharmony_ci	if (ret)
18498c2ecf20Sopenharmony_ci		return ret;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	ret = dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
18528c2ecf20Sopenharmony_ci	if (ret)
18538c2ecf20Sopenharmony_ci		return ret;
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	ret = rcar_dmac_parse_of(&pdev->dev, dmac);
18568c2ecf20Sopenharmony_ci	if (ret < 0)
18578c2ecf20Sopenharmony_ci		return ret;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	/*
18608c2ecf20Sopenharmony_ci	 * A still unconfirmed hardware bug prevents the IPMMU microTLB 0 to be
18618c2ecf20Sopenharmony_ci	 * flushed correctly, resulting in memory corruption. DMAC 0 channel 0
18628c2ecf20Sopenharmony_ci	 * is connected to microTLB 0 on currently supported platforms, so we
18638c2ecf20Sopenharmony_ci	 * can't use it with the IPMMU. As the IOMMU API operates at the device
18648c2ecf20Sopenharmony_ci	 * level we can't disable it selectively, so ignore channel 0 for now if
18658c2ecf20Sopenharmony_ci	 * the device is part of an IOMMU group.
18668c2ecf20Sopenharmony_ci	 */
18678c2ecf20Sopenharmony_ci	if (device_iommu_mapped(&pdev->dev))
18688c2ecf20Sopenharmony_ci		dmac->channels_mask &= ~BIT(0);
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	dmac->channels = devm_kcalloc(&pdev->dev, dmac->n_channels,
18718c2ecf20Sopenharmony_ci				      sizeof(*dmac->channels), GFP_KERNEL);
18728c2ecf20Sopenharmony_ci	if (!dmac->channels)
18738c2ecf20Sopenharmony_ci		return -ENOMEM;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	/* Request resources. */
18768c2ecf20Sopenharmony_ci	dmac->iomem = devm_platform_ioremap_resource(pdev, 0);
18778c2ecf20Sopenharmony_ci	if (IS_ERR(dmac->iomem))
18788c2ecf20Sopenharmony_ci		return PTR_ERR(dmac->iomem);
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	/* Enable runtime PM and initialize the device. */
18818c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
18828c2ecf20Sopenharmony_ci	ret = pm_runtime_resume_and_get(&pdev->dev);
18838c2ecf20Sopenharmony_ci	if (ret < 0) {
18848c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret);
18858c2ecf20Sopenharmony_ci		return ret;
18868c2ecf20Sopenharmony_ci	}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	ret = rcar_dmac_init(dmac);
18898c2ecf20Sopenharmony_ci	pm_runtime_put(&pdev->dev);
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	if (ret) {
18928c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to reset device\n");
18938c2ecf20Sopenharmony_ci		goto error;
18948c2ecf20Sopenharmony_ci	}
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	/* Initialize engine */
18978c2ecf20Sopenharmony_ci	engine = &dmac->engine;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, engine->cap_mask);
19008c2ecf20Sopenharmony_ci	dma_cap_set(DMA_SLAVE, engine->cap_mask);
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	engine->dev		= &pdev->dev;
19038c2ecf20Sopenharmony_ci	engine->copy_align	= ilog2(RCAR_DMAC_MEMCPY_XFER_SIZE);
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	engine->src_addr_widths	= widths;
19068c2ecf20Sopenharmony_ci	engine->dst_addr_widths	= widths;
19078c2ecf20Sopenharmony_ci	engine->directions	= BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
19088c2ecf20Sopenharmony_ci	engine->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	engine->device_alloc_chan_resources	= rcar_dmac_alloc_chan_resources;
19118c2ecf20Sopenharmony_ci	engine->device_free_chan_resources	= rcar_dmac_free_chan_resources;
19128c2ecf20Sopenharmony_ci	engine->device_prep_dma_memcpy		= rcar_dmac_prep_dma_memcpy;
19138c2ecf20Sopenharmony_ci	engine->device_prep_slave_sg		= rcar_dmac_prep_slave_sg;
19148c2ecf20Sopenharmony_ci	engine->device_prep_dma_cyclic		= rcar_dmac_prep_dma_cyclic;
19158c2ecf20Sopenharmony_ci	engine->device_config			= rcar_dmac_device_config;
19168c2ecf20Sopenharmony_ci	engine->device_pause			= rcar_dmac_chan_pause;
19178c2ecf20Sopenharmony_ci	engine->device_terminate_all		= rcar_dmac_chan_terminate_all;
19188c2ecf20Sopenharmony_ci	engine->device_tx_status		= rcar_dmac_tx_status;
19198c2ecf20Sopenharmony_ci	engine->device_issue_pending		= rcar_dmac_issue_pending;
19208c2ecf20Sopenharmony_ci	engine->device_synchronize		= rcar_dmac_device_synchronize;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&engine->channels);
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	for (i = 0; i < dmac->n_channels; ++i) {
19258c2ecf20Sopenharmony_ci		if (!(dmac->channels_mask & BIT(i)))
19268c2ecf20Sopenharmony_ci			continue;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci		ret = rcar_dmac_chan_probe(dmac, &dmac->channels[i], data, i);
19298c2ecf20Sopenharmony_ci		if (ret < 0)
19308c2ecf20Sopenharmony_ci			goto error;
19318c2ecf20Sopenharmony_ci	}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	/* Register the DMAC as a DMA provider for DT. */
19348c2ecf20Sopenharmony_ci	ret = of_dma_controller_register(pdev->dev.of_node, rcar_dmac_of_xlate,
19358c2ecf20Sopenharmony_ci					 NULL);
19368c2ecf20Sopenharmony_ci	if (ret < 0)
19378c2ecf20Sopenharmony_ci		goto error;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	/*
19408c2ecf20Sopenharmony_ci	 * Register the DMA engine device.
19418c2ecf20Sopenharmony_ci	 *
19428c2ecf20Sopenharmony_ci	 * Default transfer size of 32 bytes requires 32-byte alignment.
19438c2ecf20Sopenharmony_ci	 */
19448c2ecf20Sopenharmony_ci	ret = dma_async_device_register(engine);
19458c2ecf20Sopenharmony_ci	if (ret < 0)
19468c2ecf20Sopenharmony_ci		goto error;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	return 0;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_cierror:
19518c2ecf20Sopenharmony_ci	of_dma_controller_free(pdev->dev.of_node);
19528c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
19538c2ecf20Sopenharmony_ci	return ret;
19548c2ecf20Sopenharmony_ci}
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_cistatic int rcar_dmac_remove(struct platform_device *pdev)
19578c2ecf20Sopenharmony_ci{
19588c2ecf20Sopenharmony_ci	struct rcar_dmac *dmac = platform_get_drvdata(pdev);
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci	of_dma_controller_free(pdev->dev.of_node);
19618c2ecf20Sopenharmony_ci	dma_async_device_unregister(&dmac->engine);
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	return 0;
19668c2ecf20Sopenharmony_ci}
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_cistatic void rcar_dmac_shutdown(struct platform_device *pdev)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	struct rcar_dmac *dmac = platform_get_drvdata(pdev);
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	rcar_dmac_stop_all_chan(dmac);
19738c2ecf20Sopenharmony_ci}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_cistatic const struct rcar_dmac_of_data rcar_dmac_data = {
19768c2ecf20Sopenharmony_ci	.chan_offset_base = 0x8000,
19778c2ecf20Sopenharmony_ci	.chan_offset_stride = 0x80,
19788c2ecf20Sopenharmony_ci};
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_cistatic const struct of_device_id rcar_dmac_of_ids[] = {
19818c2ecf20Sopenharmony_ci	{
19828c2ecf20Sopenharmony_ci		.compatible = "renesas,rcar-dmac",
19838c2ecf20Sopenharmony_ci		.data = &rcar_dmac_data,
19848c2ecf20Sopenharmony_ci	},
19858c2ecf20Sopenharmony_ci	{ /* Sentinel */ }
19868c2ecf20Sopenharmony_ci};
19878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rcar_dmac_of_ids);
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_cistatic struct platform_driver rcar_dmac_driver = {
19908c2ecf20Sopenharmony_ci	.driver		= {
19918c2ecf20Sopenharmony_ci		.pm	= &rcar_dmac_pm,
19928c2ecf20Sopenharmony_ci		.name	= "rcar-dmac",
19938c2ecf20Sopenharmony_ci		.of_match_table = rcar_dmac_of_ids,
19948c2ecf20Sopenharmony_ci	},
19958c2ecf20Sopenharmony_ci	.probe		= rcar_dmac_probe,
19968c2ecf20Sopenharmony_ci	.remove		= rcar_dmac_remove,
19978c2ecf20Sopenharmony_ci	.shutdown	= rcar_dmac_shutdown,
19988c2ecf20Sopenharmony_ci};
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_cimodule_platform_driver(rcar_dmac_driver);
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("R-Car Gen2 DMA Controller Driver");
20038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
20048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
2005