162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2017
562306a36Sopenharmony_ci * Author(s): M'boumba Cedric Madianga <cedric.madianga@gmail.com>
662306a36Sopenharmony_ci *            Pierre-Yves Mordret <pierre-yves.mordret@st.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Driver for STM32 MDMA controller
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Inspired by stm32-dma.c and dma-jz4780.c
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/bitfield.h>
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/dmaengine.h>
1762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1862306a36Sopenharmony_ci#include <linux/dmapool.h>
1962306a36Sopenharmony_ci#include <linux/err.h>
2062306a36Sopenharmony_ci#include <linux/init.h>
2162306a36Sopenharmony_ci#include <linux/iopoll.h>
2262306a36Sopenharmony_ci#include <linux/jiffies.h>
2362306a36Sopenharmony_ci#include <linux/list.h>
2462306a36Sopenharmony_ci#include <linux/log2.h>
2562306a36Sopenharmony_ci#include <linux/module.h>
2662306a36Sopenharmony_ci#include <linux/of.h>
2762306a36Sopenharmony_ci#include <linux/of_dma.h>
2862306a36Sopenharmony_ci#include <linux/platform_device.h>
2962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3062306a36Sopenharmony_ci#include <linux/reset.h>
3162306a36Sopenharmony_ci#include <linux/slab.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include "virt-dma.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define STM32_MDMA_GISR0		0x0000 /* MDMA Int Status Reg 1 */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* MDMA Channel x interrupt/status register */
3862306a36Sopenharmony_ci#define STM32_MDMA_CISR(x)		(0x40 + 0x40 * (x)) /* x = 0..62 */
3962306a36Sopenharmony_ci#define STM32_MDMA_CISR_CRQA		BIT(16)
4062306a36Sopenharmony_ci#define STM32_MDMA_CISR_TCIF		BIT(4)
4162306a36Sopenharmony_ci#define STM32_MDMA_CISR_BTIF		BIT(3)
4262306a36Sopenharmony_ci#define STM32_MDMA_CISR_BRTIF		BIT(2)
4362306a36Sopenharmony_ci#define STM32_MDMA_CISR_CTCIF		BIT(1)
4462306a36Sopenharmony_ci#define STM32_MDMA_CISR_TEIF		BIT(0)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* MDMA Channel x interrupt flag clear register */
4762306a36Sopenharmony_ci#define STM32_MDMA_CIFCR(x)		(0x44 + 0x40 * (x))
4862306a36Sopenharmony_ci#define STM32_MDMA_CIFCR_CLTCIF		BIT(4)
4962306a36Sopenharmony_ci#define STM32_MDMA_CIFCR_CBTIF		BIT(3)
5062306a36Sopenharmony_ci#define STM32_MDMA_CIFCR_CBRTIF		BIT(2)
5162306a36Sopenharmony_ci#define STM32_MDMA_CIFCR_CCTCIF		BIT(1)
5262306a36Sopenharmony_ci#define STM32_MDMA_CIFCR_CTEIF		BIT(0)
5362306a36Sopenharmony_ci#define STM32_MDMA_CIFCR_CLEAR_ALL	(STM32_MDMA_CIFCR_CLTCIF \
5462306a36Sopenharmony_ci					| STM32_MDMA_CIFCR_CBTIF \
5562306a36Sopenharmony_ci					| STM32_MDMA_CIFCR_CBRTIF \
5662306a36Sopenharmony_ci					| STM32_MDMA_CIFCR_CCTCIF \
5762306a36Sopenharmony_ci					| STM32_MDMA_CIFCR_CTEIF)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* MDMA Channel x error status register */
6062306a36Sopenharmony_ci#define STM32_MDMA_CESR(x)		(0x48 + 0x40 * (x))
6162306a36Sopenharmony_ci#define STM32_MDMA_CESR_BSE		BIT(11)
6262306a36Sopenharmony_ci#define STM32_MDMA_CESR_ASR		BIT(10)
6362306a36Sopenharmony_ci#define STM32_MDMA_CESR_TEMD		BIT(9)
6462306a36Sopenharmony_ci#define STM32_MDMA_CESR_TELD		BIT(8)
6562306a36Sopenharmony_ci#define STM32_MDMA_CESR_TED		BIT(7)
6662306a36Sopenharmony_ci#define STM32_MDMA_CESR_TEA_MASK	GENMASK(6, 0)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* MDMA Channel x control register */
6962306a36Sopenharmony_ci#define STM32_MDMA_CCR(x)		(0x4C + 0x40 * (x))
7062306a36Sopenharmony_ci#define STM32_MDMA_CCR_SWRQ		BIT(16)
7162306a36Sopenharmony_ci#define STM32_MDMA_CCR_WEX		BIT(14)
7262306a36Sopenharmony_ci#define STM32_MDMA_CCR_HEX		BIT(13)
7362306a36Sopenharmony_ci#define STM32_MDMA_CCR_BEX		BIT(12)
7462306a36Sopenharmony_ci#define STM32_MDMA_CCR_SM		BIT(8)
7562306a36Sopenharmony_ci#define STM32_MDMA_CCR_PL_MASK		GENMASK(7, 6)
7662306a36Sopenharmony_ci#define STM32_MDMA_CCR_PL(n)		FIELD_PREP(STM32_MDMA_CCR_PL_MASK, (n))
7762306a36Sopenharmony_ci#define STM32_MDMA_CCR_TCIE		BIT(5)
7862306a36Sopenharmony_ci#define STM32_MDMA_CCR_BTIE		BIT(4)
7962306a36Sopenharmony_ci#define STM32_MDMA_CCR_BRTIE		BIT(3)
8062306a36Sopenharmony_ci#define STM32_MDMA_CCR_CTCIE		BIT(2)
8162306a36Sopenharmony_ci#define STM32_MDMA_CCR_TEIE		BIT(1)
8262306a36Sopenharmony_ci#define STM32_MDMA_CCR_EN		BIT(0)
8362306a36Sopenharmony_ci#define STM32_MDMA_CCR_IRQ_MASK		(STM32_MDMA_CCR_TCIE \
8462306a36Sopenharmony_ci					| STM32_MDMA_CCR_BTIE \
8562306a36Sopenharmony_ci					| STM32_MDMA_CCR_BRTIE \
8662306a36Sopenharmony_ci					| STM32_MDMA_CCR_CTCIE \
8762306a36Sopenharmony_ci					| STM32_MDMA_CCR_TEIE)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* MDMA Channel x transfer configuration register */
9062306a36Sopenharmony_ci#define STM32_MDMA_CTCR(x)		(0x50 + 0x40 * (x))
9162306a36Sopenharmony_ci#define STM32_MDMA_CTCR_BWM		BIT(31)
9262306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SWRM		BIT(30)
9362306a36Sopenharmony_ci#define STM32_MDMA_CTCR_TRGM_MSK	GENMASK(29, 28)
9462306a36Sopenharmony_ci#define STM32_MDMA_CTCR_TRGM(n)		FIELD_PREP(STM32_MDMA_CTCR_TRGM_MSK, (n))
9562306a36Sopenharmony_ci#define STM32_MDMA_CTCR_TRGM_GET(n)	FIELD_GET(STM32_MDMA_CTCR_TRGM_MSK, (n))
9662306a36Sopenharmony_ci#define STM32_MDMA_CTCR_PAM_MASK	GENMASK(27, 26)
9762306a36Sopenharmony_ci#define STM32_MDMA_CTCR_PAM(n)		FIELD_PREP(STM32_MDMA_CTCR_PAM_MASK, (n))
9862306a36Sopenharmony_ci#define STM32_MDMA_CTCR_PKE		BIT(25)
9962306a36Sopenharmony_ci#define STM32_MDMA_CTCR_TLEN_MSK	GENMASK(24, 18)
10062306a36Sopenharmony_ci#define STM32_MDMA_CTCR_TLEN(n)		FIELD_PREP(STM32_MDMA_CTCR_TLEN_MSK, (n))
10162306a36Sopenharmony_ci#define STM32_MDMA_CTCR_TLEN_GET(n)	FIELD_GET(STM32_MDMA_CTCR_TLEN_MSK, (n))
10262306a36Sopenharmony_ci#define STM32_MDMA_CTCR_LEN2_MSK	GENMASK(25, 18)
10362306a36Sopenharmony_ci#define STM32_MDMA_CTCR_LEN2(n)		FIELD_PREP(STM32_MDMA_CTCR_LEN2_MSK, (n))
10462306a36Sopenharmony_ci#define STM32_MDMA_CTCR_LEN2_GET(n)	FIELD_GET(STM32_MDMA_CTCR_LEN2_MSK, (n))
10562306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DBURST_MASK	GENMASK(17, 15)
10662306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DBURST(n)	FIELD_PREP(STM32_MDMA_CTCR_DBURST_MASK, (n))
10762306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SBURST_MASK	GENMASK(14, 12)
10862306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SBURST(n)	FIELD_PREP(STM32_MDMA_CTCR_SBURST_MASK, (n))
10962306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DINCOS_MASK	GENMASK(11, 10)
11062306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DINCOS(n)	FIELD_PREP(STM32_MDMA_CTCR_DINCOS_MASK, (n))
11162306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SINCOS_MASK	GENMASK(9, 8)
11262306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SINCOS(n)	FIELD_PREP(STM32_MDMA_CTCR_SINCOS_MASK, (n))
11362306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DSIZE_MASK	GENMASK(7, 6)
11462306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DSIZE(n)	FIELD_PREP(STM32_MDMA_CTCR_DSIZE_MASK, (n))
11562306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SSIZE_MASK	GENMASK(5, 4)
11662306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SSIZE(n)	FIELD_PREP(STM32_MDMA_CTCR_SSIZE_MASK, (n))
11762306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DINC_MASK	GENMASK(3, 2)
11862306a36Sopenharmony_ci#define STM32_MDMA_CTCR_DINC(n)		FIELD_PREP(STM32_MDMA_CTCR_DINC_MASK, (n))
11962306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SINC_MASK	GENMASK(1, 0)
12062306a36Sopenharmony_ci#define STM32_MDMA_CTCR_SINC(n)		FIELD_PREP(STM32_MDMA_CTCR_SINC_MASK, (n))
12162306a36Sopenharmony_ci#define STM32_MDMA_CTCR_CFG_MASK	(STM32_MDMA_CTCR_SINC_MASK \
12262306a36Sopenharmony_ci					| STM32_MDMA_CTCR_DINC_MASK \
12362306a36Sopenharmony_ci					| STM32_MDMA_CTCR_SINCOS_MASK \
12462306a36Sopenharmony_ci					| STM32_MDMA_CTCR_DINCOS_MASK \
12562306a36Sopenharmony_ci					| STM32_MDMA_CTCR_LEN2_MSK \
12662306a36Sopenharmony_ci					| STM32_MDMA_CTCR_TRGM_MSK)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* MDMA Channel x block number of data register */
12962306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR(x)		(0x54 + 0x40 * (x))
13062306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BRC_MK	GENMASK(31, 20)
13162306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BRC(n)	FIELD_PREP(STM32_MDMA_CBNDTR_BRC_MK, (n))
13262306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BRC_GET(n)	FIELD_GET(STM32_MDMA_CBNDTR_BRC_MK, (n))
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BRDUM		BIT(19)
13562306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BRSUM		BIT(18)
13662306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BNDT_MASK	GENMASK(16, 0)
13762306a36Sopenharmony_ci#define STM32_MDMA_CBNDTR_BNDT(n)	FIELD_PREP(STM32_MDMA_CBNDTR_BNDT_MASK, (n))
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* MDMA Channel x source address register */
14062306a36Sopenharmony_ci#define STM32_MDMA_CSAR(x)		(0x58 + 0x40 * (x))
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* MDMA Channel x destination address register */
14362306a36Sopenharmony_ci#define STM32_MDMA_CDAR(x)		(0x5C + 0x40 * (x))
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* MDMA Channel x block repeat address update register */
14662306a36Sopenharmony_ci#define STM32_MDMA_CBRUR(x)		(0x60 + 0x40 * (x))
14762306a36Sopenharmony_ci#define STM32_MDMA_CBRUR_DUV_MASK	GENMASK(31, 16)
14862306a36Sopenharmony_ci#define STM32_MDMA_CBRUR_DUV(n)		FIELD_PREP(STM32_MDMA_CBRUR_DUV_MASK, (n))
14962306a36Sopenharmony_ci#define STM32_MDMA_CBRUR_SUV_MASK	GENMASK(15, 0)
15062306a36Sopenharmony_ci#define STM32_MDMA_CBRUR_SUV(n)		FIELD_PREP(STM32_MDMA_CBRUR_SUV_MASK, (n))
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* MDMA Channel x link address register */
15362306a36Sopenharmony_ci#define STM32_MDMA_CLAR(x)		(0x64 + 0x40 * (x))
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* MDMA Channel x trigger and bus selection register */
15662306a36Sopenharmony_ci#define STM32_MDMA_CTBR(x)		(0x68 + 0x40 * (x))
15762306a36Sopenharmony_ci#define STM32_MDMA_CTBR_DBUS		BIT(17)
15862306a36Sopenharmony_ci#define STM32_MDMA_CTBR_SBUS		BIT(16)
15962306a36Sopenharmony_ci#define STM32_MDMA_CTBR_TSEL_MASK	GENMASK(5, 0)
16062306a36Sopenharmony_ci#define STM32_MDMA_CTBR_TSEL(n)		FIELD_PREP(STM32_MDMA_CTBR_TSEL_MASK, (n))
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* MDMA Channel x mask address register */
16362306a36Sopenharmony_ci#define STM32_MDMA_CMAR(x)		(0x70 + 0x40 * (x))
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* MDMA Channel x mask data register */
16662306a36Sopenharmony_ci#define STM32_MDMA_CMDR(x)		(0x74 + 0x40 * (x))
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#define STM32_MDMA_MAX_BUF_LEN		128
16962306a36Sopenharmony_ci#define STM32_MDMA_MAX_BLOCK_LEN	65536
17062306a36Sopenharmony_ci#define STM32_MDMA_MAX_CHANNELS		32
17162306a36Sopenharmony_ci#define STM32_MDMA_MAX_REQUESTS		256
17262306a36Sopenharmony_ci#define STM32_MDMA_MAX_BURST		128
17362306a36Sopenharmony_ci#define STM32_MDMA_VERY_HIGH_PRIORITY	0x3
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cienum stm32_mdma_trigger_mode {
17662306a36Sopenharmony_ci	STM32_MDMA_BUFFER,
17762306a36Sopenharmony_ci	STM32_MDMA_BLOCK,
17862306a36Sopenharmony_ci	STM32_MDMA_BLOCK_REP,
17962306a36Sopenharmony_ci	STM32_MDMA_LINKED_LIST,
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cienum stm32_mdma_width {
18362306a36Sopenharmony_ci	STM32_MDMA_BYTE,
18462306a36Sopenharmony_ci	STM32_MDMA_HALF_WORD,
18562306a36Sopenharmony_ci	STM32_MDMA_WORD,
18662306a36Sopenharmony_ci	STM32_MDMA_DOUBLE_WORD,
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cienum stm32_mdma_inc_mode {
19062306a36Sopenharmony_ci	STM32_MDMA_FIXED = 0,
19162306a36Sopenharmony_ci	STM32_MDMA_INC = 2,
19262306a36Sopenharmony_ci	STM32_MDMA_DEC = 3,
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistruct stm32_mdma_chan_config {
19662306a36Sopenharmony_ci	u32 request;
19762306a36Sopenharmony_ci	u32 priority_level;
19862306a36Sopenharmony_ci	u32 transfer_config;
19962306a36Sopenharmony_ci	u32 mask_addr;
20062306a36Sopenharmony_ci	u32 mask_data;
20162306a36Sopenharmony_ci	bool m2m_hw; /* True when MDMA is triggered by STM32 DMA */
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistruct stm32_mdma_hwdesc {
20562306a36Sopenharmony_ci	u32 ctcr;
20662306a36Sopenharmony_ci	u32 cbndtr;
20762306a36Sopenharmony_ci	u32 csar;
20862306a36Sopenharmony_ci	u32 cdar;
20962306a36Sopenharmony_ci	u32 cbrur;
21062306a36Sopenharmony_ci	u32 clar;
21162306a36Sopenharmony_ci	u32 ctbr;
21262306a36Sopenharmony_ci	u32 dummy;
21362306a36Sopenharmony_ci	u32 cmar;
21462306a36Sopenharmony_ci	u32 cmdr;
21562306a36Sopenharmony_ci} __aligned(64);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistruct stm32_mdma_desc_node {
21862306a36Sopenharmony_ci	struct stm32_mdma_hwdesc *hwdesc;
21962306a36Sopenharmony_ci	dma_addr_t hwdesc_phys;
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistruct stm32_mdma_desc {
22362306a36Sopenharmony_ci	struct virt_dma_desc vdesc;
22462306a36Sopenharmony_ci	u32 ccr;
22562306a36Sopenharmony_ci	bool cyclic;
22662306a36Sopenharmony_ci	u32 count;
22762306a36Sopenharmony_ci	struct stm32_mdma_desc_node node[];
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistruct stm32_mdma_dma_config {
23162306a36Sopenharmony_ci	u32 request;	/* STM32 DMA channel stream id, triggering MDMA */
23262306a36Sopenharmony_ci	u32 cmar;	/* STM32 DMA interrupt flag clear register address */
23362306a36Sopenharmony_ci	u32 cmdr;	/* STM32 DMA Transfer Complete flag */
23462306a36Sopenharmony_ci};
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistruct stm32_mdma_chan {
23762306a36Sopenharmony_ci	struct virt_dma_chan vchan;
23862306a36Sopenharmony_ci	struct dma_pool *desc_pool;
23962306a36Sopenharmony_ci	u32 id;
24062306a36Sopenharmony_ci	struct stm32_mdma_desc *desc;
24162306a36Sopenharmony_ci	u32 curr_hwdesc;
24262306a36Sopenharmony_ci	struct dma_slave_config dma_config;
24362306a36Sopenharmony_ci	struct stm32_mdma_chan_config chan_config;
24462306a36Sopenharmony_ci	bool busy;
24562306a36Sopenharmony_ci	u32 mem_burst;
24662306a36Sopenharmony_ci	u32 mem_width;
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistruct stm32_mdma_device {
25062306a36Sopenharmony_ci	struct dma_device ddev;
25162306a36Sopenharmony_ci	void __iomem *base;
25262306a36Sopenharmony_ci	struct clk *clk;
25362306a36Sopenharmony_ci	int irq;
25462306a36Sopenharmony_ci	u32 nr_channels;
25562306a36Sopenharmony_ci	u32 nr_requests;
25662306a36Sopenharmony_ci	u32 nr_ahb_addr_masks;
25762306a36Sopenharmony_ci	u32 chan_reserved;
25862306a36Sopenharmony_ci	struct stm32_mdma_chan chan[STM32_MDMA_MAX_CHANNELS];
25962306a36Sopenharmony_ci	u32 ahb_addr_masks[];
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic struct stm32_mdma_device *stm32_mdma_get_dev(
26362306a36Sopenharmony_ci	struct stm32_mdma_chan *chan)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	return container_of(chan->vchan.chan.device, struct stm32_mdma_device,
26662306a36Sopenharmony_ci			    ddev);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic struct stm32_mdma_chan *to_stm32_mdma_chan(struct dma_chan *c)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	return container_of(c, struct stm32_mdma_chan, vchan.chan);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic struct stm32_mdma_desc *to_stm32_mdma_desc(struct virt_dma_desc *vdesc)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	return container_of(vdesc, struct stm32_mdma_desc, vdesc);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic struct device *chan2dev(struct stm32_mdma_chan *chan)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	return &chan->vchan.chan.dev->device;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic struct device *mdma2dev(struct stm32_mdma_device *mdma_dev)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	return mdma_dev->ddev.dev;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic u32 stm32_mdma_read(struct stm32_mdma_device *dmadev, u32 reg)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	return readl_relaxed(dmadev->base + reg);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic void stm32_mdma_write(struct stm32_mdma_device *dmadev, u32 reg, u32 val)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	writel_relaxed(val, dmadev->base + reg);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void stm32_mdma_set_bits(struct stm32_mdma_device *dmadev, u32 reg,
30062306a36Sopenharmony_ci				u32 mask)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	void __iomem *addr = dmadev->base + reg;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	writel_relaxed(readl_relaxed(addr) | mask, addr);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic void stm32_mdma_clr_bits(struct stm32_mdma_device *dmadev, u32 reg,
30862306a36Sopenharmony_ci				u32 mask)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	void __iomem *addr = dmadev->base + reg;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	writel_relaxed(readl_relaxed(addr) & ~mask, addr);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic struct stm32_mdma_desc *stm32_mdma_alloc_desc(
31662306a36Sopenharmony_ci		struct stm32_mdma_chan *chan, u32 count)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct stm32_mdma_desc *desc;
31962306a36Sopenharmony_ci	int i;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	desc = kzalloc(struct_size(desc, node, count), GFP_NOWAIT);
32262306a36Sopenharmony_ci	if (!desc)
32362306a36Sopenharmony_ci		return NULL;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
32662306a36Sopenharmony_ci		desc->node[i].hwdesc =
32762306a36Sopenharmony_ci			dma_pool_alloc(chan->desc_pool, GFP_NOWAIT,
32862306a36Sopenharmony_ci				       &desc->node[i].hwdesc_phys);
32962306a36Sopenharmony_ci		if (!desc->node[i].hwdesc)
33062306a36Sopenharmony_ci			goto err;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	desc->count = count;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return desc;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cierr:
33862306a36Sopenharmony_ci	dev_err(chan2dev(chan), "Failed to allocate descriptor\n");
33962306a36Sopenharmony_ci	while (--i >= 0)
34062306a36Sopenharmony_ci		dma_pool_free(chan->desc_pool, desc->node[i].hwdesc,
34162306a36Sopenharmony_ci			      desc->node[i].hwdesc_phys);
34262306a36Sopenharmony_ci	kfree(desc);
34362306a36Sopenharmony_ci	return NULL;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void stm32_mdma_desc_free(struct virt_dma_desc *vdesc)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct stm32_mdma_desc *desc = to_stm32_mdma_desc(vdesc);
34962306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(vdesc->tx.chan);
35062306a36Sopenharmony_ci	int i;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for (i = 0; i < desc->count; i++)
35362306a36Sopenharmony_ci		dma_pool_free(chan->desc_pool, desc->node[i].hwdesc,
35462306a36Sopenharmony_ci			      desc->node[i].hwdesc_phys);
35562306a36Sopenharmony_ci	kfree(desc);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int stm32_mdma_get_width(struct stm32_mdma_chan *chan,
35962306a36Sopenharmony_ci				enum dma_slave_buswidth width)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	switch (width) {
36262306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_1_BYTE:
36362306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_2_BYTES:
36462306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_4_BYTES:
36562306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_8_BYTES:
36662306a36Sopenharmony_ci		return ffs(width) - 1;
36762306a36Sopenharmony_ci	default:
36862306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Dma bus width %i not supported\n",
36962306a36Sopenharmony_ci			width);
37062306a36Sopenharmony_ci		return -EINVAL;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic enum dma_slave_buswidth stm32_mdma_get_max_width(dma_addr_t addr,
37562306a36Sopenharmony_ci							u32 buf_len, u32 tlen)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	enum dma_slave_buswidth max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	for (max_width = DMA_SLAVE_BUSWIDTH_8_BYTES;
38062306a36Sopenharmony_ci	     max_width > DMA_SLAVE_BUSWIDTH_1_BYTE;
38162306a36Sopenharmony_ci	     max_width >>= 1) {
38262306a36Sopenharmony_ci		/*
38362306a36Sopenharmony_ci		 * Address and buffer length both have to be aligned on
38462306a36Sopenharmony_ci		 * bus width
38562306a36Sopenharmony_ci		 */
38662306a36Sopenharmony_ci		if ((((buf_len | addr) & (max_width - 1)) == 0) &&
38762306a36Sopenharmony_ci		    tlen >= max_width)
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return max_width;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic u32 stm32_mdma_get_best_burst(u32 buf_len, u32 tlen, u32 max_burst,
39562306a36Sopenharmony_ci				     enum dma_slave_buswidth width)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	u32 best_burst;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	best_burst = min((u32)1 << __ffs(tlen | buf_len),
40062306a36Sopenharmony_ci			 max_burst * width) / width;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return (best_burst > 0) ? best_burst : 1;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int stm32_mdma_disable_chan(struct stm32_mdma_chan *chan)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
40862306a36Sopenharmony_ci	u32 ccr, cisr, id, reg;
40962306a36Sopenharmony_ci	int ret;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	id = chan->id;
41262306a36Sopenharmony_ci	reg = STM32_MDMA_CCR(id);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Disable interrupts */
41562306a36Sopenharmony_ci	stm32_mdma_clr_bits(dmadev, reg, STM32_MDMA_CCR_IRQ_MASK);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ccr = stm32_mdma_read(dmadev, reg);
41862306a36Sopenharmony_ci	if (ccr & STM32_MDMA_CCR_EN) {
41962306a36Sopenharmony_ci		stm32_mdma_clr_bits(dmadev, reg, STM32_MDMA_CCR_EN);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		/* Ensure that any ongoing transfer has been completed */
42262306a36Sopenharmony_ci		ret = readl_relaxed_poll_timeout_atomic(
42362306a36Sopenharmony_ci				dmadev->base + STM32_MDMA_CISR(id), cisr,
42462306a36Sopenharmony_ci				(cisr & STM32_MDMA_CISR_CTCIF), 10, 1000);
42562306a36Sopenharmony_ci		if (ret) {
42662306a36Sopenharmony_ci			dev_err(chan2dev(chan), "%s: timeout!\n", __func__);
42762306a36Sopenharmony_ci			return -EBUSY;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void stm32_mdma_stop(struct stm32_mdma_chan *chan)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
43762306a36Sopenharmony_ci	u32 status;
43862306a36Sopenharmony_ci	int ret;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	/* Disable DMA */
44162306a36Sopenharmony_ci	ret = stm32_mdma_disable_chan(chan);
44262306a36Sopenharmony_ci	if (ret < 0)
44362306a36Sopenharmony_ci		return;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
44662306a36Sopenharmony_ci	status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id));
44762306a36Sopenharmony_ci	if (status) {
44862306a36Sopenharmony_ci		dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n",
44962306a36Sopenharmony_ci			__func__, status);
45062306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, STM32_MDMA_CIFCR(chan->id), status);
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	chan->busy = false;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic void stm32_mdma_set_bus(struct stm32_mdma_device *dmadev, u32 *ctbr,
45762306a36Sopenharmony_ci			       u32 ctbr_mask, u32 src_addr)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	u32 mask;
46062306a36Sopenharmony_ci	int i;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* Check if memory device is on AHB or AXI */
46362306a36Sopenharmony_ci	*ctbr &= ~ctbr_mask;
46462306a36Sopenharmony_ci	mask = src_addr & 0xF0000000;
46562306a36Sopenharmony_ci	for (i = 0; i < dmadev->nr_ahb_addr_masks; i++) {
46662306a36Sopenharmony_ci		if (mask == dmadev->ahb_addr_masks[i]) {
46762306a36Sopenharmony_ci			*ctbr |= ctbr_mask;
46862306a36Sopenharmony_ci			break;
46962306a36Sopenharmony_ci		}
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan,
47462306a36Sopenharmony_ci				     enum dma_transfer_direction direction,
47562306a36Sopenharmony_ci				     u32 *mdma_ccr, u32 *mdma_ctcr,
47662306a36Sopenharmony_ci				     u32 *mdma_ctbr, dma_addr_t addr,
47762306a36Sopenharmony_ci				     u32 buf_len)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
48062306a36Sopenharmony_ci	struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
48162306a36Sopenharmony_ci	enum dma_slave_buswidth src_addr_width, dst_addr_width;
48262306a36Sopenharmony_ci	phys_addr_t src_addr, dst_addr;
48362306a36Sopenharmony_ci	int src_bus_width, dst_bus_width;
48462306a36Sopenharmony_ci	u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst;
48562306a36Sopenharmony_ci	u32 ccr, ctcr, ctbr, tlen;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	src_addr_width = chan->dma_config.src_addr_width;
48862306a36Sopenharmony_ci	dst_addr_width = chan->dma_config.dst_addr_width;
48962306a36Sopenharmony_ci	src_maxburst = chan->dma_config.src_maxburst;
49062306a36Sopenharmony_ci	dst_maxburst = chan->dma_config.dst_maxburst;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & ~STM32_MDMA_CCR_EN;
49362306a36Sopenharmony_ci	ctcr = stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id));
49462306a36Sopenharmony_ci	ctbr = stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id));
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* Enable HW request mode */
49762306a36Sopenharmony_ci	ctcr &= ~STM32_MDMA_CTCR_SWRM;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* Set DINC, SINC, DINCOS, SINCOS, TRGM and TLEN retrieve from DT */
50062306a36Sopenharmony_ci	ctcr &= ~STM32_MDMA_CTCR_CFG_MASK;
50162306a36Sopenharmony_ci	ctcr |= chan_config->transfer_config & STM32_MDMA_CTCR_CFG_MASK;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/*
50462306a36Sopenharmony_ci	 * For buffer transfer length (TLEN) we have to set
50562306a36Sopenharmony_ci	 * the number of bytes - 1 in CTCR register
50662306a36Sopenharmony_ci	 */
50762306a36Sopenharmony_ci	tlen = STM32_MDMA_CTCR_LEN2_GET(ctcr);
50862306a36Sopenharmony_ci	ctcr &= ~STM32_MDMA_CTCR_LEN2_MSK;
50962306a36Sopenharmony_ci	ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Disable Pack Enable */
51262306a36Sopenharmony_ci	ctcr &= ~STM32_MDMA_CTCR_PKE;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	/* Check burst size constraints */
51562306a36Sopenharmony_ci	if (src_maxburst * src_addr_width > STM32_MDMA_MAX_BURST ||
51662306a36Sopenharmony_ci	    dst_maxburst * dst_addr_width > STM32_MDMA_MAX_BURST) {
51762306a36Sopenharmony_ci		dev_err(chan2dev(chan),
51862306a36Sopenharmony_ci			"burst size * bus width higher than %d bytes\n",
51962306a36Sopenharmony_ci			STM32_MDMA_MAX_BURST);
52062306a36Sopenharmony_ci		return -EINVAL;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if ((!is_power_of_2(src_maxburst) && src_maxburst > 0) ||
52462306a36Sopenharmony_ci	    (!is_power_of_2(dst_maxburst) && dst_maxburst > 0)) {
52562306a36Sopenharmony_ci		dev_err(chan2dev(chan), "burst size must be a power of 2\n");
52662306a36Sopenharmony_ci		return -EINVAL;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/*
53062306a36Sopenharmony_ci	 * Configure channel control:
53162306a36Sopenharmony_ci	 * - Clear SW request as in this case this is a HW one
53262306a36Sopenharmony_ci	 * - Clear WEX, HEX and BEX bits
53362306a36Sopenharmony_ci	 * - Set priority level
53462306a36Sopenharmony_ci	 */
53562306a36Sopenharmony_ci	ccr &= ~(STM32_MDMA_CCR_SWRQ | STM32_MDMA_CCR_WEX | STM32_MDMA_CCR_HEX |
53662306a36Sopenharmony_ci		 STM32_MDMA_CCR_BEX | STM32_MDMA_CCR_PL_MASK);
53762306a36Sopenharmony_ci	ccr |= STM32_MDMA_CCR_PL(chan_config->priority_level);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* Configure Trigger selection */
54062306a36Sopenharmony_ci	ctbr &= ~STM32_MDMA_CTBR_TSEL_MASK;
54162306a36Sopenharmony_ci	ctbr |= STM32_MDMA_CTBR_TSEL(chan_config->request);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	switch (direction) {
54462306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
54562306a36Sopenharmony_ci		dst_addr = chan->dma_config.dst_addr;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/* Set device data size */
54862306a36Sopenharmony_ci		if (chan_config->m2m_hw)
54962306a36Sopenharmony_ci			dst_addr_width = stm32_mdma_get_max_width(dst_addr, buf_len,
55062306a36Sopenharmony_ci								  STM32_MDMA_MAX_BUF_LEN);
55162306a36Sopenharmony_ci		dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
55262306a36Sopenharmony_ci		if (dst_bus_width < 0)
55362306a36Sopenharmony_ci			return dst_bus_width;
55462306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_DSIZE_MASK;
55562306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_DSIZE(dst_bus_width);
55662306a36Sopenharmony_ci		if (chan_config->m2m_hw) {
55762306a36Sopenharmony_ci			ctcr &= ~STM32_MDMA_CTCR_DINCOS_MASK;
55862306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_DINCOS(dst_bus_width);
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		/* Set device burst value */
56262306a36Sopenharmony_ci		if (chan_config->m2m_hw)
56362306a36Sopenharmony_ci			dst_maxburst = STM32_MDMA_MAX_BUF_LEN / dst_addr_width;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		dst_best_burst = stm32_mdma_get_best_burst(buf_len, tlen,
56662306a36Sopenharmony_ci							   dst_maxburst,
56762306a36Sopenharmony_ci							   dst_addr_width);
56862306a36Sopenharmony_ci		chan->mem_burst = dst_best_burst;
56962306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_DBURST_MASK;
57062306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci		/* Set memory data size */
57362306a36Sopenharmony_ci		src_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
57462306a36Sopenharmony_ci		chan->mem_width = src_addr_width;
57562306a36Sopenharmony_ci		src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
57662306a36Sopenharmony_ci		if (src_bus_width < 0)
57762306a36Sopenharmony_ci			return src_bus_width;
57862306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_SSIZE_MASK |
57962306a36Sopenharmony_ci			STM32_MDMA_CTCR_SINCOS_MASK;
58062306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_SSIZE(src_bus_width) |
58162306a36Sopenharmony_ci			STM32_MDMA_CTCR_SINCOS(src_bus_width);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		/* Set memory burst value */
58462306a36Sopenharmony_ci		src_maxburst = STM32_MDMA_MAX_BUF_LEN / src_addr_width;
58562306a36Sopenharmony_ci		src_best_burst = stm32_mdma_get_best_burst(buf_len, tlen,
58662306a36Sopenharmony_ci							   src_maxburst,
58762306a36Sopenharmony_ci							   src_addr_width);
58862306a36Sopenharmony_ci		chan->mem_burst = src_best_burst;
58962306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_SBURST_MASK;
59062306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		/* Select bus */
59362306a36Sopenharmony_ci		stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
59462306a36Sopenharmony_ci				   dst_addr);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (dst_bus_width != src_bus_width)
59762306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_PKE;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		/* Set destination address */
60062306a36Sopenharmony_ci		stm32_mdma_write(dmadev, STM32_MDMA_CDAR(chan->id), dst_addr);
60162306a36Sopenharmony_ci		break;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
60462306a36Sopenharmony_ci		src_addr = chan->dma_config.src_addr;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		/* Set device data size */
60762306a36Sopenharmony_ci		if (chan_config->m2m_hw)
60862306a36Sopenharmony_ci			src_addr_width = stm32_mdma_get_max_width(src_addr, buf_len,
60962306a36Sopenharmony_ci								  STM32_MDMA_MAX_BUF_LEN);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		src_bus_width = stm32_mdma_get_width(chan, src_addr_width);
61262306a36Sopenharmony_ci		if (src_bus_width < 0)
61362306a36Sopenharmony_ci			return src_bus_width;
61462306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_SSIZE_MASK;
61562306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_SSIZE(src_bus_width);
61662306a36Sopenharmony_ci		if (chan_config->m2m_hw) {
61762306a36Sopenharmony_ci			ctcr &= ~STM32_MDMA_CTCR_SINCOS_MASK;
61862306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_SINCOS(src_bus_width);
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		/* Set device burst value */
62262306a36Sopenharmony_ci		if (chan_config->m2m_hw)
62362306a36Sopenharmony_ci			src_maxburst = STM32_MDMA_MAX_BUF_LEN / src_addr_width;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		src_best_burst = stm32_mdma_get_best_burst(buf_len, tlen,
62662306a36Sopenharmony_ci							   src_maxburst,
62762306a36Sopenharmony_ci							   src_addr_width);
62862306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_SBURST_MASK;
62962306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_SBURST((ilog2(src_best_burst)));
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		/* Set memory data size */
63262306a36Sopenharmony_ci		dst_addr_width = stm32_mdma_get_max_width(addr, buf_len, tlen);
63362306a36Sopenharmony_ci		chan->mem_width = dst_addr_width;
63462306a36Sopenharmony_ci		dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width);
63562306a36Sopenharmony_ci		if (dst_bus_width < 0)
63662306a36Sopenharmony_ci			return dst_bus_width;
63762306a36Sopenharmony_ci		ctcr &= ~(STM32_MDMA_CTCR_DSIZE_MASK |
63862306a36Sopenharmony_ci			STM32_MDMA_CTCR_DINCOS_MASK);
63962306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_DSIZE(dst_bus_width) |
64062306a36Sopenharmony_ci			STM32_MDMA_CTCR_DINCOS(dst_bus_width);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		/* Set memory burst value */
64362306a36Sopenharmony_ci		dst_maxburst = STM32_MDMA_MAX_BUF_LEN / dst_addr_width;
64462306a36Sopenharmony_ci		dst_best_burst = stm32_mdma_get_best_burst(buf_len, tlen,
64562306a36Sopenharmony_ci							   dst_maxburst,
64662306a36Sopenharmony_ci							   dst_addr_width);
64762306a36Sopenharmony_ci		ctcr &= ~STM32_MDMA_CTCR_DBURST_MASK;
64862306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_DBURST((ilog2(dst_best_burst)));
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		/* Select bus */
65162306a36Sopenharmony_ci		stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
65262306a36Sopenharmony_ci				   src_addr);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		if (dst_bus_width != src_bus_width)
65562306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_PKE;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		/* Set source address */
65862306a36Sopenharmony_ci		stm32_mdma_write(dmadev, STM32_MDMA_CSAR(chan->id), src_addr);
65962306a36Sopenharmony_ci		break;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	default:
66262306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Dma direction is not supported\n");
66362306a36Sopenharmony_ci		return -EINVAL;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	*mdma_ccr = ccr;
66762306a36Sopenharmony_ci	*mdma_ctcr = ctcr;
66862306a36Sopenharmony_ci	*mdma_ctbr = ctbr;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return 0;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic void stm32_mdma_dump_hwdesc(struct stm32_mdma_chan *chan,
67462306a36Sopenharmony_ci				   struct stm32_mdma_desc_node *node)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "hwdesc:  %pad\n", &node->hwdesc_phys);
67762306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CTCR:    0x%08x\n", node->hwdesc->ctcr);
67862306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CBNDTR:  0x%08x\n", node->hwdesc->cbndtr);
67962306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CSAR:    0x%08x\n", node->hwdesc->csar);
68062306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CDAR:    0x%08x\n", node->hwdesc->cdar);
68162306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CBRUR:   0x%08x\n", node->hwdesc->cbrur);
68262306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CLAR:    0x%08x\n", node->hwdesc->clar);
68362306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CTBR:    0x%08x\n", node->hwdesc->ctbr);
68462306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CMAR:    0x%08x\n", node->hwdesc->cmar);
68562306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CMDR:    0x%08x\n\n", node->hwdesc->cmdr);
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan,
68962306a36Sopenharmony_ci				    struct stm32_mdma_desc *desc,
69062306a36Sopenharmony_ci				    enum dma_transfer_direction dir, u32 count,
69162306a36Sopenharmony_ci				    dma_addr_t src_addr, dma_addr_t dst_addr,
69262306a36Sopenharmony_ci				    u32 len, u32 ctcr, u32 ctbr, bool is_last,
69362306a36Sopenharmony_ci				    bool is_first, bool is_cyclic)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	struct stm32_mdma_chan_config *config = &chan->chan_config;
69662306a36Sopenharmony_ci	struct stm32_mdma_hwdesc *hwdesc;
69762306a36Sopenharmony_ci	u32 next = count + 1;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	hwdesc = desc->node[count].hwdesc;
70062306a36Sopenharmony_ci	hwdesc->ctcr = ctcr;
70162306a36Sopenharmony_ci	hwdesc->cbndtr &= ~(STM32_MDMA_CBNDTR_BRC_MK |
70262306a36Sopenharmony_ci			STM32_MDMA_CBNDTR_BRDUM |
70362306a36Sopenharmony_ci			STM32_MDMA_CBNDTR_BRSUM |
70462306a36Sopenharmony_ci			STM32_MDMA_CBNDTR_BNDT_MASK);
70562306a36Sopenharmony_ci	hwdesc->cbndtr |= STM32_MDMA_CBNDTR_BNDT(len);
70662306a36Sopenharmony_ci	hwdesc->csar = src_addr;
70762306a36Sopenharmony_ci	hwdesc->cdar = dst_addr;
70862306a36Sopenharmony_ci	hwdesc->cbrur = 0;
70962306a36Sopenharmony_ci	hwdesc->ctbr = ctbr;
71062306a36Sopenharmony_ci	hwdesc->cmar = config->mask_addr;
71162306a36Sopenharmony_ci	hwdesc->cmdr = config->mask_data;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (is_last) {
71462306a36Sopenharmony_ci		if (is_cyclic)
71562306a36Sopenharmony_ci			hwdesc->clar = desc->node[0].hwdesc_phys;
71662306a36Sopenharmony_ci		else
71762306a36Sopenharmony_ci			hwdesc->clar = 0;
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		hwdesc->clar = desc->node[next].hwdesc_phys;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	stm32_mdma_dump_hwdesc(chan, &desc->node[count]);
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
72662306a36Sopenharmony_ci				 struct stm32_mdma_desc *desc,
72762306a36Sopenharmony_ci				 struct scatterlist *sgl, u32 sg_len,
72862306a36Sopenharmony_ci				 enum dma_transfer_direction direction)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
73162306a36Sopenharmony_ci	struct dma_slave_config *dma_config = &chan->dma_config;
73262306a36Sopenharmony_ci	struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
73362306a36Sopenharmony_ci	struct scatterlist *sg;
73462306a36Sopenharmony_ci	dma_addr_t src_addr, dst_addr;
73562306a36Sopenharmony_ci	u32 m2m_hw_period, ccr, ctcr, ctbr;
73662306a36Sopenharmony_ci	int i, ret = 0;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (chan_config->m2m_hw)
73962306a36Sopenharmony_ci		m2m_hw_period = sg_dma_len(sgl);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	for_each_sg(sgl, sg, sg_len, i) {
74262306a36Sopenharmony_ci		if (sg_dma_len(sg) > STM32_MDMA_MAX_BLOCK_LEN) {
74362306a36Sopenharmony_ci			dev_err(chan2dev(chan), "Invalid block len\n");
74462306a36Sopenharmony_ci			return -EINVAL;
74562306a36Sopenharmony_ci		}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		if (direction == DMA_MEM_TO_DEV) {
74862306a36Sopenharmony_ci			src_addr = sg_dma_address(sg);
74962306a36Sopenharmony_ci			dst_addr = dma_config->dst_addr;
75062306a36Sopenharmony_ci			if (chan_config->m2m_hw && (i & 1))
75162306a36Sopenharmony_ci				dst_addr += m2m_hw_period;
75262306a36Sopenharmony_ci			ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
75362306a36Sopenharmony_ci							&ctcr, &ctbr, src_addr,
75462306a36Sopenharmony_ci							sg_dma_len(sg));
75562306a36Sopenharmony_ci			stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
75662306a36Sopenharmony_ci					   src_addr);
75762306a36Sopenharmony_ci		} else {
75862306a36Sopenharmony_ci			src_addr = dma_config->src_addr;
75962306a36Sopenharmony_ci			if (chan_config->m2m_hw && (i & 1))
76062306a36Sopenharmony_ci				src_addr += m2m_hw_period;
76162306a36Sopenharmony_ci			dst_addr = sg_dma_address(sg);
76262306a36Sopenharmony_ci			ret = stm32_mdma_set_xfer_param(chan, direction, &ccr,
76362306a36Sopenharmony_ci							&ctcr, &ctbr, dst_addr,
76462306a36Sopenharmony_ci							sg_dma_len(sg));
76562306a36Sopenharmony_ci			stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
76662306a36Sopenharmony_ci					   dst_addr);
76762306a36Sopenharmony_ci		}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		if (ret < 0)
77062306a36Sopenharmony_ci			return ret;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		stm32_mdma_setup_hwdesc(chan, desc, direction, i, src_addr,
77362306a36Sopenharmony_ci					dst_addr, sg_dma_len(sg), ctcr, ctbr,
77462306a36Sopenharmony_ci					i == sg_len - 1, i == 0, false);
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/* Enable interrupts */
77862306a36Sopenharmony_ci	ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
77962306a36Sopenharmony_ci	ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE;
78062306a36Sopenharmony_ci	desc->ccr = ccr;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return 0;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
78662306a36Sopenharmony_cistm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl,
78762306a36Sopenharmony_ci			 u32 sg_len, enum dma_transfer_direction direction,
78862306a36Sopenharmony_ci			 unsigned long flags, void *context)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
79162306a36Sopenharmony_ci	struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
79262306a36Sopenharmony_ci	struct stm32_mdma_desc *desc;
79362306a36Sopenharmony_ci	int i, ret;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	/*
79662306a36Sopenharmony_ci	 * Once DMA is in setup cyclic mode the channel we cannot assign this
79762306a36Sopenharmony_ci	 * channel anymore. The DMA channel needs to be aborted or terminated
79862306a36Sopenharmony_ci	 * for allowing another request.
79962306a36Sopenharmony_ci	 */
80062306a36Sopenharmony_ci	if (chan->desc && chan->desc->cyclic) {
80162306a36Sopenharmony_ci		dev_err(chan2dev(chan),
80262306a36Sopenharmony_ci			"Request not allowed when dma in cyclic mode\n");
80362306a36Sopenharmony_ci		return NULL;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	desc = stm32_mdma_alloc_desc(chan, sg_len);
80762306a36Sopenharmony_ci	if (!desc)
80862306a36Sopenharmony_ci		return NULL;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	ret = stm32_mdma_setup_xfer(chan, desc, sgl, sg_len, direction);
81162306a36Sopenharmony_ci	if (ret < 0)
81262306a36Sopenharmony_ci		goto xfer_setup_err;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/*
81562306a36Sopenharmony_ci	 * In case of M2M HW transfer triggered by STM32 DMA, we do not have to clear the
81662306a36Sopenharmony_ci	 * transfer complete flag by hardware in order to let the CPU rearm the STM32 DMA
81762306a36Sopenharmony_ci	 * with the next sg element and update some data in dmaengine framework.
81862306a36Sopenharmony_ci	 */
81962306a36Sopenharmony_ci	if (chan_config->m2m_hw && direction == DMA_MEM_TO_DEV) {
82062306a36Sopenharmony_ci		struct stm32_mdma_hwdesc *hwdesc;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		for (i = 0; i < sg_len; i++) {
82362306a36Sopenharmony_ci			hwdesc = desc->node[i].hwdesc;
82462306a36Sopenharmony_ci			hwdesc->cmar = 0;
82562306a36Sopenharmony_ci			hwdesc->cmdr = 0;
82662306a36Sopenharmony_ci		}
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	desc->cyclic = false;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cixfer_setup_err:
83462306a36Sopenharmony_ci	for (i = 0; i < desc->count; i++)
83562306a36Sopenharmony_ci		dma_pool_free(chan->desc_pool, desc->node[i].hwdesc,
83662306a36Sopenharmony_ci			      desc->node[i].hwdesc_phys);
83762306a36Sopenharmony_ci	kfree(desc);
83862306a36Sopenharmony_ci	return NULL;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
84262306a36Sopenharmony_cistm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr,
84362306a36Sopenharmony_ci			   size_t buf_len, size_t period_len,
84462306a36Sopenharmony_ci			   enum dma_transfer_direction direction,
84562306a36Sopenharmony_ci			   unsigned long flags)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
84862306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
84962306a36Sopenharmony_ci	struct dma_slave_config *dma_config = &chan->dma_config;
85062306a36Sopenharmony_ci	struct stm32_mdma_chan_config *chan_config = &chan->chan_config;
85162306a36Sopenharmony_ci	struct stm32_mdma_desc *desc;
85262306a36Sopenharmony_ci	dma_addr_t src_addr, dst_addr;
85362306a36Sopenharmony_ci	u32 ccr, ctcr, ctbr, count;
85462306a36Sopenharmony_ci	int i, ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	/*
85762306a36Sopenharmony_ci	 * Once DMA is in setup cyclic mode the channel we cannot assign this
85862306a36Sopenharmony_ci	 * channel anymore. The DMA channel needs to be aborted or terminated
85962306a36Sopenharmony_ci	 * for allowing another request.
86062306a36Sopenharmony_ci	 */
86162306a36Sopenharmony_ci	if (chan->desc && chan->desc->cyclic) {
86262306a36Sopenharmony_ci		dev_err(chan2dev(chan),
86362306a36Sopenharmony_ci			"Request not allowed when dma in cyclic mode\n");
86462306a36Sopenharmony_ci		return NULL;
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (!buf_len || !period_len || period_len > STM32_MDMA_MAX_BLOCK_LEN) {
86862306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Invalid buffer/period len\n");
86962306a36Sopenharmony_ci		return NULL;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (buf_len % period_len) {
87362306a36Sopenharmony_ci		dev_err(chan2dev(chan), "buf_len not multiple of period_len\n");
87462306a36Sopenharmony_ci		return NULL;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	count = buf_len / period_len;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	desc = stm32_mdma_alloc_desc(chan, count);
88062306a36Sopenharmony_ci	if (!desc)
88162306a36Sopenharmony_ci		return NULL;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* Select bus */
88462306a36Sopenharmony_ci	if (direction == DMA_MEM_TO_DEV) {
88562306a36Sopenharmony_ci		src_addr = buf_addr;
88662306a36Sopenharmony_ci		ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
88762306a36Sopenharmony_ci						&ctbr, src_addr, period_len);
88862306a36Sopenharmony_ci		stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS,
88962306a36Sopenharmony_ci				   src_addr);
89062306a36Sopenharmony_ci	} else {
89162306a36Sopenharmony_ci		dst_addr = buf_addr;
89262306a36Sopenharmony_ci		ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, &ctcr,
89362306a36Sopenharmony_ci						&ctbr, dst_addr, period_len);
89462306a36Sopenharmony_ci		stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS,
89562306a36Sopenharmony_ci				   dst_addr);
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (ret < 0)
89962306a36Sopenharmony_ci		goto xfer_setup_err;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* Enable interrupts */
90262306a36Sopenharmony_ci	ccr &= ~STM32_MDMA_CCR_IRQ_MASK;
90362306a36Sopenharmony_ci	ccr |= STM32_MDMA_CCR_TEIE | STM32_MDMA_CCR_CTCIE | STM32_MDMA_CCR_BTIE;
90462306a36Sopenharmony_ci	desc->ccr = ccr;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	/* Configure hwdesc list */
90762306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
90862306a36Sopenharmony_ci		if (direction == DMA_MEM_TO_DEV) {
90962306a36Sopenharmony_ci			src_addr = buf_addr + i * period_len;
91062306a36Sopenharmony_ci			dst_addr = dma_config->dst_addr;
91162306a36Sopenharmony_ci			if (chan_config->m2m_hw && (i & 1))
91262306a36Sopenharmony_ci				dst_addr += period_len;
91362306a36Sopenharmony_ci		} else {
91462306a36Sopenharmony_ci			src_addr = dma_config->src_addr;
91562306a36Sopenharmony_ci			if (chan_config->m2m_hw && (i & 1))
91662306a36Sopenharmony_ci				src_addr += period_len;
91762306a36Sopenharmony_ci			dst_addr = buf_addr + i * period_len;
91862306a36Sopenharmony_ci		}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci		stm32_mdma_setup_hwdesc(chan, desc, direction, i, src_addr,
92162306a36Sopenharmony_ci					dst_addr, period_len, ctcr, ctbr,
92262306a36Sopenharmony_ci					i == count - 1, i == 0, true);
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	desc->cyclic = true;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cixfer_setup_err:
93062306a36Sopenharmony_ci	for (i = 0; i < desc->count; i++)
93162306a36Sopenharmony_ci		dma_pool_free(chan->desc_pool, desc->node[i].hwdesc,
93262306a36Sopenharmony_ci			      desc->node[i].hwdesc_phys);
93362306a36Sopenharmony_ci	kfree(desc);
93462306a36Sopenharmony_ci	return NULL;
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
93862306a36Sopenharmony_cistm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
93962306a36Sopenharmony_ci			   size_t len, unsigned long flags)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
94262306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
94362306a36Sopenharmony_ci	enum dma_slave_buswidth max_width;
94462306a36Sopenharmony_ci	struct stm32_mdma_desc *desc;
94562306a36Sopenharmony_ci	struct stm32_mdma_hwdesc *hwdesc;
94662306a36Sopenharmony_ci	u32 ccr, ctcr, ctbr, cbndtr, count, max_burst, mdma_burst;
94762306a36Sopenharmony_ci	u32 best_burst, tlen;
94862306a36Sopenharmony_ci	size_t xfer_count, offset;
94962306a36Sopenharmony_ci	int src_bus_width, dst_bus_width;
95062306a36Sopenharmony_ci	int i;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	/*
95362306a36Sopenharmony_ci	 * Once DMA is in setup cyclic mode the channel we cannot assign this
95462306a36Sopenharmony_ci	 * channel anymore. The DMA channel needs to be aborted or terminated
95562306a36Sopenharmony_ci	 * to allow another request
95662306a36Sopenharmony_ci	 */
95762306a36Sopenharmony_ci	if (chan->desc && chan->desc->cyclic) {
95862306a36Sopenharmony_ci		dev_err(chan2dev(chan),
95962306a36Sopenharmony_ci			"Request not allowed when dma in cyclic mode\n");
96062306a36Sopenharmony_ci		return NULL;
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	count = DIV_ROUND_UP(len, STM32_MDMA_MAX_BLOCK_LEN);
96462306a36Sopenharmony_ci	desc = stm32_mdma_alloc_desc(chan, count);
96562306a36Sopenharmony_ci	if (!desc)
96662306a36Sopenharmony_ci		return NULL;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & ~STM32_MDMA_CCR_EN;
96962306a36Sopenharmony_ci	ctcr = stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id));
97062306a36Sopenharmony_ci	ctbr = stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id));
97162306a36Sopenharmony_ci	cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id));
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* Enable sw req, some interrupts and clear other bits */
97462306a36Sopenharmony_ci	ccr &= ~(STM32_MDMA_CCR_WEX | STM32_MDMA_CCR_HEX |
97562306a36Sopenharmony_ci		 STM32_MDMA_CCR_BEX | STM32_MDMA_CCR_PL_MASK |
97662306a36Sopenharmony_ci		 STM32_MDMA_CCR_IRQ_MASK);
97762306a36Sopenharmony_ci	ccr |= STM32_MDMA_CCR_TEIE;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/* Enable SW request mode, dest/src inc and clear other bits */
98062306a36Sopenharmony_ci	ctcr &= ~(STM32_MDMA_CTCR_BWM | STM32_MDMA_CTCR_TRGM_MSK |
98162306a36Sopenharmony_ci		  STM32_MDMA_CTCR_PAM_MASK | STM32_MDMA_CTCR_PKE |
98262306a36Sopenharmony_ci		  STM32_MDMA_CTCR_TLEN_MSK | STM32_MDMA_CTCR_DBURST_MASK |
98362306a36Sopenharmony_ci		  STM32_MDMA_CTCR_SBURST_MASK | STM32_MDMA_CTCR_DINCOS_MASK |
98462306a36Sopenharmony_ci		  STM32_MDMA_CTCR_SINCOS_MASK | STM32_MDMA_CTCR_DSIZE_MASK |
98562306a36Sopenharmony_ci		  STM32_MDMA_CTCR_SSIZE_MASK | STM32_MDMA_CTCR_DINC_MASK |
98662306a36Sopenharmony_ci		  STM32_MDMA_CTCR_SINC_MASK);
98762306a36Sopenharmony_ci	ctcr |= STM32_MDMA_CTCR_SWRM | STM32_MDMA_CTCR_SINC(STM32_MDMA_INC) |
98862306a36Sopenharmony_ci		STM32_MDMA_CTCR_DINC(STM32_MDMA_INC);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/* Reset HW request */
99162306a36Sopenharmony_ci	ctbr &= ~STM32_MDMA_CTBR_TSEL_MASK;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Select bus */
99462306a36Sopenharmony_ci	stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_SBUS, src);
99562306a36Sopenharmony_ci	stm32_mdma_set_bus(dmadev, &ctbr, STM32_MDMA_CTBR_DBUS, dest);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* Clear CBNDTR registers */
99862306a36Sopenharmony_ci	cbndtr &= ~(STM32_MDMA_CBNDTR_BRC_MK | STM32_MDMA_CBNDTR_BRDUM |
99962306a36Sopenharmony_ci			STM32_MDMA_CBNDTR_BRSUM | STM32_MDMA_CBNDTR_BNDT_MASK);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (len <= STM32_MDMA_MAX_BLOCK_LEN) {
100262306a36Sopenharmony_ci		cbndtr |= STM32_MDMA_CBNDTR_BNDT(len);
100362306a36Sopenharmony_ci		if (len <= STM32_MDMA_MAX_BUF_LEN) {
100462306a36Sopenharmony_ci			/* Setup a buffer transfer */
100562306a36Sopenharmony_ci			ccr |= STM32_MDMA_CCR_TCIE | STM32_MDMA_CCR_CTCIE;
100662306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_TRGM(STM32_MDMA_BUFFER);
100762306a36Sopenharmony_ci		} else {
100862306a36Sopenharmony_ci			/* Setup a block transfer */
100962306a36Sopenharmony_ci			ccr |= STM32_MDMA_CCR_BTIE | STM32_MDMA_CCR_CTCIE;
101062306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_TRGM(STM32_MDMA_BLOCK);
101162306a36Sopenharmony_ci		}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		tlen = STM32_MDMA_MAX_BUF_LEN;
101462306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_TLEN((tlen - 1));
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		/* Set source best burst size */
101762306a36Sopenharmony_ci		max_width = stm32_mdma_get_max_width(src, len, tlen);
101862306a36Sopenharmony_ci		src_bus_width = stm32_mdma_get_width(chan, max_width);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		max_burst = tlen / max_width;
102162306a36Sopenharmony_ci		best_burst = stm32_mdma_get_best_burst(len, tlen, max_burst,
102262306a36Sopenharmony_ci						       max_width);
102362306a36Sopenharmony_ci		mdma_burst = ilog2(best_burst);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_SBURST(mdma_burst) |
102662306a36Sopenharmony_ci			STM32_MDMA_CTCR_SSIZE(src_bus_width) |
102762306a36Sopenharmony_ci			STM32_MDMA_CTCR_SINCOS(src_bus_width);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		/* Set destination best burst size */
103062306a36Sopenharmony_ci		max_width = stm32_mdma_get_max_width(dest, len, tlen);
103162306a36Sopenharmony_ci		dst_bus_width = stm32_mdma_get_width(chan, max_width);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		max_burst = tlen / max_width;
103462306a36Sopenharmony_ci		best_burst = stm32_mdma_get_best_burst(len, tlen, max_burst,
103562306a36Sopenharmony_ci						       max_width);
103662306a36Sopenharmony_ci		mdma_burst = ilog2(best_burst);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_DBURST(mdma_burst) |
103962306a36Sopenharmony_ci			STM32_MDMA_CTCR_DSIZE(dst_bus_width) |
104062306a36Sopenharmony_ci			STM32_MDMA_CTCR_DINCOS(dst_bus_width);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci		if (dst_bus_width != src_bus_width)
104362306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_PKE;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		/* Prepare hardware descriptor */
104662306a36Sopenharmony_ci		hwdesc = desc->node[0].hwdesc;
104762306a36Sopenharmony_ci		hwdesc->ctcr = ctcr;
104862306a36Sopenharmony_ci		hwdesc->cbndtr = cbndtr;
104962306a36Sopenharmony_ci		hwdesc->csar = src;
105062306a36Sopenharmony_ci		hwdesc->cdar = dest;
105162306a36Sopenharmony_ci		hwdesc->cbrur = 0;
105262306a36Sopenharmony_ci		hwdesc->clar = 0;
105362306a36Sopenharmony_ci		hwdesc->ctbr = ctbr;
105462306a36Sopenharmony_ci		hwdesc->cmar = 0;
105562306a36Sopenharmony_ci		hwdesc->cmdr = 0;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		stm32_mdma_dump_hwdesc(chan, &desc->node[0]);
105862306a36Sopenharmony_ci	} else {
105962306a36Sopenharmony_ci		/* Setup a LLI transfer */
106062306a36Sopenharmony_ci		ctcr |= STM32_MDMA_CTCR_TRGM(STM32_MDMA_LINKED_LIST) |
106162306a36Sopenharmony_ci			STM32_MDMA_CTCR_TLEN((STM32_MDMA_MAX_BUF_LEN - 1));
106262306a36Sopenharmony_ci		ccr |= STM32_MDMA_CCR_BTIE | STM32_MDMA_CCR_CTCIE;
106362306a36Sopenharmony_ci		tlen = STM32_MDMA_MAX_BUF_LEN;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		for (i = 0, offset = 0; offset < len;
106662306a36Sopenharmony_ci		     i++, offset += xfer_count) {
106762306a36Sopenharmony_ci			xfer_count = min_t(size_t, len - offset,
106862306a36Sopenharmony_ci					   STM32_MDMA_MAX_BLOCK_LEN);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci			/* Set source best burst size */
107162306a36Sopenharmony_ci			max_width = stm32_mdma_get_max_width(src, len, tlen);
107262306a36Sopenharmony_ci			src_bus_width = stm32_mdma_get_width(chan, max_width);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci			max_burst = tlen / max_width;
107562306a36Sopenharmony_ci			best_burst = stm32_mdma_get_best_burst(len, tlen,
107662306a36Sopenharmony_ci							       max_burst,
107762306a36Sopenharmony_ci							       max_width);
107862306a36Sopenharmony_ci			mdma_burst = ilog2(best_burst);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_SBURST(mdma_burst) |
108162306a36Sopenharmony_ci				STM32_MDMA_CTCR_SSIZE(src_bus_width) |
108262306a36Sopenharmony_ci				STM32_MDMA_CTCR_SINCOS(src_bus_width);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci			/* Set destination best burst size */
108562306a36Sopenharmony_ci			max_width = stm32_mdma_get_max_width(dest, len, tlen);
108662306a36Sopenharmony_ci			dst_bus_width = stm32_mdma_get_width(chan, max_width);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci			max_burst = tlen / max_width;
108962306a36Sopenharmony_ci			best_burst = stm32_mdma_get_best_burst(len, tlen,
109062306a36Sopenharmony_ci							       max_burst,
109162306a36Sopenharmony_ci							       max_width);
109262306a36Sopenharmony_ci			mdma_burst = ilog2(best_burst);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci			ctcr |= STM32_MDMA_CTCR_DBURST(mdma_burst) |
109562306a36Sopenharmony_ci				STM32_MDMA_CTCR_DSIZE(dst_bus_width) |
109662306a36Sopenharmony_ci				STM32_MDMA_CTCR_DINCOS(dst_bus_width);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci			if (dst_bus_width != src_bus_width)
109962306a36Sopenharmony_ci				ctcr |= STM32_MDMA_CTCR_PKE;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci			/* Prepare hardware descriptor */
110262306a36Sopenharmony_ci			stm32_mdma_setup_hwdesc(chan, desc, DMA_MEM_TO_MEM, i,
110362306a36Sopenharmony_ci						src + offset, dest + offset,
110462306a36Sopenharmony_ci						xfer_count, ctcr, ctbr,
110562306a36Sopenharmony_ci						i == count - 1, i == 0, false);
110662306a36Sopenharmony_ci		}
110762306a36Sopenharmony_ci	}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	desc->ccr = ccr;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	desc->cyclic = false;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic void stm32_mdma_dump_reg(struct stm32_mdma_chan *chan)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CCR:     0x%08x\n",
112162306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)));
112262306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CTCR:    0x%08x\n",
112362306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CTCR(chan->id)));
112462306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CBNDTR:  0x%08x\n",
112562306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)));
112662306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CSAR:    0x%08x\n",
112762306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CSAR(chan->id)));
112862306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CDAR:    0x%08x\n",
112962306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CDAR(chan->id)));
113062306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CBRUR:   0x%08x\n",
113162306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CBRUR(chan->id)));
113262306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CLAR:    0x%08x\n",
113362306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CLAR(chan->id)));
113462306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CTBR:    0x%08x\n",
113562306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CTBR(chan->id)));
113662306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CMAR:    0x%08x\n",
113762306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CMAR(chan->id)));
113862306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "CMDR:    0x%08x\n",
113962306a36Sopenharmony_ci		stm32_mdma_read(dmadev, STM32_MDMA_CMDR(chan->id)));
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_cistatic void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
114562306a36Sopenharmony_ci	struct virt_dma_desc *vdesc;
114662306a36Sopenharmony_ci	struct stm32_mdma_hwdesc *hwdesc;
114762306a36Sopenharmony_ci	u32 id = chan->id;
114862306a36Sopenharmony_ci	u32 status, reg;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	vdesc = vchan_next_desc(&chan->vchan);
115162306a36Sopenharmony_ci	if (!vdesc) {
115262306a36Sopenharmony_ci		chan->desc = NULL;
115362306a36Sopenharmony_ci		return;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	list_del(&vdesc->node);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	chan->desc = to_stm32_mdma_desc(vdesc);
115962306a36Sopenharmony_ci	hwdesc = chan->desc->node[0].hwdesc;
116062306a36Sopenharmony_ci	chan->curr_hwdesc = 0;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CCR(id), chan->desc->ccr);
116362306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CTCR(id), hwdesc->ctcr);
116462306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CBNDTR(id), hwdesc->cbndtr);
116562306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CSAR(id), hwdesc->csar);
116662306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CDAR(id), hwdesc->cdar);
116762306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CBRUR(id), hwdesc->cbrur);
116862306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CLAR(id), hwdesc->clar);
116962306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CTBR(id), hwdesc->ctbr);
117062306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CMAR(id), hwdesc->cmar);
117162306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CMDR(id), hwdesc->cmdr);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
117462306a36Sopenharmony_ci	status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(id));
117562306a36Sopenharmony_ci	if (status)
117662306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, STM32_MDMA_CIFCR(id), status);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	stm32_mdma_dump_reg(chan);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Start DMA */
118162306a36Sopenharmony_ci	stm32_mdma_set_bits(dmadev, STM32_MDMA_CCR(id), STM32_MDMA_CCR_EN);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Set SW request in case of MEM2MEM transfer */
118462306a36Sopenharmony_ci	if (hwdesc->ctcr & STM32_MDMA_CTCR_SWRM) {
118562306a36Sopenharmony_ci		reg = STM32_MDMA_CCR(id);
118662306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CCR_SWRQ);
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	chan->busy = true;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan);
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic void stm32_mdma_issue_pending(struct dma_chan *c)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
119762306a36Sopenharmony_ci	unsigned long flags;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (!vchan_issue_pending(&chan->vchan))
120262306a36Sopenharmony_ci		goto end;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: issued\n", &chan->vchan);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (!chan->desc && !chan->busy)
120762306a36Sopenharmony_ci		stm32_mdma_start_transfer(chan);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ciend:
121062306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic int stm32_mdma_pause(struct dma_chan *c)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
121662306a36Sopenharmony_ci	unsigned long flags;
121762306a36Sopenharmony_ci	int ret;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
122062306a36Sopenharmony_ci	ret = stm32_mdma_disable_chan(chan);
122162306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (!ret)
122462306a36Sopenharmony_ci		dev_dbg(chan2dev(chan), "vchan %pK: pause\n", &chan->vchan);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	return ret;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic int stm32_mdma_resume(struct dma_chan *c)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
123262306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
123362306a36Sopenharmony_ci	struct stm32_mdma_hwdesc *hwdesc;
123462306a36Sopenharmony_ci	unsigned long flags;
123562306a36Sopenharmony_ci	u32 status, reg;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	/* Transfer can be terminated */
123862306a36Sopenharmony_ci	if (!chan->desc || (stm32_mdma_read(dmadev, STM32_MDMA_CCR(chan->id)) & STM32_MDMA_CCR_EN))
123962306a36Sopenharmony_ci		return -EPERM;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	hwdesc = chan->desc->node[chan->curr_hwdesc].hwdesc;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	/* Re-configure control register */
124662306a36Sopenharmony_ci	stm32_mdma_write(dmadev, STM32_MDMA_CCR(chan->id), chan->desc->ccr);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
124962306a36Sopenharmony_ci	status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id));
125062306a36Sopenharmony_ci	if (status)
125162306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, STM32_MDMA_CIFCR(chan->id), status);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	stm32_mdma_dump_reg(chan);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/* Re-start DMA */
125662306a36Sopenharmony_ci	reg = STM32_MDMA_CCR(chan->id);
125762306a36Sopenharmony_ci	stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CCR_EN);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* Set SW request in case of MEM2MEM transfer */
126062306a36Sopenharmony_ci	if (hwdesc->ctcr & STM32_MDMA_CTCR_SWRM)
126162306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CCR_SWRQ);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "vchan %pK: resume\n", &chan->vchan);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	return 0;
126862306a36Sopenharmony_ci}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_cistatic int stm32_mdma_terminate_all(struct dma_chan *c)
127162306a36Sopenharmony_ci{
127262306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
127362306a36Sopenharmony_ci	unsigned long flags;
127462306a36Sopenharmony_ci	LIST_HEAD(head);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
127762306a36Sopenharmony_ci	if (chan->desc) {
127862306a36Sopenharmony_ci		vchan_terminate_vdesc(&chan->desc->vdesc);
127962306a36Sopenharmony_ci		if (chan->busy)
128062306a36Sopenharmony_ci			stm32_mdma_stop(chan);
128162306a36Sopenharmony_ci		chan->desc = NULL;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci	vchan_get_all_descriptors(&chan->vchan, &head);
128462306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	vchan_dma_desc_free_list(&chan->vchan, &head);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	return 0;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic void stm32_mdma_synchronize(struct dma_chan *c)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	vchan_synchronize(&chan->vchan);
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic int stm32_mdma_slave_config(struct dma_chan *c,
129962306a36Sopenharmony_ci				   struct dma_slave_config *config)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	memcpy(&chan->dma_config, config, sizeof(*config));
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* Check if user is requesting STM32 DMA to trigger MDMA */
130662306a36Sopenharmony_ci	if (config->peripheral_size) {
130762306a36Sopenharmony_ci		struct stm32_mdma_dma_config *mdma_config;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci		mdma_config = (struct stm32_mdma_dma_config *)chan->dma_config.peripheral_config;
131062306a36Sopenharmony_ci		chan->chan_config.request = mdma_config->request;
131162306a36Sopenharmony_ci		chan->chan_config.mask_addr = mdma_config->cmar;
131262306a36Sopenharmony_ci		chan->chan_config.mask_data = mdma_config->cmdr;
131362306a36Sopenharmony_ci		chan->chan_config.m2m_hw = true;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return 0;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan,
132062306a36Sopenharmony_ci				      struct stm32_mdma_desc *desc,
132162306a36Sopenharmony_ci				      u32 curr_hwdesc,
132262306a36Sopenharmony_ci				      struct dma_tx_state *state)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
132562306a36Sopenharmony_ci	struct stm32_mdma_hwdesc *hwdesc;
132662306a36Sopenharmony_ci	u32 cisr, clar, cbndtr, residue, modulo, burst_size;
132762306a36Sopenharmony_ci	int i;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	cisr = stm32_mdma_read(dmadev, STM32_MDMA_CISR(chan->id));
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	residue = 0;
133262306a36Sopenharmony_ci	/* Get the next hw descriptor to process from current transfer */
133362306a36Sopenharmony_ci	clar = stm32_mdma_read(dmadev, STM32_MDMA_CLAR(chan->id));
133462306a36Sopenharmony_ci	for (i = desc->count - 1; i >= 0; i--) {
133562306a36Sopenharmony_ci		hwdesc = desc->node[i].hwdesc;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		if (hwdesc->clar == clar)
133862306a36Sopenharmony_ci			break;/* Current transfer found, stop cumulating */
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		/* Cumulate residue of unprocessed hw descriptors */
134162306a36Sopenharmony_ci		residue += STM32_MDMA_CBNDTR_BNDT(hwdesc->cbndtr);
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci	cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id));
134462306a36Sopenharmony_ci	residue += cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	state->in_flight_bytes = 0;
134762306a36Sopenharmony_ci	if (chan->chan_config.m2m_hw && (cisr & STM32_MDMA_CISR_CRQA))
134862306a36Sopenharmony_ci		state->in_flight_bytes = cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (!chan->mem_burst)
135162306a36Sopenharmony_ci		return residue;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	burst_size = chan->mem_burst * chan->mem_width;
135462306a36Sopenharmony_ci	modulo = residue % burst_size;
135562306a36Sopenharmony_ci	if (modulo)
135662306a36Sopenharmony_ci		residue = residue - modulo + burst_size;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	return residue;
135962306a36Sopenharmony_ci}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_cistatic enum dma_status stm32_mdma_tx_status(struct dma_chan *c,
136262306a36Sopenharmony_ci					    dma_cookie_t cookie,
136362306a36Sopenharmony_ci					    struct dma_tx_state *state)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
136662306a36Sopenharmony_ci	struct virt_dma_desc *vdesc;
136762306a36Sopenharmony_ci	enum dma_status status;
136862306a36Sopenharmony_ci	unsigned long flags;
136962306a36Sopenharmony_ci	u32 residue = 0;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	status = dma_cookie_status(c, cookie, state);
137262306a36Sopenharmony_ci	if ((status == DMA_COMPLETE) || (!state))
137362306a36Sopenharmony_ci		return status;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	spin_lock_irqsave(&chan->vchan.lock, flags);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	vdesc = vchan_find_desc(&chan->vchan, cookie);
137862306a36Sopenharmony_ci	if (chan->desc && cookie == chan->desc->vdesc.tx.cookie)
137962306a36Sopenharmony_ci		residue = stm32_mdma_desc_residue(chan, chan->desc, chan->curr_hwdesc, state);
138062306a36Sopenharmony_ci	else if (vdesc)
138162306a36Sopenharmony_ci		residue = stm32_mdma_desc_residue(chan, to_stm32_mdma_desc(vdesc), 0, state);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	dma_set_residue(state, residue);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chan->vchan.lock, flags);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return status;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void stm32_mdma_xfer_end(struct stm32_mdma_chan *chan)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	vchan_cookie_complete(&chan->desc->vdesc);
139362306a36Sopenharmony_ci	chan->desc = NULL;
139462306a36Sopenharmony_ci	chan->busy = false;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	/* Start the next transfer if this driver has a next desc */
139762306a36Sopenharmony_ci	stm32_mdma_start_transfer(chan);
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic irqreturn_t stm32_mdma_irq_handler(int irq, void *devid)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = devid;
140362306a36Sopenharmony_ci	struct stm32_mdma_chan *chan;
140462306a36Sopenharmony_ci	u32 reg, id, ccr, ien, status;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* Find out which channel generates the interrupt */
140762306a36Sopenharmony_ci	status = readl_relaxed(dmadev->base + STM32_MDMA_GISR0);
140862306a36Sopenharmony_ci	if (!status) {
140962306a36Sopenharmony_ci		dev_dbg(mdma2dev(dmadev), "spurious it\n");
141062306a36Sopenharmony_ci		return IRQ_NONE;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci	id = __ffs(status);
141362306a36Sopenharmony_ci	chan = &dmadev->chan[id];
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	/* Handle interrupt for the channel */
141662306a36Sopenharmony_ci	spin_lock(&chan->vchan.lock);
141762306a36Sopenharmony_ci	status = stm32_mdma_read(dmadev, STM32_MDMA_CISR(id));
141862306a36Sopenharmony_ci	/* Mask Channel ReQuest Active bit which can be set in case of MEM2MEM */
141962306a36Sopenharmony_ci	status &= ~STM32_MDMA_CISR_CRQA;
142062306a36Sopenharmony_ci	ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(id));
142162306a36Sopenharmony_ci	ien = (ccr & STM32_MDMA_CCR_IRQ_MASK) >> 1;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (!(status & ien)) {
142462306a36Sopenharmony_ci		spin_unlock(&chan->vchan.lock);
142562306a36Sopenharmony_ci		if (chan->busy)
142662306a36Sopenharmony_ci			dev_warn(chan2dev(chan),
142762306a36Sopenharmony_ci				 "spurious it (status=0x%04x, ien=0x%04x)\n", status, ien);
142862306a36Sopenharmony_ci		else
142962306a36Sopenharmony_ci			dev_dbg(chan2dev(chan),
143062306a36Sopenharmony_ci				"spurious it (status=0x%04x, ien=0x%04x)\n", status, ien);
143162306a36Sopenharmony_ci		return IRQ_NONE;
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	reg = STM32_MDMA_CIFCR(id);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (status & STM32_MDMA_CISR_TEIF) {
143762306a36Sopenharmony_ci		dev_err(chan2dev(chan), "Transfer Err: stat=0x%08x\n",
143862306a36Sopenharmony_ci			readl_relaxed(dmadev->base + STM32_MDMA_CESR(id)));
143962306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CTEIF);
144062306a36Sopenharmony_ci		status &= ~STM32_MDMA_CISR_TEIF;
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	if (status & STM32_MDMA_CISR_CTCIF) {
144462306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CCTCIF);
144562306a36Sopenharmony_ci		status &= ~STM32_MDMA_CISR_CTCIF;
144662306a36Sopenharmony_ci		stm32_mdma_xfer_end(chan);
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (status & STM32_MDMA_CISR_BRTIF) {
145062306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CBRTIF);
145162306a36Sopenharmony_ci		status &= ~STM32_MDMA_CISR_BRTIF;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (status & STM32_MDMA_CISR_BTIF) {
145562306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CBTIF);
145662306a36Sopenharmony_ci		status &= ~STM32_MDMA_CISR_BTIF;
145762306a36Sopenharmony_ci		chan->curr_hwdesc++;
145862306a36Sopenharmony_ci		if (chan->desc && chan->desc->cyclic) {
145962306a36Sopenharmony_ci			if (chan->curr_hwdesc == chan->desc->count)
146062306a36Sopenharmony_ci				chan->curr_hwdesc = 0;
146162306a36Sopenharmony_ci			vchan_cyclic_callback(&chan->desc->vdesc);
146262306a36Sopenharmony_ci		}
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	if (status & STM32_MDMA_CISR_TCIF) {
146662306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, STM32_MDMA_CIFCR_CLTCIF);
146762306a36Sopenharmony_ci		status &= ~STM32_MDMA_CISR_TCIF;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	if (status) {
147162306a36Sopenharmony_ci		stm32_mdma_set_bits(dmadev, reg, status);
147262306a36Sopenharmony_ci		dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);
147362306a36Sopenharmony_ci		if (!(ccr & STM32_MDMA_CCR_EN))
147462306a36Sopenharmony_ci			dev_err(chan2dev(chan), "chan disabled by HW\n");
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	spin_unlock(&chan->vchan.lock);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	return IRQ_HANDLED;
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic int stm32_mdma_alloc_chan_resources(struct dma_chan *c)
148362306a36Sopenharmony_ci{
148462306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
148562306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
148662306a36Sopenharmony_ci	int ret;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	chan->desc_pool = dmam_pool_create(dev_name(&c->dev->device),
148962306a36Sopenharmony_ci					   c->device->dev,
149062306a36Sopenharmony_ci					   sizeof(struct stm32_mdma_hwdesc),
149162306a36Sopenharmony_ci					  __alignof__(struct stm32_mdma_hwdesc),
149262306a36Sopenharmony_ci					   0);
149362306a36Sopenharmony_ci	if (!chan->desc_pool) {
149462306a36Sopenharmony_ci		dev_err(chan2dev(chan), "failed to allocate descriptor pool\n");
149562306a36Sopenharmony_ci		return -ENOMEM;
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dmadev->ddev.dev);
149962306a36Sopenharmony_ci	if (ret < 0)
150062306a36Sopenharmony_ci		return ret;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	ret = stm32_mdma_disable_chan(chan);
150362306a36Sopenharmony_ci	if (ret < 0)
150462306a36Sopenharmony_ci		pm_runtime_put(dmadev->ddev.dev);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	return ret;
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_cistatic void stm32_mdma_free_chan_resources(struct dma_chan *c)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
151262306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
151362306a36Sopenharmony_ci	unsigned long flags;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	if (chan->busy) {
151862306a36Sopenharmony_ci		spin_lock_irqsave(&chan->vchan.lock, flags);
151962306a36Sopenharmony_ci		stm32_mdma_stop(chan);
152062306a36Sopenharmony_ci		chan->desc = NULL;
152162306a36Sopenharmony_ci		spin_unlock_irqrestore(&chan->vchan.lock, flags);
152262306a36Sopenharmony_ci	}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	pm_runtime_put(dmadev->ddev.dev);
152562306a36Sopenharmony_ci	vchan_free_chan_resources(to_virt_chan(c));
152662306a36Sopenharmony_ci	dmam_pool_destroy(chan->desc_pool);
152762306a36Sopenharmony_ci	chan->desc_pool = NULL;
152862306a36Sopenharmony_ci}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_cistatic bool stm32_mdma_filter_fn(struct dma_chan *c, void *fn_param)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c);
153362306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	/* Check if chan is marked Secure */
153662306a36Sopenharmony_ci	if (dmadev->chan_reserved & BIT(chan->id))
153762306a36Sopenharmony_ci		return false;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	return true;
154062306a36Sopenharmony_ci}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_cistatic struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec,
154362306a36Sopenharmony_ci					    struct of_dma *ofdma)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = ofdma->of_dma_data;
154662306a36Sopenharmony_ci	dma_cap_mask_t mask = dmadev->ddev.cap_mask;
154762306a36Sopenharmony_ci	struct stm32_mdma_chan *chan;
154862306a36Sopenharmony_ci	struct dma_chan *c;
154962306a36Sopenharmony_ci	struct stm32_mdma_chan_config config;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	if (dma_spec->args_count < 5) {
155262306a36Sopenharmony_ci		dev_err(mdma2dev(dmadev), "Bad number of args\n");
155362306a36Sopenharmony_ci		return NULL;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	memset(&config, 0, sizeof(config));
155762306a36Sopenharmony_ci	config.request = dma_spec->args[0];
155862306a36Sopenharmony_ci	config.priority_level = dma_spec->args[1];
155962306a36Sopenharmony_ci	config.transfer_config = dma_spec->args[2];
156062306a36Sopenharmony_ci	config.mask_addr = dma_spec->args[3];
156162306a36Sopenharmony_ci	config.mask_data = dma_spec->args[4];
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (config.request >= dmadev->nr_requests) {
156462306a36Sopenharmony_ci		dev_err(mdma2dev(dmadev), "Bad request line\n");
156562306a36Sopenharmony_ci		return NULL;
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (config.priority_level > STM32_MDMA_VERY_HIGH_PRIORITY) {
156962306a36Sopenharmony_ci		dev_err(mdma2dev(dmadev), "Priority level not supported\n");
157062306a36Sopenharmony_ci		return NULL;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	c = __dma_request_channel(&mask, stm32_mdma_filter_fn, &config, ofdma->of_node);
157462306a36Sopenharmony_ci	if (!c) {
157562306a36Sopenharmony_ci		dev_err(mdma2dev(dmadev), "No more channels available\n");
157662306a36Sopenharmony_ci		return NULL;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	chan = to_stm32_mdma_chan(c);
158062306a36Sopenharmony_ci	chan->chan_config = config;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	return c;
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic const struct of_device_id stm32_mdma_of_match[] = {
158662306a36Sopenharmony_ci	{ .compatible = "st,stm32h7-mdma", },
158762306a36Sopenharmony_ci	{ /* sentinel */ },
158862306a36Sopenharmony_ci};
158962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_mdma_of_match);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic int stm32_mdma_probe(struct platform_device *pdev)
159262306a36Sopenharmony_ci{
159362306a36Sopenharmony_ci	struct stm32_mdma_chan *chan;
159462306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev;
159562306a36Sopenharmony_ci	struct dma_device *dd;
159662306a36Sopenharmony_ci	struct device_node *of_node;
159762306a36Sopenharmony_ci	struct reset_control *rst;
159862306a36Sopenharmony_ci	u32 nr_channels, nr_requests;
159962306a36Sopenharmony_ci	int i, count, ret;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	of_node = pdev->dev.of_node;
160262306a36Sopenharmony_ci	if (!of_node)
160362306a36Sopenharmony_ci		return -ENODEV;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "dma-channels",
160662306a36Sopenharmony_ci				       &nr_channels);
160762306a36Sopenharmony_ci	if (ret) {
160862306a36Sopenharmony_ci		nr_channels = STM32_MDMA_MAX_CHANNELS;
160962306a36Sopenharmony_ci		dev_warn(&pdev->dev, "MDMA defaulting on %i channels\n",
161062306a36Sopenharmony_ci			 nr_channels);
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "dma-requests",
161462306a36Sopenharmony_ci				       &nr_requests);
161562306a36Sopenharmony_ci	if (ret) {
161662306a36Sopenharmony_ci		nr_requests = STM32_MDMA_MAX_REQUESTS;
161762306a36Sopenharmony_ci		dev_warn(&pdev->dev, "MDMA defaulting on %i request lines\n",
161862306a36Sopenharmony_ci			 nr_requests);
161962306a36Sopenharmony_ci	}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	count = device_property_count_u32(&pdev->dev, "st,ahb-addr-masks");
162262306a36Sopenharmony_ci	if (count < 0)
162362306a36Sopenharmony_ci		count = 0;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	dmadev = devm_kzalloc(&pdev->dev,
162662306a36Sopenharmony_ci			      struct_size(dmadev, ahb_addr_masks, count),
162762306a36Sopenharmony_ci			      GFP_KERNEL);
162862306a36Sopenharmony_ci	if (!dmadev)
162962306a36Sopenharmony_ci		return -ENOMEM;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	dmadev->nr_channels = nr_channels;
163262306a36Sopenharmony_ci	dmadev->nr_requests = nr_requests;
163362306a36Sopenharmony_ci	device_property_read_u32_array(&pdev->dev, "st,ahb-addr-masks",
163462306a36Sopenharmony_ci				       dmadev->ahb_addr_masks,
163562306a36Sopenharmony_ci				       count);
163662306a36Sopenharmony_ci	dmadev->nr_ahb_addr_masks = count;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	dmadev->base = devm_platform_ioremap_resource(pdev, 0);
163962306a36Sopenharmony_ci	if (IS_ERR(dmadev->base))
164062306a36Sopenharmony_ci		return PTR_ERR(dmadev->base);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	dmadev->clk = devm_clk_get(&pdev->dev, NULL);
164362306a36Sopenharmony_ci	if (IS_ERR(dmadev->clk))
164462306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(dmadev->clk),
164562306a36Sopenharmony_ci				     "Missing clock controller\n");
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	ret = clk_prepare_enable(dmadev->clk);
164862306a36Sopenharmony_ci	if (ret < 0) {
164962306a36Sopenharmony_ci		dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret);
165062306a36Sopenharmony_ci		return ret;
165162306a36Sopenharmony_ci	}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	rst = devm_reset_control_get(&pdev->dev, NULL);
165462306a36Sopenharmony_ci	if (IS_ERR(rst)) {
165562306a36Sopenharmony_ci		ret = PTR_ERR(rst);
165662306a36Sopenharmony_ci		if (ret == -EPROBE_DEFER)
165762306a36Sopenharmony_ci			goto err_clk;
165862306a36Sopenharmony_ci	} else {
165962306a36Sopenharmony_ci		reset_control_assert(rst);
166062306a36Sopenharmony_ci		udelay(2);
166162306a36Sopenharmony_ci		reset_control_deassert(rst);
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	dd = &dmadev->ddev;
166562306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, dd->cap_mask);
166662306a36Sopenharmony_ci	dma_cap_set(DMA_PRIVATE, dd->cap_mask);
166762306a36Sopenharmony_ci	dma_cap_set(DMA_CYCLIC, dd->cap_mask);
166862306a36Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, dd->cap_mask);
166962306a36Sopenharmony_ci	dd->device_alloc_chan_resources = stm32_mdma_alloc_chan_resources;
167062306a36Sopenharmony_ci	dd->device_free_chan_resources = stm32_mdma_free_chan_resources;
167162306a36Sopenharmony_ci	dd->device_tx_status = stm32_mdma_tx_status;
167262306a36Sopenharmony_ci	dd->device_issue_pending = stm32_mdma_issue_pending;
167362306a36Sopenharmony_ci	dd->device_prep_slave_sg = stm32_mdma_prep_slave_sg;
167462306a36Sopenharmony_ci	dd->device_prep_dma_cyclic = stm32_mdma_prep_dma_cyclic;
167562306a36Sopenharmony_ci	dd->device_prep_dma_memcpy = stm32_mdma_prep_dma_memcpy;
167662306a36Sopenharmony_ci	dd->device_config = stm32_mdma_slave_config;
167762306a36Sopenharmony_ci	dd->device_pause = stm32_mdma_pause;
167862306a36Sopenharmony_ci	dd->device_resume = stm32_mdma_resume;
167962306a36Sopenharmony_ci	dd->device_terminate_all = stm32_mdma_terminate_all;
168062306a36Sopenharmony_ci	dd->device_synchronize = stm32_mdma_synchronize;
168162306a36Sopenharmony_ci	dd->descriptor_reuse = true;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
168462306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
168562306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
168662306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
168762306a36Sopenharmony_ci	dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
168862306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
168962306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
169062306a36Sopenharmony_ci		BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
169162306a36Sopenharmony_ci	dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
169262306a36Sopenharmony_ci		BIT(DMA_MEM_TO_MEM);
169362306a36Sopenharmony_ci	dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
169462306a36Sopenharmony_ci	dd->max_burst = STM32_MDMA_MAX_BURST;
169562306a36Sopenharmony_ci	dd->dev = &pdev->dev;
169662306a36Sopenharmony_ci	INIT_LIST_HEAD(&dd->channels);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	for (i = 0; i < dmadev->nr_channels; i++) {
169962306a36Sopenharmony_ci		chan = &dmadev->chan[i];
170062306a36Sopenharmony_ci		chan->id = i;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci		if (stm32_mdma_read(dmadev, STM32_MDMA_CCR(i)) & STM32_MDMA_CCR_SM)
170362306a36Sopenharmony_ci			dmadev->chan_reserved |= BIT(i);
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci		chan->vchan.desc_free = stm32_mdma_desc_free;
170662306a36Sopenharmony_ci		vchan_init(&chan->vchan, dd);
170762306a36Sopenharmony_ci	}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	dmadev->irq = platform_get_irq(pdev, 0);
171062306a36Sopenharmony_ci	if (dmadev->irq < 0) {
171162306a36Sopenharmony_ci		ret = dmadev->irq;
171262306a36Sopenharmony_ci		goto err_clk;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, dmadev->irq, stm32_mdma_irq_handler,
171662306a36Sopenharmony_ci			       0, dev_name(&pdev->dev), dmadev);
171762306a36Sopenharmony_ci	if (ret) {
171862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to request IRQ\n");
171962306a36Sopenharmony_ci		goto err_clk;
172062306a36Sopenharmony_ci	}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	ret = dmaenginem_async_device_register(dd);
172362306a36Sopenharmony_ci	if (ret)
172462306a36Sopenharmony_ci		goto err_clk;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	ret = of_dma_controller_register(of_node, stm32_mdma_of_xlate, dmadev);
172762306a36Sopenharmony_ci	if (ret < 0) {
172862306a36Sopenharmony_ci		dev_err(&pdev->dev,
172962306a36Sopenharmony_ci			"STM32 MDMA DMA OF registration failed %d\n", ret);
173062306a36Sopenharmony_ci		goto err_clk;
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	platform_set_drvdata(pdev, dmadev);
173462306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
173562306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
173662306a36Sopenharmony_ci	pm_runtime_get_noresume(&pdev->dev);
173762306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	dev_info(&pdev->dev, "STM32 MDMA driver registered\n");
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	return 0;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_cierr_clk:
174462306a36Sopenharmony_ci	clk_disable_unprepare(dmadev->clk);
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	return ret;
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci#ifdef CONFIG_PM
175062306a36Sopenharmony_cistatic int stm32_mdma_runtime_suspend(struct device *dev)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = dev_get_drvdata(dev);
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	clk_disable_unprepare(dmadev->clk);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	return 0;
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic int stm32_mdma_runtime_resume(struct device *dev)
176062306a36Sopenharmony_ci{
176162306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = dev_get_drvdata(dev);
176262306a36Sopenharmony_ci	int ret;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	ret = clk_prepare_enable(dmadev->clk);
176562306a36Sopenharmony_ci	if (ret) {
176662306a36Sopenharmony_ci		dev_err(dev, "failed to prepare_enable clock\n");
176762306a36Sopenharmony_ci		return ret;
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	return 0;
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci#endif
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
177562306a36Sopenharmony_cistatic int stm32_mdma_pm_suspend(struct device *dev)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	struct stm32_mdma_device *dmadev = dev_get_drvdata(dev);
177862306a36Sopenharmony_ci	u32 ccr, id;
177962306a36Sopenharmony_ci	int ret;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(dev);
178262306a36Sopenharmony_ci	if (ret < 0)
178362306a36Sopenharmony_ci		return ret;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	for (id = 0; id < dmadev->nr_channels; id++) {
178662306a36Sopenharmony_ci		ccr = stm32_mdma_read(dmadev, STM32_MDMA_CCR(id));
178762306a36Sopenharmony_ci		if (ccr & STM32_MDMA_CCR_EN) {
178862306a36Sopenharmony_ci			dev_warn(dev, "Suspend is prevented by Chan %i\n", id);
178962306a36Sopenharmony_ci			return -EBUSY;
179062306a36Sopenharmony_ci		}
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	pm_runtime_force_suspend(dev);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	return 0;
179862306a36Sopenharmony_ci}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_cistatic int stm32_mdma_pm_resume(struct device *dev)
180162306a36Sopenharmony_ci{
180262306a36Sopenharmony_ci	return pm_runtime_force_resume(dev);
180362306a36Sopenharmony_ci}
180462306a36Sopenharmony_ci#endif
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_cistatic const struct dev_pm_ops stm32_mdma_pm_ops = {
180762306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(stm32_mdma_pm_suspend, stm32_mdma_pm_resume)
180862306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(stm32_mdma_runtime_suspend,
180962306a36Sopenharmony_ci			   stm32_mdma_runtime_resume, NULL)
181062306a36Sopenharmony_ci};
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cistatic struct platform_driver stm32_mdma_driver = {
181362306a36Sopenharmony_ci	.probe = stm32_mdma_probe,
181462306a36Sopenharmony_ci	.driver = {
181562306a36Sopenharmony_ci		.name = "stm32-mdma",
181662306a36Sopenharmony_ci		.of_match_table = stm32_mdma_of_match,
181762306a36Sopenharmony_ci		.pm = &stm32_mdma_pm_ops,
181862306a36Sopenharmony_ci	},
181962306a36Sopenharmony_ci};
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_cistatic int __init stm32_mdma_init(void)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	return platform_driver_register(&stm32_mdma_driver);
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_cisubsys_initcall(stm32_mdma_init);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for STM32 MDMA controller");
182962306a36Sopenharmony_ciMODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
183062306a36Sopenharmony_ciMODULE_AUTHOR("Pierre-Yves Mordret <pierre-yves.mordret@st.com>");
1831