forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/sound/soc/sh/rcar/ssiu.c
....@@ -10,25 +10,62 @@
1010
1111 struct rsnd_ssiu {
1212 struct rsnd_mod mod;
13
+ u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
14
+ unsigned int usrcnt;
15
+ int id;
16
+ int id_sub;
1317 };
1418
19
+/* SSI_MODE */
20
+#define TDM_EXT (1 << 0)
21
+#define TDM_SPLIT (1 << 8)
22
+
1523 #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
24
+#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
1625 #define for_each_rsnd_ssiu(pos, priv, i) \
1726 for (i = 0; \
1827 (i < rsnd_ssiu_nr(priv)) && \
1928 ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \
2029 i++)
2130
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
+
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
+
2258 static int rsnd_ssiu_init(struct rsnd_mod *mod,
2359 struct rsnd_dai_stream *io,
2460 struct rsnd_priv *priv)
2561 {
2662 struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
27
- u32 multi_ssi_slaves = rsnd_ssi_multi_slaves_runtime(io);
63
+ u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
2864 int use_busif = rsnd_ssi_use_busif(io);
2965 int id = rsnd_mod_id(mod);
30
- u32 mask1, val1;
31
- u32 mask2, val2;
66
+ int is_clk_master = rsnd_rdai_is_clk_master(rdai);
67
+ u32 val1, val2;
68
+ int i;
3269
3370 /* clear status */
3471 switch (id) {
....@@ -37,16 +74,12 @@
3774 case 2:
3875 case 3:
3976 case 4:
40
- rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4));
41
- rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4));
42
- rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4));
43
- rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4));
77
+ for (i = 0; i < 4; i++)
78
+ rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
4479 break;
4580 case 9:
46
- rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4);
47
- rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4);
48
- rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4);
49
- rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4);
81
+ for (i = 0; i < 4; i++)
82
+ rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4);
5083 break;
5184 }
5285
....@@ -56,71 +89,70 @@
5689 rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
5790
5891 /*
59
- * SSI_MODE1
92
+ * SSI_MODE1 / SSI_MODE2
93
+ *
94
+ * FIXME
95
+ * sharing/multi with SSI0 are mainly supported
6096 */
61
- mask1 = (1 << 4) | (1 << 20); /* mask sync bit */
62
- mask2 = (1 << 4); /* mask sync bit */
63
- val1 = val2 = 0;
64
- if (id == 8) {
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) {
65104 /*
66
- * SSI8 pin is sharing with SSI7, nothing to do.
105
+ * Multi SSI
106
+ *
107
+ * set synchronized bit here
67108 */
68
- } else if (rsnd_ssi_is_pin_sharing(io)) {
69
- int shift = -1;
70109
71
- switch (id) {
72
- case 1:
73
- shift = 0;
74
- break;
75
- case 2:
76
- shift = 2;
77
- break;
78
- case 4:
79
- shift = 16;
80
- break;
81
- default:
82
- return -EINVAL;
83
- }
84
-
85
- mask1 |= 0x3 << shift;
86
- val1 = rsnd_rdai_is_clk_master(rdai) ?
87
- 0x2 << shift : 0x1 << shift;
88
-
89
- } else if (multi_ssi_slaves) {
90
-
91
- mask2 |= 0x00000007;
92
- mask1 |= 0x0000000f;
93
-
94
- switch (multi_ssi_slaves) {
95
- case 0x0206: /* SSI0/1/2/9 */
96
- val2 = (1 << 4) | /* SSI0129 sync */
97
- (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1);
98
- /* fall through */
99
- case 0x0006: /* SSI0/1/2 */
100
- val1 = rsnd_rdai_is_clk_master(rdai) ?
101
- 0xa : 0x5;
102
-
103
- if (!val2) /* SSI012 sync */
104
- val1 |= (1 << 4);
105
- }
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);
106119 }
107120
108
- rsnd_mod_bset(mod, SSI_MODE1, mask1, val1);
109
- rsnd_mod_bset(mod, SSI_MODE2, mask2, val2);
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);
110139
111140 return 0;
112141 }
113142
114143 static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
115
- .name = SSIU_NAME,
116
- .init = rsnd_ssiu_init,
144
+ .name = SSIU_NAME,
145
+ .init = rsnd_ssiu_init,
146
+ .get_status = rsnd_ssiu_get_status,
117147 };
118148
119149 static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
120150 struct rsnd_dai_stream *io,
121151 struct rsnd_priv *priv)
122152 {
123
- int hdmi = rsnd_ssi_hdmi_port(io);
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);
124156 int ret;
125157 u32 mode = 0;
126158
....@@ -128,30 +160,47 @@
128160 if (ret < 0)
129161 return ret;
130162
131
- if (rsnd_runtime_is_ssi_tdm(io)) {
132
- /*
133
- * TDM Extend Mode
134
- * see
135
- * rsnd_ssi_config_init()
136
- */
137
- mode = 0x1;
138
- }
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;
139174
140175 rsnd_mod_write(mod, SSI_MODE, mode);
141176
142177 if (rsnd_ssi_use_busif(io)) {
143
- rsnd_mod_write(mod, SSI_BUSIF_ADINR,
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,
144193 rsnd_get_adinr_bit(mod, io) |
145194 (rsnd_io_is_play(io) ?
146195 rsnd_runtime_channel_after_ctu(io) :
147196 rsnd_runtime_channel_original(io)));
148
- rsnd_mod_write(mod, SSI_BUSIF_MODE,
197
+ rsnd_mod_write(mod, mode_reg,
149198 rsnd_get_busif_shift(io, mod) | 1);
150
- rsnd_mod_write(mod, SSI_BUSIF_DALIGN,
199
+ rsnd_mod_write(mod, dalign_reg,
151200 rsnd_get_dalign(mod, io));
152201 }
153202
154
- if (hdmi) {
203
+ if (has_hdmi0 || has_hdmi1) {
155204 enum rsnd_mod_type rsnd_ssi_array[] = {
156205 RSND_MOD_SSIM1,
157206 RSND_MOD_SSIM2,
....@@ -177,14 +226,10 @@
177226 rsnd_mod_id(pos) << shift;
178227 }
179228
180
- switch (hdmi) {
181
- case RSND_SSI_HDMI_PORT0:
229
+ if (has_hdmi0)
182230 rsnd_mod_write(mod, HDMI0_SEL, val);
183
- break;
184
- case RSND_SSI_HDMI_PORT1:
231
+ if (has_hdmi1)
185232 rsnd_mod_write(mod, HDMI1_SEL, val);
186
- break;
187
- }
188233 }
189234
190235 return 0;
....@@ -194,12 +239,14 @@
194239 struct rsnd_dai_stream *io,
195240 struct rsnd_priv *priv)
196241 {
242
+ int busif = rsnd_mod_id_sub(mod);
243
+
197244 if (!rsnd_ssi_use_busif(io))
198245 return 0;
199246
200
- rsnd_mod_write(mod, SSI_CTRL, 0x1);
247
+ rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
201248
202
- if (rsnd_ssi_multi_slaves_runtime(io))
249
+ if (rsnd_ssi_multi_secondaries_runtime(io))
203250 rsnd_mod_write(mod, SSI_CONTROL, 0x1);
204251
205252 return 0;
....@@ -209,22 +256,70 @@
209256 struct rsnd_dai_stream *io,
210257 struct rsnd_priv *priv)
211258 {
259
+ struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
260
+ int busif = rsnd_mod_id_sub(mod);
261
+
212262 if (!rsnd_ssi_use_busif(io))
213263 return 0;
214264
215
- rsnd_mod_write(mod, SSI_CTRL, 0);
265
+ rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
216266
217
- if (rsnd_ssi_multi_slaves_runtime(io))
267
+ if (--ssiu->usrcnt)
268
+ return 0;
269
+
270
+ if (rsnd_ssi_multi_secondaries_runtime(io))
218271 rsnd_mod_write(mod, SSI_CONTROL, 0);
219272
220273 return 0;
221274 }
222275
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
+
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
+
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
+
223316 static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
224
- .name = SSIU_NAME,
225
- .init = rsnd_ssiu_init_gen2,
226
- .start = rsnd_ssiu_start_gen2,
227
- .stop = rsnd_ssiu_stop_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,
228323 };
229324
230325 static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
....@@ -235,26 +330,85 @@
235330 return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
236331 }
237332
238
-int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
239
- struct rsnd_mod *ssi_mod)
333
+static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
334
+ struct rsnd_dai_stream *io)
240335 {
241
- struct rsnd_priv *priv = rsnd_io_to_priv(io);
242
- struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod));
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;
243340
244
- rsnd_mod_confirm_ssi(ssi_mod);
341
+ if (!ssi_mod)
342
+ return;
245343
246
- return rsnd_dai_connect(mod, io, mod->type);
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
+
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);
247388 }
248389
249390 int rsnd_ssiu_probe(struct rsnd_priv *priv)
250391 {
251392 struct device *dev = rsnd_priv_to_dev(priv);
393
+ struct device_node *node;
252394 struct rsnd_ssiu *ssiu;
253395 struct rsnd_mod_ops *ops;
396
+ const int *list = NULL;
254397 int i, nr, ret;
255398
256
- /* same number to SSI */
257
- nr = priv->ssi_nr;
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
+
258412 ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
259413 if (!ssiu)
260414 return -ENOMEM;
....@@ -267,10 +421,46 @@
267421 else
268422 ops = &rsnd_ssiu_ops_gen2;
269423
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
+
270443 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
+
271462 ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
272
- ops, NULL, rsnd_mod_get_status,
273
- RSND_MOD_SSIU, i);
463
+ ops, NULL, RSND_MOD_SSIU, i);
274464 if (ret)
275465 return ret;
276466 }