162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for STM32 DMA controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Inspired by dma-jz4740.c and tegra20-apb-dma.c
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) M'boumba Cedric Madianga 2015
862306a36Sopenharmony_ci * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
962306a36Sopenharmony_ci *         Pierre-Yves Mordret <pierre-yves.mordret@st.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/bitfield.h>
1362306a36Sopenharmony_ci#include <linux/clk.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/dmaengine.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/err.h>
1862306a36Sopenharmony_ci#include <linux/init.h>
1962306a36Sopenharmony_ci#include <linux/iopoll.h>
2062306a36Sopenharmony_ci#include <linux/jiffies.h>
2162306a36Sopenharmony_ci#include <linux/list.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/of_device.h>
2562306a36Sopenharmony_ci#include <linux/of_dma.h>
2662306a36Sopenharmony_ci#include <linux/platform_device.h>
2762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2862306a36Sopenharmony_ci#include <linux/reset.h>
2962306a36Sopenharmony_ci#include <linux/sched.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "virt-dma.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define STM32_DMA_LISR			0x0000 /* DMA Low Int Status Reg */
3562306a36Sopenharmony_ci#define STM32_DMA_HISR			0x0004 /* DMA High Int Status Reg */
3662306a36Sopenharmony_ci#define STM32_DMA_ISR(n)		(((n) & 4) ? STM32_DMA_HISR : STM32_DMA_LISR)
3762306a36Sopenharmony_ci#define STM32_DMA_LIFCR			0x0008 /* DMA Low Int Flag Clear Reg */
3862306a36Sopenharmony_ci#define STM32_DMA_HIFCR			0x000c /* DMA High Int Flag Clear Reg */
3962306a36Sopenharmony_ci#define STM32_DMA_IFCR(n)		(((n) & 4) ? STM32_DMA_HIFCR : STM32_DMA_LIFCR)
4062306a36Sopenharmony_ci#define STM32_DMA_TCI			BIT(5) /* Transfer Complete Interrupt */
4162306a36Sopenharmony_ci#define STM32_DMA_HTI			BIT(4) /* Half Transfer Interrupt */
4262306a36Sopenharmony_ci#define STM32_DMA_TEI			BIT(3) /* Transfer Error Interrupt */
4362306a36Sopenharmony_ci#define STM32_DMA_DMEI			BIT(2) /* Direct Mode Error Interrupt */
4462306a36Sopenharmony_ci#define STM32_DMA_FEI			BIT(0) /* FIFO Error Interrupt */
4562306a36Sopenharmony_ci#define STM32_DMA_MASKI			(STM32_DMA_TCI \
4662306a36Sopenharmony_ci					 | STM32_DMA_TEI \
4762306a36Sopenharmony_ci					 | STM32_DMA_DMEI \
4862306a36Sopenharmony_ci					 | STM32_DMA_FEI)
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * If (chan->id % 4) is 2 or 3, left shift the mask by 16 bits;
5162306a36Sopenharmony_ci * if (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits.
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_ci#define STM32_DMA_FLAGS_SHIFT(n)	({ typeof(n) (_n) = (n); \
5462306a36Sopenharmony_ci					   (((_n) & 2) << 3) | (((_n) & 1) * 6); })
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* DMA Stream x Configuration Register */
5762306a36Sopenharmony_ci#define STM32_DMA_SCR(x)		(0x0010 + 0x18 * (x)) /* x = 0..7 */
5862306a36Sopenharmony_ci#define STM32_DMA_SCR_REQ_MASK		GENMASK(27, 25)
5962306a36Sopenharmony_ci#define STM32_DMA_SCR_MBURST_MASK	GENMASK(24, 23)
6062306a36Sopenharmony_ci#define STM32_DMA_SCR_PBURST_MASK	GENMASK(22, 21)
6162306a36Sopenharmony_ci#define STM32_DMA_SCR_PL_MASK		GENMASK(17, 16)
6262306a36Sopenharmony_ci#define STM32_DMA_SCR_MSIZE_MASK	GENMASK(14, 13)
6362306a36Sopenharmony_ci#define STM32_DMA_SCR_PSIZE_MASK	GENMASK(12, 11)
6462306a36Sopenharmony_ci#define STM32_DMA_SCR_DIR_MASK		GENMASK(7, 6)
6562306a36Sopenharmony_ci#define STM32_DMA_SCR_TRBUFF		BIT(20) /* Bufferable transfer for USART/UART */
6662306a36Sopenharmony_ci#define STM32_DMA_SCR_CT		BIT(19) /* Target in double buffer */
6762306a36Sopenharmony_ci#define STM32_DMA_SCR_DBM		BIT(18) /* Double Buffer Mode */
6862306a36Sopenharmony_ci#define STM32_DMA_SCR_PINCOS		BIT(15) /* Peripheral inc offset size */
6962306a36Sopenharmony_ci#define STM32_DMA_SCR_MINC		BIT(10) /* Memory increment mode */
7062306a36Sopenharmony_ci#define STM32_DMA_SCR_PINC		BIT(9) /* Peripheral increment mode */
7162306a36Sopenharmony_ci#define STM32_DMA_SCR_CIRC		BIT(8) /* Circular mode */
7262306a36Sopenharmony_ci#define STM32_DMA_SCR_PFCTRL		BIT(5) /* Peripheral Flow Controller */
7362306a36Sopenharmony_ci#define STM32_DMA_SCR_TCIE		BIT(4) /* Transfer Complete Int Enable
7462306a36Sopenharmony_ci						*/
7562306a36Sopenharmony_ci#define STM32_DMA_SCR_TEIE		BIT(2) /* Transfer Error Int Enable */
7662306a36Sopenharmony_ci#define STM32_DMA_SCR_DMEIE		BIT(1) /* Direct Mode Err Int Enable */
7762306a36Sopenharmony_ci#define STM32_DMA_SCR_EN		BIT(0) /* Stream Enable */
7862306a36Sopenharmony_ci#define STM32_DMA_SCR_CFG_MASK		(STM32_DMA_SCR_PINC \
7962306a36Sopenharmony_ci					| STM32_DMA_SCR_MINC \
8062306a36Sopenharmony_ci					| STM32_DMA_SCR_PINCOS \
8162306a36Sopenharmony_ci					| STM32_DMA_SCR_PL_MASK)
8262306a36Sopenharmony_ci#define STM32_DMA_SCR_IRQ_MASK		(STM32_DMA_SCR_TCIE \
8362306a36Sopenharmony_ci					| STM32_DMA_SCR_TEIE \
8462306a36Sopenharmony_ci					| STM32_DMA_SCR_DMEIE)
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* DMA Stream x number of data register */
8762306a36Sopenharmony_ci#define STM32_DMA_SNDTR(x)		(0x0014 + 0x18 * (x))
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* DMA stream peripheral address register */
9062306a36Sopenharmony_ci#define STM32_DMA_SPAR(x)		(0x0018 + 0x18 * (x))
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* DMA stream x memory 0 address register */
9362306a36Sopenharmony_ci#define STM32_DMA_SM0AR(x)		(0x001c + 0x18 * (x))
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* DMA stream x memory 1 address register */
9662306a36Sopenharmony_ci#define STM32_DMA_SM1AR(x)		(0x0020 + 0x18 * (x))
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* DMA stream x FIFO control register */
9962306a36Sopenharmony_ci#define STM32_DMA_SFCR(x)		(0x0024 + 0x18 * (x))
10062306a36Sopenharmony_ci#define STM32_DMA_SFCR_FTH_MASK		GENMASK(1, 0)
10162306a36Sopenharmony_ci#define STM32_DMA_SFCR_FEIE		BIT(7) /* FIFO error interrupt enable */
10262306a36Sopenharmony_ci#define STM32_DMA_SFCR_DMDIS		BIT(2) /* Direct mode disable */
10362306a36Sopenharmony_ci#define STM32_DMA_SFCR_MASK		(STM32_DMA_SFCR_FEIE \
10462306a36Sopenharmony_ci					| STM32_DMA_SFCR_DMDIS)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* DMA direction */
10762306a36Sopenharmony_ci#define STM32_DMA_DEV_TO_MEM		0x00
10862306a36Sopenharmony_ci#define	STM32_DMA_MEM_TO_DEV		0x01
10962306a36Sopenharmony_ci#define	STM32_DMA_MEM_TO_MEM		0x02
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* DMA priority level */
11262306a36Sopenharmony_ci#define STM32_DMA_PRIORITY_LOW		0x00
11362306a36Sopenharmony_ci#define STM32_DMA_PRIORITY_MEDIUM	0x01
11462306a36Sopenharmony_ci#define STM32_DMA_PRIORITY_HIGH		0x02
11562306a36Sopenharmony_ci#define STM32_DMA_PRIORITY_VERY_HIGH	0x03
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/* DMA FIFO threshold selection */
11862306a36Sopenharmony_ci#define STM32_DMA_FIFO_THRESHOLD_1QUARTERFULL		0x00
11962306a36Sopenharmony_ci#define STM32_DMA_FIFO_THRESHOLD_HALFFULL		0x01
12062306a36Sopenharmony_ci#define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL		0x02
12162306a36Sopenharmony_ci#define STM32_DMA_FIFO_THRESHOLD_FULL			0x03
12262306a36Sopenharmony_ci#define STM32_DMA_FIFO_THRESHOLD_NONE			0x04
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define STM32_DMA_MAX_DATA_ITEMS	0xffff
12562306a36Sopenharmony_ci/*
12662306a36Sopenharmony_ci * Valid transfer starts from @0 to @0xFFFE leading to unaligned scatter
12762306a36Sopenharmony_ci * gather at boundary. Thus it's safer to round down this value on FIFO
12862306a36Sopenharmony_ci * size (16 Bytes)
12962306a36Sopenharmony_ci */
13062306a36Sopenharmony_ci#define STM32_DMA_ALIGNED_MAX_DATA_ITEMS	\
13162306a36Sopenharmony_ci	ALIGN_DOWN(STM32_DMA_MAX_DATA_ITEMS, 16)
13262306a36Sopenharmony_ci#define STM32_DMA_MAX_CHANNELS		0x08
13362306a36Sopenharmony_ci#define STM32_DMA_MAX_REQUEST_ID	0x08
13462306a36Sopenharmony_ci#define STM32_DMA_MAX_DATA_PARAM	0x03
13562306a36Sopenharmony_ci#define STM32_DMA_FIFO_SIZE		16	/* FIFO is 16 bytes */
13662306a36Sopenharmony_ci#define STM32_DMA_MIN_BURST		4
13762306a36Sopenharmony_ci#define STM32_DMA_MAX_BURST		16
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* DMA Features */
14062306a36Sopenharmony_ci#define STM32_DMA_THRESHOLD_FTR_MASK	GENMASK(1, 0)
14162306a36Sopenharmony_ci#define STM32_DMA_DIRECT_MODE_MASK	BIT(2)
14262306a36Sopenharmony_ci#define STM32_DMA_ALT_ACK_MODE_MASK	BIT(4)
14362306a36Sopenharmony_ci#define STM32_DMA_MDMA_STREAM_ID_MASK	GENMASK(19, 16)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cienum stm32_dma_width {
14662306a36Sopenharmony_ci	STM32_DMA_BYTE,
14762306a36Sopenharmony_ci	STM32_DMA_HALF_WORD,
14862306a36Sopenharmony_ci	STM32_DMA_WORD,
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cienum stm32_dma_burst_size {
15262306a36Sopenharmony_ci	STM32_DMA_BURST_SINGLE,
15362306a36Sopenharmony_ci	STM32_DMA_BURST_INCR4,
15462306a36Sopenharmony_ci	STM32_DMA_BURST_INCR8,
15562306a36Sopenharmony_ci	STM32_DMA_BURST_INCR16,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/**
15962306a36Sopenharmony_ci * struct stm32_dma_cfg - STM32 DMA custom configuration
16062306a36Sopenharmony_ci * @channel_id: channel ID
16162306a36Sopenharmony_ci * @request_line: DMA request
16262306a36Sopenharmony_ci * @stream_config: 32bit mask specifying the DMA channel configuration
16362306a36Sopenharmony_ci * @features: 32bit mask specifying the DMA Feature list
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_cistruct stm32_dma_cfg {
16662306a36Sopenharmony_ci	u32 channel_id;
16762306a36Sopenharmony_ci	u32 request_line;
16862306a36Sopenharmony_ci	u32 stream_config;
16962306a36Sopenharmony_ci	u32 features;
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistruct stm32_dma_chan_reg {
17362306a36Sopenharmony_ci	u32 dma_lisr;
17462306a36Sopenharmony_ci	u32 dma_hisr;
17562306a36Sopenharmony_ci	u32 dma_lifcr;
17662306a36Sopenharmony_ci	u32 dma_hifcr;
17762306a36Sopenharmony_ci	u32 dma_scr;
17862306a36Sopenharmony_ci	u32 dma_sndtr;
17962306a36Sopenharmony_ci	u32 dma_spar;
18062306a36Sopenharmony_ci	u32 dma_sm0ar;
18162306a36Sopenharmony_ci	u32 dma_sm1ar;
18262306a36Sopenharmony_ci	u32 dma_sfcr;
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistruct stm32_dma_sg_req {
18662306a36Sopenharmony_ci	u32 len;
18762306a36Sopenharmony_ci	struct stm32_dma_chan_reg chan_reg;
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistruct stm32_dma_desc {
19162306a36Sopenharmony_ci	struct virt_dma_desc vdesc;
19262306a36Sopenharmony_ci	bool cyclic;
19362306a36Sopenharmony_ci	u32 num_sgs;
19462306a36Sopenharmony_ci	struct stm32_dma_sg_req sg_req[];
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/**
19862306a36Sopenharmony_ci * struct stm32_dma_mdma_config - STM32 DMA MDMA configuration
19962306a36Sopenharmony_ci * @stream_id: DMA request to trigger STM32 MDMA transfer
20062306a36Sopenharmony_ci * @ifcr: DMA interrupt flag clear register address,
20162306a36Sopenharmony_ci *        used by STM32 MDMA to clear DMA Transfer Complete flag
20262306a36Sopenharmony_ci * @tcf: DMA Transfer Complete flag
20362306a36Sopenharmony_ci */
20462306a36Sopenharmony_cistruct stm32_dma_mdma_config {
20562306a36Sopenharmony_ci	u32 stream_id;
20662306a36Sopenharmony_ci	u32 ifcr;
20762306a36Sopenharmony_ci	u32 tcf;
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistruct stm32_dma_chan {
21162306a36Sopenharmony_ci	struct virt_dma_chan vchan;
21262306a36Sopenharmony_ci	bool config_init;
21362306a36Sopenharmony_ci	bool busy;
21462306a36Sopenharmony_ci	u32 id;
21562306a36Sopenharmony_ci	u32 irq;
21662306a36Sopenharmony_ci	struct stm32_dma_desc *desc;
21762306a36Sopenharmony_ci	u32 next_sg;
21862306a36Sopenharmony_ci	struct dma_slave_config	dma_sconfig;
21962306a36Sopenharmony_ci	struct stm32_dma_chan_reg chan_reg;
22062306a36Sopenharmony_ci	u32 threshold;
22162306a36Sopenharmony_ci	u32 mem_burst;
22262306a36Sopenharmony_ci	u32 mem_width;
22362306a36Sopenharmony_ci	enum dma_status status;
22462306a36Sopenharmony_ci	bool trig_mdma;
22562306a36Sopenharmony_ci	struct stm32_dma_mdma_config mdma_config;
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistruct stm32_dma_device {
22962306a36Sopenharmony_ci	struct dma_device ddev;
23062306a36Sopenharmony_ci	void __iomem *base;
23162306a36Sopenharmony_ci	struct clk *clk;
23262306a36Sopenharmony_ci	bool mem2mem;
23362306a36Sopenharmony_ci	struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS];
23462306a36Sopenharmony_ci};
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	return container_of(chan->vchan.chan.device, struct stm32_dma_device,
23962306a36Sopenharmony_ci			    ddev);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic struct stm32_dma_chan *to_stm32_dma_chan(struct dma_chan *c)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	return container_of(c, struct stm32_dma_chan, vchan.chan);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic struct stm32_dma_desc *to_stm32_dma_desc(struct virt_dma_desc *vdesc)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	return container_of(vdesc, struct stm32_dma_desc, vdesc);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic struct device *chan2dev(struct stm32_dma_chan *chan)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	return &chan->vchan.chan.dev->device;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic u32 stm32_dma_read(struct stm32_dma_device *dmadev, u32 reg)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	return readl_relaxed(dmadev->base + reg);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void stm32_dma_write(struct stm32_dma_device *dmadev, u32 reg, u32 val)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	writel_relaxed(val, dmadev->base + reg);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int stm32_dma_get_width(struct stm32_dma_chan *chan,
26862306a36Sopenharmony_ci			       enum dma_slave_buswidth width)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	switch (width) {
27162306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_1_BYTE:
27262306a36Sopenharmony_ci		return STM32_DMA_BYTE;
27362306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_2_BYTES:
27462306a36Sopenharmony_ci		return STM32_DMA_HALF_WORD;
27562306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_4_BYTES:
27662306a36Sopenharmony_ci		return STM32_DMA_WORD;
27762306a36Sopenharmony_ci	default:
27862306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Dma bus width not supported\n");
27962306a36Sopenharmony_ci		return -EINVAL;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len,
28462306a36Sopenharmony_ci						       dma_addr_t buf_addr,
28562306a36Sopenharmony_ci						       u32 threshold)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	enum dma_slave_buswidth max_width;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL)
29062306a36Sopenharmony_ci		max_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
29162306a36Sopenharmony_ci	else
29262306a36Sopenharmony_ci		max_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	while ((buf_len < max_width  || buf_len % max_width) &&
29562306a36Sopenharmony_ci	       max_width > DMA_SLAVE_BUSWIDTH_1_BYTE)
29662306a36Sopenharmony_ci		max_width = max_width >> 1;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (buf_addr & (max_width - 1))
29962306a36Sopenharmony_ci		max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return max_width;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold,
30562306a36Sopenharmony_ci						enum dma_slave_buswidth width)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	u32 remaining;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE)
31062306a36Sopenharmony_ci		return false;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) {
31362306a36Sopenharmony_ci		if (burst != 0) {
31462306a36Sopenharmony_ci			/*
31562306a36Sopenharmony_ci			 * If number of beats fit in several whole bursts
31662306a36Sopenharmony_ci			 * this configuration is allowed.
31762306a36Sopenharmony_ci			 */
31862306a36Sopenharmony_ci			remaining = ((STM32_DMA_FIFO_SIZE / width) *
31962306a36Sopenharmony_ci				     (threshold + 1) / 4) % burst;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci			if (remaining == 0)
32262306a36Sopenharmony_ci				return true;
32362306a36Sopenharmony_ci		} else {
32462306a36Sopenharmony_ci			return true;
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return false;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	/* If FIFO direct mode, burst is not possible */
33462306a36Sopenharmony_ci	if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE)
33562306a36Sopenharmony_ci		return false;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * Buffer or period length has to be aligned on FIFO depth.
33962306a36Sopenharmony_ci	 * Otherwise bytes may be stuck within FIFO at buffer or period
34062306a36Sopenharmony_ci	 * length.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	return ((buf_len % ((threshold + 1) * 4)) == 0);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold,
34662306a36Sopenharmony_ci				    enum dma_slave_buswidth width)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	u32 best_burst = max_burst;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (best_burst == 1 || !stm32_dma_is_burst_possible(buf_len, threshold))
35162306a36Sopenharmony_ci		return 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	while ((buf_len < best_burst * width && best_burst > 1) ||
35462306a36Sopenharmony_ci	       !stm32_dma_fifo_threshold_is_allowed(best_burst, threshold,
35562306a36Sopenharmony_ci						    width)) {
35662306a36Sopenharmony_ci		if (best_burst > STM32_DMA_MIN_BURST)
35762306a36Sopenharmony_ci			best_burst = best_burst >> 1;
35862306a36Sopenharmony_ci		else
35962306a36Sopenharmony_ci			best_burst = 0;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return best_burst;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	switch (maxburst) {
36862306a36Sopenharmony_ci	case 0:
36962306a36Sopenharmony_ci	case 1:
37062306a36Sopenharmony_ci		return STM32_DMA_BURST_SINGLE;
37162306a36Sopenharmony_ci	case 4:
37262306a36Sopenharmony_ci		return STM32_DMA_BURST_INCR4;
37362306a36Sopenharmony_ci	case 8:
37462306a36Sopenharmony_ci		return STM32_DMA_BURST_INCR8;
37562306a36Sopenharmony_ci	case 16:
37662306a36Sopenharmony_ci		return STM32_DMA_BURST_INCR16;
37762306a36Sopenharmony_ci	default:
37862306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Dma burst size not supported\n");
37962306a36Sopenharmony_ci		return -EINVAL;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan,
38462306a36Sopenharmony_ci				      u32 src_burst, u32 dst_burst)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_MASK;
38762306a36Sopenharmony_ci	chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_DMEIE;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (!src_burst && !dst_burst) {
39062306a36Sopenharmony_ci		/* Using direct mode */
39162306a36Sopenharmony_ci		chan->chan_reg.dma_scr |= STM32_DMA_SCR_DMEIE;
39262306a36Sopenharmony_ci	} else {
39362306a36Sopenharmony_ci		/* Using FIFO mode */
39462306a36Sopenharmony_ci		chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int stm32_dma_slave_config(struct dma_chan *c,
39962306a36Sopenharmony_ci				  struct dma_slave_config *config)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	memcpy(&chan->dma_sconfig, config, sizeof(*config));
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Check if user is requesting DMA to trigger STM32 MDMA */
40662306a36Sopenharmony_ci	if (config->peripheral_size) {
40762306a36Sopenharmony_ci		config->peripheral_config = &chan->mdma_config;
40862306a36Sopenharmony_ci		config->peripheral_size = sizeof(chan->mdma_config);
40962306a36Sopenharmony_ci		chan->trig_mdma = true;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	chan->config_init = true;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return 0;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic u32 stm32_dma_irq_status(struct stm32_dma_chan *chan)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
42062306a36Sopenharmony_ci	u32 flags, dma_isr;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/*
42362306a36Sopenharmony_ci	 * Read "flags" from DMA_xISR register corresponding to the selected
42462306a36Sopenharmony_ci	 * DMA channel at the correct bit offset inside that register.
42562306a36Sopenharmony_ci	 */
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	dma_isr = stm32_dma_read(dmadev, STM32_DMA_ISR(chan->id));
42862306a36Sopenharmony_ci	flags = dma_isr >> STM32_DMA_FLAGS_SHIFT(chan->id);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	return flags & STM32_DMA_MASKI;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
43662306a36Sopenharmony_ci	u32 dma_ifcr;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/*
43962306a36Sopenharmony_ci	 * Write "flags" to the DMA_xIFCR register corresponding to the selected
44062306a36Sopenharmony_ci	 * DMA channel at the correct bit offset inside that register.
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	flags &= STM32_DMA_MASKI;
44362306a36Sopenharmony_ci	dma_ifcr = flags << STM32_DMA_FLAGS_SHIFT(chan->id);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_IFCR(chan->id), dma_ifcr);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int stm32_dma_disable_chan(struct stm32_dma_chan *chan)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
45162306a36Sopenharmony_ci	u32 dma_scr, id, reg;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	id = chan->id;
45462306a36Sopenharmony_ci	reg = STM32_DMA_SCR(id);
45562306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, reg);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (dma_scr & STM32_DMA_SCR_EN) {
45862306a36Sopenharmony_ci		dma_scr &= ~STM32_DMA_SCR_EN;
45962306a36Sopenharmony_ci		stm32_dma_write(dmadev, reg, dma_scr);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		return readl_relaxed_poll_timeout_atomic(dmadev->base + reg,
46262306a36Sopenharmony_ci					dma_scr, !(dma_scr & STM32_DMA_SCR_EN),
46362306a36Sopenharmony_ci					10, 1000000);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic void stm32_dma_stop(struct stm32_dma_chan *chan)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
47262306a36Sopenharmony_ci	u32 dma_scr, dma_sfcr, status;
47362306a36Sopenharmony_ci	int ret;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* Disable interrupts */
47662306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
47762306a36Sopenharmony_ci	dma_scr &= ~STM32_DMA_SCR_IRQ_MASK;
47862306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr);
47962306a36Sopenharmony_ci	dma_sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
48062306a36Sopenharmony_ci	dma_sfcr &= ~STM32_DMA_SFCR_FEIE;
48162306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), dma_sfcr);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* Disable DMA */
48462306a36Sopenharmony_ci	ret = stm32_dma_disable_chan(chan);
48562306a36Sopenharmony_ci	if (ret < 0)
48662306a36Sopenharmony_ci		return;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
48962306a36Sopenharmony_ci	status = stm32_dma_irq_status(chan);
49062306a36Sopenharmony_ci	if (status) {
49162306a36Sopenharmony_ci		dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n",
49262306a36Sopenharmony_ci			__func__, status);
49362306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, status);
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	chan->busy = false;
49762306a36Sopenharmony_ci	chan->status = DMA_COMPLETE;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int stm32_dma_terminate_all(struct dma_chan *c)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
50362306a36Sopenharmony_ci	unsigned long flags;
50462306a36Sopenharmony_ci	LIST_HEAD(head);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (chan->desc) {
50962306a36Sopenharmony_ci		dma_cookie_complete(&chan->desc->vdesc.tx);
51062306a36Sopenharmony_ci		vchan_terminate_vdesc(&chan->desc->vdesc);
51162306a36Sopenharmony_ci		if (chan->busy)
51262306a36Sopenharmony_ci			stm32_dma_stop(chan);
51362306a36Sopenharmony_ci		chan->desc = NULL;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	vchan_get_all_descriptors(&chan->vchan, &head);
51762306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
51862306a36Sopenharmony_ci	vchan_dma_desc_free_list(&chan->vchan, &head);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return 0;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic void stm32_dma_synchronize(struct dma_chan *c)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	vchan_synchronize(&chan->vchan);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
53362306a36Sopenharmony_ci	u32 scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
53462306a36Sopenharmony_ci	u32 ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
53562306a36Sopenharmony_ci	u32 spar = stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id));
53662306a36Sopenharmony_ci	u32 sm0ar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id));
53762306a36Sopenharmony_ci	u32 sm1ar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id));
53862306a36Sopenharmony_ci	u32 sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "SCR:   0x%08x\n", scr);
54162306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "NDTR:  0x%08x\n", ndtr);
54262306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "SPAR:  0x%08x\n", spar);
54362306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n", sm0ar);
54462306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n", sm1ar);
54562306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "SFCR:  0x%08x\n", sfcr);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic void stm32_dma_sg_inc(struct stm32_dma_chan *chan)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	chan->next_sg++;
55162306a36Sopenharmony_ci	if (chan->desc->cyclic && (chan->next_sg == chan->desc->num_sgs))
55262306a36Sopenharmony_ci		chan->next_sg = 0;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic void stm32_dma_start_transfer(struct stm32_dma_chan *chan)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
56062306a36Sopenharmony_ci	struct virt_dma_desc *vdesc;
56162306a36Sopenharmony_ci	struct stm32_dma_sg_req *sg_req;
56262306a36Sopenharmony_ci	struct stm32_dma_chan_reg *reg;
56362306a36Sopenharmony_ci	u32 status;
56462306a36Sopenharmony_ci	int ret;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	ret = stm32_dma_disable_chan(chan);
56762306a36Sopenharmony_ci	if (ret < 0)
56862306a36Sopenharmony_ci		return;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (!chan->desc) {
57162306a36Sopenharmony_ci		vdesc = vchan_next_desc(&chan->vchan);
57262306a36Sopenharmony_ci		if (!vdesc)
57362306a36Sopenharmony_ci			return;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		list_del(&vdesc->node);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		chan->desc = to_stm32_dma_desc(vdesc);
57862306a36Sopenharmony_ci		chan->next_sg = 0;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (chan->next_sg == chan->desc->num_sgs)
58262306a36Sopenharmony_ci		chan->next_sg = 0;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	sg_req = &chan->desc->sg_req[chan->next_sg];
58562306a36Sopenharmony_ci	reg = &sg_req->chan_reg;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* When DMA triggers STM32 MDMA, DMA Transfer Complete is managed by STM32 MDMA */
58862306a36Sopenharmony_ci	if (chan->trig_mdma && chan->dma_sconfig.direction != DMA_MEM_TO_DEV)
58962306a36Sopenharmony_ci		reg->dma_scr &= ~STM32_DMA_SCR_TCIE;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	reg->dma_scr &= ~STM32_DMA_SCR_EN;
59262306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr);
59362306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar);
59462306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar);
59562306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), reg->dma_sfcr);
59662306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar);
59762306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	stm32_dma_sg_inc(chan);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
60262306a36Sopenharmony_ci	status = stm32_dma_irq_status(chan);
60362306a36Sopenharmony_ci	if (status)
60462306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, status);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (chan->desc->cyclic)
60762306a36Sopenharmony_ci		stm32_dma_configure_next_sg(chan);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	stm32_dma_dump_reg(chan);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/* Start DMA */
61262306a36Sopenharmony_ci	chan->busy = true;
61362306a36Sopenharmony_ci	chan->status = DMA_IN_PROGRESS;
61462306a36Sopenharmony_ci	reg->dma_scr |= STM32_DMA_SCR_EN;
61562306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan);
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
62362306a36Sopenharmony_ci	struct stm32_dma_sg_req *sg_req;
62462306a36Sopenharmony_ci	u32 dma_scr, dma_sm0ar, dma_sm1ar, id;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	id = chan->id;
62762306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	sg_req = &chan->desc->sg_req[chan->next_sg];
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (dma_scr & STM32_DMA_SCR_CT) {
63262306a36Sopenharmony_ci		dma_sm0ar = sg_req->chan_reg.dma_sm0ar;
63362306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar);
63462306a36Sopenharmony_ci		dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n",
63562306a36Sopenharmony_ci			stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)));
63662306a36Sopenharmony_ci	} else {
63762306a36Sopenharmony_ci		dma_sm1ar = sg_req->chan_reg.dma_sm1ar;
63862306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar);
63962306a36Sopenharmony_ci		dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n",
64062306a36Sopenharmony_ci			stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)));
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
64762306a36Sopenharmony_ci	u32 dma_scr;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/*
65062306a36Sopenharmony_ci	 * Read and store current remaining data items and peripheral/memory addresses to be
65162306a36Sopenharmony_ci	 * updated on resume
65262306a36Sopenharmony_ci	 */
65362306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
65462306a36Sopenharmony_ci	/*
65562306a36Sopenharmony_ci	 * Transfer can be paused while between a previous resume and reconfiguration on transfer
65662306a36Sopenharmony_ci	 * complete. If transfer is cyclic and CIRC and DBM have been deactivated for resume, need
65762306a36Sopenharmony_ci	 * to set it here in SCR backup to ensure a good reconfiguration on transfer complete.
65862306a36Sopenharmony_ci	 */
65962306a36Sopenharmony_ci	if (chan->desc && chan->desc->cyclic) {
66062306a36Sopenharmony_ci		if (chan->desc->num_sgs == 1)
66162306a36Sopenharmony_ci			dma_scr |= STM32_DMA_SCR_CIRC;
66262306a36Sopenharmony_ci		else
66362306a36Sopenharmony_ci			dma_scr |= STM32_DMA_SCR_DBM;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci	chan->chan_reg.dma_scr = dma_scr;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/*
66862306a36Sopenharmony_ci	 * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt, otherwise
66962306a36Sopenharmony_ci	 * on resume NDTR autoreload value will be wrong (lower than the initial period length)
67062306a36Sopenharmony_ci	 */
67162306a36Sopenharmony_ci	if (chan->desc && chan->desc->cyclic) {
67262306a36Sopenharmony_ci		dma_scr &= ~(STM32_DMA_SCR_DBM | STM32_DMA_SCR_CIRC);
67362306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr);
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	chan->status = DMA_PAUSED;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan);
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
68662306a36Sopenharmony_ci	struct stm32_dma_sg_req *sg_req;
68762306a36Sopenharmony_ci	u32 dma_scr, status, id;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	id = chan->id;
69062306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
69362306a36Sopenharmony_ci	status = stm32_dma_irq_status(chan);
69462306a36Sopenharmony_ci	if (status)
69562306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, status);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (!chan->next_sg)
69862306a36Sopenharmony_ci		sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1];
69962306a36Sopenharmony_ci	else
70062306a36Sopenharmony_ci		sg_req = &chan->desc->sg_req[chan->next_sg - 1];
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* Reconfigure NDTR with the initial value */
70362306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), sg_req->chan_reg.dma_sndtr);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* Restore SPAR */
70662306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SPAR(id), sg_req->chan_reg.dma_spar);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* Restore SM0AR/SM1AR whatever DBM/CT as they may have been modified */
70962306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), sg_req->chan_reg.dma_sm0ar);
71062306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), sg_req->chan_reg.dma_sm1ar);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/* Reactivate CIRC/DBM if needed */
71362306a36Sopenharmony_ci	if (chan->chan_reg.dma_scr & STM32_DMA_SCR_DBM) {
71462306a36Sopenharmony_ci		dma_scr |= STM32_DMA_SCR_DBM;
71562306a36Sopenharmony_ci		/* Restore CT */
71662306a36Sopenharmony_ci		if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CT)
71762306a36Sopenharmony_ci			dma_scr &= ~STM32_DMA_SCR_CT;
71862306a36Sopenharmony_ci		else
71962306a36Sopenharmony_ci			dma_scr |= STM32_DMA_SCR_CT;
72062306a36Sopenharmony_ci	} else if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CIRC) {
72162306a36Sopenharmony_ci		dma_scr |= STM32_DMA_SCR_CIRC;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	stm32_dma_configure_next_sg(chan);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	stm32_dma_dump_reg(chan);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	dma_scr |= STM32_DMA_SCR_EN;
73062306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: reconfigured after pause/resume\n", &chan->vchan);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan, u32 scr)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	if (!chan->desc)
73862306a36Sopenharmony_ci		return;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (chan->desc->cyclic) {
74162306a36Sopenharmony_ci		vchan_cyclic_callback(&chan->desc->vdesc);
74262306a36Sopenharmony_ci		if (chan->trig_mdma)
74362306a36Sopenharmony_ci			return;
74462306a36Sopenharmony_ci		stm32_dma_sg_inc(chan);
74562306a36Sopenharmony_ci		/* cyclic while CIRC/DBM disable => post resume reconfiguration needed */
74662306a36Sopenharmony_ci		if (!(scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM)))
74762306a36Sopenharmony_ci			stm32_dma_post_resume_reconfigure(chan);
74862306a36Sopenharmony_ci		else if (scr & STM32_DMA_SCR_DBM)
74962306a36Sopenharmony_ci			stm32_dma_configure_next_sg(chan);
75062306a36Sopenharmony_ci	} else {
75162306a36Sopenharmony_ci		chan->busy = false;
75262306a36Sopenharmony_ci		chan->status = DMA_COMPLETE;
75362306a36Sopenharmony_ci		if (chan->next_sg == chan->desc->num_sgs) {
75462306a36Sopenharmony_ci			vchan_cookie_complete(&chan->desc->vdesc);
75562306a36Sopenharmony_ci			chan->desc = NULL;
75662306a36Sopenharmony_ci		}
75762306a36Sopenharmony_ci		stm32_dma_start_transfer(chan);
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct stm32_dma_chan *chan = devid;
76462306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
76562306a36Sopenharmony_ci	u32 status, scr, sfcr;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	spin_lock(&chan->vchan.lock);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	status = stm32_dma_irq_status(chan);
77062306a36Sopenharmony_ci	scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
77162306a36Sopenharmony_ci	sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id));
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (status & STM32_DMA_FEI) {
77462306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, STM32_DMA_FEI);
77562306a36Sopenharmony_ci		status &= ~STM32_DMA_FEI;
77662306a36Sopenharmony_ci		if (sfcr & STM32_DMA_SFCR_FEIE) {
77762306a36Sopenharmony_ci			if (!(scr & STM32_DMA_SCR_EN) &&
77862306a36Sopenharmony_ci			    !(status & STM32_DMA_TCI))
77962306a36Sopenharmony_ci				dev_err(chan2dev(chan), "FIFO Error\n");
78062306a36Sopenharmony_ci			else
78162306a36Sopenharmony_ci				dev_dbg(chan2dev(chan), "FIFO over/underrun\n");
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci	if (status & STM32_DMA_DMEI) {
78562306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, STM32_DMA_DMEI);
78662306a36Sopenharmony_ci		status &= ~STM32_DMA_DMEI;
78762306a36Sopenharmony_ci		if (sfcr & STM32_DMA_SCR_DMEIE)
78862306a36Sopenharmony_ci			dev_dbg(chan2dev(chan), "Direct mode overrun\n");
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (status & STM32_DMA_TCI) {
79262306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, STM32_DMA_TCI);
79362306a36Sopenharmony_ci		if (scr & STM32_DMA_SCR_TCIE) {
79462306a36Sopenharmony_ci			if (chan->status != DMA_PAUSED)
79562306a36Sopenharmony_ci				stm32_dma_handle_chan_done(chan, scr);
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci		status &= ~STM32_DMA_TCI;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (status & STM32_DMA_HTI) {
80162306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, STM32_DMA_HTI);
80262306a36Sopenharmony_ci		status &= ~STM32_DMA_HTI;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (status) {
80662306a36Sopenharmony_ci		stm32_dma_irq_clear(chan, status);
80762306a36Sopenharmony_ci		dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);
80862306a36Sopenharmony_ci		if (!(scr & STM32_DMA_SCR_EN))
80962306a36Sopenharmony_ci			dev_err(chan2dev(chan), "chan disabled by HW\n");
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	spin_unlock(&chan->vchan.lock);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return IRQ_HANDLED;
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic void stm32_dma_issue_pending(struct dma_chan *c)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
82062306a36Sopenharmony_ci	unsigned long flags;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
82362306a36Sopenharmony_ci	if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) {
82462306a36Sopenharmony_ci		dev_dbg(chan2dev(chan), "vchan %pK: issued\n", &chan->vchan);
82562306a36Sopenharmony_ci		stm32_dma_start_transfer(chan);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_cistatic int stm32_dma_pause(struct dma_chan *c)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
83462306a36Sopenharmony_ci	unsigned long flags;
83562306a36Sopenharmony_ci	int ret;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (chan->status != DMA_IN_PROGRESS)
83862306a36Sopenharmony_ci		return -EPERM;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	ret = stm32_dma_disable_chan(chan);
84362306a36Sopenharmony_ci	if (!ret)
84462306a36Sopenharmony_ci		stm32_dma_handle_chan_paused(chan);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return ret;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic int stm32_dma_resume(struct dma_chan *c)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
85462306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
85562306a36Sopenharmony_ci	struct stm32_dma_chan_reg chan_reg = chan->chan_reg;
85662306a36Sopenharmony_ci	u32 id = chan->id, scr, ndtr, offset, spar, sm0ar, sm1ar;
85762306a36Sopenharmony_ci	struct stm32_dma_sg_req *sg_req;
85862306a36Sopenharmony_ci	unsigned long flags;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (chan->status != DMA_PAUSED)
86162306a36Sopenharmony_ci		return -EPERM;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
86462306a36Sopenharmony_ci	if (WARN_ON(scr & STM32_DMA_SCR_EN))
86562306a36Sopenharmony_ci		return -EPERM;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	/* sg_reg[prev_sg] contains original ndtr, sm0ar and sm1ar before pausing the transfer */
87062306a36Sopenharmony_ci	if (!chan->next_sg)
87162306a36Sopenharmony_ci		sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1];
87262306a36Sopenharmony_ci	else
87362306a36Sopenharmony_ci		sg_req = &chan->desc->sg_req[chan->next_sg - 1];
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	ndtr = sg_req->chan_reg.dma_sndtr;
87662306a36Sopenharmony_ci	offset = (ndtr - chan_reg.dma_sndtr);
87762306a36Sopenharmony_ci	offset <<= FIELD_GET(STM32_DMA_SCR_PSIZE_MASK, chan_reg.dma_scr);
87862306a36Sopenharmony_ci	spar = sg_req->chan_reg.dma_spar;
87962306a36Sopenharmony_ci	sm0ar = sg_req->chan_reg.dma_sm0ar;
88062306a36Sopenharmony_ci	sm1ar = sg_req->chan_reg.dma_sm1ar;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/*
88362306a36Sopenharmony_ci	 * The peripheral and/or memory addresses have to be updated in order to adjust the
88462306a36Sopenharmony_ci	 * address pointers. Need to check increment.
88562306a36Sopenharmony_ci	 */
88662306a36Sopenharmony_ci	if (chan_reg.dma_scr & STM32_DMA_SCR_PINC)
88762306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SPAR(id), spar + offset);
88862306a36Sopenharmony_ci	else
88962306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SPAR(id), spar);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if (!(chan_reg.dma_scr & STM32_DMA_SCR_MINC))
89262306a36Sopenharmony_ci		offset = 0;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	/*
89562306a36Sopenharmony_ci	 * In case of DBM, the current target could be SM1AR.
89662306a36Sopenharmony_ci	 * Need to temporarily deactivate CIRC/DBM to finish the current transfer, so
89762306a36Sopenharmony_ci	 * SM0AR becomes the current target and must be updated with SM1AR + offset if CT=1.
89862306a36Sopenharmony_ci	 */
89962306a36Sopenharmony_ci	if ((chan_reg.dma_scr & STM32_DMA_SCR_DBM) && (chan_reg.dma_scr & STM32_DMA_SCR_CT))
90062306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), sm1ar + offset);
90162306a36Sopenharmony_ci	else
90262306a36Sopenharmony_ci		stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), sm0ar + offset);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* NDTR must be restored otherwise internal HW counter won't be correctly reset */
90562306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SNDTR(id), chan_reg.dma_sndtr);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	/*
90862306a36Sopenharmony_ci	 * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt,
90962306a36Sopenharmony_ci	 * otherwise NDTR autoreload value will be wrong (lower than the initial period length)
91062306a36Sopenharmony_ci	 */
91162306a36Sopenharmony_ci	if (chan_reg.dma_scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM))
91262306a36Sopenharmony_ci		chan_reg.dma_scr &= ~(STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (chan_reg.dma_scr & STM32_DMA_SCR_DBM)
91562306a36Sopenharmony_ci		stm32_dma_configure_next_sg(chan);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	stm32_dma_dump_reg(chan);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	/* The stream may then be re-enabled to restart transfer from the point it was stopped */
92062306a36Sopenharmony_ci	chan->status = DMA_IN_PROGRESS;
92162306a36Sopenharmony_ci	chan_reg.dma_scr |= STM32_DMA_SCR_EN;
92262306a36Sopenharmony_ci	stm32_dma_write(dmadev, STM32_DMA_SCR(id), chan_reg.dma_scr);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: resumed\n", &chan->vchan);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	return 0;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan,
93262306a36Sopenharmony_ci				    enum dma_transfer_direction direction,
93362306a36Sopenharmony_ci				    enum dma_slave_buswidth *buswidth,
93462306a36Sopenharmony_ci				    u32 buf_len, dma_addr_t buf_addr)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	enum dma_slave_buswidth src_addr_width, dst_addr_width;
93762306a36Sopenharmony_ci	int src_bus_width, dst_bus_width;
93862306a36Sopenharmony_ci	int src_burst_size, dst_burst_size;
93962306a36Sopenharmony_ci	u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst;
94062306a36Sopenharmony_ci	u32 dma_scr, fifoth;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	src_addr_width = chan->dma_sconfig.src_addr_width;
94362306a36Sopenharmony_ci	dst_addr_width = chan->dma_sconfig.dst_addr_width;
94462306a36Sopenharmony_ci	src_maxburst = chan->dma_sconfig.src_maxburst;
94562306a36Sopenharmony_ci	dst_maxburst = chan->dma_sconfig.dst_maxburst;
94662306a36Sopenharmony_ci	fifoth = chan->threshold;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	switch (direction) {
94962306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
95062306a36Sopenharmony_ci		/* Set device data size */
95162306a36Sopenharmony_ci		dst_bus_width = stm32_dma_get_width(chan, dst_addr_width);
95262306a36Sopenharmony_ci		if (dst_bus_width < 0)
95362306a36Sopenharmony_ci			return dst_bus_width;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci		/* Set device burst size */
95662306a36Sopenharmony_ci		dst_best_burst = stm32_dma_get_best_burst(buf_len,
95762306a36Sopenharmony_ci							  dst_maxburst,
95862306a36Sopenharmony_ci							  fifoth,
95962306a36Sopenharmony_ci							  dst_addr_width);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst);
96262306a36Sopenharmony_ci		if (dst_burst_size < 0)
96362306a36Sopenharmony_ci			return dst_burst_size;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		/* Set memory data size */
96662306a36Sopenharmony_ci		src_addr_width = stm32_dma_get_max_width(buf_len, buf_addr,
96762306a36Sopenharmony_ci							 fifoth);
96862306a36Sopenharmony_ci		chan->mem_width = src_addr_width;
96962306a36Sopenharmony_ci		src_bus_width = stm32_dma_get_width(chan, src_addr_width);
97062306a36Sopenharmony_ci		if (src_bus_width < 0)
97162306a36Sopenharmony_ci			return src_bus_width;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		/*
97462306a36Sopenharmony_ci		 * Set memory burst size - burst not possible if address is not aligned on
97562306a36Sopenharmony_ci		 * the address boundary equal to the size of the transfer
97662306a36Sopenharmony_ci		 */
97762306a36Sopenharmony_ci		if (buf_addr & (buf_len - 1))
97862306a36Sopenharmony_ci			src_maxburst = 1;
97962306a36Sopenharmony_ci		else
98062306a36Sopenharmony_ci			src_maxburst = STM32_DMA_MAX_BURST;
98162306a36Sopenharmony_ci		src_best_burst = stm32_dma_get_best_burst(buf_len,
98262306a36Sopenharmony_ci							  src_maxburst,
98362306a36Sopenharmony_ci							  fifoth,
98462306a36Sopenharmony_ci							  src_addr_width);
98562306a36Sopenharmony_ci		src_burst_size = stm32_dma_get_burst(chan, src_best_burst);
98662306a36Sopenharmony_ci		if (src_burst_size < 0)
98762306a36Sopenharmony_ci			return src_burst_size;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci		dma_scr = FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_MEM_TO_DEV) |
99062306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_PSIZE_MASK, dst_bus_width) |
99162306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_MSIZE_MASK, src_bus_width) |
99262306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, dst_burst_size) |
99362306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, src_burst_size);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		/* Set FIFO threshold */
99662306a36Sopenharmony_ci		chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK;
99762306a36Sopenharmony_ci		if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE)
99862306a36Sopenharmony_ci			chan->chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, fifoth);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		/* Set peripheral address */
100162306a36Sopenharmony_ci		chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr;
100262306a36Sopenharmony_ci		*buswidth = dst_addr_width;
100362306a36Sopenharmony_ci		break;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
100662306a36Sopenharmony_ci		/* Set device data size */
100762306a36Sopenharmony_ci		src_bus_width = stm32_dma_get_width(chan, src_addr_width);
100862306a36Sopenharmony_ci		if (src_bus_width < 0)
100962306a36Sopenharmony_ci			return src_bus_width;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci		/* Set device burst size */
101262306a36Sopenharmony_ci		src_best_burst = stm32_dma_get_best_burst(buf_len,
101362306a36Sopenharmony_ci							  src_maxburst,
101462306a36Sopenharmony_ci							  fifoth,
101562306a36Sopenharmony_ci							  src_addr_width);
101662306a36Sopenharmony_ci		chan->mem_burst = src_best_burst;
101762306a36Sopenharmony_ci		src_burst_size = stm32_dma_get_burst(chan, src_best_burst);
101862306a36Sopenharmony_ci		if (src_burst_size < 0)
101962306a36Sopenharmony_ci			return src_burst_size;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		/* Set memory data size */
102262306a36Sopenharmony_ci		dst_addr_width = stm32_dma_get_max_width(buf_len, buf_addr,
102362306a36Sopenharmony_ci							 fifoth);
102462306a36Sopenharmony_ci		chan->mem_width = dst_addr_width;
102562306a36Sopenharmony_ci		dst_bus_width = stm32_dma_get_width(chan, dst_addr_width);
102662306a36Sopenharmony_ci		if (dst_bus_width < 0)
102762306a36Sopenharmony_ci			return dst_bus_width;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		/*
103062306a36Sopenharmony_ci		 * Set memory burst size - burst not possible if address is not aligned on
103162306a36Sopenharmony_ci		 * the address boundary equal to the size of the transfer
103262306a36Sopenharmony_ci		 */
103362306a36Sopenharmony_ci		if (buf_addr & (buf_len - 1))
103462306a36Sopenharmony_ci			dst_maxburst = 1;
103562306a36Sopenharmony_ci		else
103662306a36Sopenharmony_ci			dst_maxburst = STM32_DMA_MAX_BURST;
103762306a36Sopenharmony_ci		dst_best_burst = stm32_dma_get_best_burst(buf_len,
103862306a36Sopenharmony_ci							  dst_maxburst,
103962306a36Sopenharmony_ci							  fifoth,
104062306a36Sopenharmony_ci							  dst_addr_width);
104162306a36Sopenharmony_ci		chan->mem_burst = dst_best_burst;
104262306a36Sopenharmony_ci		dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst);
104362306a36Sopenharmony_ci		if (dst_burst_size < 0)
104462306a36Sopenharmony_ci			return dst_burst_size;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		dma_scr = FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_DEV_TO_MEM) |
104762306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_PSIZE_MASK, src_bus_width) |
104862306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_MSIZE_MASK, dst_bus_width) |
104962306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, src_burst_size) |
105062306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, dst_burst_size);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		/* Set FIFO threshold */
105362306a36Sopenharmony_ci		chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK;
105462306a36Sopenharmony_ci		if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE)
105562306a36Sopenharmony_ci			chan->chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, fifoth);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		/* Set peripheral address */
105862306a36Sopenharmony_ci		chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr;
105962306a36Sopenharmony_ci		*buswidth = chan->dma_sconfig.src_addr_width;
106062306a36Sopenharmony_ci		break;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	default:
106362306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Dma direction is not supported\n");
106462306a36Sopenharmony_ci		return -EINVAL;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	stm32_dma_set_fifo_config(chan, src_best_burst, dst_best_burst);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	/* Set DMA control register */
107062306a36Sopenharmony_ci	chan->chan_reg.dma_scr &= ~(STM32_DMA_SCR_DIR_MASK |
107162306a36Sopenharmony_ci			STM32_DMA_SCR_PSIZE_MASK | STM32_DMA_SCR_MSIZE_MASK |
107262306a36Sopenharmony_ci			STM32_DMA_SCR_PBURST_MASK | STM32_DMA_SCR_MBURST_MASK);
107362306a36Sopenharmony_ci	chan->chan_reg.dma_scr |= dma_scr;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	return 0;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	memset(regs, 0, sizeof(struct stm32_dma_chan_reg));
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg(
108462306a36Sopenharmony_ci	struct dma_chan *c, struct scatterlist *sgl,
108562306a36Sopenharmony_ci	u32 sg_len, enum dma_transfer_direction direction,
108662306a36Sopenharmony_ci	unsigned long flags, void *context)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
108962306a36Sopenharmony_ci	struct stm32_dma_desc *desc;
109062306a36Sopenharmony_ci	struct scatterlist *sg;
109162306a36Sopenharmony_ci	enum dma_slave_buswidth buswidth;
109262306a36Sopenharmony_ci	u32 nb_data_items;
109362306a36Sopenharmony_ci	int i, ret;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	if (!chan->config_init) {
109662306a36Sopenharmony_ci		dev_err(chan2dev(chan), "dma channel is not configured\n");
109762306a36Sopenharmony_ci		return NULL;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (sg_len < 1) {
110162306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Invalid segment length %d\n", sg_len);
110262306a36Sopenharmony_ci		return NULL;
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	desc = kzalloc(struct_size(desc, sg_req, sg_len), GFP_NOWAIT);
110662306a36Sopenharmony_ci	if (!desc)
110762306a36Sopenharmony_ci		return NULL;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	/* Set peripheral flow controller */
111062306a36Sopenharmony_ci	if (chan->dma_sconfig.device_fc)
111162306a36Sopenharmony_ci		chan->chan_reg.dma_scr |= STM32_DMA_SCR_PFCTRL;
111262306a36Sopenharmony_ci	else
111362306a36Sopenharmony_ci		chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	/* Activate Double Buffer Mode if DMA triggers STM32 MDMA and more than 1 sg */
111662306a36Sopenharmony_ci	if (chan->trig_mdma && sg_len > 1) {
111762306a36Sopenharmony_ci		chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM;
111862306a36Sopenharmony_ci		chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_CT;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	for_each_sg(sgl, sg, sg_len, i) {
112262306a36Sopenharmony_ci		ret = stm32_dma_set_xfer_param(chan, direction, &buswidth,
112362306a36Sopenharmony_ci					       sg_dma_len(sg),
112462306a36Sopenharmony_ci					       sg_dma_address(sg));
112562306a36Sopenharmony_ci		if (ret < 0)
112662306a36Sopenharmony_ci			goto err;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		desc->sg_req[i].len = sg_dma_len(sg);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		nb_data_items = desc->sg_req[i].len / buswidth;
113162306a36Sopenharmony_ci		if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) {
113262306a36Sopenharmony_ci			dev_err(chan2dev(chan), "nb items not supported\n");
113362306a36Sopenharmony_ci			goto err;
113462306a36Sopenharmony_ci		}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci		stm32_dma_clear_reg(&desc->sg_req[i].chan_reg);
113762306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr;
113862306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr;
113962306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar;
114062306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg);
114162306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg);
114262306a36Sopenharmony_ci		if (chan->trig_mdma)
114362306a36Sopenharmony_ci			desc->sg_req[i].chan_reg.dma_sm1ar += sg_dma_len(sg);
114462306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items;
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	desc->num_sgs = sg_len;
114862306a36Sopenharmony_ci	desc->cyclic = false;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cierr:
115362306a36Sopenharmony_ci	kfree(desc);
115462306a36Sopenharmony_ci	return NULL;
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic(
115862306a36Sopenharmony_ci	struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len,
115962306a36Sopenharmony_ci	size_t period_len, enum dma_transfer_direction direction,
116062306a36Sopenharmony_ci	unsigned long flags)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
116362306a36Sopenharmony_ci	struct stm32_dma_desc *desc;
116462306a36Sopenharmony_ci	enum dma_slave_buswidth buswidth;
116562306a36Sopenharmony_ci	u32 num_periods, nb_data_items;
116662306a36Sopenharmony_ci	int i, ret;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (!buf_len || !period_len) {
116962306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Invalid buffer/period len\n");
117062306a36Sopenharmony_ci		return NULL;
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (!chan->config_init) {
117462306a36Sopenharmony_ci		dev_err(chan2dev(chan), "dma channel is not configured\n");
117562306a36Sopenharmony_ci		return NULL;
117662306a36Sopenharmony_ci	}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	if (buf_len % period_len) {
117962306a36Sopenharmony_ci		dev_err(chan2dev(chan), "buf_len not multiple of period_len\n");
118062306a36Sopenharmony_ci		return NULL;
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/*
118462306a36Sopenharmony_ci	 * We allow to take more number of requests till DMA is
118562306a36Sopenharmony_ci	 * not started. The driver will loop over all requests.
118662306a36Sopenharmony_ci	 * Once DMA is started then new requests can be queued only after
118762306a36Sopenharmony_ci	 * terminating the DMA.
118862306a36Sopenharmony_ci	 */
118962306a36Sopenharmony_ci	if (chan->busy) {
119062306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Request not allowed when dma busy\n");
119162306a36Sopenharmony_ci		return NULL;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len,
119562306a36Sopenharmony_ci				       buf_addr);
119662306a36Sopenharmony_ci	if (ret < 0)
119762306a36Sopenharmony_ci		return NULL;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	nb_data_items = period_len / buswidth;
120062306a36Sopenharmony_ci	if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) {
120162306a36Sopenharmony_ci		dev_err(chan2dev(chan), "number of items not supported\n");
120262306a36Sopenharmony_ci		return NULL;
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/*  Enable Circular mode or double buffer mode */
120662306a36Sopenharmony_ci	if (buf_len == period_len) {
120762306a36Sopenharmony_ci		chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC;
120862306a36Sopenharmony_ci	} else {
120962306a36Sopenharmony_ci		chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM;
121062306a36Sopenharmony_ci		chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_CT;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	/* Clear periph ctrl if client set it */
121462306a36Sopenharmony_ci	chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	num_periods = buf_len / period_len;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	desc = kzalloc(struct_size(desc, sg_req, num_periods), GFP_NOWAIT);
121962306a36Sopenharmony_ci	if (!desc)
122062306a36Sopenharmony_ci		return NULL;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	for (i = 0; i < num_periods; i++) {
122362306a36Sopenharmony_ci		desc->sg_req[i].len = period_len;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci		stm32_dma_clear_reg(&desc->sg_req[i].chan_reg);
122662306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr;
122762306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr;
122862306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar;
122962306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sm0ar = buf_addr;
123062306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sm1ar = buf_addr;
123162306a36Sopenharmony_ci		if (chan->trig_mdma)
123262306a36Sopenharmony_ci			desc->sg_req[i].chan_reg.dma_sm1ar += period_len;
123362306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items;
123462306a36Sopenharmony_ci		if (!chan->trig_mdma)
123562306a36Sopenharmony_ci			buf_addr += period_len;
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	desc->num_sgs = num_periods;
123962306a36Sopenharmony_ci	desc->cyclic = true;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy(
124562306a36Sopenharmony_ci	struct dma_chan *c, dma_addr_t dest,
124662306a36Sopenharmony_ci	dma_addr_t src, size_t len, unsigned long flags)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
124962306a36Sopenharmony_ci	enum dma_slave_buswidth max_width;
125062306a36Sopenharmony_ci	struct stm32_dma_desc *desc;
125162306a36Sopenharmony_ci	size_t xfer_count, offset;
125262306a36Sopenharmony_ci	u32 num_sgs, best_burst, threshold;
125362306a36Sopenharmony_ci	int dma_burst, i;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	num_sgs = DIV_ROUND_UP(len, STM32_DMA_ALIGNED_MAX_DATA_ITEMS);
125662306a36Sopenharmony_ci	desc = kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT);
125762306a36Sopenharmony_ci	if (!desc)
125862306a36Sopenharmony_ci		return NULL;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	threshold = chan->threshold;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	for (offset = 0, i = 0; offset < len; offset += xfer_count, i++) {
126362306a36Sopenharmony_ci		xfer_count = min_t(size_t, len - offset,
126462306a36Sopenharmony_ci				   STM32_DMA_ALIGNED_MAX_DATA_ITEMS);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci		/* Compute best burst size */
126762306a36Sopenharmony_ci		max_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
126862306a36Sopenharmony_ci		best_burst = stm32_dma_get_best_burst(len, STM32_DMA_MAX_BURST,
126962306a36Sopenharmony_ci						      threshold, max_width);
127062306a36Sopenharmony_ci		dma_burst = stm32_dma_get_burst(chan, best_burst);
127162306a36Sopenharmony_ci		if (dma_burst < 0) {
127262306a36Sopenharmony_ci			kfree(desc);
127362306a36Sopenharmony_ci			return NULL;
127462306a36Sopenharmony_ci		}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		stm32_dma_clear_reg(&desc->sg_req[i].chan_reg);
127762306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_scr =
127862306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_MEM_TO_MEM) |
127962306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, dma_burst) |
128062306a36Sopenharmony_ci			FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, dma_burst) |
128162306a36Sopenharmony_ci			STM32_DMA_SCR_MINC |
128262306a36Sopenharmony_ci			STM32_DMA_SCR_PINC |
128362306a36Sopenharmony_ci			STM32_DMA_SCR_TCIE |
128462306a36Sopenharmony_ci			STM32_DMA_SCR_TEIE;
128562306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK;
128662306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, threshold);
128762306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_spar = src + offset;
128862306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sm0ar = dest + offset;
128962306a36Sopenharmony_ci		desc->sg_req[i].chan_reg.dma_sndtr = xfer_count;
129062306a36Sopenharmony_ci		desc->sg_req[i].len = xfer_count;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	desc->num_sgs = num_sgs;
129462306a36Sopenharmony_ci	desc->cyclic = false;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	u32 dma_scr, width, ndtr;
130262306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
130562306a36Sopenharmony_ci	width = FIELD_GET(STM32_DMA_SCR_PSIZE_MASK, dma_scr);
130662306a36Sopenharmony_ci	ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	return ndtr << width;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci/**
131262306a36Sopenharmony_ci * stm32_dma_is_current_sg - check that expected sg_req is currently transferred
131362306a36Sopenharmony_ci * @chan: dma channel
131462306a36Sopenharmony_ci *
131562306a36Sopenharmony_ci * This function called when IRQ are disable, checks that the hardware has not
131662306a36Sopenharmony_ci * switched on the next transfer in double buffer mode. The test is done by
131762306a36Sopenharmony_ci * comparing the next_sg memory address with the hardware related register
131862306a36Sopenharmony_ci * (based on CT bit value).
131962306a36Sopenharmony_ci *
132062306a36Sopenharmony_ci * Returns true if expected current transfer is still running or double
132162306a36Sopenharmony_ci * buffer mode is not activated.
132262306a36Sopenharmony_ci */
132362306a36Sopenharmony_cistatic bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
132662306a36Sopenharmony_ci	struct stm32_dma_sg_req *sg_req;
132762306a36Sopenharmony_ci	u32 dma_scr, dma_smar, id, period_len;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	id = chan->id;
133062306a36Sopenharmony_ci	dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* In cyclic CIRC but not DBM, CT is not used */
133362306a36Sopenharmony_ci	if (!(dma_scr & STM32_DMA_SCR_DBM))
133462306a36Sopenharmony_ci		return true;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	sg_req = &chan->desc->sg_req[chan->next_sg];
133762306a36Sopenharmony_ci	period_len = sg_req->len;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	/* DBM - take care of a previous pause/resume not yet post reconfigured */
134062306a36Sopenharmony_ci	if (dma_scr & STM32_DMA_SCR_CT) {
134162306a36Sopenharmony_ci		dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id));
134262306a36Sopenharmony_ci		/*
134362306a36Sopenharmony_ci		 * If transfer has been pause/resumed,
134462306a36Sopenharmony_ci		 * SM0AR is in the range of [SM0AR:SM0AR+period_len]
134562306a36Sopenharmony_ci		 */
134662306a36Sopenharmony_ci		return (dma_smar >= sg_req->chan_reg.dma_sm0ar &&
134762306a36Sopenharmony_ci			dma_smar < sg_req->chan_reg.dma_sm0ar + period_len);
134862306a36Sopenharmony_ci	}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id));
135162306a36Sopenharmony_ci	/*
135262306a36Sopenharmony_ci	 * If transfer has been pause/resumed,
135362306a36Sopenharmony_ci	 * SM1AR is in the range of [SM1AR:SM1AR+period_len]
135462306a36Sopenharmony_ci	 */
135562306a36Sopenharmony_ci	return (dma_smar >= sg_req->chan_reg.dma_sm1ar &&
135662306a36Sopenharmony_ci		dma_smar < sg_req->chan_reg.dma_sm1ar + period_len);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
136062306a36Sopenharmony_ci				     struct stm32_dma_desc *desc,
136162306a36Sopenharmony_ci				     u32 next_sg)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	u32 modulo, burst_size;
136462306a36Sopenharmony_ci	u32 residue;
136562306a36Sopenharmony_ci	u32 n_sg = next_sg;
136662306a36Sopenharmony_ci	struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg];
136762306a36Sopenharmony_ci	int i;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	/*
137062306a36Sopenharmony_ci	 * Calculate the residue means compute the descriptors
137162306a36Sopenharmony_ci	 * information:
137262306a36Sopenharmony_ci	 * - the sg_req currently transferred
137362306a36Sopenharmony_ci	 * - the Hardware remaining position in this sg (NDTR bits field).
137462306a36Sopenharmony_ci	 *
137562306a36Sopenharmony_ci	 * A race condition may occur if DMA is running in cyclic or double
137662306a36Sopenharmony_ci	 * buffer mode, since the DMA register are automatically reloaded at end
137762306a36Sopenharmony_ci	 * of period transfer. The hardware may have switched to the next
137862306a36Sopenharmony_ci	 * transfer (CT bit updated) just before the position (SxNDTR reg) is
137962306a36Sopenharmony_ci	 * read.
138062306a36Sopenharmony_ci	 * In this case the SxNDTR reg could (or not) correspond to the new
138162306a36Sopenharmony_ci	 * transfer position, and not the expected one.
138262306a36Sopenharmony_ci	 * The strategy implemented in the stm32 driver is to:
138362306a36Sopenharmony_ci	 *  - read the SxNDTR register
138462306a36Sopenharmony_ci	 *  - crosscheck that hardware is still in current transfer.
138562306a36Sopenharmony_ci	 * In case of switch, we can assume that the DMA is at the beginning of
138662306a36Sopenharmony_ci	 * the next transfer. So we approximate the residue in consequence, by
138762306a36Sopenharmony_ci	 * pointing on the beginning of next transfer.
138862306a36Sopenharmony_ci	 *
138962306a36Sopenharmony_ci	 * This race condition doesn't apply for none cyclic mode, as double
139062306a36Sopenharmony_ci	 * buffer is not used. In such situation registers are updated by the
139162306a36Sopenharmony_ci	 * software.
139262306a36Sopenharmony_ci	 */
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	residue = stm32_dma_get_remaining_bytes(chan);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if ((chan->desc->cyclic || chan->trig_mdma) && !stm32_dma_is_current_sg(chan)) {
139762306a36Sopenharmony_ci		n_sg++;
139862306a36Sopenharmony_ci		if (n_sg == chan->desc->num_sgs)
139962306a36Sopenharmony_ci			n_sg = 0;
140062306a36Sopenharmony_ci		if (!chan->trig_mdma)
140162306a36Sopenharmony_ci			residue = sg_req->len;
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/*
140562306a36Sopenharmony_ci	 * In cyclic mode, for the last period, residue = remaining bytes
140662306a36Sopenharmony_ci	 * from NDTR,
140762306a36Sopenharmony_ci	 * else for all other periods in cyclic mode, and in sg mode,
140862306a36Sopenharmony_ci	 * residue = remaining bytes from NDTR + remaining
140962306a36Sopenharmony_ci	 * periods/sg to be transferred
141062306a36Sopenharmony_ci	 */
141162306a36Sopenharmony_ci	if ((!chan->desc->cyclic && !chan->trig_mdma) || n_sg != 0)
141262306a36Sopenharmony_ci		for (i = n_sg; i < desc->num_sgs; i++)
141362306a36Sopenharmony_ci			residue += desc->sg_req[i].len;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (!chan->mem_burst)
141662306a36Sopenharmony_ci		return residue;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	burst_size = chan->mem_burst * chan->mem_width;
141962306a36Sopenharmony_ci	modulo = residue % burst_size;
142062306a36Sopenharmony_ci	if (modulo)
142162306a36Sopenharmony_ci		residue = residue - modulo + burst_size;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	return residue;
142462306a36Sopenharmony_ci}
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_cistatic enum dma_status stm32_dma_tx_status(struct dma_chan *c,
142762306a36Sopenharmony_ci					   dma_cookie_t cookie,
142862306a36Sopenharmony_ci					   struct dma_tx_state *state)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
143162306a36Sopenharmony_ci	struct virt_dma_desc *vdesc;
143262306a36Sopenharmony_ci	enum dma_status status;
143362306a36Sopenharmony_ci	unsigned long flags;
143462306a36Sopenharmony_ci	u32 residue = 0;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	status = dma_cookie_status(c, cookie, state);
143762306a36Sopenharmony_ci	if (status == DMA_COMPLETE)
143862306a36Sopenharmony_ci		return status;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	status = chan->status;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (!state)
144362306a36Sopenharmony_ci		return status;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
144662306a36Sopenharmony_ci	vdesc = vchan_find_desc(&chan->vchan, cookie);
144762306a36Sopenharmony_ci	if (chan->desc && cookie == chan->desc->vdesc.tx.cookie)
144862306a36Sopenharmony_ci		residue = stm32_dma_desc_residue(chan, chan->desc,
144962306a36Sopenharmony_ci						 chan->next_sg);
145062306a36Sopenharmony_ci	else if (vdesc)
145162306a36Sopenharmony_ci		residue = stm32_dma_desc_residue(chan,
145262306a36Sopenharmony_ci						 to_stm32_dma_desc(vdesc), 0);
145362306a36Sopenharmony_ci	dma_set_residue(state, residue);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	return status;
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic int stm32_dma_alloc_chan_resources(struct dma_chan *c)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
146362306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
146462306a36Sopenharmony_ci	int ret;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	chan->config_init = false;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dmadev->ddev.dev);
146962306a36Sopenharmony_ci	if (ret < 0)
147062306a36Sopenharmony_ci		return ret;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	ret = stm32_dma_disable_chan(chan);
147362306a36Sopenharmony_ci	if (ret < 0)
147462306a36Sopenharmony_ci		pm_runtime_put(dmadev->ddev.dev);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	return ret;
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic void stm32_dma_free_chan_resources(struct dma_chan *c)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
148262306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
148362306a36Sopenharmony_ci	unsigned long flags;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (chan->busy) {
148862306a36Sopenharmony_ci		spin_lock_irqsave(&chan->vchan.lock, flags);
148962306a36Sopenharmony_ci		stm32_dma_stop(chan);
149062306a36Sopenharmony_ci		chan->desc = NULL;
149162306a36Sopenharmony_ci		spin_unlock_irqrestore(&chan->vchan.lock, flags);
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	pm_runtime_put(dmadev->ddev.dev);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	vchan_free_chan_resources(to_virt_chan(c));
149762306a36Sopenharmony_ci	stm32_dma_clear_reg(&chan->chan_reg);
149862306a36Sopenharmony_ci	chan->threshold = 0;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic void stm32_dma_desc_free(struct virt_dma_desc *vdesc)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	kfree(container_of(vdesc, struct stm32_dma_desc, vdesc));
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic void stm32_dma_set_config(struct stm32_dma_chan *chan,
150762306a36Sopenharmony_ci				 struct stm32_dma_cfg *cfg)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	stm32_dma_clear_reg(&chan->chan_reg);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	chan->chan_reg.dma_scr = cfg->stream_config & STM32_DMA_SCR_CFG_MASK;
151262306a36Sopenharmony_ci	chan->chan_reg.dma_scr |= FIELD_PREP(STM32_DMA_SCR_REQ_MASK, cfg->request_line);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* Enable Interrupts  */
151562306a36Sopenharmony_ci	chan->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	chan->threshold = FIELD_GET(STM32_DMA_THRESHOLD_FTR_MASK, cfg->features);
151862306a36Sopenharmony_ci	if (FIELD_GET(STM32_DMA_DIRECT_MODE_MASK, cfg->features))
151962306a36Sopenharmony_ci		chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE;
152062306a36Sopenharmony_ci	if (FIELD_GET(STM32_DMA_ALT_ACK_MODE_MASK, cfg->features))
152162306a36Sopenharmony_ci		chan->chan_reg.dma_scr |= STM32_DMA_SCR_TRBUFF;
152262306a36Sopenharmony_ci	chan->mdma_config.stream_id = FIELD_GET(STM32_DMA_MDMA_STREAM_ID_MASK, cfg->features);
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cistatic struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
152662306a36Sopenharmony_ci					   struct of_dma *ofdma)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = ofdma->of_dma_data;
152962306a36Sopenharmony_ci	struct device *dev = dmadev->ddev.dev;
153062306a36Sopenharmony_ci	struct stm32_dma_cfg cfg;
153162306a36Sopenharmony_ci	struct stm32_dma_chan *chan;
153262306a36Sopenharmony_ci	struct dma_chan *c;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	if (dma_spec->args_count < 4) {
153562306a36Sopenharmony_ci		dev_err(dev, "Bad number of cells\n");
153662306a36Sopenharmony_ci		return NULL;
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	cfg.channel_id = dma_spec->args[0];
154062306a36Sopenharmony_ci	cfg.request_line = dma_spec->args[1];
154162306a36Sopenharmony_ci	cfg.stream_config = dma_spec->args[2];
154262306a36Sopenharmony_ci	cfg.features = dma_spec->args[3];
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (cfg.channel_id >= STM32_DMA_MAX_CHANNELS ||
154562306a36Sopenharmony_ci	    cfg.request_line >= STM32_DMA_MAX_REQUEST_ID) {
154662306a36Sopenharmony_ci		dev_err(dev, "Bad channel and/or request id\n");
154762306a36Sopenharmony_ci		return NULL;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	chan = &dmadev->chan[cfg.channel_id];
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	c = dma_get_slave_channel(&chan->vchan.chan);
155362306a36Sopenharmony_ci	if (!c) {
155462306a36Sopenharmony_ci		dev_err(dev, "No more channels available\n");
155562306a36Sopenharmony_ci		return NULL;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	stm32_dma_set_config(chan, &cfg);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	return c;
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic const struct of_device_id stm32_dma_of_match[] = {
156462306a36Sopenharmony_ci	{ .compatible = "st,stm32-dma", },
156562306a36Sopenharmony_ci	{ /* sentinel */ },
156662306a36Sopenharmony_ci};
156762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_dma_of_match);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic int stm32_dma_probe(struct platform_device *pdev)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	struct stm32_dma_chan *chan;
157262306a36Sopenharmony_ci	struct stm32_dma_device *dmadev;
157362306a36Sopenharmony_ci	struct dma_device *dd;
157462306a36Sopenharmony_ci	const struct of_device_id *match;
157562306a36Sopenharmony_ci	struct resource *res;
157662306a36Sopenharmony_ci	struct reset_control *rst;
157762306a36Sopenharmony_ci	int i, ret;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	match = of_match_device(stm32_dma_of_match, &pdev->dev);
158062306a36Sopenharmony_ci	if (!match) {
158162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Error: No device match found\n");
158262306a36Sopenharmony_ci		return -ENODEV;
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
158662306a36Sopenharmony_ci	if (!dmadev)
158762306a36Sopenharmony_ci		return -ENOMEM;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	dd = &dmadev->ddev;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	dmadev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
159262306a36Sopenharmony_ci	if (IS_ERR(dmadev->base))
159362306a36Sopenharmony_ci		return PTR_ERR(dmadev->base);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	dmadev->clk = devm_clk_get(&pdev->dev, NULL);
159662306a36Sopenharmony_ci	if (IS_ERR(dmadev->clk))
159762306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(dmadev->clk), "Can't get clock\n");
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	ret = clk_prepare_enable(dmadev->clk);
160062306a36Sopenharmony_ci	if (ret < 0) {
160162306a36Sopenharmony_ci		dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret);
160262306a36Sopenharmony_ci		return ret;
160362306a36Sopenharmony_ci	}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node,
160662306a36Sopenharmony_ci						"st,mem2mem");
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	rst = devm_reset_control_get(&pdev->dev, NULL);
160962306a36Sopenharmony_ci	if (IS_ERR(rst)) {
161062306a36Sopenharmony_ci		ret = PTR_ERR(rst);
161162306a36Sopenharmony_ci		if (ret == -EPROBE_DEFER)
161262306a36Sopenharmony_ci			goto clk_free;
161362306a36Sopenharmony_ci	} else {
161462306a36Sopenharmony_ci		reset_control_assert(rst);
161562306a36Sopenharmony_ci		udelay(2);
161662306a36Sopenharmony_ci		reset_control_deassert(rst);
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, dd->cap_mask);
162262306a36Sopenharmony_ci	dma_cap_set(DMA_PRIVATE, dd->cap_mask);
162362306a36Sopenharmony_ci	dma_cap_set(DMA_CYCLIC, dd->cap_mask);
162462306a36Sopenharmony_ci	dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources;
162562306a36Sopenharmony_ci	dd->device_free_chan_resources = stm32_dma_free_chan_resources;
162662306a36Sopenharmony_ci	dd->device_tx_status = stm32_dma_tx_status;
162762306a36Sopenharmony_ci	dd->device_issue_pending = stm32_dma_issue_pending;
162862306a36Sopenharmony_ci	dd->device_prep_slave_sg = stm32_dma_prep_slave_sg;
162962306a36Sopenharmony_ci	dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic;
163062306a36Sopenharmony_ci	dd->device_config = stm32_dma_slave_config;
163162306a36Sopenharmony_ci	dd->device_pause = stm32_dma_pause;
163262306a36Sopenharmony_ci	dd->device_resume = stm32_dma_resume;
163362306a36Sopenharmony_ci	dd->device_terminate_all = stm32_dma_terminate_all;
163462306a36Sopenharmony_ci	dd->device_synchronize = stm32_dma_synchronize;
163562306a36Sopenharmony_ci	dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
163662306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
163762306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
163862306a36Sopenharmony_ci	dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
163962306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
164062306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
164162306a36Sopenharmony_ci	dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
164262306a36Sopenharmony_ci	dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
164362306a36Sopenharmony_ci	dd->copy_align = DMAENGINE_ALIGN_32_BYTES;
164462306a36Sopenharmony_ci	dd->max_burst = STM32_DMA_MAX_BURST;
164562306a36Sopenharmony_ci	dd->max_sg_burst = STM32_DMA_ALIGNED_MAX_DATA_ITEMS;
164662306a36Sopenharmony_ci	dd->descriptor_reuse = true;
164762306a36Sopenharmony_ci	dd->dev = &pdev->dev;
164862306a36Sopenharmony_ci	INIT_LIST_HEAD(&dd->channels);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (dmadev->mem2mem) {
165162306a36Sopenharmony_ci		dma_cap_set(DMA_MEMCPY, dd->cap_mask);
165262306a36Sopenharmony_ci		dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy;
165362306a36Sopenharmony_ci		dd->directions |= BIT(DMA_MEM_TO_MEM);
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
165762306a36Sopenharmony_ci		chan = &dmadev->chan[i];
165862306a36Sopenharmony_ci		chan->id = i;
165962306a36Sopenharmony_ci		chan->vchan.desc_free = stm32_dma_desc_free;
166062306a36Sopenharmony_ci		vchan_init(&chan->vchan, dd);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci		chan->mdma_config.ifcr = res->start;
166362306a36Sopenharmony_ci		chan->mdma_config.ifcr += STM32_DMA_IFCR(chan->id);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci		chan->mdma_config.tcf = STM32_DMA_TCI;
166662306a36Sopenharmony_ci		chan->mdma_config.tcf <<= STM32_DMA_FLAGS_SHIFT(chan->id);
166762306a36Sopenharmony_ci	}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	ret = dma_async_device_register(dd);
167062306a36Sopenharmony_ci	if (ret)
167162306a36Sopenharmony_ci		goto clk_free;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
167462306a36Sopenharmony_ci		chan = &dmadev->chan[i];
167562306a36Sopenharmony_ci		ret = platform_get_irq(pdev, i);
167662306a36Sopenharmony_ci		if (ret < 0)
167762306a36Sopenharmony_ci			goto err_unregister;
167862306a36Sopenharmony_ci		chan->irq = ret;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci		ret = devm_request_irq(&pdev->dev, chan->irq,
168162306a36Sopenharmony_ci				       stm32_dma_chan_irq, 0,
168262306a36Sopenharmony_ci				       dev_name(chan2dev(chan)), chan);
168362306a36Sopenharmony_ci		if (ret) {
168462306a36Sopenharmony_ci			dev_err(&pdev->dev,
168562306a36Sopenharmony_ci				"request_irq failed with err %d channel %d\n",
168662306a36Sopenharmony_ci				ret, i);
168762306a36Sopenharmony_ci			goto err_unregister;
168862306a36Sopenharmony_ci		}
168962306a36Sopenharmony_ci	}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	ret = of_dma_controller_register(pdev->dev.of_node,
169262306a36Sopenharmony_ci					 stm32_dma_of_xlate, dmadev);
169362306a36Sopenharmony_ci	if (ret < 0) {
169462306a36Sopenharmony_ci		dev_err(&pdev->dev,
169562306a36Sopenharmony_ci			"STM32 DMA DMA OF registration failed %d\n", ret);
169662306a36Sopenharmony_ci		goto err_unregister;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	platform_set_drvdata(pdev, dmadev);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
170262306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
170362306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
170462306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	dev_info(&pdev->dev, "STM32 DMA driver registered\n");
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	return 0;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_cierr_unregister:
171162306a36Sopenharmony_ci	dma_async_device_unregister(dd);
171262306a36Sopenharmony_ciclk_free:
171362306a36Sopenharmony_ci	clk_disable_unprepare(dmadev->clk);
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	return ret;
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci#ifdef CONFIG_PM
171962306a36Sopenharmony_cistatic int stm32_dma_runtime_suspend(struct device *dev)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = dev_get_drvdata(dev);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	clk_disable_unprepare(dmadev->clk);
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	return 0;
172662306a36Sopenharmony_ci}
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_cistatic int stm32_dma_runtime_resume(struct device *dev)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = dev_get_drvdata(dev);
173162306a36Sopenharmony_ci	int ret;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	ret = clk_prepare_enable(dmadev->clk);
173462306a36Sopenharmony_ci	if (ret) {
173562306a36Sopenharmony_ci		dev_err(dev, "failed to prepare_enable clock\n");
173662306a36Sopenharmony_ci		return ret;
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	return 0;
174062306a36Sopenharmony_ci}
174162306a36Sopenharmony_ci#endif
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
174462306a36Sopenharmony_cistatic int stm32_dma_pm_suspend(struct device *dev)
174562306a36Sopenharmony_ci{
174662306a36Sopenharmony_ci	struct stm32_dma_device *dmadev = dev_get_drvdata(dev);
174762306a36Sopenharmony_ci	int id, ret, scr;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
175062306a36Sopenharmony_ci	if (ret < 0)
175162306a36Sopenharmony_ci		return ret;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	for (id = 0; id < STM32_DMA_MAX_CHANNELS; id++) {
175462306a36Sopenharmony_ci		scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
175562306a36Sopenharmony_ci		if (scr & STM32_DMA_SCR_EN) {
175662306a36Sopenharmony_ci			dev_warn(dev, "Suspend is prevented by Chan %i\n", id);
175762306a36Sopenharmony_ci			return -EBUSY;
175862306a36Sopenharmony_ci		}
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	pm_runtime_force_suspend(dev);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	return 0;
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic int stm32_dma_pm_resume(struct device *dev)
176962306a36Sopenharmony_ci{
177062306a36Sopenharmony_ci	return pm_runtime_force_resume(dev);
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci#endif
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_cistatic const struct dev_pm_ops stm32_dma_pm_ops = {
177562306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_pm_suspend, stm32_dma_pm_resume)
177662306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend,
177762306a36Sopenharmony_ci			   stm32_dma_runtime_resume, NULL)
177862306a36Sopenharmony_ci};
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_cistatic struct platform_driver stm32_dma_driver = {
178162306a36Sopenharmony_ci	.driver = {
178262306a36Sopenharmony_ci		.name = "stm32-dma",
178362306a36Sopenharmony_ci		.of_match_table = stm32_dma_of_match,
178462306a36Sopenharmony_ci		.pm = &stm32_dma_pm_ops,
178562306a36Sopenharmony_ci	},
178662306a36Sopenharmony_ci	.probe = stm32_dma_probe,
178762306a36Sopenharmony_ci};
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_cistatic int __init stm32_dma_init(void)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	return platform_driver_register(&stm32_dma_driver);
179262306a36Sopenharmony_ci}
179362306a36Sopenharmony_cisubsys_initcall(stm32_dma_init);
1794