1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Renesas R-Car SSIU support
4 //
5 // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6
7 #include "rsnd.h"
8
9 #define SSIU_NAME "ssiu"
10
11 struct rsnd_ssiu {
12 struct rsnd_mod mod;
13 u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
14 unsigned int usrcnt;
15 int id;
16 int id_sub;
17 };
18
19 /* SSI_MODE */
20 #define TDM_EXT (1 << 0)
21 #define TDM_SPLIT (1 << 8)
22
23 #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
24 #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
25 #define for_each_rsnd_ssiu(pos, priv, i) \
26 for (i = 0; \
27 (i < rsnd_ssiu_nr(priv)) && \
28 ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
29 i++)
30
31 /*
32 * SSI Gen2 Gen3
33 * 0 BUSIF0-3 BUSIF0-7
34 * 1 BUSIF0-3 BUSIF0-7
35 * 2 BUSIF0-3 BUSIF0-7
36 * 3 BUSIF0 BUSIF0-7
37 * 4 BUSIF0 BUSIF0-7
38 * 5 BUSIF0 BUSIF0
39 * 6 BUSIF0 BUSIF0
40 * 7 BUSIF0 BUSIF0
41 * 8 BUSIF0 BUSIF0
42 * 9 BUSIF0-3 BUSIF0-7
43 * total 22 52
44 */
45 static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 };
46 static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
47
rsnd_ssiu_get_status(struct rsnd_mod * mod,struct rsnd_dai_stream * io,enum rsnd_mod_type type)48 static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
49 struct rsnd_dai_stream *io,
50 enum rsnd_mod_type type)
51 {
52 struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
53 int busif = rsnd_mod_id_sub(mod);
54
55 return &ssiu->busif_status[busif];
56 }
57
rsnd_ssiu_init(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)58 static int rsnd_ssiu_init(struct rsnd_mod *mod,
59 struct rsnd_dai_stream *io,
60 struct rsnd_priv *priv)
61 {
62 struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
63 u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
64 int use_busif = rsnd_ssi_use_busif(io);
65 int id = rsnd_mod_id(mod);
66 int is_clk_master = rsnd_rdai_is_clk_master(rdai);
67 u32 val1, val2;
68 int i;
69
70 /* clear status */
71 switch (id) {
72 case 0:
73 case 1:
74 case 2:
75 case 3:
76 case 4:
77 for (i = 0; i < 4; i++)
78 rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
79 break;
80 case 9:
81 for (i = 0; i < 4; i++)
82 rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4);
83 break;
84 }
85
86 /*
87 * SSI_MODE0
88 */
89 rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
90
91 /*
92 * SSI_MODE1 / SSI_MODE2
93 *
94 * FIXME
95 * sharing/multi with SSI0 are mainly supported
96 */
97 val1 = rsnd_mod_read(mod, SSI_MODE1);
98 val2 = rsnd_mod_read(mod, SSI_MODE2);
99 if (rsnd_ssi_is_pin_sharing(io)) {
100
101 ssis |= (1 << id);
102
103 } else if (ssis) {
104 /*
105 * Multi SSI
106 *
107 * set synchronized bit here
108 */
109
110 /* SSI4 is synchronized with SSI3 */
111 if (ssis & (1 << 4))
112 val1 |= (1 << 20);
113 /* SSI012 are synchronized */
114 if (ssis == 0x0006)
115 val1 |= (1 << 4);
116 /* SSI0129 are synchronized */
117 if (ssis == 0x0206)
118 val2 |= (1 << 4);
119 }
120
121 /* SSI1 is sharing pin with SSI0 */
122 if (ssis & (1 << 1))
123 val1 |= is_clk_master ? 0x2 : 0x1;
124
125 /* SSI2 is sharing pin with SSI0 */
126 if (ssis & (1 << 2))
127 val1 |= is_clk_master ? 0x2 << 2 :
128 0x1 << 2;
129 /* SSI4 is sharing pin with SSI3 */
130 if (ssis & (1 << 4))
131 val1 |= is_clk_master ? 0x2 << 16 :
132 0x1 << 16;
133 /* SSI9 is sharing pin with SSI0 */
134 if (ssis & (1 << 9))
135 val2 |= is_clk_master ? 0x2 : 0x1;
136
137 rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
138 rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
139
140 return 0;
141 }
142
143 static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
144 .name = SSIU_NAME,
145 .init = rsnd_ssiu_init,
146 .get_status = rsnd_ssiu_get_status,
147 };
148
rsnd_ssiu_init_gen2(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)149 static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
150 struct rsnd_dai_stream *io,
151 struct rsnd_priv *priv)
152 {
153 struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
154 u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
155 u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
156 int ret;
157 u32 mode = 0;
158
159 ret = rsnd_ssiu_init(mod, io, priv);
160 if (ret < 0)
161 return ret;
162
163 ssiu->usrcnt++;
164
165 /*
166 * TDM Extend/Split Mode
167 * see
168 * rsnd_ssi_config_init()
169 */
170 if (rsnd_runtime_is_tdm(io))
171 mode = TDM_EXT;
172 else if (rsnd_runtime_is_tdm_split(io))
173 mode = TDM_SPLIT;
174
175 rsnd_mod_write(mod, SSI_MODE, mode);
176
177 if (rsnd_ssi_use_busif(io)) {
178 int id = rsnd_mod_id(mod);
179 int busif = rsnd_mod_id_sub(mod);
180 enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
181
182 if ((id == 9) && (busif >= 4)) {
183 adinr_reg = SSI9_BUSIF_ADINR(busif);
184 mode_reg = SSI9_BUSIF_MODE(busif);
185 dalign_reg = SSI9_BUSIF_DALIGN(busif);
186 } else {
187 adinr_reg = SSI_BUSIF_ADINR(busif);
188 mode_reg = SSI_BUSIF_MODE(busif);
189 dalign_reg = SSI_BUSIF_DALIGN(busif);
190 }
191
192 rsnd_mod_write(mod, adinr_reg,
193 rsnd_get_adinr_bit(mod, io) |
194 (rsnd_io_is_play(io) ?
195 rsnd_runtime_channel_after_ctu(io) :
196 rsnd_runtime_channel_original(io)));
197 rsnd_mod_write(mod, mode_reg,
198 rsnd_get_busif_shift(io, mod) | 1);
199 rsnd_mod_write(mod, dalign_reg,
200 rsnd_get_dalign(mod, io));
201 }
202
203 if (has_hdmi0 || has_hdmi1) {
204 enum rsnd_mod_type rsnd_ssi_array[] = {
205 RSND_MOD_SSIM1,
206 RSND_MOD_SSIM2,
207 RSND_MOD_SSIM3,
208 };
209 struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
210 struct rsnd_mod *pos;
211 u32 val;
212 int i, shift;
213
214 i = rsnd_mod_id(ssi_mod);
215
216 /* output all same SSI as default */
217 val = i << 16 |
218 i << 20 |
219 i << 24 |
220 i << 28 |
221 i;
222
223 for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
224 shift = (i * 4) + 20;
225 val = (val & ~(0xF << shift)) |
226 rsnd_mod_id(pos) << shift;
227 }
228
229 if (has_hdmi0)
230 rsnd_mod_write(mod, HDMI0_SEL, val);
231 if (has_hdmi1)
232 rsnd_mod_write(mod, HDMI1_SEL, val);
233 }
234
235 return 0;
236 }
237
rsnd_ssiu_start_gen2(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)238 static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
239 struct rsnd_dai_stream *io,
240 struct rsnd_priv *priv)
241 {
242 int busif = rsnd_mod_id_sub(mod);
243
244 if (!rsnd_ssi_use_busif(io))
245 return 0;
246
247 rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
248
249 if (rsnd_ssi_multi_secondaries_runtime(io))
250 rsnd_mod_write(mod, SSI_CONTROL, 0x1);
251
252 return 0;
253 }
254
rsnd_ssiu_stop_gen2(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)255 static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
256 struct rsnd_dai_stream *io,
257 struct rsnd_priv *priv)
258 {
259 struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
260 int busif = rsnd_mod_id_sub(mod);
261
262 if (!rsnd_ssi_use_busif(io))
263 return 0;
264
265 rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
266
267 if (--ssiu->usrcnt)
268 return 0;
269
270 if (rsnd_ssi_multi_secondaries_runtime(io))
271 rsnd_mod_write(mod, SSI_CONTROL, 0);
272
273 return 0;
274 }
275
rsnd_ssiu_id(struct rsnd_mod * mod)276 static int rsnd_ssiu_id(struct rsnd_mod *mod)
277 {
278 struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
279
280 /* see rsnd_ssiu_probe() */
281 return ssiu->id;
282 }
283
rsnd_ssiu_id_sub(struct rsnd_mod * mod)284 static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
285 {
286 struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
287
288 /* see rsnd_ssiu_probe() */
289 return ssiu->id_sub;
290 }
291
rsnd_ssiu_dma_req(struct rsnd_dai_stream * io,struct rsnd_mod * mod)292 static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
293 struct rsnd_mod *mod)
294 {
295 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
296 int is_play = rsnd_io_is_play(io);
297 char *name;
298
299 /*
300 * It should use "rcar_sound,ssiu" on DT.
301 * But, we need to keep compatibility for old version.
302 *
303 * If it has "rcar_sound.ssiu", it will be used.
304 * If not, "rcar_sound.ssi" will be used.
305 * see
306 * rsnd_ssi_dma_req()
307 * rsnd_dma_of_path()
308 */
309
310 name = is_play ? "rx" : "tx";
311
312 return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
313 mod, name);
314 }
315
316 static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
317 .name = SSIU_NAME,
318 .dma_req = rsnd_ssiu_dma_req,
319 .init = rsnd_ssiu_init_gen2,
320 .start = rsnd_ssiu_start_gen2,
321 .stop = rsnd_ssiu_stop_gen2,
322 .get_status = rsnd_ssiu_get_status,
323 };
324
rsnd_ssiu_mod_get(struct rsnd_priv * priv,int id)325 static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
326 {
327 if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
328 id = 0;
329
330 return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
331 }
332
rsnd_parse_connect_ssiu_compatible(struct rsnd_priv * priv,struct rsnd_dai_stream * io)333 static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
334 struct rsnd_dai_stream *io)
335 {
336 struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
337 struct rsnd_mod *mod;
338 struct rsnd_ssiu *ssiu;
339 int i;
340
341 if (!ssi_mod)
342 return;
343
344 /* select BUSIF0 */
345 for_each_rsnd_ssiu(ssiu, priv, i) {
346 mod = rsnd_mod_get(ssiu);
347
348 if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
349 (rsnd_mod_id_sub(mod) == 0)) {
350 rsnd_dai_connect(mod, io, mod->type);
351 return;
352 }
353 }
354 }
355
rsnd_parse_connect_ssiu(struct rsnd_dai * rdai,struct device_node * playback,struct device_node * capture)356 void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
357 struct device_node *playback,
358 struct device_node *capture)
359 {
360 struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
361 struct device_node *node = rsnd_ssiu_of_node(priv);
362 struct device_node *np;
363 struct rsnd_mod *mod;
364 struct rsnd_dai_stream *io_p = &rdai->playback;
365 struct rsnd_dai_stream *io_c = &rdai->capture;
366 int i;
367
368 /* use rcar_sound,ssiu if exist */
369 if (node) {
370 i = 0;
371 for_each_child_of_node(node, np) {
372 mod = rsnd_ssiu_mod_get(priv, i);
373 if (np == playback)
374 rsnd_dai_connect(mod, io_p, mod->type);
375 if (np == capture)
376 rsnd_dai_connect(mod, io_c, mod->type);
377 i++;
378 }
379
380 of_node_put(node);
381 }
382
383 /* Keep DT compatibility */
384 if (!rsnd_io_to_mod_ssiu(io_p))
385 rsnd_parse_connect_ssiu_compatible(priv, io_p);
386 if (!rsnd_io_to_mod_ssiu(io_c))
387 rsnd_parse_connect_ssiu_compatible(priv, io_c);
388 }
389
rsnd_ssiu_probe(struct rsnd_priv * priv)390 int rsnd_ssiu_probe(struct rsnd_priv *priv)
391 {
392 struct device *dev = rsnd_priv_to_dev(priv);
393 struct device_node *node;
394 struct rsnd_ssiu *ssiu;
395 struct rsnd_mod_ops *ops;
396 const int *list = NULL;
397 int i, nr, ret;
398
399 /*
400 * Keep DT compatibility.
401 * if it has "rcar_sound,ssiu", use it.
402 * if not, use "rcar_sound,ssi"
403 * see
404 * rsnd_ssiu_bufsif_to_id()
405 */
406 node = rsnd_ssiu_of_node(priv);
407 if (node)
408 nr = of_get_child_count(node);
409 else
410 nr = priv->ssi_nr;
411
412 ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
413 if (!ssiu)
414 return -ENOMEM;
415
416 priv->ssiu = ssiu;
417 priv->ssiu_nr = nr;
418
419 if (rsnd_is_gen1(priv))
420 ops = &rsnd_ssiu_ops_gen1;
421 else
422 ops = &rsnd_ssiu_ops_gen2;
423
424 /* Keep compatibility */
425 nr = 0;
426 if ((node) &&
427 (ops == &rsnd_ssiu_ops_gen2)) {
428 ops->id = rsnd_ssiu_id;
429 ops->id_sub = rsnd_ssiu_id_sub;
430
431 if (rsnd_is_gen2(priv)) {
432 list = gen2_id;
433 nr = ARRAY_SIZE(gen2_id);
434 } else if (rsnd_is_gen3(priv)) {
435 list = gen3_id;
436 nr = ARRAY_SIZE(gen3_id);
437 } else {
438 dev_err(dev, "unknown SSIU\n");
439 return -ENODEV;
440 }
441 }
442
443 for_each_rsnd_ssiu(ssiu, priv, i) {
444 if (node) {
445 int j;
446
447 /*
448 * see
449 * rsnd_ssiu_get_id()
450 * rsnd_ssiu_get_id_sub()
451 */
452 for (j = 0; j < nr; j++) {
453 if (list[j] > i)
454 break;
455 ssiu->id = j;
456 ssiu->id_sub = i - list[ssiu->id];
457 }
458 } else {
459 ssiu->id = i;
460 }
461
462 ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
463 ops, NULL, RSND_MOD_SSIU, i);
464 if (ret)
465 return ret;
466 }
467
468 return 0;
469 }
470
rsnd_ssiu_remove(struct rsnd_priv * priv)471 void rsnd_ssiu_remove(struct rsnd_priv *priv)
472 {
473 struct rsnd_ssiu *ssiu;
474 int i;
475
476 for_each_rsnd_ssiu(ssiu, priv, i) {
477 rsnd_mod_quit(rsnd_mod_get(ssiu));
478 }
479 }
480