162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the TXx9 SoC DMA Controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009 Atsushi Nemoto
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#ifndef TXX9DMAC_H
862306a36Sopenharmony_ci#define TXX9DMAC_H
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/dmaengine.h>
1162306a36Sopenharmony_ci#include <asm/txx9/dmac.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Design Notes:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This DMAC have four channels and one FIFO buffer.  Each channel can
1762306a36Sopenharmony_ci * be configured for memory-memory or device-memory transfer, but only
1862306a36Sopenharmony_ci * one channel can do alignment-free memory-memory transfer at a time
1962306a36Sopenharmony_ci * while the channel should occupy the FIFO buffer for effective
2062306a36Sopenharmony_ci * transfers.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Instead of dynamically assign the FIFO buffer to channels, I chose
2362306a36Sopenharmony_ci * make one dedicated channel for memory-memory transfer.  The
2462306a36Sopenharmony_ci * dedicated channel is public.  Other channels are private and used
2562306a36Sopenharmony_ci * for slave transfer.  Some devices in the SoC are wired to certain
2662306a36Sopenharmony_ci * DMA channel.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#ifdef CONFIG_MACH_TX49XX
3062306a36Sopenharmony_cistatic inline bool txx9_dma_have_SMPCHN(void)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	return true;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci#define TXX9_DMA_USE_SIMPLE_CHAIN
3562306a36Sopenharmony_ci#else
3662306a36Sopenharmony_cistatic inline bool txx9_dma_have_SMPCHN(void)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	return false;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
4362306a36Sopenharmony_ci#ifdef CONFIG_MACH_TX49XX
4462306a36Sopenharmony_ci#define CCR_LE	TXX9_DMA_CCR_LE
4562306a36Sopenharmony_ci#define MCR_LE	0
4662306a36Sopenharmony_ci#else
4762306a36Sopenharmony_ci#define CCR_LE	0
4862306a36Sopenharmony_ci#define MCR_LE	TXX9_DMA_MCR_LE
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci#else
5162306a36Sopenharmony_ci#define CCR_LE	0
5262306a36Sopenharmony_ci#define MCR_LE	0
5362306a36Sopenharmony_ci#endif
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * Redefine this macro to handle differences between 32- and 64-bit
5762306a36Sopenharmony_ci * addressing, big vs. little endian, etc.
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
6062306a36Sopenharmony_ci#define TXX9_DMA_REG32(name)		u32 __pad_##name; u32 name
6162306a36Sopenharmony_ci#else
6262306a36Sopenharmony_ci#define TXX9_DMA_REG32(name)		u32 name; u32 __pad_##name
6362306a36Sopenharmony_ci#endif
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Hardware register definitions. */
6662306a36Sopenharmony_cistruct txx9dmac_cregs {
6762306a36Sopenharmony_ci#if defined(CONFIG_32BIT) && !defined(CONFIG_PHYS_ADDR_T_64BIT)
6862306a36Sopenharmony_ci	TXX9_DMA_REG32(CHAR);	/* Chain Address Register */
6962306a36Sopenharmony_ci#else
7062306a36Sopenharmony_ci	u64 CHAR;		/* Chain Address Register */
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci	u64 SAR;		/* Source Address Register */
7362306a36Sopenharmony_ci	u64 DAR;		/* Destination Address Register */
7462306a36Sopenharmony_ci	TXX9_DMA_REG32(CNTR);	/* Count Register */
7562306a36Sopenharmony_ci	TXX9_DMA_REG32(SAIR);	/* Source Address Increment Register */
7662306a36Sopenharmony_ci	TXX9_DMA_REG32(DAIR);	/* Destination Address Increment Register */
7762306a36Sopenharmony_ci	TXX9_DMA_REG32(CCR);	/* Channel Control Register */
7862306a36Sopenharmony_ci	TXX9_DMA_REG32(CSR);	/* Channel Status Register */
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_cistruct txx9dmac_cregs32 {
8162306a36Sopenharmony_ci	u32 CHAR;
8262306a36Sopenharmony_ci	u32 SAR;
8362306a36Sopenharmony_ci	u32 DAR;
8462306a36Sopenharmony_ci	u32 CNTR;
8562306a36Sopenharmony_ci	u32 SAIR;
8662306a36Sopenharmony_ci	u32 DAIR;
8762306a36Sopenharmony_ci	u32 CCR;
8862306a36Sopenharmony_ci	u32 CSR;
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistruct txx9dmac_regs {
9262306a36Sopenharmony_ci	/* per-channel registers */
9362306a36Sopenharmony_ci	struct txx9dmac_cregs	CHAN[TXX9_DMA_MAX_NR_CHANNELS];
9462306a36Sopenharmony_ci	u64	__pad[9];
9562306a36Sopenharmony_ci	u64	MFDR;		/* Memory Fill Data Register */
9662306a36Sopenharmony_ci	TXX9_DMA_REG32(MCR);	/* Master Control Register */
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_cistruct txx9dmac_regs32 {
9962306a36Sopenharmony_ci	struct txx9dmac_cregs32	CHAN[TXX9_DMA_MAX_NR_CHANNELS];
10062306a36Sopenharmony_ci	u32	__pad[9];
10162306a36Sopenharmony_ci	u32	MFDR;
10262306a36Sopenharmony_ci	u32	MCR;
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* bits for MCR */
10662306a36Sopenharmony_ci#define TXX9_DMA_MCR_EIS(ch)	(0x10000000<<(ch))
10762306a36Sopenharmony_ci#define TXX9_DMA_MCR_DIS(ch)	(0x01000000<<(ch))
10862306a36Sopenharmony_ci#define TXX9_DMA_MCR_RSFIF	0x00000080
10962306a36Sopenharmony_ci#define TXX9_DMA_MCR_FIFUM(ch)	(0x00000008<<(ch))
11062306a36Sopenharmony_ci#define TXX9_DMA_MCR_LE		0x00000004
11162306a36Sopenharmony_ci#define TXX9_DMA_MCR_RPRT	0x00000002
11262306a36Sopenharmony_ci#define TXX9_DMA_MCR_MSTEN	0x00000001
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* bits for CCRn */
11562306a36Sopenharmony_ci#define TXX9_DMA_CCR_IMMCHN	0x20000000
11662306a36Sopenharmony_ci#define TXX9_DMA_CCR_USEXFSZ	0x10000000
11762306a36Sopenharmony_ci#define TXX9_DMA_CCR_LE		0x08000000
11862306a36Sopenharmony_ci#define TXX9_DMA_CCR_DBINH	0x04000000
11962306a36Sopenharmony_ci#define TXX9_DMA_CCR_SBINH	0x02000000
12062306a36Sopenharmony_ci#define TXX9_DMA_CCR_CHRST	0x01000000
12162306a36Sopenharmony_ci#define TXX9_DMA_CCR_RVBYTE	0x00800000
12262306a36Sopenharmony_ci#define TXX9_DMA_CCR_ACKPOL	0x00400000
12362306a36Sopenharmony_ci#define TXX9_DMA_CCR_REQPL	0x00200000
12462306a36Sopenharmony_ci#define TXX9_DMA_CCR_EGREQ	0x00100000
12562306a36Sopenharmony_ci#define TXX9_DMA_CCR_CHDN	0x00080000
12662306a36Sopenharmony_ci#define TXX9_DMA_CCR_DNCTL	0x00060000
12762306a36Sopenharmony_ci#define TXX9_DMA_CCR_EXTRQ	0x00010000
12862306a36Sopenharmony_ci#define TXX9_DMA_CCR_INTRQD	0x0000e000
12962306a36Sopenharmony_ci#define TXX9_DMA_CCR_INTENE	0x00001000
13062306a36Sopenharmony_ci#define TXX9_DMA_CCR_INTENC	0x00000800
13162306a36Sopenharmony_ci#define TXX9_DMA_CCR_INTENT	0x00000400
13262306a36Sopenharmony_ci#define TXX9_DMA_CCR_CHNEN	0x00000200
13362306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFACT	0x00000100
13462306a36Sopenharmony_ci#define TXX9_DMA_CCR_SMPCHN	0x00000020
13562306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ(order)	(((order) << 2) & 0x0000001c)
13662306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_1	TXX9_DMA_CCR_XFSZ(0)
13762306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_2	TXX9_DMA_CCR_XFSZ(1)
13862306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_4	TXX9_DMA_CCR_XFSZ(2)
13962306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_8	TXX9_DMA_CCR_XFSZ(3)
14062306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_X4	TXX9_DMA_CCR_XFSZ(4)
14162306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_X8	TXX9_DMA_CCR_XFSZ(5)
14262306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_X16	TXX9_DMA_CCR_XFSZ(6)
14362306a36Sopenharmony_ci#define TXX9_DMA_CCR_XFSZ_X32	TXX9_DMA_CCR_XFSZ(7)
14462306a36Sopenharmony_ci#define TXX9_DMA_CCR_MEMIO	0x00000002
14562306a36Sopenharmony_ci#define TXX9_DMA_CCR_SNGAD	0x00000001
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/* bits for CSRn */
14862306a36Sopenharmony_ci#define TXX9_DMA_CSR_CHNEN	0x00000400
14962306a36Sopenharmony_ci#define TXX9_DMA_CSR_STLXFER	0x00000200
15062306a36Sopenharmony_ci#define TXX9_DMA_CSR_XFACT	0x00000100
15162306a36Sopenharmony_ci#define TXX9_DMA_CSR_ABCHC	0x00000080
15262306a36Sopenharmony_ci#define TXX9_DMA_CSR_NCHNC	0x00000040
15362306a36Sopenharmony_ci#define TXX9_DMA_CSR_NTRNFC	0x00000020
15462306a36Sopenharmony_ci#define TXX9_DMA_CSR_EXTDN	0x00000010
15562306a36Sopenharmony_ci#define TXX9_DMA_CSR_CFERR	0x00000008
15662306a36Sopenharmony_ci#define TXX9_DMA_CSR_CHERR	0x00000004
15762306a36Sopenharmony_ci#define TXX9_DMA_CSR_DESERR	0x00000002
15862306a36Sopenharmony_ci#define TXX9_DMA_CSR_SORERR	0x00000001
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistruct txx9dmac_chan {
16162306a36Sopenharmony_ci	struct dma_chan		chan;
16262306a36Sopenharmony_ci	struct dma_device	dma;
16362306a36Sopenharmony_ci	struct txx9dmac_dev	*ddev;
16462306a36Sopenharmony_ci	void __iomem		*ch_regs;
16562306a36Sopenharmony_ci	struct tasklet_struct	tasklet;
16662306a36Sopenharmony_ci	int			irq;
16762306a36Sopenharmony_ci	u32			ccr;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	spinlock_t		lock;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* these other elements are all protected by lock */
17262306a36Sopenharmony_ci	struct list_head	active_list;
17362306a36Sopenharmony_ci	struct list_head	queue;
17462306a36Sopenharmony_ci	struct list_head	free_list;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	unsigned int		descs_allocated;
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistruct txx9dmac_dev {
18062306a36Sopenharmony_ci	void __iomem		*regs;
18162306a36Sopenharmony_ci	struct tasklet_struct	tasklet;
18262306a36Sopenharmony_ci	int			irq;
18362306a36Sopenharmony_ci	struct txx9dmac_chan	*chan[TXX9_DMA_MAX_NR_CHANNELS];
18462306a36Sopenharmony_ci	bool			have_64bit_regs;
18562306a36Sopenharmony_ci	unsigned int		descsize;
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic inline bool __is_dmac64(const struct txx9dmac_dev *ddev)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	return ddev->have_64bit_regs;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic inline bool is_dmac64(const struct txx9dmac_chan *dc)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	return __is_dmac64(dc->ddev);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci#ifdef TXX9_DMA_USE_SIMPLE_CHAIN
19962306a36Sopenharmony_ci/* Hardware descriptor definition. (for simple-chain) */
20062306a36Sopenharmony_cistruct txx9dmac_hwdesc {
20162306a36Sopenharmony_ci#if defined(CONFIG_32BIT) && !defined(CONFIG_PHYS_ADDR_T_64BIT)
20262306a36Sopenharmony_ci	TXX9_DMA_REG32(CHAR);
20362306a36Sopenharmony_ci#else
20462306a36Sopenharmony_ci	u64 CHAR;
20562306a36Sopenharmony_ci#endif
20662306a36Sopenharmony_ci	u64 SAR;
20762306a36Sopenharmony_ci	u64 DAR;
20862306a36Sopenharmony_ci	TXX9_DMA_REG32(CNTR);
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_cistruct txx9dmac_hwdesc32 {
21162306a36Sopenharmony_ci	u32 CHAR;
21262306a36Sopenharmony_ci	u32 SAR;
21362306a36Sopenharmony_ci	u32 DAR;
21462306a36Sopenharmony_ci	u32 CNTR;
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci#else
21762306a36Sopenharmony_ci#define txx9dmac_hwdesc txx9dmac_cregs
21862306a36Sopenharmony_ci#define txx9dmac_hwdesc32 txx9dmac_cregs32
21962306a36Sopenharmony_ci#endif
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct txx9dmac_desc {
22262306a36Sopenharmony_ci	/* FIRST values the hardware uses */
22362306a36Sopenharmony_ci	union {
22462306a36Sopenharmony_ci		struct txx9dmac_hwdesc hwdesc;
22562306a36Sopenharmony_ci		struct txx9dmac_hwdesc32 hwdesc32;
22662306a36Sopenharmony_ci	};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* THEN values for driver housekeeping */
22962306a36Sopenharmony_ci	struct list_head		desc_node ____cacheline_aligned;
23062306a36Sopenharmony_ci	struct list_head		tx_list;
23162306a36Sopenharmony_ci	struct dma_async_tx_descriptor	txd;
23262306a36Sopenharmony_ci	size_t				len;
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#ifdef TXX9_DMA_USE_SIMPLE_CHAIN
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic inline bool txx9dmac_chan_INTENT(struct txx9dmac_chan *dc)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	return (dc->ccr & TXX9_DMA_CCR_INTENT) != 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic inline void txx9dmac_chan_set_INTENT(struct txx9dmac_chan *dc)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	dc->ccr |= TXX9_DMA_CCR_INTENT;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic inline void txx9dmac_desc_set_INTENT(struct txx9dmac_dev *ddev,
24862306a36Sopenharmony_ci					    struct txx9dmac_desc *desc)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic inline void txx9dmac_chan_set_SMPCHN(struct txx9dmac_chan *dc)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	dc->ccr |= TXX9_DMA_CCR_SMPCHN;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic inline void txx9dmac_desc_set_nosimple(struct txx9dmac_dev *ddev,
25862306a36Sopenharmony_ci					      struct txx9dmac_desc *desc,
25962306a36Sopenharmony_ci					      u32 sair, u32 dair, u32 ccr)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#else /* TXX9_DMA_USE_SIMPLE_CHAIN */
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic inline bool txx9dmac_chan_INTENT(struct txx9dmac_chan *dc)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return true;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void txx9dmac_chan_set_INTENT(struct txx9dmac_chan *dc)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic inline void txx9dmac_desc_set_INTENT(struct txx9dmac_dev *ddev,
27562306a36Sopenharmony_ci					    struct txx9dmac_desc *desc)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	if (__is_dmac64(ddev))
27862306a36Sopenharmony_ci		desc->hwdesc.CCR |= TXX9_DMA_CCR_INTENT;
27962306a36Sopenharmony_ci	else
28062306a36Sopenharmony_ci		desc->hwdesc32.CCR |= TXX9_DMA_CCR_INTENT;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic inline void txx9dmac_chan_set_SMPCHN(struct txx9dmac_chan *dc)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic inline void txx9dmac_desc_set_nosimple(struct txx9dmac_dev *ddev,
28862306a36Sopenharmony_ci					      struct txx9dmac_desc *desc,
28962306a36Sopenharmony_ci					      u32 sai, u32 dai, u32 ccr)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	if (__is_dmac64(ddev)) {
29262306a36Sopenharmony_ci		desc->hwdesc.SAIR = sai;
29362306a36Sopenharmony_ci		desc->hwdesc.DAIR = dai;
29462306a36Sopenharmony_ci		desc->hwdesc.CCR = ccr;
29562306a36Sopenharmony_ci	} else {
29662306a36Sopenharmony_ci		desc->hwdesc32.SAIR = sai;
29762306a36Sopenharmony_ci		desc->hwdesc32.DAIR = dai;
29862306a36Sopenharmony_ci		desc->hwdesc32.CCR = ccr;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci#endif /* TXX9_DMA_USE_SIMPLE_CHAIN */
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci#endif /* TXX9DMAC_H */
305