xref: /linux/sound/soc/renesas/rcar/dma.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
1*c087a94bSLad Prabhakar // SPDX-License-Identifier: GPL-2.0
2*c087a94bSLad Prabhakar //
3*c087a94bSLad Prabhakar // Renesas R-Car Audio DMAC support
4*c087a94bSLad Prabhakar //
5*c087a94bSLad Prabhakar // Copyright (C) 2015 Renesas Electronics Corp.
6*c087a94bSLad Prabhakar // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7*c087a94bSLad Prabhakar 
8*c087a94bSLad Prabhakar #include <linux/delay.h>
9*c087a94bSLad Prabhakar #include <linux/of_dma.h>
10*c087a94bSLad Prabhakar #include <sound/dmaengine_pcm.h>
11*c087a94bSLad Prabhakar #include "rsnd.h"
12*c087a94bSLad Prabhakar 
13*c087a94bSLad Prabhakar /*
14*c087a94bSLad Prabhakar  * Audio DMAC peri peri register
15*c087a94bSLad Prabhakar  */
16*c087a94bSLad Prabhakar #define PDMASAR		0x00
17*c087a94bSLad Prabhakar #define PDMADAR		0x04
18*c087a94bSLad Prabhakar #define PDMACHCR	0x0c
19*c087a94bSLad Prabhakar 
20*c087a94bSLad Prabhakar /* PDMACHCR */
21*c087a94bSLad Prabhakar #define PDMACHCR_DE		(1 << 0)
22*c087a94bSLad Prabhakar 
23*c087a94bSLad Prabhakar 
24*c087a94bSLad Prabhakar struct rsnd_dmaen {
25*c087a94bSLad Prabhakar 	struct dma_chan		*chan;
26*c087a94bSLad Prabhakar };
27*c087a94bSLad Prabhakar 
28*c087a94bSLad Prabhakar struct rsnd_dmapp {
29*c087a94bSLad Prabhakar 	int			dmapp_id;
30*c087a94bSLad Prabhakar 	u32			chcr;
31*c087a94bSLad Prabhakar };
32*c087a94bSLad Prabhakar 
33*c087a94bSLad Prabhakar struct rsnd_dma {
34*c087a94bSLad Prabhakar 	struct rsnd_mod		mod;
35*c087a94bSLad Prabhakar 	struct rsnd_mod		*mod_from;
36*c087a94bSLad Prabhakar 	struct rsnd_mod		*mod_to;
37*c087a94bSLad Prabhakar 	dma_addr_t		src_addr;
38*c087a94bSLad Prabhakar 	dma_addr_t		dst_addr;
39*c087a94bSLad Prabhakar 	union {
40*c087a94bSLad Prabhakar 		struct rsnd_dmaen en;
41*c087a94bSLad Prabhakar 		struct rsnd_dmapp pp;
42*c087a94bSLad Prabhakar 	} dma;
43*c087a94bSLad Prabhakar };
44*c087a94bSLad Prabhakar 
45*c087a94bSLad Prabhakar struct rsnd_dma_ctrl {
46*c087a94bSLad Prabhakar 	void __iomem *ppbase;
47*c087a94bSLad Prabhakar 	phys_addr_t ppres;
48*c087a94bSLad Prabhakar 	int dmaen_num;
49*c087a94bSLad Prabhakar 	int dmapp_num;
50*c087a94bSLad Prabhakar };
51*c087a94bSLad Prabhakar 
52*c087a94bSLad Prabhakar #define rsnd_priv_to_dmac(p)	((struct rsnd_dma_ctrl *)(p)->dma)
53*c087a94bSLad Prabhakar #define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
54*c087a94bSLad Prabhakar #define rsnd_dma_to_dmaen(dma)	(&(dma)->dma.en)
55*c087a94bSLad Prabhakar #define rsnd_dma_to_dmapp(dma)	(&(dma)->dma.pp)
56*c087a94bSLad Prabhakar 
57*c087a94bSLad Prabhakar /* for DEBUG */
58*c087a94bSLad Prabhakar static struct rsnd_mod_ops mem_ops = {
59*c087a94bSLad Prabhakar 	.name = "mem",
60*c087a94bSLad Prabhakar };
61*c087a94bSLad Prabhakar 
62*c087a94bSLad Prabhakar static struct rsnd_mod mem = {
63*c087a94bSLad Prabhakar };
64*c087a94bSLad Prabhakar 
65*c087a94bSLad Prabhakar /*
66*c087a94bSLad Prabhakar  *		Audio DMAC
67*c087a94bSLad Prabhakar  */
68*c087a94bSLad Prabhakar static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
69*c087a94bSLad Prabhakar 						   struct rsnd_mod *mod_from,
70*c087a94bSLad Prabhakar 						   struct rsnd_mod *mod_to)
71*c087a94bSLad Prabhakar {
72*c087a94bSLad Prabhakar 	if ((!mod_from && !mod_to) ||
73*c087a94bSLad Prabhakar 	    (mod_from && mod_to))
74*c087a94bSLad Prabhakar 		return NULL;
75*c087a94bSLad Prabhakar 
76*c087a94bSLad Prabhakar 	if (mod_from)
77*c087a94bSLad Prabhakar 		return rsnd_mod_dma_req(io, mod_from);
78*c087a94bSLad Prabhakar 	else
79*c087a94bSLad Prabhakar 		return rsnd_mod_dma_req(io, mod_to);
80*c087a94bSLad Prabhakar }
81*c087a94bSLad Prabhakar 
82*c087a94bSLad Prabhakar static int rsnd_dmaen_stop(struct rsnd_mod *mod,
83*c087a94bSLad Prabhakar 			   struct rsnd_dai_stream *io,
84*c087a94bSLad Prabhakar 			   struct rsnd_priv *priv)
85*c087a94bSLad Prabhakar {
86*c087a94bSLad Prabhakar 	return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP);
87*c087a94bSLad Prabhakar }
88*c087a94bSLad Prabhakar 
89*c087a94bSLad Prabhakar static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
90*c087a94bSLad Prabhakar 			      struct rsnd_dai_stream *io,
91*c087a94bSLad Prabhakar 			      struct rsnd_priv *priv)
92*c087a94bSLad Prabhakar {
93*c087a94bSLad Prabhakar 	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
94*c087a94bSLad Prabhakar 	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
95*c087a94bSLad Prabhakar 
96*c087a94bSLad Prabhakar 	/*
97*c087a94bSLad Prabhakar 	 * DMAEngine release uses mutex lock.
98*c087a94bSLad Prabhakar 	 * Thus, it shouldn't be called under spinlock.
99*c087a94bSLad Prabhakar 	 * Let's call it under prepare
100*c087a94bSLad Prabhakar 	 */
101*c087a94bSLad Prabhakar 	if (dmaen->chan)
102*c087a94bSLad Prabhakar 		snd_dmaengine_pcm_close_release_chan(io->substream);
103*c087a94bSLad Prabhakar 
104*c087a94bSLad Prabhakar 	dmaen->chan = NULL;
105*c087a94bSLad Prabhakar 
106*c087a94bSLad Prabhakar 	return 0;
107*c087a94bSLad Prabhakar }
108*c087a94bSLad Prabhakar 
109*c087a94bSLad Prabhakar static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
110*c087a94bSLad Prabhakar 			      struct rsnd_dai_stream *io,
111*c087a94bSLad Prabhakar 			      struct rsnd_priv *priv)
112*c087a94bSLad Prabhakar {
113*c087a94bSLad Prabhakar 	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
114*c087a94bSLad Prabhakar 	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
115*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
116*c087a94bSLad Prabhakar 
117*c087a94bSLad Prabhakar 	/* maybe suspended */
118*c087a94bSLad Prabhakar 	if (dmaen->chan)
119*c087a94bSLad Prabhakar 		return 0;
120*c087a94bSLad Prabhakar 
121*c087a94bSLad Prabhakar 	/*
122*c087a94bSLad Prabhakar 	 * DMAEngine request uses mutex lock.
123*c087a94bSLad Prabhakar 	 * Thus, it shouldn't be called under spinlock.
124*c087a94bSLad Prabhakar 	 * Let's call it under prepare
125*c087a94bSLad Prabhakar 	 */
126*c087a94bSLad Prabhakar 	dmaen->chan = rsnd_dmaen_request_channel(io,
127*c087a94bSLad Prabhakar 						 dma->mod_from,
128*c087a94bSLad Prabhakar 						 dma->mod_to);
129*c087a94bSLad Prabhakar 	if (IS_ERR_OR_NULL(dmaen->chan)) {
130*c087a94bSLad Prabhakar 		dmaen->chan = NULL;
131*c087a94bSLad Prabhakar 		dev_err(dev, "can't get dma channel\n");
132*c087a94bSLad Prabhakar 		return -EIO;
133*c087a94bSLad Prabhakar 	}
134*c087a94bSLad Prabhakar 
135*c087a94bSLad Prabhakar 	return snd_dmaengine_pcm_open(io->substream, dmaen->chan);
136*c087a94bSLad Prabhakar }
137*c087a94bSLad Prabhakar 
138*c087a94bSLad Prabhakar static int rsnd_dmaen_start(struct rsnd_mod *mod,
139*c087a94bSLad Prabhakar 			    struct rsnd_dai_stream *io,
140*c087a94bSLad Prabhakar 			    struct rsnd_priv *priv)
141*c087a94bSLad Prabhakar {
142*c087a94bSLad Prabhakar 	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
143*c087a94bSLad Prabhakar 	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
144*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
145*c087a94bSLad Prabhakar 	struct dma_slave_config cfg = {};
146*c087a94bSLad Prabhakar 	enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
147*c087a94bSLad Prabhakar 	int ret;
148*c087a94bSLad Prabhakar 
149*c087a94bSLad Prabhakar 	/*
150*c087a94bSLad Prabhakar 	 * in case of monaural data writing or reading through Audio-DMAC
151*c087a94bSLad Prabhakar 	 * data is always in Left Justified format, so both src and dst
152*c087a94bSLad Prabhakar 	 * DMA Bus width need to be set equal to physical data width.
153*c087a94bSLad Prabhakar 	 */
154*c087a94bSLad Prabhakar 	if (rsnd_runtime_channel_original(io) == 1) {
155*c087a94bSLad Prabhakar 		struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
156*c087a94bSLad Prabhakar 		int bits = snd_pcm_format_physical_width(runtime->format);
157*c087a94bSLad Prabhakar 
158*c087a94bSLad Prabhakar 		switch (bits) {
159*c087a94bSLad Prabhakar 		case 8:
160*c087a94bSLad Prabhakar 			buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
161*c087a94bSLad Prabhakar 			break;
162*c087a94bSLad Prabhakar 		case 16:
163*c087a94bSLad Prabhakar 			buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
164*c087a94bSLad Prabhakar 			break;
165*c087a94bSLad Prabhakar 		case 32:
166*c087a94bSLad Prabhakar 			buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
167*c087a94bSLad Prabhakar 			break;
168*c087a94bSLad Prabhakar 		default:
169*c087a94bSLad Prabhakar 			dev_err(dev, "invalid format width %d\n", bits);
170*c087a94bSLad Prabhakar 			return -EINVAL;
171*c087a94bSLad Prabhakar 		}
172*c087a94bSLad Prabhakar 	}
173*c087a94bSLad Prabhakar 
174*c087a94bSLad Prabhakar 	cfg.direction	= snd_pcm_substream_to_dma_direction(io->substream);
175*c087a94bSLad Prabhakar 	cfg.src_addr	= dma->src_addr;
176*c087a94bSLad Prabhakar 	cfg.dst_addr	= dma->dst_addr;
177*c087a94bSLad Prabhakar 	cfg.src_addr_width = buswidth;
178*c087a94bSLad Prabhakar 	cfg.dst_addr_width = buswidth;
179*c087a94bSLad Prabhakar 
180*c087a94bSLad Prabhakar 	dev_dbg(dev, "%s %pad -> %pad\n",
181*c087a94bSLad Prabhakar 		rsnd_mod_name(mod),
182*c087a94bSLad Prabhakar 		&cfg.src_addr, &cfg.dst_addr);
183*c087a94bSLad Prabhakar 
184*c087a94bSLad Prabhakar 	ret = dmaengine_slave_config(dmaen->chan, &cfg);
185*c087a94bSLad Prabhakar 	if (ret < 0)
186*c087a94bSLad Prabhakar 		return ret;
187*c087a94bSLad Prabhakar 
188*c087a94bSLad Prabhakar 	return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START);
189*c087a94bSLad Prabhakar }
190*c087a94bSLad Prabhakar 
191*c087a94bSLad Prabhakar struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
192*c087a94bSLad Prabhakar 					  struct rsnd_mod *mod, char *x)
193*c087a94bSLad Prabhakar {
194*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
195*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
196*c087a94bSLad Prabhakar 	struct dma_chan *chan = NULL;
197*c087a94bSLad Prabhakar 	struct device_node *np;
198*c087a94bSLad Prabhakar 	int i = 0;
199*c087a94bSLad Prabhakar 
200*c087a94bSLad Prabhakar 	for_each_child_of_node(of_node, np) {
201*c087a94bSLad Prabhakar 		i = rsnd_node_fixed_index(dev, np, name, i);
202*c087a94bSLad Prabhakar 		if (i < 0) {
203*c087a94bSLad Prabhakar 			chan = NULL;
204*c087a94bSLad Prabhakar 			of_node_put(np);
205*c087a94bSLad Prabhakar 			break;
206*c087a94bSLad Prabhakar 		}
207*c087a94bSLad Prabhakar 
208*c087a94bSLad Prabhakar 		if (i == rsnd_mod_id_raw(mod) && (!chan))
209*c087a94bSLad Prabhakar 			chan = of_dma_request_slave_channel(np, x);
210*c087a94bSLad Prabhakar 		i++;
211*c087a94bSLad Prabhakar 	}
212*c087a94bSLad Prabhakar 
213*c087a94bSLad Prabhakar 	/* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
214*c087a94bSLad Prabhakar 	of_node_put(of_node);
215*c087a94bSLad Prabhakar 
216*c087a94bSLad Prabhakar 	return chan;
217*c087a94bSLad Prabhakar }
218*c087a94bSLad Prabhakar 
219*c087a94bSLad Prabhakar static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
220*c087a94bSLad Prabhakar 			   struct rsnd_dma *dma,
221*c087a94bSLad Prabhakar 			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
222*c087a94bSLad Prabhakar {
223*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
224*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
225*c087a94bSLad Prabhakar 	struct dma_chan *chan;
226*c087a94bSLad Prabhakar 
227*c087a94bSLad Prabhakar 	/* try to get DMAEngine channel */
228*c087a94bSLad Prabhakar 	chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
229*c087a94bSLad Prabhakar 	if (IS_ERR_OR_NULL(chan)) {
230*c087a94bSLad Prabhakar 		/* Let's follow when -EPROBE_DEFER case */
231*c087a94bSLad Prabhakar 		if (PTR_ERR(chan) == -EPROBE_DEFER)
232*c087a94bSLad Prabhakar 			return PTR_ERR(chan);
233*c087a94bSLad Prabhakar 
234*c087a94bSLad Prabhakar 		/*
235*c087a94bSLad Prabhakar 		 * DMA failed. try to PIO mode
236*c087a94bSLad Prabhakar 		 * see
237*c087a94bSLad Prabhakar 		 *	rsnd_ssi_fallback()
238*c087a94bSLad Prabhakar 		 *	rsnd_rdai_continuance_probe()
239*c087a94bSLad Prabhakar 		 */
240*c087a94bSLad Prabhakar 		return -EAGAIN;
241*c087a94bSLad Prabhakar 	}
242*c087a94bSLad Prabhakar 
243*c087a94bSLad Prabhakar 	/*
244*c087a94bSLad Prabhakar 	 * use it for IPMMU if needed
245*c087a94bSLad Prabhakar 	 * see
246*c087a94bSLad Prabhakar 	 *	rsnd_preallocate_pages()
247*c087a94bSLad Prabhakar 	 */
248*c087a94bSLad Prabhakar 	io->dmac_dev = chan->device->dev;
249*c087a94bSLad Prabhakar 
250*c087a94bSLad Prabhakar 	dma_release_channel(chan);
251*c087a94bSLad Prabhakar 
252*c087a94bSLad Prabhakar 	dmac->dmaen_num++;
253*c087a94bSLad Prabhakar 
254*c087a94bSLad Prabhakar 	return 0;
255*c087a94bSLad Prabhakar }
256*c087a94bSLad Prabhakar 
257*c087a94bSLad Prabhakar static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
258*c087a94bSLad Prabhakar 			      struct rsnd_dai_stream *io,
259*c087a94bSLad Prabhakar 			      snd_pcm_uframes_t *pointer)
260*c087a94bSLad Prabhakar {
261*c087a94bSLad Prabhakar 	*pointer = snd_dmaengine_pcm_pointer(io->substream);
262*c087a94bSLad Prabhakar 
263*c087a94bSLad Prabhakar 	return 0;
264*c087a94bSLad Prabhakar }
265*c087a94bSLad Prabhakar 
266*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_dmaen_ops = {
267*c087a94bSLad Prabhakar 	.name		= "audmac",
268*c087a94bSLad Prabhakar 	.prepare	= rsnd_dmaen_prepare,
269*c087a94bSLad Prabhakar 	.cleanup	= rsnd_dmaen_cleanup,
270*c087a94bSLad Prabhakar 	.start		= rsnd_dmaen_start,
271*c087a94bSLad Prabhakar 	.stop		= rsnd_dmaen_stop,
272*c087a94bSLad Prabhakar 	.pointer	= rsnd_dmaen_pointer,
273*c087a94bSLad Prabhakar 	.get_status	= rsnd_mod_get_status,
274*c087a94bSLad Prabhakar };
275*c087a94bSLad Prabhakar 
276*c087a94bSLad Prabhakar /*
277*c087a94bSLad Prabhakar  *		Audio DMAC peri peri
278*c087a94bSLad Prabhakar  */
279*c087a94bSLad Prabhakar static const u8 gen2_id_table_ssiu[] = {
280*c087a94bSLad Prabhakar 	/* SSI00 ~ SSI07 */
281*c087a94bSLad Prabhakar 	0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c,
282*c087a94bSLad Prabhakar 	/* SSI10 ~ SSI17 */
283*c087a94bSLad Prabhakar 	0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40,
284*c087a94bSLad Prabhakar 	/* SSI20 ~ SSI27 */
285*c087a94bSLad Prabhakar 	0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44,
286*c087a94bSLad Prabhakar 	/* SSI30 ~ SSI37 */
287*c087a94bSLad Prabhakar 	0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
288*c087a94bSLad Prabhakar 	/* SSI40 ~ SSI47 */
289*c087a94bSLad Prabhakar 	0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
290*c087a94bSLad Prabhakar 	/* SSI5 */
291*c087a94bSLad Prabhakar 	0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292*c087a94bSLad Prabhakar 	/* SSI6 */
293*c087a94bSLad Prabhakar 	0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294*c087a94bSLad Prabhakar 	/* SSI7 */
295*c087a94bSLad Prabhakar 	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296*c087a94bSLad Prabhakar 	/* SSI8 */
297*c087a94bSLad Prabhakar 	0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298*c087a94bSLad Prabhakar 	/* SSI90 ~ SSI97 */
299*c087a94bSLad Prabhakar 	0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56,
300*c087a94bSLad Prabhakar };
301*c087a94bSLad Prabhakar static const u8 gen2_id_table_scu[] = {
302*c087a94bSLad Prabhakar 	0x2d, /* SCU_SRCI0 */
303*c087a94bSLad Prabhakar 	0x2e, /* SCU_SRCI1 */
304*c087a94bSLad Prabhakar 	0x2f, /* SCU_SRCI2 */
305*c087a94bSLad Prabhakar 	0x30, /* SCU_SRCI3 */
306*c087a94bSLad Prabhakar 	0x31, /* SCU_SRCI4 */
307*c087a94bSLad Prabhakar 	0x32, /* SCU_SRCI5 */
308*c087a94bSLad Prabhakar 	0x33, /* SCU_SRCI6 */
309*c087a94bSLad Prabhakar 	0x34, /* SCU_SRCI7 */
310*c087a94bSLad Prabhakar 	0x35, /* SCU_SRCI8 */
311*c087a94bSLad Prabhakar 	0x36, /* SCU_SRCI9 */
312*c087a94bSLad Prabhakar };
313*c087a94bSLad Prabhakar static const u8 gen2_id_table_cmd[] = {
314*c087a94bSLad Prabhakar 	0x37, /* SCU_CMD0 */
315*c087a94bSLad Prabhakar 	0x38, /* SCU_CMD1 */
316*c087a94bSLad Prabhakar };
317*c087a94bSLad Prabhakar 
318*c087a94bSLad Prabhakar static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
319*c087a94bSLad Prabhakar 			     struct rsnd_mod *mod)
320*c087a94bSLad Prabhakar {
321*c087a94bSLad Prabhakar 	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
322*c087a94bSLad Prabhakar 	struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
323*c087a94bSLad Prabhakar 	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
324*c087a94bSLad Prabhakar 	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
325*c087a94bSLad Prabhakar 	const u8 *entry = NULL;
326*c087a94bSLad Prabhakar 	int id = 255;
327*c087a94bSLad Prabhakar 	int size = 0;
328*c087a94bSLad Prabhakar 
329*c087a94bSLad Prabhakar 	if ((mod == ssi) ||
330*c087a94bSLad Prabhakar 	    (mod == ssiu)) {
331*c087a94bSLad Prabhakar 		int busif = rsnd_mod_id_sub(ssiu);
332*c087a94bSLad Prabhakar 
333*c087a94bSLad Prabhakar 		entry = gen2_id_table_ssiu;
334*c087a94bSLad Prabhakar 		size = ARRAY_SIZE(gen2_id_table_ssiu);
335*c087a94bSLad Prabhakar 		id = (rsnd_mod_id(mod) * 8) + busif;
336*c087a94bSLad Prabhakar 	} else if (mod == src) {
337*c087a94bSLad Prabhakar 		entry = gen2_id_table_scu;
338*c087a94bSLad Prabhakar 		size = ARRAY_SIZE(gen2_id_table_scu);
339*c087a94bSLad Prabhakar 		id = rsnd_mod_id(mod);
340*c087a94bSLad Prabhakar 	} else if (mod == dvc) {
341*c087a94bSLad Prabhakar 		entry = gen2_id_table_cmd;
342*c087a94bSLad Prabhakar 		size = ARRAY_SIZE(gen2_id_table_cmd);
343*c087a94bSLad Prabhakar 		id = rsnd_mod_id(mod);
344*c087a94bSLad Prabhakar 	}
345*c087a94bSLad Prabhakar 
346*c087a94bSLad Prabhakar 	if ((!entry) || (size <= id)) {
347*c087a94bSLad Prabhakar 		struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
348*c087a94bSLad Prabhakar 
349*c087a94bSLad Prabhakar 		dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod));
350*c087a94bSLad Prabhakar 
351*c087a94bSLad Prabhakar 		/* use non-prohibited SRS number as error */
352*c087a94bSLad Prabhakar 		return 0x00; /* SSI00 */
353*c087a94bSLad Prabhakar 	}
354*c087a94bSLad Prabhakar 
355*c087a94bSLad Prabhakar 	return entry[id];
356*c087a94bSLad Prabhakar }
357*c087a94bSLad Prabhakar 
358*c087a94bSLad Prabhakar static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
359*c087a94bSLad Prabhakar 			       struct rsnd_mod *mod_from,
360*c087a94bSLad Prabhakar 			       struct rsnd_mod *mod_to)
361*c087a94bSLad Prabhakar {
362*c087a94bSLad Prabhakar 	return	(rsnd_dmapp_get_id(io, mod_from) << 24) +
363*c087a94bSLad Prabhakar 		(rsnd_dmapp_get_id(io, mod_to) << 16);
364*c087a94bSLad Prabhakar }
365*c087a94bSLad Prabhakar 
366*c087a94bSLad Prabhakar #define rsnd_dmapp_addr(dmac, dma, reg) \
367*c087a94bSLad Prabhakar 	(dmac->ppbase + 0x20 + reg + \
368*c087a94bSLad Prabhakar 	 (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
369*c087a94bSLad Prabhakar static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
370*c087a94bSLad Prabhakar {
371*c087a94bSLad Prabhakar 	struct rsnd_mod *mod = rsnd_mod_get(dma);
372*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
373*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
374*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
375*c087a94bSLad Prabhakar 
376*c087a94bSLad Prabhakar 	dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
377*c087a94bSLad Prabhakar 
378*c087a94bSLad Prabhakar 	iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg));
379*c087a94bSLad Prabhakar }
380*c087a94bSLad Prabhakar 
381*c087a94bSLad Prabhakar static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
382*c087a94bSLad Prabhakar {
383*c087a94bSLad Prabhakar 	struct rsnd_mod *mod = rsnd_mod_get(dma);
384*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
385*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
386*c087a94bSLad Prabhakar 
387*c087a94bSLad Prabhakar 	return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
388*c087a94bSLad Prabhakar }
389*c087a94bSLad Prabhakar 
390*c087a94bSLad Prabhakar static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg)
391*c087a94bSLad Prabhakar {
392*c087a94bSLad Prabhakar 	struct rsnd_mod *mod = rsnd_mod_get(dma);
393*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
394*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
395*c087a94bSLad Prabhakar 	void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg);
396*c087a94bSLad Prabhakar 	u32 val = ioread32(addr);
397*c087a94bSLad Prabhakar 
398*c087a94bSLad Prabhakar 	val &= ~mask;
399*c087a94bSLad Prabhakar 	val |= (data & mask);
400*c087a94bSLad Prabhakar 
401*c087a94bSLad Prabhakar 	iowrite32(val, addr);
402*c087a94bSLad Prabhakar }
403*c087a94bSLad Prabhakar 
404*c087a94bSLad Prabhakar static int rsnd_dmapp_stop(struct rsnd_mod *mod,
405*c087a94bSLad Prabhakar 			   struct rsnd_dai_stream *io,
406*c087a94bSLad Prabhakar 			   struct rsnd_priv *priv)
407*c087a94bSLad Prabhakar {
408*c087a94bSLad Prabhakar 	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
409*c087a94bSLad Prabhakar 	int i;
410*c087a94bSLad Prabhakar 
411*c087a94bSLad Prabhakar 	rsnd_dmapp_bset(dma, 0,  PDMACHCR_DE, PDMACHCR);
412*c087a94bSLad Prabhakar 
413*c087a94bSLad Prabhakar 	for (i = 0; i < 1024; i++) {
414*c087a94bSLad Prabhakar 		if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE))
415*c087a94bSLad Prabhakar 			return 0;
416*c087a94bSLad Prabhakar 		udelay(1);
417*c087a94bSLad Prabhakar 	}
418*c087a94bSLad Prabhakar 
419*c087a94bSLad Prabhakar 	return -EIO;
420*c087a94bSLad Prabhakar }
421*c087a94bSLad Prabhakar 
422*c087a94bSLad Prabhakar static int rsnd_dmapp_start(struct rsnd_mod *mod,
423*c087a94bSLad Prabhakar 			    struct rsnd_dai_stream *io,
424*c087a94bSLad Prabhakar 			    struct rsnd_priv *priv)
425*c087a94bSLad Prabhakar {
426*c087a94bSLad Prabhakar 	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
427*c087a94bSLad Prabhakar 	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
428*c087a94bSLad Prabhakar 
429*c087a94bSLad Prabhakar 	rsnd_dmapp_write(dma, dma->src_addr,	PDMASAR);
430*c087a94bSLad Prabhakar 	rsnd_dmapp_write(dma, dma->dst_addr,	PDMADAR);
431*c087a94bSLad Prabhakar 	rsnd_dmapp_write(dma, dmapp->chcr,	PDMACHCR);
432*c087a94bSLad Prabhakar 
433*c087a94bSLad Prabhakar 	return 0;
434*c087a94bSLad Prabhakar }
435*c087a94bSLad Prabhakar 
436*c087a94bSLad Prabhakar static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
437*c087a94bSLad Prabhakar 			     struct rsnd_dma *dma,
438*c087a94bSLad Prabhakar 			     struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
439*c087a94bSLad Prabhakar {
440*c087a94bSLad Prabhakar 	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
441*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
442*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
443*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
444*c087a94bSLad Prabhakar 
445*c087a94bSLad Prabhakar 	dmapp->dmapp_id = dmac->dmapp_num;
446*c087a94bSLad Prabhakar 	dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE;
447*c087a94bSLad Prabhakar 
448*c087a94bSLad Prabhakar 	dmac->dmapp_num++;
449*c087a94bSLad Prabhakar 
450*c087a94bSLad Prabhakar 	dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
451*c087a94bSLad Prabhakar 		dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
452*c087a94bSLad Prabhakar 
453*c087a94bSLad Prabhakar 	return 0;
454*c087a94bSLad Prabhakar }
455*c087a94bSLad Prabhakar 
456*c087a94bSLad Prabhakar #ifdef CONFIG_DEBUG_FS
457*c087a94bSLad Prabhakar static void rsnd_dmapp_debug_info(struct seq_file *m,
458*c087a94bSLad Prabhakar 				  struct rsnd_dai_stream *io,
459*c087a94bSLad Prabhakar 				  struct rsnd_mod *mod)
460*c087a94bSLad Prabhakar {
461*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
462*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
463*c087a94bSLad Prabhakar 	struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
464*c087a94bSLad Prabhakar 	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
465*c087a94bSLad Prabhakar 
466*c087a94bSLad Prabhakar 	rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase,
467*c087a94bSLad Prabhakar 			      0x20 + 0x10 * dmapp->dmapp_id, 0x10);
468*c087a94bSLad Prabhakar }
469*c087a94bSLad Prabhakar #define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info
470*c087a94bSLad Prabhakar #else
471*c087a94bSLad Prabhakar #define DEBUG_INFO
472*c087a94bSLad Prabhakar #endif
473*c087a94bSLad Prabhakar 
474*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_dmapp_ops = {
475*c087a94bSLad Prabhakar 	.name		= "audmac-pp",
476*c087a94bSLad Prabhakar 	.start		= rsnd_dmapp_start,
477*c087a94bSLad Prabhakar 	.stop		= rsnd_dmapp_stop,
478*c087a94bSLad Prabhakar 	.quit		= rsnd_dmapp_stop,
479*c087a94bSLad Prabhakar 	.get_status	= rsnd_mod_get_status,
480*c087a94bSLad Prabhakar 	DEBUG_INFO
481*c087a94bSLad Prabhakar };
482*c087a94bSLad Prabhakar 
483*c087a94bSLad Prabhakar /*
484*c087a94bSLad Prabhakar  *		Common DMAC Interface
485*c087a94bSLad Prabhakar  */
486*c087a94bSLad Prabhakar 
487*c087a94bSLad Prabhakar /*
488*c087a94bSLad Prabhakar  *	DMA read/write register offset
489*c087a94bSLad Prabhakar  *
490*c087a94bSLad Prabhakar  *	RSND_xxx_I_N	for Audio DMAC input
491*c087a94bSLad Prabhakar  *	RSND_xxx_O_N	for Audio DMAC output
492*c087a94bSLad Prabhakar  *	RSND_xxx_I_P	for Audio DMAC peri peri input
493*c087a94bSLad Prabhakar  *	RSND_xxx_O_P	for Audio DMAC peri peri output
494*c087a94bSLad Prabhakar  *
495*c087a94bSLad Prabhakar  *	ex) R-Car H2 case
496*c087a94bSLad Prabhakar  *	      mod        / DMAC in    / DMAC out   / DMAC PP in / DMAC pp out
497*c087a94bSLad Prabhakar  *	SSI : 0xec541000 / 0xec241008 / 0xec24100c
498*c087a94bSLad Prabhakar  *	SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
499*c087a94bSLad Prabhakar  *	SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
500*c087a94bSLad Prabhakar  *	CMD : 0xec500000 /            / 0xec008000                0xec308000
501*c087a94bSLad Prabhakar  */
502*c087a94bSLad Prabhakar #define RDMA_SSI_I_N(addr, i)	(addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
503*c087a94bSLad Prabhakar #define RDMA_SSI_O_N(addr, i)	(addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
504*c087a94bSLad Prabhakar 
505*c087a94bSLad Prabhakar #define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
506*c087a94bSLad Prabhakar #define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j)
507*c087a94bSLad Prabhakar 
508*c087a94bSLad Prabhakar #define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
509*c087a94bSLad Prabhakar #define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j)
510*c087a94bSLad Prabhakar 
511*c087a94bSLad Prabhakar #define RDMA_SRC_I_N(addr, i)	(addr ##_reg - 0x00500000 + (0x400 * i))
512*c087a94bSLad Prabhakar #define RDMA_SRC_O_N(addr, i)	(addr ##_reg - 0x004fc000 + (0x400 * i))
513*c087a94bSLad Prabhakar 
514*c087a94bSLad Prabhakar #define RDMA_SRC_I_P(addr, i)	(addr ##_reg - 0x00200000 + (0x400 * i))
515*c087a94bSLad Prabhakar #define RDMA_SRC_O_P(addr, i)	(addr ##_reg - 0x001fc000 + (0x400 * i))
516*c087a94bSLad Prabhakar 
517*c087a94bSLad Prabhakar #define RDMA_CMD_O_N(addr, i)	(addr ##_reg - 0x004f8000 + (0x400 * i))
518*c087a94bSLad Prabhakar #define RDMA_CMD_O_P(addr, i)	(addr ##_reg - 0x001f8000 + (0x400 * i))
519*c087a94bSLad Prabhakar 
520*c087a94bSLad Prabhakar static dma_addr_t
521*c087a94bSLad Prabhakar rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
522*c087a94bSLad Prabhakar 		   struct rsnd_mod *mod,
523*c087a94bSLad Prabhakar 		   int is_play, int is_from)
524*c087a94bSLad Prabhakar {
525*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
526*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
527*c087a94bSLad Prabhakar 	phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
528*c087a94bSLad Prabhakar 	phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
529*c087a94bSLad Prabhakar 	int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
530*c087a94bSLad Prabhakar 		     !!(rsnd_io_to_mod_ssiu(io) == mod);
531*c087a94bSLad Prabhakar 	int use_src = !!rsnd_io_to_mod_src(io);
532*c087a94bSLad Prabhakar 	int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
533*c087a94bSLad Prabhakar 		      !!rsnd_io_to_mod_mix(io) ||
534*c087a94bSLad Prabhakar 		      !!rsnd_io_to_mod_ctu(io);
535*c087a94bSLad Prabhakar 	int id = rsnd_mod_id(mod);
536*c087a94bSLad Prabhakar 	int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
537*c087a94bSLad Prabhakar 	struct dma_addr {
538*c087a94bSLad Prabhakar 		dma_addr_t out_addr;
539*c087a94bSLad Prabhakar 		dma_addr_t in_addr;
540*c087a94bSLad Prabhakar 	} dma_addrs[3][2][3] = {
541*c087a94bSLad Prabhakar 		/* SRC */
542*c087a94bSLad Prabhakar 		/* Capture */
543*c087a94bSLad Prabhakar 		{{{ 0,				0 },
544*c087a94bSLad Prabhakar 		  { RDMA_SRC_O_N(src, id),	RDMA_SRC_I_P(src, id) },
545*c087a94bSLad Prabhakar 		  { RDMA_CMD_O_N(src, id),	RDMA_SRC_I_P(src, id) } },
546*c087a94bSLad Prabhakar 		 /* Playback */
547*c087a94bSLad Prabhakar 		 {{ 0,				0, },
548*c087a94bSLad Prabhakar 		  { RDMA_SRC_O_P(src, id),	RDMA_SRC_I_N(src, id) },
549*c087a94bSLad Prabhakar 		  { RDMA_CMD_O_P(src, id),	RDMA_SRC_I_N(src, id) } }
550*c087a94bSLad Prabhakar 		},
551*c087a94bSLad Prabhakar 		/* SSI */
552*c087a94bSLad Prabhakar 		/* Capture */
553*c087a94bSLad Prabhakar 		{{{ RDMA_SSI_O_N(ssi, id),		0 },
554*c087a94bSLad Prabhakar 		  { RDMA_SSIU_O_P(ssi, id, busif),	0 },
555*c087a94bSLad Prabhakar 		  { RDMA_SSIU_O_P(ssi, id, busif),	0 } },
556*c087a94bSLad Prabhakar 		 /* Playback */
557*c087a94bSLad Prabhakar 		 {{ 0,			RDMA_SSI_I_N(ssi, id) },
558*c087a94bSLad Prabhakar 		  { 0,			RDMA_SSIU_I_P(ssi, id, busif) },
559*c087a94bSLad Prabhakar 		  { 0,			RDMA_SSIU_I_P(ssi, id, busif) } }
560*c087a94bSLad Prabhakar 		},
561*c087a94bSLad Prabhakar 		/* SSIU */
562*c087a94bSLad Prabhakar 		/* Capture */
563*c087a94bSLad Prabhakar 		{{{ RDMA_SSIU_O_N(ssi, id, busif),	0 },
564*c087a94bSLad Prabhakar 		  { RDMA_SSIU_O_P(ssi, id, busif),	0 },
565*c087a94bSLad Prabhakar 		  { RDMA_SSIU_O_P(ssi, id, busif),	0 } },
566*c087a94bSLad Prabhakar 		 /* Playback */
567*c087a94bSLad Prabhakar 		 {{ 0,			RDMA_SSIU_I_N(ssi, id, busif) },
568*c087a94bSLad Prabhakar 		  { 0,			RDMA_SSIU_I_P(ssi, id, busif) },
569*c087a94bSLad Prabhakar 		  { 0,			RDMA_SSIU_I_P(ssi, id, busif) } } },
570*c087a94bSLad Prabhakar 	};
571*c087a94bSLad Prabhakar 
572*c087a94bSLad Prabhakar 	/*
573*c087a94bSLad Prabhakar 	 * FIXME
574*c087a94bSLad Prabhakar 	 *
575*c087a94bSLad Prabhakar 	 * We can't support SSI9-4/5/6/7, because its address is
576*c087a94bSLad Prabhakar 	 * out of calculation rule
577*c087a94bSLad Prabhakar 	 */
578*c087a94bSLad Prabhakar 	if ((id == 9) && (busif >= 4))
579*c087a94bSLad Prabhakar 		dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
580*c087a94bSLad Prabhakar 			id, busif);
581*c087a94bSLad Prabhakar 
582*c087a94bSLad Prabhakar 	/* it shouldn't happen */
583*c087a94bSLad Prabhakar 	if (use_cmd && !use_src)
584*c087a94bSLad Prabhakar 		dev_err(dev, "DVC is selected without SRC\n");
585*c087a94bSLad Prabhakar 
586*c087a94bSLad Prabhakar 	/* use SSIU or SSI ? */
587*c087a94bSLad Prabhakar 	if (is_ssi && rsnd_ssi_use_busif(io))
588*c087a94bSLad Prabhakar 		is_ssi++;
589*c087a94bSLad Prabhakar 
590*c087a94bSLad Prabhakar 	return (is_from) ?
591*c087a94bSLad Prabhakar 		dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
592*c087a94bSLad Prabhakar 		dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
593*c087a94bSLad Prabhakar }
594*c087a94bSLad Prabhakar 
595*c087a94bSLad Prabhakar /*
596*c087a94bSLad Prabhakar  *	Gen4 DMA read/write register offset
597*c087a94bSLad Prabhakar  *
598*c087a94bSLad Prabhakar  *	ex) R-Car V4H case
599*c087a94bSLad Prabhakar  *		  mod		/ SYS-DMAC in	/ SYS-DMAC out
600*c087a94bSLad Prabhakar  *	SSI_SDMC: 0xec400000	/ 0xec400000	/ 0xec400000
601*c087a94bSLad Prabhakar  */
602*c087a94bSLad Prabhakar #define RDMA_SSI_SDMC(addr, i)	(addr + (0x8000 * i))
603*c087a94bSLad Prabhakar static dma_addr_t
604*c087a94bSLad Prabhakar rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
605*c087a94bSLad Prabhakar 		   int is_play, int is_from)
606*c087a94bSLad Prabhakar {
607*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
608*c087a94bSLad Prabhakar 	phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC);
609*c087a94bSLad Prabhakar 	int id = rsnd_mod_id(mod);
610*c087a94bSLad Prabhakar 	int busif = rsnd_mod_id_sub(mod);
611*c087a94bSLad Prabhakar 
612*c087a94bSLad Prabhakar 	/*
613*c087a94bSLad Prabhakar 	 * SSI0 only is supported
614*c087a94bSLad Prabhakar 	 */
615*c087a94bSLad Prabhakar 	if (id != 0) {
616*c087a94bSLad Prabhakar 		struct device *dev = rsnd_priv_to_dev(priv);
617*c087a94bSLad Prabhakar 
618*c087a94bSLad Prabhakar 		dev_err(dev, "This driver doesn't support non SSI0");
619*c087a94bSLad Prabhakar 		return -EINVAL;
620*c087a94bSLad Prabhakar 	}
621*c087a94bSLad Prabhakar 
622*c087a94bSLad Prabhakar 	return RDMA_SSI_SDMC(addr, busif);
623*c087a94bSLad Prabhakar }
624*c087a94bSLad Prabhakar 
625*c087a94bSLad Prabhakar static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
626*c087a94bSLad Prabhakar 				struct rsnd_mod *mod,
627*c087a94bSLad Prabhakar 				int is_play, int is_from)
628*c087a94bSLad Prabhakar {
629*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
630*c087a94bSLad Prabhakar 
631*c087a94bSLad Prabhakar 	if (!mod)
632*c087a94bSLad Prabhakar 		return 0;
633*c087a94bSLad Prabhakar 
634*c087a94bSLad Prabhakar 	/*
635*c087a94bSLad Prabhakar 	 * gen1 uses default DMA addr
636*c087a94bSLad Prabhakar 	 */
637*c087a94bSLad Prabhakar 	if (rsnd_is_gen1(priv))
638*c087a94bSLad Prabhakar 		return 0;
639*c087a94bSLad Prabhakar 	else if (rsnd_is_gen4(priv))
640*c087a94bSLad Prabhakar 		return rsnd_gen4_dma_addr(io, mod, is_play, is_from);
641*c087a94bSLad Prabhakar 	else
642*c087a94bSLad Prabhakar 		return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
643*c087a94bSLad Prabhakar }
644*c087a94bSLad Prabhakar 
645*c087a94bSLad Prabhakar #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
646*c087a94bSLad Prabhakar static void rsnd_dma_of_path(struct rsnd_mod *this,
647*c087a94bSLad Prabhakar 			     struct rsnd_dai_stream *io,
648*c087a94bSLad Prabhakar 			     int is_play,
649*c087a94bSLad Prabhakar 			     struct rsnd_mod **mod_from,
650*c087a94bSLad Prabhakar 			     struct rsnd_mod **mod_to)
651*c087a94bSLad Prabhakar {
652*c087a94bSLad Prabhakar 	struct rsnd_mod *ssi;
653*c087a94bSLad Prabhakar 	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
654*c087a94bSLad Prabhakar 	struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
655*c087a94bSLad Prabhakar 	struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
656*c087a94bSLad Prabhakar 	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
657*c087a94bSLad Prabhakar 	struct rsnd_mod *mod[MOD_MAX];
658*c087a94bSLad Prabhakar 	struct rsnd_mod *mod_start, *mod_end;
659*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(this);
660*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
661*c087a94bSLad Prabhakar 	int nr, i, idx;
662*c087a94bSLad Prabhakar 
663*c087a94bSLad Prabhakar 	/*
664*c087a94bSLad Prabhakar 	 * It should use "rcar_sound,ssiu" on DT.
665*c087a94bSLad Prabhakar 	 * But, we need to keep compatibility for old version.
666*c087a94bSLad Prabhakar 	 *
667*c087a94bSLad Prabhakar 	 * If it has "rcar_sound.ssiu", it will be used.
668*c087a94bSLad Prabhakar 	 * If not, "rcar_sound.ssi" will be used.
669*c087a94bSLad Prabhakar 	 * see
670*c087a94bSLad Prabhakar 	 *	rsnd_ssiu_dma_req()
671*c087a94bSLad Prabhakar 	 *	rsnd_ssi_dma_req()
672*c087a94bSLad Prabhakar 	 */
673*c087a94bSLad Prabhakar 	if (rsnd_ssiu_of_node(priv)) {
674*c087a94bSLad Prabhakar 		struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
675*c087a94bSLad Prabhakar 
676*c087a94bSLad Prabhakar 		/* use SSIU */
677*c087a94bSLad Prabhakar 		ssi = ssiu;
678*c087a94bSLad Prabhakar 		if (this == rsnd_io_to_mod_ssi(io))
679*c087a94bSLad Prabhakar 			this = ssiu;
680*c087a94bSLad Prabhakar 	} else {
681*c087a94bSLad Prabhakar 		/* keep compatible, use SSI */
682*c087a94bSLad Prabhakar 		ssi = rsnd_io_to_mod_ssi(io);
683*c087a94bSLad Prabhakar 	}
684*c087a94bSLad Prabhakar 
685*c087a94bSLad Prabhakar 	if (!ssi)
686*c087a94bSLad Prabhakar 		return;
687*c087a94bSLad Prabhakar 
688*c087a94bSLad Prabhakar 	nr = 0;
689*c087a94bSLad Prabhakar 	for (i = 0; i < MOD_MAX; i++) {
690*c087a94bSLad Prabhakar 		mod[i] = NULL;
691*c087a94bSLad Prabhakar 		nr += !!rsnd_io_to_mod(io, i);
692*c087a94bSLad Prabhakar 	}
693*c087a94bSLad Prabhakar 
694*c087a94bSLad Prabhakar 	/*
695*c087a94bSLad Prabhakar 	 * [S] -*-> [E]
696*c087a94bSLad Prabhakar 	 * [S] -*-> SRC -o-> [E]
697*c087a94bSLad Prabhakar 	 * [S] -*-> SRC -> DVC -o-> [E]
698*c087a94bSLad Prabhakar 	 * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
699*c087a94bSLad Prabhakar 	 *
700*c087a94bSLad Prabhakar 	 * playback	[S] = mem
701*c087a94bSLad Prabhakar 	 *		[E] = SSI
702*c087a94bSLad Prabhakar 	 *
703*c087a94bSLad Prabhakar 	 * capture	[S] = SSI
704*c087a94bSLad Prabhakar 	 *		[E] = mem
705*c087a94bSLad Prabhakar 	 *
706*c087a94bSLad Prabhakar 	 * -*->		Audio DMAC
707*c087a94bSLad Prabhakar 	 * -o->		Audio DMAC peri peri
708*c087a94bSLad Prabhakar 	 */
709*c087a94bSLad Prabhakar 	mod_start	= (is_play) ? NULL : ssi;
710*c087a94bSLad Prabhakar 	mod_end		= (is_play) ? ssi  : NULL;
711*c087a94bSLad Prabhakar 
712*c087a94bSLad Prabhakar 	idx = 0;
713*c087a94bSLad Prabhakar 	mod[idx++] = mod_start;
714*c087a94bSLad Prabhakar 	for (i = 1; i < nr; i++) {
715*c087a94bSLad Prabhakar 		if (src) {
716*c087a94bSLad Prabhakar 			mod[idx++] = src;
717*c087a94bSLad Prabhakar 			src = NULL;
718*c087a94bSLad Prabhakar 		} else if (ctu) {
719*c087a94bSLad Prabhakar 			mod[idx++] = ctu;
720*c087a94bSLad Prabhakar 			ctu = NULL;
721*c087a94bSLad Prabhakar 		} else if (mix) {
722*c087a94bSLad Prabhakar 			mod[idx++] = mix;
723*c087a94bSLad Prabhakar 			mix = NULL;
724*c087a94bSLad Prabhakar 		} else if (dvc) {
725*c087a94bSLad Prabhakar 			mod[idx++] = dvc;
726*c087a94bSLad Prabhakar 			dvc = NULL;
727*c087a94bSLad Prabhakar 		}
728*c087a94bSLad Prabhakar 	}
729*c087a94bSLad Prabhakar 	mod[idx] = mod_end;
730*c087a94bSLad Prabhakar 
731*c087a94bSLad Prabhakar 	/*
732*c087a94bSLad Prabhakar 	 *		| SSI | SRC |
733*c087a94bSLad Prabhakar 	 * -------------+-----+-----+
734*c087a94bSLad Prabhakar 	 *  is_play	|  o  |  *  |
735*c087a94bSLad Prabhakar 	 * !is_play	|  *  |  o  |
736*c087a94bSLad Prabhakar 	 */
737*c087a94bSLad Prabhakar 	if ((this == ssi) == (is_play)) {
738*c087a94bSLad Prabhakar 		*mod_from	= mod[idx - 1];
739*c087a94bSLad Prabhakar 		*mod_to		= mod[idx];
740*c087a94bSLad Prabhakar 	} else {
741*c087a94bSLad Prabhakar 		*mod_from	= mod[0];
742*c087a94bSLad Prabhakar 		*mod_to		= mod[1];
743*c087a94bSLad Prabhakar 	}
744*c087a94bSLad Prabhakar 
745*c087a94bSLad Prabhakar 	dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this));
746*c087a94bSLad Prabhakar 	for (i = 0; i <= idx; i++) {
747*c087a94bSLad Prabhakar 		dev_dbg(dev, "  %s%s\n",
748*c087a94bSLad Prabhakar 			rsnd_mod_name(mod[i] ? mod[i] : &mem),
749*c087a94bSLad Prabhakar 			(mod[i] == *mod_from) ? " from" :
750*c087a94bSLad Prabhakar 			(mod[i] == *mod_to)   ? " to" : "");
751*c087a94bSLad Prabhakar 	}
752*c087a94bSLad Prabhakar }
753*c087a94bSLad Prabhakar 
754*c087a94bSLad Prabhakar static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
755*c087a94bSLad Prabhakar 			  struct rsnd_mod **dma_mod)
756*c087a94bSLad Prabhakar {
757*c087a94bSLad Prabhakar 	struct rsnd_mod *mod_from = NULL;
758*c087a94bSLad Prabhakar 	struct rsnd_mod *mod_to = NULL;
759*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_io_to_priv(io);
760*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
761*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
762*c087a94bSLad Prabhakar 	struct rsnd_dma *dma;
763*c087a94bSLad Prabhakar 	struct rsnd_mod_ops *ops;
764*c087a94bSLad Prabhakar 	enum rsnd_mod_type type;
765*c087a94bSLad Prabhakar 	int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
766*c087a94bSLad Prabhakar 		      struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
767*c087a94bSLad Prabhakar 	int is_play = rsnd_io_is_play(io);
768*c087a94bSLad Prabhakar 	int ret, dma_id;
769*c087a94bSLad Prabhakar 
770*c087a94bSLad Prabhakar 	/*
771*c087a94bSLad Prabhakar 	 * DMA failed. try to PIO mode
772*c087a94bSLad Prabhakar 	 * see
773*c087a94bSLad Prabhakar 	 *	rsnd_ssi_fallback()
774*c087a94bSLad Prabhakar 	 *	rsnd_rdai_continuance_probe()
775*c087a94bSLad Prabhakar 	 */
776*c087a94bSLad Prabhakar 	if (!dmac)
777*c087a94bSLad Prabhakar 		return -EAGAIN;
778*c087a94bSLad Prabhakar 
779*c087a94bSLad Prabhakar 	rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
780*c087a94bSLad Prabhakar 
781*c087a94bSLad Prabhakar 	/* for Gen2 or later */
782*c087a94bSLad Prabhakar 	if (mod_from && mod_to) {
783*c087a94bSLad Prabhakar 		ops	= &rsnd_dmapp_ops;
784*c087a94bSLad Prabhakar 		attach	= rsnd_dmapp_attach;
785*c087a94bSLad Prabhakar 		dma_id	= dmac->dmapp_num;
786*c087a94bSLad Prabhakar 		type	= RSND_MOD_AUDMAPP;
787*c087a94bSLad Prabhakar 	} else {
788*c087a94bSLad Prabhakar 		ops	= &rsnd_dmaen_ops;
789*c087a94bSLad Prabhakar 		attach	= rsnd_dmaen_attach;
790*c087a94bSLad Prabhakar 		dma_id	= dmac->dmaen_num;
791*c087a94bSLad Prabhakar 		type	= RSND_MOD_AUDMA;
792*c087a94bSLad Prabhakar 	}
793*c087a94bSLad Prabhakar 
794*c087a94bSLad Prabhakar 	/* for Gen1, overwrite */
795*c087a94bSLad Prabhakar 	if (rsnd_is_gen1(priv)) {
796*c087a94bSLad Prabhakar 		ops	= &rsnd_dmaen_ops;
797*c087a94bSLad Prabhakar 		attach	= rsnd_dmaen_attach;
798*c087a94bSLad Prabhakar 		dma_id	= dmac->dmaen_num;
799*c087a94bSLad Prabhakar 		type	= RSND_MOD_AUDMA;
800*c087a94bSLad Prabhakar 	}
801*c087a94bSLad Prabhakar 
802*c087a94bSLad Prabhakar 	dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
803*c087a94bSLad Prabhakar 	if (!dma)
804*c087a94bSLad Prabhakar 		return -ENOMEM;
805*c087a94bSLad Prabhakar 
806*c087a94bSLad Prabhakar 	*dma_mod = rsnd_mod_get(dma);
807*c087a94bSLad Prabhakar 
808*c087a94bSLad Prabhakar 	ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
809*c087a94bSLad Prabhakar 			    type, dma_id);
810*c087a94bSLad Prabhakar 	if (ret < 0)
811*c087a94bSLad Prabhakar 		return ret;
812*c087a94bSLad Prabhakar 
813*c087a94bSLad Prabhakar 	dev_dbg(dev, "%s %s -> %s\n",
814*c087a94bSLad Prabhakar 		rsnd_mod_name(*dma_mod),
815*c087a94bSLad Prabhakar 		rsnd_mod_name(mod_from ? mod_from : &mem),
816*c087a94bSLad Prabhakar 		rsnd_mod_name(mod_to   ? mod_to   : &mem));
817*c087a94bSLad Prabhakar 
818*c087a94bSLad Prabhakar 	ret = attach(io, dma, mod_from, mod_to);
819*c087a94bSLad Prabhakar 	if (ret < 0)
820*c087a94bSLad Prabhakar 		return ret;
821*c087a94bSLad Prabhakar 
822*c087a94bSLad Prabhakar 	dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
823*c087a94bSLad Prabhakar 	dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
824*c087a94bSLad Prabhakar 	dma->mod_from = mod_from;
825*c087a94bSLad Prabhakar 	dma->mod_to   = mod_to;
826*c087a94bSLad Prabhakar 
827*c087a94bSLad Prabhakar 	return 0;
828*c087a94bSLad Prabhakar }
829*c087a94bSLad Prabhakar 
830*c087a94bSLad Prabhakar int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
831*c087a94bSLad Prabhakar 		    struct rsnd_mod **dma_mod)
832*c087a94bSLad Prabhakar {
833*c087a94bSLad Prabhakar 	if (!(*dma_mod)) {
834*c087a94bSLad Prabhakar 		int ret = rsnd_dma_alloc(io, mod, dma_mod);
835*c087a94bSLad Prabhakar 
836*c087a94bSLad Prabhakar 		if (ret < 0)
837*c087a94bSLad Prabhakar 			return ret;
838*c087a94bSLad Prabhakar 	}
839*c087a94bSLad Prabhakar 
840*c087a94bSLad Prabhakar 	return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type);
841*c087a94bSLad Prabhakar }
842*c087a94bSLad Prabhakar 
843*c087a94bSLad Prabhakar int rsnd_dma_probe(struct rsnd_priv *priv)
844*c087a94bSLad Prabhakar {
845*c087a94bSLad Prabhakar 	struct platform_device *pdev = rsnd_priv_to_pdev(priv);
846*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
847*c087a94bSLad Prabhakar 	struct rsnd_dma_ctrl *dmac;
848*c087a94bSLad Prabhakar 	struct resource *res;
849*c087a94bSLad Prabhakar 
850*c087a94bSLad Prabhakar 	/*
851*c087a94bSLad Prabhakar 	 * for Gen1
852*c087a94bSLad Prabhakar 	 */
853*c087a94bSLad Prabhakar 	if (rsnd_is_gen1(priv))
854*c087a94bSLad Prabhakar 		return 0;
855*c087a94bSLad Prabhakar 
856*c087a94bSLad Prabhakar 	/*
857*c087a94bSLad Prabhakar 	 * for Gen2 or later
858*c087a94bSLad Prabhakar 	 */
859*c087a94bSLad Prabhakar 	dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL);
860*c087a94bSLad Prabhakar 	if (!dmac) {
861*c087a94bSLad Prabhakar 		dev_err(dev, "dma allocate failed\n");
862*c087a94bSLad Prabhakar 		return 0; /* it will be PIO mode */
863*c087a94bSLad Prabhakar 	}
864*c087a94bSLad Prabhakar 
865*c087a94bSLad Prabhakar 	/* for Gen4 doesn't have DMA-pp */
866*c087a94bSLad Prabhakar 	if (rsnd_is_gen4(priv))
867*c087a94bSLad Prabhakar 		goto audmapp_end;
868*c087a94bSLad Prabhakar 
869*c087a94bSLad Prabhakar 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
870*c087a94bSLad Prabhakar 	if (!res) {
871*c087a94bSLad Prabhakar 		dev_err(dev, "lack of audmapp in DT\n");
872*c087a94bSLad Prabhakar 		return 0; /* it will be PIO mode */
873*c087a94bSLad Prabhakar 	}
874*c087a94bSLad Prabhakar 
875*c087a94bSLad Prabhakar 	dmac->dmapp_num = 0;
876*c087a94bSLad Prabhakar 	dmac->ppres  = res->start;
877*c087a94bSLad Prabhakar 	dmac->ppbase = devm_ioremap_resource(dev, res);
878*c087a94bSLad Prabhakar 	if (IS_ERR(dmac->ppbase))
879*c087a94bSLad Prabhakar 		return PTR_ERR(dmac->ppbase);
880*c087a94bSLad Prabhakar audmapp_end:
881*c087a94bSLad Prabhakar 	priv->dma = dmac;
882*c087a94bSLad Prabhakar 
883*c087a94bSLad Prabhakar 	/* dummy mem mod for debug */
884*c087a94bSLad Prabhakar 	return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
885*c087a94bSLad Prabhakar }
886