1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 // Keyon Jie <yang.jie@linux.intel.com>
7
8 #include <sof/audio/component.h>
9 #include <sof/drivers/ssp.h>
10 #include <sof/lib/alloc.h>
11 #include <sof/lib/dai.h>
12 #include <sof/lib/dma.h>
13 #include <sof/lib/shim.h>
14 #include <sof/spinlock.h>
15 #include <sof/trace/trace.h>
16 #include <ipc/dai.h>
17 #include <ipc/dai-intel.h>
18 #include <ipc/stream.h>
19 #include <ipc/topology.h>
20 #include <user/trace.h>
21 #include <errno.h>
22 #include <stdbool.h>
23 #include <stdint.h>
24
25 /* save SSP context prior to entering D3 */
ssp_context_store(struct dai * dai)26 static int ssp_context_store(struct dai *dai)
27 {
28 struct ssp_pdata *ssp = dai_get_drvdata(dai);
29
30 ssp->sscr0 = ssp_read(dai, SSCR0);
31 ssp->sscr1 = ssp_read(dai, SSCR1);
32
33 /* FIXME: need to store sscr2,3,4,5 */
34 ssp->psp = ssp_read(dai, SSPSP);
35
36 return 0;
37 }
38
39 /* restore SSP context after leaving D3 */
ssp_context_restore(struct dai * dai)40 static int ssp_context_restore(struct dai *dai)
41 {
42 struct ssp_pdata *ssp = dai_get_drvdata(dai);
43
44 ssp_write(dai, SSCR0, ssp->sscr0);
45 ssp_write(dai, SSCR1, ssp->sscr1);
46 /* FIXME: need to restore sscr2,3,4,5 */
47 ssp_write(dai, SSPSP, ssp->psp);
48
49 return 0;
50 }
51
52 /* Digital Audio interface formatting */
ssp_set_config(struct dai * dai,struct ipc_config_dai * common_config,void * spec_config)53 static int ssp_set_config(struct dai *dai, struct ipc_config_dai *common_config,
54 void *spec_config)
55 {
56 struct sof_ipc_dai_config *config = spec_config;
57 struct ssp_pdata *ssp = dai_get_drvdata(dai);
58 uint32_t sscr0;
59 uint32_t sscr1;
60 uint32_t sscr2;
61 uint32_t sspsp;
62 uint32_t sspsp2;
63 uint32_t mdiv;
64 uint32_t bdiv;
65 uint32_t data_size;
66 uint32_t start_delay;
67 uint32_t frame_end_padding;
68 uint32_t slot_end_padding;
69 uint32_t frame_len = 0;
70 uint32_t bdiv_min;
71 uint32_t format;
72 bool inverted_frame = false;
73 int ret = 0;
74
75 spin_lock(&dai->lock);
76
77 /* is playback/capture already running */
78 if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE ||
79 ssp->state[DAI_DIR_CAPTURE] == COMP_STATE_ACTIVE) {
80 dai_info(dai, "ssp_set_config(): playback/capture active. Ignore config");
81 goto out;
82 }
83
84 dai_info(dai, "ssp_set_config()");
85
86 /* disable clock */
87 shim_update_bits(SHIM_CLKCTL, SHIM_CLKCTL_EN_SSP(dai->index), 0);
88
89 /* enable MCLK */
90 shim_update_bits(SHIM_CLKCTL, SHIM_CLKCTL_SMOS(0x3),
91 SHIM_CLKCTL_SMOS(0x3));
92
93 /* reset SSP settings */
94 /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */
95 sscr0 = SSCR0_MOD | SSCR0_PSP;
96
97 /* sscr1 dynamic settings are TFT, RFT, SFRMDIR, SCLKDIR, SCFR */
98 sscr1 = SSCR1_TTE | SSCR1_TTELP;
99
100 /* enable Transmit underrun mode 1 */
101 sscr2 = SSCR2_TURM1;
102
103 /* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */
104 sspsp = 0x0;
105
106 /* sspsp2 no dynamic setting */
107 sspsp2 = 0x0;
108
109 ssp->config = *config;
110 ssp->params = config->ssp;
111
112 switch (config->format & SOF_DAI_FMT_CLOCK_PROVIDER_MASK) {
113 case SOF_DAI_FMT_CBP_CFP:
114 sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
115 #ifdef ENABLE_SSRCR1_SCFR
116 sscr1 |= SSCR1_SCFR;
117 #endif
118 break;
119 case SOF_DAI_FMT_CBC_CFC:
120 break;
121 case SOF_DAI_FMT_CBP_CFC:
122 sscr1 |= SSCR1_SCLKDIR;
123 #ifdef ENABLE_SSRCR1_SCFR
124 sscr1 |= SSCR1_SCFR;
125 #endif
126 break;
127 case SOF_DAI_FMT_CBC_CFP:
128 sscr1 |= SSCR1_SFRMDIR;
129 break;
130 default:
131 dai_err(dai, "ssp_set_config(): format & PROVIDER_MASK EINVAL");
132 ret = -EINVAL;
133 goto out;
134 }
135
136 /* clock signal polarity */
137 switch (config->format & SOF_DAI_FMT_INV_MASK) {
138 case SOF_DAI_FMT_NB_NF:
139 break;
140 case SOF_DAI_FMT_NB_IF:
141 inverted_frame = true; /* handled later with format */
142 break;
143 case SOF_DAI_FMT_IB_IF:
144 sspsp |= SSPSP_SCMODE(2);
145 inverted_frame = true; /* handled later with format */
146 break;
147 case SOF_DAI_FMT_IB_NF:
148 sspsp |= SSPSP_SCMODE(2);
149 break;
150 default:
151 dai_err(dai, "ssp_set_config(): format & INV_MASK EINVAL");
152 ret = -EINVAL;
153 goto out;
154 }
155
156 /* Additional hardware settings */
157
158 /* Receiver Time-out Interrupt Disabled/Enabled */
159 sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_TINTE) ?
160 SSCR1_TINTE : 0;
161
162 /* Peripheral Trailing Byte Interrupts Disable/Enable */
163 sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PINTE) ?
164 SSCR1_PINTE : 0;
165
166 /* Enable/disable internal loopback. Output of transmit serial
167 * shifter connected to input of receive serial shifter, internally.
168 */
169 sscr1 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_LBM) ?
170 SSCR1_LBM : 0;
171
172 /* Transmit data are driven at the same/opposite clock edge specified
173 * in SSPSP.SCMODE[1:0]
174 */
175 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_SMTATF) ?
176 SSCR2_SMTATF : 0;
177
178 /* Receive data are sampled at the same/opposite clock edge specified
179 * in SSPSP.SCMODE[1:0]
180 */
181 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_MMRATF) ?
182 SSCR2_MMRATF : 0;
183
184 /* Enable/disable the fix for PSP consumer mode TXD wait for frame
185 * de-assertion before starting the second channel
186 */
187 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD) ?
188 SSCR2_PSPSTWFDFD : 0;
189
190 /* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
191 * frame end padding capability
192 */
193 sscr2 |= (ssp->params.quirks & SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD) ?
194 SSCR2_PSPSRWFDFD : 0;
195
196 /* BCLK is generated from MCLK - must be divisable */
197 if (config->ssp.mclk_rate % config->ssp.bclk_rate) {
198 dai_err(dai, "ssp_set_config(): MCLK is not divisable");
199 ret = -EINVAL;
200 goto out;
201 }
202
203 /* divisor must be within SCR range */
204 mdiv = (config->ssp.mclk_rate / config->ssp.bclk_rate) - 1;
205 if (mdiv > (SSCR0_SCR_MASK >> 8)) {
206 dai_err(dai, "ssp_set_config(): divisor is not within SCR range");
207 ret = -EINVAL;
208 goto out;
209 }
210
211 /* set the SCR divisor */
212 sscr0 |= SSCR0_SCR(mdiv);
213
214 /* calc frame width based on BCLK and rate - must be divisable */
215 if (config->ssp.bclk_rate % config->ssp.fsync_rate) {
216 dai_err(dai, "ssp_set_config(): BLCK is not divisable");
217 ret = -EINVAL;
218 goto out;
219 }
220
221 /* must be enouch BCLKs for data */
222 bdiv = config->ssp.bclk_rate / config->ssp.fsync_rate;
223 if (bdiv < config->ssp.tdm_slot_width *
224 config->ssp.tdm_slots) {
225 dai_err(dai, "ssp_set_config(): not enough BCLKs");
226 ret = -EINVAL;
227 goto out;
228 }
229
230 /* tdm_slot_width must be <= 38 for SSP */
231 if (config->ssp.tdm_slot_width > 38) {
232 dai_err(dai, "ssp_set_config(): tdm_slot_width > 38");
233 ret = -EINVAL;
234 goto out;
235 }
236
237 bdiv_min = config->ssp.tdm_slots * config->ssp.sample_valid_bits;
238 if (bdiv < bdiv_min) {
239 dai_err(dai, "ssp_set_config(): bdiv < bdiv_min");
240 ret = -EINVAL;
241 goto out;
242 }
243
244 frame_end_padding = bdiv - bdiv_min;
245 if (frame_end_padding > SSPSP2_FEP_MASK) {
246 dai_err(dai, "ssp_set_config(): frame_end_padding > SSPSP2_FEP_MASK");
247 ret = -EINVAL;
248 goto out;
249 }
250
251 /* format */
252 format = config->format & SOF_DAI_FMT_FORMAT_MASK;
253 switch (format) {
254 case SOF_DAI_FMT_I2S:
255 case SOF_DAI_FMT_LEFT_J:
256
257 if (format == SOF_DAI_FMT_I2S) {
258 start_delay = 1;
259
260 /*
261 * handle frame polarity, I2S default is falling/active low,
262 * non-inverted(inverted_frame=0) -- active low(SFRMP=0),
263 * inverted(inverted_frame=1) -- rising/active high(SFRMP=1),
264 * so, we should set SFRMP to inverted_frame.
265 */
266 sspsp |= SSPSP_SFRMP(inverted_frame);
267 sspsp |= SSPSP_FSRT;
268
269 } else {
270 start_delay = 0;
271
272 /*
273 * handle frame polarity, LEFT_J default is rising/active high,
274 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
275 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
276 * so, we should set SFRMP to !inverted_frame.
277 */
278 sspsp |= SSPSP_SFRMP(!inverted_frame);
279 }
280
281 sscr0 |= SSCR0_FRDC(config->ssp.tdm_slots);
282
283 if (bdiv % 2) {
284 dai_err(dai, "ssp_set_config(): bdiv is not divisible by 2");
285 ret = -EINVAL;
286 goto out;
287 }
288
289 /* set asserted frame length to half frame length */
290 frame_len = bdiv / 2;
291
292 /*
293 * for I2S/LEFT_J, the padding has to happen at the end
294 * of each slot
295 */
296 if (frame_end_padding % 2) {
297 dai_err(dai, "ssp_set_config(): frame_end_padding is not divisible by 2");
298 ret = -EINVAL;
299 goto out;
300 }
301
302 slot_end_padding = frame_end_padding / 2;
303
304 if (slot_end_padding > 15) {
305 /* can't handle padding over 15 bits */
306 dai_err(dai, "ssp_set_config(): slot_end_padding over 15 bits");
307 ret = -EINVAL;
308 goto out;
309 }
310
311 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
312 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
313 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
314
315 break;
316 case SOF_DAI_FMT_DSP_A:
317
318 start_delay = 1;
319
320 sscr0 |= SSCR0_FRDC(config->ssp.tdm_slots);
321
322 /* set asserted frame length */
323 frame_len = 1;
324
325 /* handle frame polarity, DSP_A default is rising/active high */
326 sspsp |= SSPSP_SFRMP(!inverted_frame);
327 sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
328
329 break;
330 case SOF_DAI_FMT_DSP_B:
331
332 start_delay = 0;
333
334 sscr0 |= SSCR0_FRDC(config->ssp.tdm_slots);
335
336 /* set asserted frame length */
337 frame_len = 1;
338
339 /* handle frame polarity, DSP_B default is rising/active high */
340 sspsp |= SSPSP_SFRMP(!inverted_frame);
341 sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
342
343 break;
344 default:
345 dai_err(dai, "ssp_set_config(): invalid format");
346 ret = -EINVAL;
347 goto out;
348 }
349
350 if (start_delay)
351 sspsp |= SSPSP_FSRT;
352
353 sspsp |= SSPSP_SFRMWDTH(frame_len);
354
355 data_size = config->ssp.sample_valid_bits;
356
357 if (data_size > 16)
358 sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
359 else
360 sscr0 |= SSCR0_DSIZE(data_size);
361
362 sscr1 |= SSCR1_TFT(0x8) | SSCR1_RFT(0x8);
363
364 ssp_write(dai, SSCR0, sscr0);
365 ssp_write(dai, SSCR1, sscr1);
366 ssp_write(dai, SSCR2, sscr2);
367 ssp_write(dai, SSPSP, sspsp);
368 ssp_write(dai, SSTSA, SSTSA_SSTSA(config->ssp.tx_slots));
369 ssp_write(dai, SSRSA, SSRSA_SSRSA(config->ssp.rx_slots));
370 ssp_write(dai, SSPSP2, sspsp2);
371
372 ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE;
373 ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
374
375 /* enable clock */
376 shim_update_bits(SHIM_CLKCTL, SHIM_CLKCTL_EN_SSP(dai->index),
377 SHIM_CLKCTL_EN_SSP(dai->index));
378
379 /* enable free running clock */
380 ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
381 ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
382
383 dai_info(dai, "ssp_set_config(), done");
384
385 out:
386 spin_unlock(&dai->lock);
387
388 return ret;
389 }
390
391 /* get SSP hw params */
ssp_get_hw_params(struct dai * dai,struct sof_ipc_stream_params * params,int dir)392 static int ssp_get_hw_params(struct dai *dai,
393 struct sof_ipc_stream_params *params, int dir)
394 {
395 struct ssp_pdata *ssp = dai_get_drvdata(dai);
396
397 params->rate = ssp->params.fsync_rate;
398 params->buffer_fmt = 0;
399
400 if (dir == SOF_IPC_STREAM_PLAYBACK)
401 params->channels = popcount(ssp->params.tx_slots);
402 else
403 params->channels = popcount(ssp->params.rx_slots);
404
405 switch (ssp->params.sample_valid_bits) {
406 case 16:
407 params->frame_fmt = SOF_IPC_FRAME_S16_LE;
408 break;
409 case 24:
410 params->frame_fmt = SOF_IPC_FRAME_S24_4LE;
411 break;
412 case 32:
413 params->frame_fmt = SOF_IPC_FRAME_S32_LE;
414 break;
415 default:
416 dai_err(dai, "ssp_get_hw_params(): not supported format");
417 return -EINVAL;
418 }
419
420 return 0;
421 }
422
423 /* start the SSP for either playback or capture */
ssp_start(struct dai * dai,int direction)424 static void ssp_start(struct dai *dai, int direction)
425 {
426 struct ssp_pdata *ssp = dai_get_drvdata(dai);
427
428 spin_lock(&dai->lock);
429
430 dai_info(dai, "ssp_start()");
431
432 /* enable DMA */
433 if (direction == DAI_DIR_PLAYBACK) {
434 ssp_update_bits(dai, SSCR1, SSCR1_TSRE | SSCR1_EBCEI,
435 SSCR1_TSRE | SSCR1_EBCEI);
436 ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
437 ssp_update_bits(dai, SSCR0, SSCR0_TIM, 0);
438 ssp_update_bits(dai, SSTSA, SSTSA_TSEN, SSTSA_TSEN);
439 } else {
440 ssp_update_bits(dai, SSCR1, SSCR1_RSRE | SSCR1_EBCEI,
441 SSCR1_RSRE | SSCR1_EBCEI);
442 ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
443 ssp_update_bits(dai, SSCR0, SSCR0_RIM, 0);
444 ssp_update_bits(dai, SSRSA, SSRSA_RSEN, SSRSA_RSEN);
445 }
446
447 /* enable port */
448 ssp->state[direction] = COMP_STATE_ACTIVE;
449
450 spin_unlock(&dai->lock);
451 }
452
453 /* stop the SSP for either playback or capture */
ssp_stop(struct dai * dai,int direction)454 static void ssp_stop(struct dai *dai, int direction)
455 {
456 struct ssp_pdata *ssp = dai_get_drvdata(dai);
457
458 spin_lock(&dai->lock);
459
460 /* stop Rx if neeed */
461 if (direction == DAI_DIR_CAPTURE &&
462 ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_PREPARE) {
463 ssp_update_bits(dai, SSCR1, SSCR1_RSRE, 0);
464 ssp_update_bits(dai, SSCR0, SSCR0_RIM, SSCR0_RIM);
465 ssp_update_bits(dai, SSRSA, SSRSA_RSEN, 0);
466 ssp->state[SOF_IPC_STREAM_CAPTURE] = COMP_STATE_PREPARE;
467 dai_info(dai, "ssp_stop(), RX stop");
468 }
469
470 /* stop Tx if needed */
471 if (direction == DAI_DIR_PLAYBACK &&
472 ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_PREPARE) {
473 ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0);
474 ssp_update_bits(dai, SSCR0, SSCR0_TIM, SSCR0_TIM);
475 ssp_update_bits(dai, SSTSA, SSTSA_TSEN, 0);
476 ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE;
477 dai_info(dai, "ssp_stop(), TX stop");
478 }
479
480 /* disable SSP port if no users */
481 if (ssp->state[SOF_IPC_STREAM_CAPTURE] == COMP_STATE_PREPARE &&
482 ssp->state[SOF_IPC_STREAM_PLAYBACK] == COMP_STATE_PREPARE) {
483 ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
484 dai_info(dai, "ssp_stop(), SSP port disabled");
485 }
486
487 spin_unlock(&dai->lock);
488 }
489
ssp_pause(struct dai * dai,int direction)490 static void ssp_pause(struct dai *dai, int direction)
491 {
492 struct ssp_pdata *ssp = dai_get_drvdata(dai);
493
494 if (direction == SOF_IPC_STREAM_CAPTURE)
495 dai_info(dai, "ssp_pause(), RX");
496 else
497 dai_info(dai, "ssp_pause(), TX");
498
499 ssp->state[direction] = COMP_STATE_PAUSED;
500 }
501
ssp_trigger(struct dai * dai,int cmd,int direction)502 static int ssp_trigger(struct dai *dai, int cmd, int direction)
503 {
504 struct ssp_pdata *ssp = dai_get_drvdata(dai);
505
506 dai_info(dai, "ssp_trigger()");
507
508 switch (cmd) {
509 case COMP_TRIGGER_START:
510 if (ssp->state[direction] == COMP_STATE_PREPARE ||
511 ssp->state[direction] == COMP_STATE_PAUSED)
512 ssp_start(dai, direction);
513 break;
514 case COMP_TRIGGER_RELEASE:
515 if (ssp->state[direction] == COMP_STATE_PAUSED ||
516 ssp->state[direction] == COMP_STATE_PREPARE)
517 ssp_start(dai, direction);
518 break;
519 case COMP_TRIGGER_STOP:
520 ssp_stop(dai, direction);
521 break;
522 case COMP_TRIGGER_PAUSE:
523 ssp_pause(dai, direction);
524 break;
525 case COMP_TRIGGER_RESUME:
526 ssp_context_restore(dai);
527 break;
528 case COMP_TRIGGER_SUSPEND:
529 ssp_context_store(dai);
530 break;
531 default:
532 break;
533 }
534
535 return 0;
536 }
537
ssp_probe(struct dai * dai)538 static int ssp_probe(struct dai *dai)
539 {
540 struct ssp_pdata *ssp;
541
542 /* allocate private data */
543 ssp = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*ssp));
544 dai_set_drvdata(dai, ssp);
545
546 ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
547 ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;
548
549 return 0;
550 }
551
ssp_get_handshake(struct dai * dai,int direction,int stream_id)552 static int ssp_get_handshake(struct dai *dai, int direction, int stream_id)
553 {
554 return dai->plat_data.fifo[direction].handshake;
555 }
556
ssp_get_fifo(struct dai * dai,int direction,int stream_id)557 static int ssp_get_fifo(struct dai *dai, int direction, int stream_id)
558 {
559 return dai->plat_data.fifo[direction].offset;
560 }
561
562 const struct dai_driver ssp_driver = {
563 .type = SOF_DAI_INTEL_SSP,
564 .dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP,
565 .dma_dev = DMA_DEV_SSP,
566 .ops = {
567 .trigger = ssp_trigger,
568 .set_config = ssp_set_config,
569 .pm_context_store = ssp_context_store,
570 .pm_context_restore = ssp_context_restore,
571 .get_hw_params = ssp_get_hw_params,
572 .get_handshake = ssp_get_handshake,
573 .get_fifo = ssp_get_fifo,
574 .probe = ssp_probe,
575 },
576 };
577