1 /*
2 * Copyright (c) 2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <zephyr/sys/util_macro.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <zephyr/spinlock.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/pm/device_runtime.h>
15 #define LOG_DOMAIN dai_intel_ssp
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(LOG_DOMAIN);
18
19 #include "ssp.h"
20
21 #define DT_DRV_COMPAT intel_ssp_dai
22
23 #define dai_set_drvdata(dai, data) (dai->priv_data = data)
24 #define dai_get_drvdata(dai) dai->priv_data
25 #define dai_get_mn(dai) dai->plat_data.mn_inst
26 #define dai_get_ftable(dai) dai->plat_data.ftable
27 #define dai_get_fsources(dai) dai->plat_data.fsources
28 #define dai_mn_base(dai) dai->plat_data.mn_inst->base
29 #define dai_base(dai) dai->plat_data.base
30 #define dai_ip_base(dai) dai->plat_data.ip_base
31 #define dai_shim_base(dai) dai->plat_data.shim_base
32 #define dai_hdamlssp_base(dai) dai->plat_data.hdamlssp_base
33 #define dai_i2svss_base(dai) dai->plat_data.i2svss_base
34
35 #define DAI_DIR_PLAYBACK 0
36 #define DAI_DIR_CAPTURE 1
37 #define SSP_ARRAY_INDEX(dir) dir == DAI_DIR_RX ? DAI_DIR_CAPTURE : DAI_DIR_PLAYBACK
38
dai_ssp_update_bits(struct dai_intel_ssp * dp,uint32_t reg,uint32_t mask,uint32_t val)39 static void dai_ssp_update_bits(struct dai_intel_ssp *dp, uint32_t reg, uint32_t mask, uint32_t val)
40 {
41 uint32_t dest = dai_base(dp) + reg;
42
43 LOG_INF("%s base %x, reg %x, mask %x, value %x", __func__,
44 dai_base(dp), reg, mask, val);
45
46 sys_write32((sys_read32(dest) & (~mask)) | (val & mask), dest);
47 }
48
49 #if CONFIG_INTEL_MN
dai_ssp_gcd(int a,int b)50 static int dai_ssp_gcd(int a, int b)
51 {
52 int aux;
53 int k;
54
55 if (a == 0) {
56 return b;
57 }
58
59 if (b == 0) {
60 return a;
61 }
62
63 /* If the numbers are negative, convert them to positive numbers
64 * gcd(a, b) = gcd(-a, -b) = gcd(-a, b) = gcd(a, -b)
65 */
66 if (a < 0) {
67 a = -a;
68 }
69
70 if (b < 0) {
71 b = -b;
72 }
73
74 /* Find the greatest power of 2 that devides both a and b */
75 for (k = 0; ((a | b) & 1) == 0; k++) {
76 a >>= 1;
77 b >>= 1;
78 }
79
80 /* divide by 2 until a becomes odd */
81 while ((a & 1) == 0) {
82 a >>= 1;
83 }
84
85 do {
86 /*if b is even, remove all factors of 2*/
87 while ((b & 1) == 0) {
88 b >>= 1;
89 }
90
91 /* both a and b are odd now. Swap so a <= b
92 * then set b = b - a, which is also even
93 */
94 if (a > b) {
95 aux = a;
96 a = b;
97 b = aux;
98 }
99
100 b = b - a;
101
102 } while (b != 0);
103
104 /* restore common factors of 2 */
105 return a << k;
106 }
107 #endif
108
109 /**
110 * \brief Checks if given clock is used as source for any MCLK.
111 *
112 * \return true if any port use given clock source, false otherwise.
113 */
dai_ssp_is_mclk_source_in_use(struct dai_intel_ssp * dp)114 static bool dai_ssp_is_mclk_source_in_use(struct dai_intel_ssp *dp)
115 {
116 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
117 bool ret = false;
118 int i;
119
120 for (i = 0; i < ARRAY_SIZE(mp->mclk_sources_ref); i++) {
121 if (mp->mclk_sources_ref[i] > 0) {
122 ret = true;
123 break;
124 }
125 }
126
127 return ret;
128 }
129
130 /**
131 * \brief Configures source clock for MCLK.
132 * All MCLKs share the same source, so it should be changed
133 * only if there are no other ports using it already.
134 * \param[in] mclk_rate main clock frequency.
135 * \return 0 on success, error code otherwise.
136 */
dai_ssp_setup_initial_mclk_source(struct dai_intel_ssp * dp,uint32_t mclk_id,uint32_t mclk_rate)137 static int dai_ssp_setup_initial_mclk_source(struct dai_intel_ssp *dp, uint32_t mclk_id,
138 uint32_t mclk_rate)
139 {
140 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
141 uint32_t *fs = dai_get_fsources(dp);
142 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
143 int clk_index = -1;
144 uint32_t mdivc;
145 int ret = 0;
146 int i;
147
148 if (mclk_id >= DAI_INTEL_SSP_NUM_MCLK) {
149 LOG_ERR("%s can't configure MCLK %d, only %d mclk[s] existed!",
150 __func__, mclk_id, DAI_INTEL_SSP_NUM_MCLK);
151 ret = -EINVAL;
152 goto out;
153 }
154
155 /* searching the smallest possible mclk source */
156 for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++) {
157 if (ft[i].freq % mclk_rate == 0) {
158 clk_index = i;
159 break;
160 }
161 }
162
163 if (clk_index < 0) {
164 LOG_ERR("%s MCLK %d, no valid source", __func__, mclk_rate);
165 ret = -EINVAL;
166 goto out;
167 }
168
169 mp->mclk_source_clock = clk_index;
170
171 mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
172
173 /* enable MCLK divider */
174 mdivc |= MN_MDIVCTRL_M_DIV_ENABLE(mclk_id);
175
176 /* clear source mclk clock - bits 17-16 */
177 mdivc &= ~MCDSS(MN_SOURCE_CLKS_MASK);
178
179 /* select source clock */
180 mdivc |= MCDSS(fs[clk_index]);
181
182 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
183
184 mp->mclk_sources_ref[mclk_id]++;
185 out:
186
187 return ret;
188 }
189
190 /**
191 * \brief Checks if requested MCLK can be achieved with current source.
192 * \param[in] mclk_rate main clock frequency.
193 * \return 0 on success, error code otherwise.
194 */
dai_ssp_check_current_mclk_source(struct dai_intel_ssp * dp,uint16_t mclk_id,uint32_t mclk_rate)195 static int dai_ssp_check_current_mclk_source(struct dai_intel_ssp *dp, uint16_t mclk_id,
196 uint32_t mclk_rate)
197 {
198 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
199 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
200 uint32_t mdivc;
201 int ret = 0;
202
203 LOG_INF("%s MCLK %d, source = %d", __func__, mclk_rate, mp->mclk_source_clock);
204
205 if (ft[mp->mclk_source_clock].freq % mclk_rate != 0) {
206 LOG_ERR("%s MCLK %d, no valid configuration for already selected source = %d",
207 __func__, mclk_rate, mp->mclk_source_clock);
208 ret = -EINVAL;
209 }
210
211 /* if the mclk is already used, can't change its divider, just increase ref count */
212 if (mp->mclk_sources_ref[mclk_id] > 0) {
213 if (mp->mclk_rate[mclk_id] != mclk_rate) {
214 LOG_ERR("%s Can't set MCLK %d to %d, it is already configured to %d",
215 __func__, mclk_id, mclk_rate, mp->mclk_rate[mclk_id]);
216 return -EINVAL;
217 }
218
219 mp->mclk_sources_ref[mclk_id]++;
220 } else {
221 mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
222
223 /* enable MCLK divider */
224 mdivc |= MN_MDIVCTRL_M_DIV_ENABLE(mclk_id);
225 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
226
227 mp->mclk_sources_ref[mclk_id]++;
228 }
229
230 return ret;
231 }
232
233 /**
234 * \brief Sets MCLK divider to given value.
235 * \param[in] mclk_id ID of MCLK.
236 * \param[in] mdivr_val divider value.
237 * \return 0 on success, error code otherwise.
238 */
dai_ssp_set_mclk_divider(struct dai_intel_ssp * dp,uint16_t mclk_id,uint32_t mdivr_val)239 static int dai_ssp_set_mclk_divider(struct dai_intel_ssp *dp, uint16_t mclk_id, uint32_t mdivr_val)
240 {
241 uint32_t mdivr;
242
243 LOG_INF("%s mclk_id %d mdivr_val %d", __func__, mclk_id, mdivr_val);
244 switch (mdivr_val) {
245 case 1:
246 mdivr = 0x00000fff; /* bypass divider for MCLK */
247 break;
248 case 2 ... 8:
249 mdivr = mdivr_val - 2; /* 1/n */
250 break;
251 default:
252 LOG_ERR("%s invalid mdivr_val %d", __func__, mdivr_val);
253 return -EINVAL;
254 }
255
256 sys_write32(mdivr, dai_mn_base(dp) + MN_MDIVR(mclk_id));
257
258 return 0;
259 }
260
dai_ssp_mn_set_mclk(struct dai_intel_ssp * dp,uint16_t mclk_id,uint32_t mclk_rate)261 static int dai_ssp_mn_set_mclk(struct dai_intel_ssp *dp, uint16_t mclk_id, uint32_t mclk_rate)
262 {
263 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
264 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
265 k_spinlock_key_t key;
266 int ret = 0;
267
268 if (mclk_id >= DAI_INTEL_SSP_NUM_MCLK) {
269 LOG_ERR("%s mclk ID (%d) >= %d", __func__, mclk_id, DAI_INTEL_SSP_NUM_MCLK);
270 return -EINVAL;
271 }
272
273 key = k_spin_lock(&mp->lock);
274
275 if (dai_ssp_is_mclk_source_in_use(dp)) {
276 ret = dai_ssp_check_current_mclk_source(dp, mclk_id, mclk_rate);
277 } else {
278 ret = dai_ssp_setup_initial_mclk_source(dp, mclk_id, mclk_rate);
279 }
280
281 if (ret < 0) {
282 goto out;
283 }
284
285 LOG_INF("%s mclk_rate %d, mclk_source_clock %d", __func__,
286 mclk_rate, mp->mclk_source_clock);
287
288 ret = dai_ssp_set_mclk_divider(dp, mclk_id, ft[mp->mclk_source_clock].freq / mclk_rate);
289 if (!ret) {
290 mp->mclk_rate[mclk_id] = mclk_rate;
291 }
292
293 out:
294 k_spin_unlock(&mp->lock, key);
295
296 return ret;
297 }
298
dai_ssp_mn_set_mclk_blob(struct dai_intel_ssp * dp,uint32_t mdivc,uint32_t mdivr)299 static int dai_ssp_mn_set_mclk_blob(struct dai_intel_ssp *dp, uint32_t mdivc, uint32_t mdivr)
300 {
301 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
302 sys_write32(mdivr, dai_mn_base(dp) + MN_MDIVR(0));
303
304 return 0;
305 }
306
dai_ssp_mn_release_mclk(struct dai_intel_ssp * dp,uint32_t mclk_id)307 static void dai_ssp_mn_release_mclk(struct dai_intel_ssp *dp, uint32_t mclk_id)
308 {
309 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
310 k_spinlock_key_t key;
311 uint32_t mdivc;
312
313 key = k_spin_lock(&mp->lock);
314
315 mp->mclk_sources_ref[mclk_id]--;
316
317 /* disable MCLK divider if nobody use it */
318 if (!mp->mclk_sources_ref[mclk_id]) {
319 mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
320
321 mdivc &= ~MN_MDIVCTRL_M_DIV_ENABLE(mclk_id);
322 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
323 }
324
325 /* release the clock source if all mclks are released */
326 if (!dai_ssp_is_mclk_source_in_use(dp)) {
327 mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
328
329 /* clear source mclk clock - bits 17-16 */
330 mdivc &= ~MCDSS(MN_SOURCE_CLKS_MASK);
331
332 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
333
334 mp->mclk_source_clock = 0;
335 }
336 k_spin_unlock(&mp->lock, key);
337 }
338
339 #if CONFIG_INTEL_MN
340 /**
341 * \brief Finds valid M/(N * SCR) values for given frequencies.
342 * \param[in] freq SSP clock frequency.
343 * \param[in] bclk Bit clock frequency.
344 * \param[out] out_scr_div SCR divisor.
345 * \param[out] out_m M value of M/N divider.
346 * \param[out] out_n N value of M/N divider.
347 * \return true if found suitable values, false otherwise.
348 */
dai_ssp_find_mn(uint32_t freq,uint32_t bclk,uint32_t * out_scr_div,uint32_t * out_m,uint32_t * out_n)349 static bool dai_ssp_find_mn(uint32_t freq, uint32_t bclk, uint32_t *out_scr_div, uint32_t *out_m,
350 uint32_t *out_n)
351 {
352 uint32_t m, n, mn_div;
353 uint32_t scr_div = freq / bclk;
354
355 LOG_INF("%s for freq %d bclk %d", __func__, freq, bclk);
356 /* check if just SCR is enough */
357 if (freq % bclk == 0 && scr_div < (SSCR0_SCR_MASK >> 8) + 1) {
358 *out_scr_div = scr_div;
359 *out_m = 1;
360 *out_n = 1;
361
362 return true;
363 }
364
365 /* M/(N * scr_div) has to be less than 1/2 */
366 if ((bclk * 2) >= freq) {
367 return false;
368 }
369
370 /* odd SCR gives lower duty cycle */
371 if (scr_div > 1 && scr_div % 2 != 0) {
372 --scr_div;
373 }
374
375 /* clamp to valid SCR range */
376 scr_div = MIN(scr_div, (SSCR0_SCR_MASK >> 8) + 1);
377
378 /* find highest even divisor */
379 while (scr_div > 1 && freq % scr_div != 0) {
380 scr_div -= 2;
381 }
382
383 /* compute M/N with smallest dividend and divisor */
384 mn_div = dai_ssp_gcd(bclk, freq / scr_div);
385
386 m = bclk / mn_div;
387 n = freq / scr_div / mn_div;
388
389 /* M/N values can be up to 24 bits */
390 if (n & (~0xffffff)) {
391 return false;
392 }
393
394 *out_scr_div = scr_div;
395 *out_m = m;
396 *out_n = n;
397
398 LOG_INF("%s m %d n %d", __func__, m, n);
399 return true;
400 }
401
402 /**
403 * \brief Finds index of clock valid for given BCLK rate.
404 * Clock that can use just SCR is preferred.
405 * M/N other than 1/1 is used only if there are no other possibilities.
406 * \param[in] bclk Bit clock frequency.
407 * \param[out] scr_div SCR divisor.
408 * \param[out] m M value of M/N divider.
409 * \param[out] n N value of M/N divider.
410 * \return index of suitable clock if could find it, -EINVAL otherwise.
411 */
dai_ssp_find_bclk_source(struct dai_intel_ssp * dp,uint32_t bclk,uint32_t * scr_div,uint32_t * m,uint32_t * n)412 static int dai_ssp_find_bclk_source(struct dai_intel_ssp *dp, uint32_t bclk, uint32_t *scr_div,
413 uint32_t *m, uint32_t *n)
414 {
415 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
416 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
417 int i;
418
419 /* check if we can use MCLK source clock */
420 if (dai_ssp_is_mclk_source_in_use(dp)) {
421 if (dai_ssp_find_mn(ft[mp->mclk_source_clock].freq, bclk, scr_div, m, n)) {
422 return mp->mclk_source_clock;
423 }
424
425 LOG_WRN("%s BCLK %d warning: cannot use MCLK source %d",
426 __func__, bclk, ft[mp->mclk_source_clock].freq);
427 }
428
429 /* searching the smallest possible bclk source */
430 for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++)
431 if (ft[i].freq % bclk == 0) {
432 *scr_div = ft[i].freq / bclk;
433 return i;
434 }
435
436 /* check if we can get target BCLK with M/N */
437 for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++) {
438 if (dai_ssp_find_mn(ft[i].freq, bclk, scr_div, m, n)) {
439 return i;
440 }
441 }
442
443 return -EINVAL;
444 }
445
446 /**
447 * \brief Finds index of SSP clock with the given clock source encoded index.
448 * \return the index in ssp_freq if could find it, -EINVAL otherwise.
449 */
dai_ssp_find_clk_ssp_index(struct dai_intel_ssp * dp,uint32_t src_enc)450 static int dai_ssp_find_clk_ssp_index(struct dai_intel_ssp *dp, uint32_t src_enc)
451 {
452 uint32_t *fs = dai_get_fsources(dp);
453 int i;
454
455 /* searching for the encode value matched bclk source */
456 for (i = 0; i <= DAI_INTEL_SSP_MAX_FREQ_INDEX; i++) {
457 if (fs[i] == src_enc) {
458 return i;
459 }
460 }
461
462 return -EINVAL;
463 }
464
465 /**
466 * \brief Checks if given clock is used as source for any BCLK.
467 * \param[in] clk_src Bit clock source.
468 * \return true if any port use given clock source, false otherwise.
469 */
dai_ssp_is_bclk_source_in_use(struct dai_intel_ssp * dp,enum bclk_source clk_src)470 static bool dai_ssp_is_bclk_source_in_use(struct dai_intel_ssp *dp, enum bclk_source clk_src)
471 {
472 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
473 bool ret = false;
474 int i;
475
476 for (i = 0; i < ARRAY_SIZE(mp->bclk_sources); i++) {
477 if (mp->bclk_sources[i] == clk_src) {
478 ret = true;
479 break;
480 }
481 }
482
483 return ret;
484 }
485
486 /**
487 * \brief Configures M/N source clock for BCLK.
488 * All ports that use M/N share the same source, so it should be changed
489 * only if there are no other ports using M/N already.
490 * \param[in] bclk Bit clock frequency.
491 * \param[out] scr_div SCR divisor.
492 * \param[out] m M value of M/N divider.
493 * \param[out] n N value of M/N divider.
494 * \return 0 on success, error code otherwise.
495 */
dai_ssp_setup_initial_bclk_mn_source(struct dai_intel_ssp * dp,uint32_t bclk,uint32_t * scr_div,uint32_t * m,uint32_t * n)496 static int dai_ssp_setup_initial_bclk_mn_source(struct dai_intel_ssp *dp, uint32_t bclk,
497 uint32_t *scr_div, uint32_t *m, uint32_t *n)
498 {
499 uint32_t *fs = dai_get_fsources(dp);
500 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
501 uint32_t mdivc;
502 int clk_index = dai_ssp_find_bclk_source(dp, bclk, scr_div, m, n);
503
504 if (clk_index < 0) {
505 LOG_ERR("%s BCLK %d, no valid source", __func__, bclk);
506 return -EINVAL;
507 }
508
509 mp->bclk_source_mn_clock = clk_index;
510
511 mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
512
513 /* clear source bclk clock - 21-20 bits */
514 mdivc &= ~MNDSS(MN_SOURCE_CLKS_MASK);
515
516 /* select source clock */
517 mdivc |= MNDSS(fs[clk_index]);
518
519 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
520
521 return 0;
522 }
523
524 /**
525 * \brief Reset M/N source clock for BCLK.
526 * If no port is using bclk, reset to use SSP_CLOCK_XTAL_OSCILLATOR
527 * as the default clock source.
528 */
dai_ssp_reset_bclk_mn_source(struct dai_intel_ssp * dp)529 static void dai_ssp_reset_bclk_mn_source(struct dai_intel_ssp *dp)
530 {
531 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
532 uint32_t mdivc;
533 int clk_index = dai_ssp_find_clk_ssp_index(dp, DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR);
534
535 if (clk_index < 0) {
536 LOG_ERR("%s BCLK reset failed, no SSP_CLOCK_XTAL_OSCILLATOR source!",
537 __func__);
538 return;
539 }
540
541 mdivc = sys_read32(dai_mn_base(dp) + MN_MDIVCTRL);
542
543 /* reset to use XTAL Oscillator */
544 mdivc &= ~MNDSS(MN_SOURCE_CLKS_MASK);
545 mdivc |= MNDSS(DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR);
546
547 sys_write32(mdivc, dai_mn_base(dp) + MN_MDIVCTRL);
548
549 mp->bclk_source_mn_clock = clk_index;
550 }
551
552 /**
553 * \brief Finds valid M/(N * SCR) values for source clock that is already locked
554 * because other ports use it.
555 * \param[in] bclk Bit clock frequency.
556 * \param[out] scr_div SCR divisor.
557 * \param[out] m M value of M/N divider.
558 * \param[out] n N value of M/N divider.
559 * \return 0 on success, error code otherwise.
560 */
dai_ssp_setup_current_bclk_mn_source(struct dai_intel_ssp * dp,uint32_t bclk,uint32_t * scr_div,uint32_t * m,uint32_t * n)561 static int dai_ssp_setup_current_bclk_mn_source(struct dai_intel_ssp *dp, uint32_t bclk,
562 uint32_t *scr_div, uint32_t *m, uint32_t *n)
563 {
564 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
565 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
566 int ret = 0;
567
568 /* source for M/N is already set, no need to do it */
569 if (dai_ssp_find_mn(ft[mp->bclk_source_mn_clock].freq, bclk, scr_div, m, n)) {
570 goto out;
571 }
572
573 LOG_ERR("%s BCLK %d, no valid configuration for already selected source = %d",
574 __func__, bclk, mp->bclk_source_mn_clock);
575 ret = -EINVAL;
576
577 out:
578
579 return ret;
580 }
581
dai_ssp_check_bclk_xtal_source(uint32_t bclk,bool mn_in_use,uint32_t * scr_div)582 static bool dai_ssp_check_bclk_xtal_source(uint32_t bclk, bool mn_in_use,
583 uint32_t *scr_div)
584 {
585 /* since cAVS 2.0 bypassing XTAL (ECS=0) is not supported */
586 return false;
587 }
588
dai_ssp_mn_set_bclk(struct dai_intel_ssp * dp,uint32_t dai_index,uint32_t bclk_rate,uint32_t * out_scr_div,bool * out_need_ecs)589 static int dai_ssp_mn_set_bclk(struct dai_intel_ssp *dp, uint32_t dai_index, uint32_t bclk_rate,
590 uint32_t *out_scr_div, bool *out_need_ecs)
591 {
592 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
593 k_spinlock_key_t key;
594 uint32_t m = 1;
595 uint32_t n = 1;
596 int ret = 0;
597 bool mn_in_use;
598
599 key = k_spin_lock(&mp->lock);
600
601 mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
602
603 mn_in_use = dai_ssp_is_bclk_source_in_use(dp, MN_BCLK_SOURCE_MN);
604
605 if (dai_ssp_check_bclk_xtal_source(bclk_rate, mn_in_use, out_scr_div)) {
606 mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_XTAL;
607 *out_need_ecs = false;
608 goto out;
609 }
610
611 *out_need_ecs = true;
612
613 if (mn_in_use) {
614 ret = dai_ssp_setup_current_bclk_mn_source(dp, bclk_rate, out_scr_div, &m, &n);
615 } else {
616 ret = dai_ssp_setup_initial_bclk_mn_source(dp, bclk_rate, out_scr_div, &m, &n);
617 }
618
619 if (ret >= 0) {
620 mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_MN;
621
622 LOG_INF("%s bclk_rate %d, *out_scr_div %d, m %d, n %d",
623 __func__, bclk_rate, *out_scr_div, m, n);
624
625 sys_write32(m, dai_mn_base(dp) + MN_MDIV_M_VAL(dai_index));
626 sys_write32(n, dai_mn_base(dp) + MN_MDIV_N_VAL(dai_index));
627 }
628
629 out:
630
631 k_spin_unlock(&mp->lock, key);
632
633 return ret;
634 }
635
dai_ssp_mn_release_bclk(struct dai_intel_ssp * dp,uint32_t dai_index)636 static void dai_ssp_mn_release_bclk(struct dai_intel_ssp *dp, uint32_t dai_index)
637 {
638 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
639 k_spinlock_key_t key;
640 bool mn_in_use;
641
642 key = k_spin_lock(&mp->lock);
643 mp->bclk_sources[dai_index] = MN_BCLK_SOURCE_NONE;
644
645 mn_in_use = dai_ssp_is_bclk_source_in_use(dp, MN_BCLK_SOURCE_MN);
646 /* release the M/N clock source if not used */
647 if (!mn_in_use) {
648 dai_ssp_reset_bclk_mn_source(dp);
649 }
650
651 k_spin_unlock(&mp->lock, key);
652 }
653
dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp * dp,uint32_t dai_index)654 static void dai_ssp_mn_reset_bclk_divider(struct dai_intel_ssp *dp, uint32_t dai_index)
655 {
656 struct dai_intel_ssp_mn *mp = dai_get_mn(dp);
657 k_spinlock_key_t key;
658
659 key = k_spin_lock(&mp->lock);
660
661 sys_write32(1, dai_mn_base(dp) + MN_MDIV_M_VAL(dai_index));
662 sys_write32(1, dai_mn_base(dp) + MN_MDIV_N_VAL(dai_index));
663
664 k_spin_unlock(&mp->lock, key);
665 }
666 #endif
667
dai_ssp_poll_for_register_delay(uint32_t reg,uint32_t mask,uint32_t val,uint64_t us)668 static int dai_ssp_poll_for_register_delay(uint32_t reg, uint32_t mask,
669 uint32_t val, uint64_t us)
670 {
671 if (!WAIT_FOR((sys_read32(reg) & mask) == val, us, k_busy_wait(1))) {
672 LOG_ERR("%s poll timeout reg %u mask %u val %u us %u",
673 __func__, reg, mask, val, (uint32_t)us);
674 return -EIO;
675 }
676
677 return 0;
678 }
679
dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp * dp,uint32_t index)680 static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index)
681 {
682 #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING
683 uint32_t shim_reg;
684
685 shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) |
686 (index < CONFIG_DAI_INTEL_SSP_NUM_BASE ?
687 SHIM_CLKCTL_I2SFDCGB(index) :
688 SHIM_CLKCTL_I2SEFDCGB(index -
689 CONFIG_DAI_INTEL_SSP_NUM_BASE));
690
691 sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL);
692
693 LOG_INF("%s index %d CLKCTL %08x", __func__, index, shim_reg);
694 #endif
695 }
696
dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp * dp,uint32_t index)697 static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp, uint32_t index)
698 {
699 #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING
700 uint32_t shim_reg;
701
702 shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) &
703 ~(index < CONFIG_DAI_INTEL_SSP_NUM_BASE ?
704 SHIM_CLKCTL_I2SFDCGB(index) :
705 SHIM_CLKCTL_I2SEFDCGB(index -
706 CONFIG_DAI_INTEL_SSP_NUM_BASE));
707
708 sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL);
709
710 LOG_INF("%s index %d CLKCTL %08x", __func__, index, shim_reg);
711 #endif
712 }
713
dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp * dp,uint32_t index)714 static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t index)
715 {
716 #if CONFIG_DAI_SSP_HAS_POWER_CONTROL
717 int ret;
718
719 LOG_INF("%s en_ssp_power index %d", __func__, index);
720 #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS
721 sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(index),
722 dai_ip_base(dp) + I2SLCTL_OFFSET);
723
724 /* Check if powered on. */
725 ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
726 I2SLCTL_CPA(index), 0,
727 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
728 #elif CONFIG_SOC_INTEL_ACE20_LNL
729 sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) |
730 I2SLCTL_SPA(index),
731 dai_hdamlssp_base(dp) + I2SLCTL_OFFSET);
732 /* Check if powered on. */
733 ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET,
734 I2SLCTL_CPA(index), 0,
735 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
736 #else
737 #error need to define SOC
738 #endif
739 if (ret) {
740 LOG_WRN("%s warning: timeout", __func__);
741 }
742
743 LOG_INF("%s I2SLCTL", __func__);
744 #else
745 ARG_UNUSED(dp);
746 ARG_UNUSED(index);
747 #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
748 }
749
dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp * dp,uint32_t index)750 static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t index)
751 {
752 #if CONFIG_DAI_SSP_HAS_POWER_CONTROL
753 int ret;
754
755 LOG_INF("%s index %d", __func__, index);
756 #if CONFIG_SOC_INTEL_ACE15_MTPM || CONFIG_SOC_SERIES_INTEL_ADSP_CAVS
757 sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)),
758 dai_ip_base(dp) + I2SLCTL_OFFSET);
759
760 /* Check if powered off. */
761 ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
762 I2SLCTL_CPA(index), I2SLCTL_CPA(index),
763 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
764 #elif CONFIG_SOC_INTEL_ACE20_LNL
765 sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)),
766 dai_hdamlssp_base(dp) + I2SLCTL_OFFSET);
767
768 /* Check if powered off. */
769 ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET,
770 I2SLCTL_CPA(index), I2SLCTL_CPA(index),
771 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
772 #else
773 #error need to define SOC
774 #endif
775 if (ret) {
776 LOG_WRN("%s warning: timeout", __func__);
777 }
778
779 LOG_INF("%s I2SLCTL", __func__);
780 #else
781 ARG_UNUSED(dp);
782 ARG_UNUSED(index);
783 #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
784 }
785
dai_ssp_program_channel_map(struct dai_intel_ssp * dp,const struct dai_config * cfg,uint32_t index)786 static void dai_ssp_program_channel_map(struct dai_intel_ssp *dp,
787 const struct dai_config *cfg, uint32_t index)
788 {
789 #ifdef CONFIG_SOC_INTEL_ACE20_LNL
790 uint16_t pcmsycm = cfg->link_config;
791 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
792
793 /* Set upper slot number from configuration */
794 pcmsycm = pcmsycm | (ssp->params.tdm_slots - 1) << 4;
795
796 if (DAI_INTEL_SSP_IS_BIT_SET(pcmsycm, 15)) {
797 uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS0CM_OFFSET;
798 /* Program HDA output stream parameters */
799 sys_write16((pcmsycm & 0xffff), reg_add);
800 } else {
801 uint32_t reg_add = dai_ip_base(dp) + 0x1000 * index + PCMS1CM_OFFSET;
802 /* Program HDA input stream parameters */
803 sys_write16((pcmsycm & 0xffff), reg_add);
804 }
805 #else
806 ARG_UNUSED(dp);
807 ARG_UNUSED(cfg);
808 ARG_UNUSED(index);
809 #endif /* CONFIG_SOC_INTEL_ACE20_LNL */
810 }
811
812 /* empty SSP transmit FIFO */
dai_ssp_empty_tx_fifo(struct dai_intel_ssp * dp)813 static void dai_ssp_empty_tx_fifo(struct dai_intel_ssp *dp)
814 {
815 int ret;
816 uint32_t sssr;
817
818 /*
819 * SSSR_TNF is cleared when TX FIFO is empty or full,
820 * so wait for set TNF then for TFL zero - order matter.
821 */
822 ret = dai_ssp_poll_for_register_delay(dai_base(dp) + SSSR, SSSR_TNF, SSSR_TNF,
823 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
824 ret |= dai_ssp_poll_for_register_delay(dai_base(dp) + SSCR3, SSCR3_TFL_MASK, 0,
825 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE *
826 (DAI_INTEL_SSP_FIFO_DEPTH - 1) / 2);
827
828 if (ret) {
829 LOG_WRN("%s warning: timeout", __func__);
830 }
831
832 sssr = sys_read32(dai_base(dp) + SSSR);
833
834 /* clear interrupt */
835 if (sssr & SSSR_TUR) {
836 sys_write32(sssr, dai_base(dp) + SSSR);
837 }
838 }
839
840 /* empty SSP receive FIFO */
dai_ssp_empty_rx_fifo(struct dai_intel_ssp * dp)841 static void dai_ssp_empty_rx_fifo(struct dai_intel_ssp *dp)
842 {
843 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
844 uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX;
845 uint32_t entries;
846 uint32_t i;
847
848 /*
849 * To make sure all the RX FIFO entries are read out for the flushing,
850 * we need to wait a minimal SSP port delay after entries are all read,
851 * and then re-check to see if there is any subsequent entries written
852 * to the FIFO. This will help to make sure there is no sample mismatched
853 * issue for the next run with the SSP RX.
854 */
855 while ((sys_read32(dai_base(dp) + SSSR) & SSSR_RNE) && retry--) {
856 entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
857 LOG_DBG("%s before flushing, entries %d", __func__, entries);
858 for (i = 0; i < entries + 1; i++) {
859 /* read to try empty fifo */
860 sys_read32(dai_base(dp) + SSDR);
861 }
862
863 /* wait to get valid fifo status and re-check */
864 k_busy_wait(ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0);
865 entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
866 LOG_DBG("%s after flushing, entries %d", __func__, entries);
867 }
868
869 /* clear interrupt */
870 dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR);
871 }
872
dai_ssp_mclk_prepare_enable(struct dai_intel_ssp * dp)873 static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp)
874 {
875 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
876 int ret;
877
878 if (ssp->clk_active & SSP_CLK_MCLK_ACTIVE) {
879 return 0;
880 }
881
882 /* MCLK config */
883 ret = dai_ssp_mn_set_mclk(dp, ssp->params.mclk_id, ssp->params.mclk_rate);
884 if (ret < 0) {
885 LOG_ERR("%s invalid mclk_rate = %d for mclk_id = %d", __func__,
886 ssp->params.mclk_rate, ssp->params.mclk_id);
887 } else {
888 ssp->clk_active |= SSP_CLK_MCLK_ACTIVE;
889 }
890
891 return ret;
892 }
893
dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp * dp)894 static void dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp *dp)
895 {
896 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
897
898 if (!(ssp->clk_active & SSP_CLK_MCLK_ACTIVE)) {
899 return;
900 }
901
902 dai_ssp_mn_release_mclk(dp, ssp->params.mclk_id);
903
904 ssp->clk_active &= ~SSP_CLK_MCLK_ACTIVE;
905 }
906
dai_ssp_bclk_prepare_enable(struct dai_intel_ssp * dp)907 static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp)
908 {
909 #if !(CONFIG_INTEL_MN)
910 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
911 #endif
912 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
913 struct dai_config *config = &ssp->config;
914 uint32_t sscr0;
915 uint32_t mdiv;
916 bool need_ecs = false;
917 int ret = 0;
918
919 if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
920 return 0;
921 }
922
923 sscr0 = sys_read32(dai_base(dp) + SSCR0);
924
925 #if CONFIG_INTEL_MN
926 /* BCLK config */
927 ret = dai_ssp_mn_set_bclk(dp, config->dai_index, ssp->params.bclk_rate,
928 &mdiv, &need_ecs);
929 if (ret < 0) {
930 LOG_ERR("%s invalid bclk_rate = %d for dai_index = %d", __func__,
931 ssp->params.bclk_rate, config->dai_index);
932 goto out;
933 }
934 #else
935 if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp->params.bclk_rate != 0) {
936 LOG_ERR("%s invalid bclk_rate = %d for dai_index = %d", __func__,
937 ssp->params.bclk_rate, config->dai_index);
938 ret = -EINVAL;
939 goto out;
940 }
941
942 mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp->params.bclk_rate;
943 #endif
944
945 if (need_ecs) {
946 sscr0 |= SSCR0_ECS;
947 }
948
949 /* clock divisor is SCR + 1 */
950 mdiv -= 1;
951
952 /* divisor must be within SCR range */
953 if (mdiv > (SSCR0_SCR_MASK >> 8)) {
954 LOG_ERR("%s divisor %d is not within SCR range", __func__, mdiv);
955 ret = -EINVAL;
956 goto out;
957 }
958
959 /* set the SCR divisor */
960 sscr0 &= ~SSCR0_SCR_MASK;
961 sscr0 |= SSCR0_SCR(mdiv);
962
963 sys_write32(sscr0, dai_base(dp) + SSCR0);
964
965 LOG_INF("%s sscr0 = 0x%08x", __func__, sscr0);
966 out:
967 if (!ret) {
968 ssp->clk_active |= SSP_CLK_BCLK_ACTIVE;
969 }
970
971 return ret;
972 }
973
dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp * dp)974 static void dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp *dp)
975 {
976 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
977
978 if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) {
979 return;
980 }
981 #if CONFIG_INTEL_MN
982 dai_ssp_mn_release_bclk(dp, dp->index);
983 #endif
984 ssp->clk_active &= ~SSP_CLK_BCLK_ACTIVE;
985 }
986
dai_ssp_log_ssp_data(struct dai_intel_ssp * dp)987 static void dai_ssp_log_ssp_data(struct dai_intel_ssp *dp)
988 {
989 LOG_INF("%s dai index: %u", __func__, dp->index);
990 LOG_INF("%s plat_data base: %u", __func__, dp->plat_data.base);
991 LOG_INF("%s plat_data irq: %u", __func__, dp->plat_data.irq);
992 LOG_INF("%s plat_data fifo playback offset: %u", __func__,
993 dp->plat_data.fifo[DAI_DIR_PLAYBACK].offset);
994 LOG_INF("%s plat_data fifo playback handshake: %u", __func__,
995 dp->plat_data.fifo[DAI_DIR_PLAYBACK].handshake);
996 LOG_INF("%s plat_data fifo capture offset: %u", __func__,
997 dp->plat_data.fifo[DAI_DIR_CAPTURE].offset);
998 LOG_INF("%s plat_data fifo capture handshake: %u", __func__,
999 dp->plat_data.fifo[DAI_DIR_CAPTURE].handshake);
1000 }
1001
1002 /* Digital Audio interface formatting */
dai_ssp_set_config_tplg(struct dai_intel_ssp * dp,const struct dai_config * config,const void * bespoke_cfg)1003 static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_config *config,
1004 const void *bespoke_cfg)
1005 {
1006 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1007 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
1008 uint32_t sscr0;
1009 uint32_t sscr1;
1010 uint32_t sscr2;
1011 uint32_t sscr3;
1012 uint32_t sspsp;
1013 uint32_t sspsp2;
1014 uint32_t sstsa;
1015 uint32_t ssrsa;
1016 uint32_t ssto;
1017 uint32_t ssioc;
1018 uint32_t bdiv;
1019 uint32_t data_size;
1020 uint32_t frame_end_padding;
1021 uint32_t slot_end_padding;
1022 uint32_t frame_len = 0;
1023 uint32_t bdiv_min;
1024 uint32_t tft;
1025 uint32_t rft;
1026 uint32_t active_tx_slots = 2;
1027 uint32_t active_rx_slots = 2;
1028 uint32_t sample_width = 2;
1029
1030 bool inverted_bclk = false;
1031 bool inverted_frame = false;
1032 bool cfs = false;
1033 bool start_delay = false;
1034 k_spinlock_key_t key;
1035 int ret = 0;
1036
1037 dai_ssp_log_ssp_data(dp);
1038
1039 key = k_spin_lock(&dp->lock);
1040
1041 /* ignore config if SSP is already configured */
1042 if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY ||
1043 ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) {
1044 if (!memcmp(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params))) {
1045 LOG_INF("%s Already configured. Ignore config", __func__);
1046 goto clk;
1047 }
1048
1049 if (ssp->clk_active & (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) {
1050 LOG_WRN("%s SSP active, cannot change config", __func__);
1051 goto clk;
1052 }
1053
1054 /* safe to proceed and change HW config */
1055 }
1056
1057 LOG_INF("%s", __func__);
1058
1059 /* reset SSP settings */
1060 /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */
1061 /*
1062 * FIXME: MOD, ACS, NCS are not set,
1063 * no support for network mode for now
1064 */
1065 sscr0 = SSCR0_PSP | SSCR0_RIM | SSCR0_TIM;
1066
1067 /* sscr1 dynamic settings are SFRMDIR, SCLKDIR, SCFR, RSRE, TSRE */
1068 sscr1 = SSCR1_TTE | SSCR1_TTELP | SSCR1_TRAIL;
1069
1070 /* sscr2 dynamic setting is LJDFD */
1071 sscr2 = SSCR2_SDFD | SSCR2_TURM1;
1072
1073 /* sscr3 dynamic settings are TFT, RFT */
1074 sscr3 = 0;
1075
1076 /* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */
1077 sspsp = 0;
1078
1079 ssp->config = *config;
1080 memcpy(&ssp->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params));
1081
1082 /* sspsp2 no dynamic setting */
1083 sspsp2 = 0x0;
1084
1085 /* ssioc dynamic setting is SFCR */
1086 ssioc = SSIOC_SCOE;
1087
1088 /* ssto no dynamic setting */
1089 ssto = 0x0;
1090
1091 /* sstsa dynamic setting is TTSA, default 2 slots */
1092 sstsa = SSTSA_SSTSA(ssp->params.tx_slots);
1093
1094 /* ssrsa dynamic setting is RTSA, default 2 slots */
1095 ssrsa = SSRSA_SSRSA(ssp->params.rx_slots);
1096
1097 switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1098 case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP:
1099 sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
1100 break;
1101 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1102 sscr1 |= SSCR1_SCFR;
1103 cfs = true;
1104 break;
1105 case DAI_INTEL_IPC3_SSP_FMT_CBP_CFC:
1106 sscr1 |= SSCR1_SCLKDIR;
1107 /* FIXME: this mode has not been tested */
1108
1109 cfs = true;
1110 break;
1111 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFP:
1112 sscr1 |= SSCR1_SCFR | SSCR1_SFRMDIR;
1113 /* FIXME: this mode has not been tested */
1114 break;
1115 default:
1116 LOG_ERR("%s format & PROVIDER_MASK EINVAL", __func__);
1117 ret = -EINVAL;
1118 goto out;
1119 }
1120
1121 /* clock signal polarity */
1122 switch (config->format & DAI_INTEL_IPC3_SSP_FMT_INV_MASK) {
1123 case DAI_INTEL_IPC3_SSP_FMT_NB_NF:
1124 break;
1125 case DAI_INTEL_IPC3_SSP_FMT_NB_IF:
1126 inverted_frame = true; /* handled later with format */
1127 break;
1128 case DAI_INTEL_IPC3_SSP_FMT_IB_IF:
1129 inverted_bclk = true; /* handled later with bclk idle */
1130 inverted_frame = true; /* handled later with format */
1131 break;
1132 case DAI_INTEL_IPC3_SSP_FMT_IB_NF:
1133 inverted_bclk = true; /* handled later with bclk idle */
1134 break;
1135 default:
1136 LOG_ERR("%s format & INV_MASK EINVAL", __func__);
1137 ret = -EINVAL;
1138 goto out;
1139 }
1140
1141 /* supporting bclk idle state */
1142 if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) {
1143 /* bclk idle state high */
1144 sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3);
1145 } else {
1146 /* bclk idle state low */
1147 sspsp |= SSPSP_SCMODE(inverted_bclk);
1148 }
1149
1150 sscr0 |= SSCR0_MOD | SSCR0_ACS;
1151
1152 /* Additional hardware settings */
1153
1154 /* Receiver Time-out Interrupt Disabled/Enabled */
1155 sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ?
1156 SSCR1_TINTE : 0;
1157
1158 /* Peripheral Trailing Byte Interrupts Disable/Enable */
1159 sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ?
1160 SSCR1_PINTE : 0;
1161
1162 /* Enable/disable internal loopback. Output of transmit serial
1163 * shifter connected to input of receive serial shifter, internally.
1164 */
1165 sscr1 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ?
1166 SSCR1_LBM : 0;
1167
1168 if (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) {
1169 LOG_INF("%s going for loopback!", __func__);
1170 } else {
1171 LOG_INF("%s no loopback!", __func__);
1172 }
1173
1174 /* Transmit data are driven at the same/opposite clock edge specified
1175 * in SSPSP.SCMODE[1:0]
1176 */
1177 sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ?
1178 SSCR2_SMTATF : 0;
1179
1180 /* Receive data are sampled at the same/opposite clock edge specified
1181 * in SSPSP.SCMODE[1:0]
1182 */
1183 sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ?
1184 SSCR2_MMRATF : 0;
1185
1186 /* Enable/disable the fix for PSP consumer mode TXD wait for frame
1187 * de-assertion before starting the second channel
1188 */
1189 sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ?
1190 SSCR2_PSPSTWFDFD : 0;
1191
1192 /* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
1193 * frame end padding capability
1194 */
1195 sscr2 |= (ssp->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ?
1196 SSCR2_PSPSRWFDFD : 0;
1197
1198 if (!ssp->params.mclk_rate ||
1199 ssp->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) {
1200 LOG_ERR("%s invalid MCLK = %d Hz (valid < %d)", __func__,
1201 ssp->params.mclk_rate,
1202 ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq);
1203 ret = -EINVAL;
1204 goto out;
1205 }
1206
1207 if (!ssp->params.bclk_rate || ssp->params.bclk_rate > ssp->params.mclk_rate) {
1208 LOG_ERR("%s BCLK %d Hz = 0 or > MCLK %d Hz", __func__,
1209 ssp->params.bclk_rate, ssp->params.mclk_rate);
1210 ret = -EINVAL;
1211 goto out;
1212 }
1213
1214 /* calc frame width based on BCLK and rate - must be divisable */
1215 if (ssp->params.bclk_rate % ssp->params.fsync_rate) {
1216 LOG_ERR("%s BCLK %d is not divisable by rate %d", __func__,
1217 ssp->params.bclk_rate, ssp->params.fsync_rate);
1218 ret = -EINVAL;
1219 goto out;
1220 }
1221
1222 /* must be enough BCLKs for data */
1223 bdiv = ssp->params.bclk_rate / ssp->params.fsync_rate;
1224 if (bdiv < ssp->params.tdm_slot_width * ssp->params.tdm_slots) {
1225 LOG_ERR("%s not enough BCLKs need %d", __func__,
1226 ssp->params.tdm_slot_width *
1227 ssp->params.tdm_slots);
1228 ret = -EINVAL;
1229 goto out;
1230 }
1231
1232 /* tdm_slot_width must be <= 38 for SSP */
1233 if (ssp->params.tdm_slot_width > 38) {
1234 LOG_ERR("%s tdm_slot_width %d > 38", __func__,
1235 ssp->params.tdm_slot_width);
1236 ret = -EINVAL;
1237 goto out;
1238 }
1239
1240 bdiv_min = ssp->params.tdm_slots *
1241 (ssp->params.tdm_per_slot_padding_flag ?
1242 ssp->params.tdm_slot_width : ssp->params.sample_valid_bits);
1243 if (bdiv < bdiv_min) {
1244 LOG_ERR("%s bdiv(%d) < bdiv_min(%d)", __func__,
1245 bdiv, bdiv_min);
1246 ret = -EINVAL;
1247 goto out;
1248 }
1249
1250 frame_end_padding = bdiv - bdiv_min;
1251 if (frame_end_padding > SSPSP2_FEP_MASK) {
1252 LOG_ERR("%s frame_end_padding too big: %u", __func__,
1253 frame_end_padding);
1254 ret = -EINVAL;
1255 goto out;
1256 }
1257
1258 /* format */
1259 switch (config->format & DAI_INTEL_IPC3_SSP_FMT_FORMAT_MASK) {
1260 case DAI_INTEL_IPC3_SSP_FMT_I2S:
1261
1262 start_delay = true;
1263
1264 sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots);
1265
1266 if (bdiv % 2) {
1267 LOG_ERR("%s bdiv %d is not divisible by 2", __func__, bdiv);
1268 ret = -EINVAL;
1269 goto out;
1270 }
1271
1272 /* set asserted frame length to half frame length */
1273 frame_len = bdiv / 2;
1274
1275 /*
1276 * handle frame polarity, I2S default is falling/active low,
1277 * non-inverted(inverted_frame=0) -- active low(SFRMP=0),
1278 * inverted(inverted_frame=1) -- rising/active high(SFRMP=1),
1279 * so, we should set SFRMP to inverted_frame.
1280 */
1281 sspsp |= SSPSP_SFRMP(inverted_frame);
1282
1283 /*
1284 * for I2S/LEFT_J, the padding has to happen at the end
1285 * of each slot
1286 */
1287 if (frame_end_padding % 2) {
1288 LOG_ERR("%s frame_end_padding %d is not divisible by 2",
1289 __func__, frame_end_padding);
1290 ret = -EINVAL;
1291 goto out;
1292 }
1293
1294 slot_end_padding = frame_end_padding / 2;
1295
1296 if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) {
1297 /* too big padding */
1298 LOG_ERR("%s slot_end_padding > %d", __func__,
1299 DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX);
1300 ret = -EINVAL;
1301 goto out;
1302 }
1303
1304 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1305 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1306 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1307
1308 break;
1309
1310 case DAI_INTEL_IPC3_SSP_FMT_LEFT_J:
1311
1312 /* default start_delay value is set to false */
1313
1314 sscr0 |= SSCR0_FRDC(ssp->params.tdm_slots);
1315
1316 /* LJDFD enable */
1317 sscr2 &= ~SSCR2_LJDFD;
1318
1319 if (bdiv % 2) {
1320 LOG_ERR("%s bdiv %d is not divisible by 2", __func__, bdiv);
1321 ret = -EINVAL;
1322 goto out;
1323 }
1324
1325 /* set asserted frame length to half frame length */
1326 frame_len = bdiv / 2;
1327
1328 /*
1329 * handle frame polarity, LEFT_J default is rising/active high,
1330 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
1331 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
1332 * so, we should set SFRMP to !inverted_frame.
1333 */
1334 sspsp |= SSPSP_SFRMP(!inverted_frame);
1335
1336 /*
1337 * for I2S/LEFT_J, the padding has to happen at the end
1338 * of each slot
1339 */
1340 if (frame_end_padding % 2) {
1341 LOG_ERR("%s frame_end_padding %d is not divisible by 2",
1342 __func__, frame_end_padding);
1343 ret = -EINVAL;
1344 goto out;
1345 }
1346
1347 slot_end_padding = frame_end_padding / 2;
1348
1349 if (slot_end_padding > 15) {
1350 /* can't handle padding over 15 bits */
1351 LOG_ERR("%s slot_end_padding %d > 15 bits", __func__,
1352 slot_end_padding);
1353 ret = -EINVAL;
1354 goto out;
1355 }
1356
1357 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1358 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1359 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1360
1361 break;
1362 case DAI_INTEL_IPC3_SSP_FMT_DSP_A:
1363
1364 start_delay = true;
1365
1366 /* fallthrough */
1367
1368 case DAI_INTEL_IPC3_SSP_FMT_DSP_B:
1369
1370 /* default start_delay value is set to false */
1371
1372 sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp->params.tdm_slots);
1373
1374 /* set asserted frame length */
1375 frame_len = 1; /* default */
1376
1377 if (cfs && ssp->params.frame_pulse_width > 0 &&
1378 ssp->params.frame_pulse_width <=
1379 DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) {
1380 frame_len = ssp->params.frame_pulse_width;
1381 }
1382
1383 /* frame_pulse_width must less or equal 38 */
1384 if (ssp->params.frame_pulse_width >
1385 DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) {
1386 LOG_ERR("%s frame_pulse_width > %d", __func__,
1387 DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX);
1388 ret = -EINVAL;
1389 goto out;
1390 }
1391 /*
1392 * handle frame polarity, DSP_B default is rising/active high,
1393 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
1394 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
1395 * so, we should set SFRMP to !inverted_frame.
1396 */
1397 sspsp |= SSPSP_SFRMP(!inverted_frame);
1398
1399 active_tx_slots = POPCOUNT(ssp->params.tx_slots);
1400 active_rx_slots = POPCOUNT(ssp->params.rx_slots);
1401
1402 /*
1403 * handle TDM mode, TDM mode has padding at the end of
1404 * each slot. The amount of padding is equal to result of
1405 * subtracting slot width and valid bits per slot.
1406 */
1407 if (ssp->params.tdm_per_slot_padding_flag) {
1408 frame_end_padding = bdiv - ssp->params.tdm_slots *
1409 ssp->params.tdm_slot_width;
1410
1411 slot_end_padding = ssp->params.tdm_slot_width -
1412 ssp->params.sample_valid_bits;
1413
1414 if (slot_end_padding >
1415 DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) {
1416 LOG_ERR("%s slot_end_padding > %d", __func__,
1417 DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX);
1418 ret = -EINVAL;
1419 goto out;
1420 }
1421
1422 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1423 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1424 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1425 }
1426
1427 sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
1428
1429 break;
1430 default:
1431 LOG_ERR("%s invalid format 0x%04x", __func__,
1432 config->format);
1433 ret = -EINVAL;
1434 goto out;
1435 }
1436
1437 if (start_delay) {
1438 sspsp |= SSPSP_FSRT;
1439 }
1440
1441 sspsp |= SSPSP_SFRMWDTH(frame_len);
1442
1443 data_size = ssp->params.sample_valid_bits;
1444
1445 if (data_size > 16) {
1446 sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
1447 } else {
1448 sscr0 |= SSCR0_DSIZE(data_size);
1449 }
1450
1451 /* setting TFT and RFT */
1452 switch (ssp->params.sample_valid_bits) {
1453 case 16:
1454 /* use 2 bytes for each slot */
1455 sample_width = 2;
1456 break;
1457 case 24:
1458 case 32:
1459 /* use 4 bytes for each slot */
1460 sample_width = 4;
1461 break;
1462 default:
1463 LOG_ERR("%s sample_valid_bits %d", __func__,
1464 ssp->params.sample_valid_bits);
1465 ret = -EINVAL;
1466 goto out;
1467 }
1468
1469 tft = MIN(DAI_INTEL_SSP_FIFO_DEPTH - DAI_INTEL_SSP_FIFO_WATERMARK,
1470 sample_width * active_tx_slots);
1471 rft = MIN(DAI_INTEL_SSP_FIFO_DEPTH - DAI_INTEL_SSP_FIFO_WATERMARK,
1472 sample_width * active_rx_slots);
1473
1474 sscr3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
1475
1476 sys_write32(sscr0, dai_base(dp) + SSCR0);
1477 sys_write32(sscr1, dai_base(dp) + SSCR1);
1478 sys_write32(sscr2, dai_base(dp) + SSCR2);
1479 sys_write32(sscr3, dai_base(dp) + SSCR3);
1480 sys_write32(sspsp, dai_base(dp) + SSPSP);
1481 sys_write32(sspsp2, dai_base(dp) + SSPSP2);
1482 sys_write32(ssioc, dai_base(dp) + SSIOC);
1483 sys_write32(ssto, dai_base(dp) + SSTO);
1484 sys_write32(sstsa, dai_base(dp) + SSTSA);
1485 sys_write32(ssrsa, dai_base(dp) + SSRSA);
1486
1487 LOG_INF("%s sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
1488 __func__, sscr0, sscr1, ssto, sspsp);
1489 LOG_INF("%s sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x, ssioc = 0x%08x",
1490 __func__, sscr2, sspsp2, sscr3, ssioc);
1491 LOG_INF("%s ssrsa = 0x%08x, sstsa = 0x%08x",
1492 __func__, ssrsa, sstsa);
1493
1494 ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1495 ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1496
1497 clk:
1498 switch (config->options & DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK) {
1499 case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS:
1500 if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) {
1501 ret = dai_ssp_mclk_prepare_enable(dp);
1502 if (ret < 0) {
1503 goto out;
1504 }
1505
1506 ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
1507
1508 LOG_INF("%s hw_params stage: enabled MCLK clocks for SSP%d...",
1509 __func__, dp->index);
1510 }
1511
1512 if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) {
1513 bool enable_sse = false;
1514
1515 if (!(ssp->clk_active & SSP_CLK_BCLK_ACTIVE)) {
1516 enable_sse = true;
1517 }
1518
1519 ret = dai_ssp_bclk_prepare_enable(dp);
1520 if (ret < 0) {
1521 goto out;
1522 }
1523
1524 ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
1525
1526 if (enable_sse) {
1527
1528 /* enable TRSE/RSRE before SSE */
1529 dai_ssp_update_bits(dp, SSCR1,
1530 SSCR1_TSRE | SSCR1_RSRE,
1531 SSCR1_TSRE | SSCR1_RSRE);
1532
1533 /* enable port */
1534 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1535
1536 LOG_INF("%s SSE set for SSP%d", __func__, dp->index);
1537 }
1538
1539 LOG_INF("%s hw_params stage: enabled BCLK clocks for SSP%d...",
1540 __func__, dp->index);
1541 }
1542 break;
1543 case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE:
1544 /* disable SSP port if no users */
1545 if (ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING ||
1546 ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) {
1547 LOG_INF("%s hw_free stage: ignore since SSP%d still in use",
1548 __func__, dp->index);
1549 break;
1550 }
1551
1552 if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) {
1553 LOG_INF("%s hw_free stage: releasing BCLK clocks for SSP%d...",
1554 __func__, dp->index);
1555 if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
1556 /* clear TRSE/RSRE before SSE */
1557 dai_ssp_update_bits(dp, SSCR1,
1558 SSCR1_TSRE | SSCR1_RSRE,
1559 0);
1560
1561 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0);
1562 LOG_INF("%s SSE clear for SSP%d", __func__, dp->index);
1563 }
1564 dai_ssp_bclk_disable_unprepare(dp);
1565 ssp->clk_active &= ~SSP_CLK_BCLK_ES_REQ;
1566 }
1567 if (ssp->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) {
1568 LOG_INF("%s hw_free stage: releasing MCLK clocks for SSP%d...",
1569 __func__, dp->index);
1570 dai_ssp_mclk_disable_unprepare(dp);
1571 ssp->clk_active &= ~SSP_CLK_MCLK_ES_REQ;
1572 }
1573 break;
1574 default:
1575 break;
1576 }
1577 out:
1578
1579 k_spin_unlock(&dp->lock, key);
1580
1581 return ret;
1582 }
1583
dai_ssp_check_aux_data(struct ssp_intel_aux_tlv * aux_tlv,int aux_len,int parsed_len)1584 static int dai_ssp_check_aux_data(struct ssp_intel_aux_tlv *aux_tlv, int aux_len, int parsed_len)
1585 {
1586 struct ssp_intel_sync_ctl *sync;
1587 int size, size_left;
1588
1589 switch (aux_tlv->type) {
1590 case SSP_MN_DIVIDER_CONTROLS:
1591 size = sizeof(struct ssp_intel_mn_ctl);
1592 break;
1593 case SSP_DMA_CLK_CONTROLS:
1594 size = sizeof(struct ssp_intel_clk_ctl);
1595 break;
1596 case SSP_DMA_TRANSMISSION_START:
1597 case SSP_DMA_TRANSMISSION_STOP:
1598 size = sizeof(struct ssp_intel_tr_ctl);
1599 case SSP_DMA_ALWAYS_RUNNING_MODE:
1600 size = sizeof(struct ssp_intel_run_ctl);
1601 break;
1602 case SSP_DMA_SYNC_DATA:
1603 size = sizeof(struct ssp_intel_sync_ctl);
1604 sync = (struct ssp_intel_sync_ctl *)&aux_tlv->val;
1605 size += sync->count * sizeof(struct ssp_intel_node_ctl);
1606 break;
1607 case SSP_DMA_CLK_CONTROLS_EXT:
1608 size = sizeof(struct ssp_intel_ext_ctl);
1609 break;
1610 case SSP_LINK_CLK_SOURCE:
1611 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
1612 size = sizeof(struct ssp_intel_link_ctl);
1613 break;
1614 #else
1615 return 0;
1616 #endif
1617 default:
1618 LOG_ERR("%s undefined aux data type %u", __func__, aux_tlv->type);
1619 return -EINVAL;
1620 }
1621
1622 /* check for malformed struct, size greater than aux_data or described in tlv */
1623 size_left = aux_len - parsed_len - sizeof(struct ssp_intel_aux_tlv);
1624 if (size > size_left || size != aux_tlv->size) {
1625 LOG_ERR("%s malformed struct, size %d, size_left %d, tlv_size %d", __func__, size,
1626 size_left, aux_tlv->size);
1627 return -EINVAL;
1628 }
1629
1630 return 0;
1631 }
1632
dai_ssp_parse_aux_data(struct dai_intel_ssp * dp,const void * spec_config)1633 static int dai_ssp_parse_aux_data(struct dai_intel_ssp *dp, const void *spec_config)
1634 {
1635 const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob = spec_config;
1636 int aux_tlv_size = sizeof(struct ssp_intel_aux_tlv);
1637 int hop, i, j, cfg_len, pre_aux_len, aux_len;
1638 struct ssp_intel_aux_tlv *aux_tlv;
1639 struct ssp_intel_mn_ctl *mn;
1640 struct ssp_intel_clk_ctl *clk;
1641 struct ssp_intel_tr_ctl *tr;
1642 struct ssp_intel_run_ctl *run;
1643 struct ssp_intel_node_ctl *node;
1644 struct ssp_intel_sync_ctl *sync;
1645 struct ssp_intel_ext_ctl *ext;
1646 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
1647 struct ssp_intel_link_ctl *link;
1648 #endif
1649 uint8_t *aux_ptr;
1650
1651 cfg_len = blob->size;
1652 pre_aux_len = sizeof(*blob) + blob->i2s_mclk_control.mdivrcnt * sizeof(uint32_t);
1653 aux_len = cfg_len - pre_aux_len;
1654 aux_ptr = (uint8_t *)blob + pre_aux_len;
1655
1656 if (aux_len <= 0)
1657 return 0;
1658
1659 for (i = 0; i < aux_len; i += hop) {
1660 aux_tlv = (struct ssp_intel_aux_tlv *)(aux_ptr);
1661 if (dai_ssp_check_aux_data(aux_tlv, aux_len, i)) {
1662 return -EINVAL;
1663 }
1664 switch (aux_tlv->type) {
1665 case SSP_MN_DIVIDER_CONTROLS:
1666 mn = (struct ssp_intel_mn_ctl *)&aux_tlv->val;
1667 LOG_INF("%s mn div_m %u, div_n %u", __func__, mn->div_m, mn->div_n);
1668 break;
1669 case SSP_DMA_CLK_CONTROLS:
1670 clk = (struct ssp_intel_clk_ctl *)&aux_tlv->val;
1671 LOG_INF("%s clk start %u, stop %u", __func__, clk->start, clk->stop);
1672 break;
1673 case SSP_DMA_TRANSMISSION_START:
1674 case SSP_DMA_TRANSMISSION_STOP:
1675 tr = (struct ssp_intel_tr_ctl *)&aux_tlv->val;
1676 LOG_INF("%s tr sampling frequency %u, bit_depth %u, channel_map %u,",
1677 __func__, tr->sampling_frequency, tr->bit_depth, tr->channel_map);
1678 LOG_INF("channel_config %u, interleaving_style %u, format %u",
1679 tr->channel_config, tr->interleaving_style, tr->format);
1680 break;
1681 case SSP_DMA_ALWAYS_RUNNING_MODE:
1682 run = (struct ssp_intel_run_ctl *)&aux_tlv->val;
1683 LOG_INF("%s run enabled %u", __func__, run->enabled);
1684 break;
1685 case SSP_DMA_SYNC_DATA:
1686 sync = (struct ssp_intel_sync_ctl *)&aux_tlv->val;
1687 LOG_INF("%s sync sync_denominator %u, count %u", __func__,
1688 sync->sync_denominator, sync->count);
1689 node = (struct ssp_intel_node_ctl *)((uint8_t *)sync +
1690 sizeof(struct ssp_intel_sync_ctl));
1691 for (j = 0; j < sync->count; j++) {
1692 LOG_INF("%s node node_id %u, sampling_rate %u", __func__,
1693 node->node_id, node->sampling_rate);
1694 node++;
1695 }
1696 break;
1697 case SSP_DMA_CLK_CONTROLS_EXT:
1698 ext = (struct ssp_intel_ext_ctl *)&aux_tlv->val;
1699 LOG_INF("%s ext ext_data %u", __func__, ext->ext_data);
1700 break;
1701 case SSP_LINK_CLK_SOURCE:
1702 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
1703 link = (struct ssp_intel_link_ctl *)&aux_tlv->val;
1704
1705 #if CONFIG_SOC_INTEL_ACE15_MTPM
1706 sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) |
1707 I2CLCTL_MLCS(link->clock_source), dai_ip_base(dp) +
1708 I2SLCTL_OFFSET);
1709 #elif CONFIG_SOC_INTEL_ACE20_LNL
1710 sys_write32(sys_read32(dai_i2svss_base(dp) + I2SLCTL_OFFSET) |
1711 I2CLCTL_MLCS(link->clock_source), dai_i2svss_base(dp) +
1712 I2SLCTL_OFFSET);
1713 #endif
1714 LOG_INF("%s link clock_source %u", __func__, link->clock_source);
1715 #endif
1716 break;
1717 default:
1718 LOG_ERR("%s undefined aux data type %u", __func__, aux_tlv->type);
1719 return -EINVAL;
1720 }
1721
1722 hop = aux_tlv->size + aux_tlv_size;
1723 aux_ptr += hop;
1724 }
1725
1726 return 0;
1727 }
1728
dai_ssp_set_clock_control_ver_1_5(struct dai_intel_ssp * dp,const struct dai_intel_ipc4_ssp_mclk_config_2 * cc)1729 static int dai_ssp_set_clock_control_ver_1_5(struct dai_intel_ssp *dp,
1730 const struct dai_intel_ipc4_ssp_mclk_config_2 *cc)
1731 {
1732 /* currently we only support 1 divider */
1733 if (cc->mdivrcnt != 1) {
1734 LOG_ERR("%s bad clock divider count %u", __func__,
1735 cc->mdivrcnt);
1736 return -EINVAL;
1737 }
1738
1739 /* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
1740 * mclk and bclk at this time.
1741 */
1742 dai_ssp_mn_set_mclk_blob(dp, cc->mdivctlr, cc->mdivr[0]);
1743
1744 return 0;
1745 }
1746
dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp * dp,const struct dai_intel_ipc4_ssp_mclk_config * cc)1747 static int dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp *dp,
1748 const struct dai_intel_ipc4_ssp_mclk_config *cc)
1749 {
1750 /* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
1751 * mclk and bclk at this time.
1752 */
1753 dai_ssp_mn_set_mclk_blob(dp, cc->mdivc, cc->mdivr);
1754
1755 return 0;
1756 }
1757
dai_ssp_set_reg_config(struct dai_intel_ssp * dp,const struct dai_config * cfg,const struct dai_intel_ipc4_ssp_config * regs)1758 static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg,
1759 const struct dai_intel_ipc4_ssp_config *regs)
1760 {
1761 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1762 uint32_t ssc0, sstsa, ssrsa;
1763
1764 ssc0 = regs->ssc0;
1765 sstsa = regs->sstsa;
1766 ssrsa = regs->ssrsa;
1767
1768 sys_write32(ssc0, dai_base(dp) + SSCR0);
1769 sys_write32(regs->ssc2 & ~SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
1770 sys_write32(regs->ssc1, dai_base(dp) + SSCR1);
1771 sys_write32(regs->ssc2 | SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
1772 sys_write32(regs->ssc2, dai_base(dp) + SSCR2);
1773 sys_write32(regs->ssc3, dai_base(dp) + SSCR3);
1774 sys_write32(regs->sspsp, dai_base(dp) + SSPSP);
1775 sys_write32(regs->sspsp2, dai_base(dp) + SSPSP2);
1776 sys_write32(regs->ssioc, dai_base(dp) + SSIOC);
1777 sys_write32(regs->sscto, dai_base(dp) + SSTO);
1778 sys_write32(sstsa, dai_base(dp) + SSTSA);
1779 sys_write32(ssrsa, dai_base(dp) + SSRSA);
1780
1781 LOG_INF("%s sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x", __func__,
1782 ssc0, regs->ssc1, regs->sscto, regs->sspsp);
1783 LOG_INF("%s sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x", __func__,
1784 regs->ssc2, regs->sspsp2, regs->ssc3);
1785 LOG_INF("%s ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", __func__,
1786 regs->ssioc, ssrsa, sstsa);
1787
1788 ssp->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0);
1789 if (ssc0 & SSCR0_EDSS) {
1790 ssp->params.sample_valid_bits += 16;
1791 }
1792
1793 ssp->params.tdm_slots = SSCR0_FRDC_GET(ssc0);
1794 ssp->params.tx_slots = SSTSA_GET(sstsa);
1795 ssp->params.rx_slots = SSRSA_GET(ssrsa);
1796 ssp->params.fsync_rate = cfg->rate;
1797
1798 ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1799 ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1800 }
1801
dai_ssp_set_config_blob(struct dai_intel_ssp * dp,const struct dai_config * cfg,const void * spec_config)1802 static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_config *cfg,
1803 const void *spec_config)
1804 {
1805 const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config;
1806 const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config;
1807 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1808 int err;
1809
1810 /* set config only once for playback or capture */
1811 if (ssp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY ||
1812 ssp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY)
1813 return 0;
1814
1815 if (blob15->version == SSP_BLOB_VER_1_5) {
1816 err = dai_ssp_parse_aux_data(dp, spec_config);
1817 if (err)
1818 return err;
1819 dai_ssp_set_reg_config(dp, cfg, &blob15->i2s_ssp_config);
1820 err = dai_ssp_set_clock_control_ver_1_5(dp, &blob15->i2s_mclk_control);
1821 if (err)
1822 return err;
1823 } else {
1824 dai_ssp_set_reg_config(dp, cfg, &blob->i2s_driver_config.i2s_config);
1825 err = dai_ssp_set_clock_control_ver_1(dp, &blob->i2s_driver_config.mclk_config);
1826 if (err)
1827 return err;
1828 }
1829
1830 ssp->clk_active |= SSP_CLK_MCLK_ES_REQ;
1831 /* enable TRSE/RSRE before SSE */
1832 dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, SSCR1_TSRE | SSCR1_RSRE);
1833
1834 /* enable port */
1835 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1836 ssp->clk_active |= SSP_CLK_BCLK_ES_REQ;
1837
1838 return 0;
1839 }
1840
1841 /*
1842 * Portion of the SSP configuration should be applied just before the
1843 * SSP dai is activated, for either power saving or params runtime
1844 * configurable flexibility.
1845 */
dai_ssp_pre_start(struct dai_intel_ssp * dp)1846 static int dai_ssp_pre_start(struct dai_intel_ssp *dp)
1847 {
1848 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1849 int ret = 0;
1850
1851 LOG_INF("%s", __func__);
1852
1853 /*
1854 * We will test if mclk/bclk is configured in
1855 * ssp_mclk/bclk_prepare_enable/disable functions
1856 */
1857 if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
1858 /* MCLK config */
1859 ret = dai_ssp_mclk_prepare_enable(dp);
1860 if (ret < 0) {
1861 return ret;
1862 }
1863 }
1864
1865 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1866 ret = dai_ssp_bclk_prepare_enable(dp);
1867 }
1868
1869 return ret;
1870 }
1871
1872 /*
1873 * For power saving, we should do kinds of power release when the SSP
1874 * dai is changed to inactive, though the runtime param configuration
1875 * don't have to be reset.
1876 */
dai_ssp_post_stop(struct dai_intel_ssp * dp)1877 static void dai_ssp_post_stop(struct dai_intel_ssp *dp)
1878 {
1879 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1880
1881 /* release clocks if SSP is inactive */
1882 if (ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING &&
1883 ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) {
1884 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1885 LOG_INF("%s releasing BCLK clocks for SSP%d...",
1886 __func__, dp->index);
1887 dai_ssp_bclk_disable_unprepare(dp);
1888 }
1889 if (!(ssp->clk_active & SSP_CLK_MCLK_ES_REQ)) {
1890 LOG_INF("%s releasing MCLK clocks for SSP%d...",
1891 __func__, dp->index);
1892 dai_ssp_mclk_disable_unprepare(dp);
1893 }
1894 }
1895 }
1896
dai_ssp_early_start(struct dai_intel_ssp * dp,int direction)1897 static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction)
1898 {
1899 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1900 k_spinlock_key_t key;
1901
1902 key = k_spin_lock(&dp->lock);
1903
1904 /* request mclk/bclk */
1905 dai_ssp_pre_start(dp);
1906
1907 if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) {
1908 /* enable TRSE/RSRE before SSE */
1909 dai_ssp_update_bits(dp, SSCR1,
1910 SSCR1_TSRE | SSCR1_RSRE,
1911 SSCR1_TSRE | SSCR1_RSRE);
1912
1913 /* enable port */
1914 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1915 LOG_INF("%s SSE set for SSP%d", __func__, dp->index);
1916 }
1917
1918 k_spin_unlock(&dp->lock, key);
1919 }
1920
1921 /* start the SSP for either playback or capture */
dai_ssp_start(struct dai_intel_ssp * dp,int direction)1922 static void dai_ssp_start(struct dai_intel_ssp *dp, int direction)
1923 {
1924 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1925 k_spinlock_key_t key;
1926
1927 key = k_spin_lock(&dp->lock);
1928
1929 LOG_INF("%s", __func__);
1930
1931 /* enable DMA */
1932 if (direction == DAI_DIR_PLAYBACK) {
1933 dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN);
1934 } else {
1935 dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN);
1936 }
1937
1938 ssp->state[direction] = DAI_STATE_RUNNING;
1939
1940 /*
1941 * Wait to get valid fifo status in clock consumer mode. TODO it's
1942 * uncertain which SSP clock consumer modes need the delay atm, but
1943 * these can be added here when confirmed.
1944 */
1945 switch (ssp->config.format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1946 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1947 break;
1948 default:
1949 /* delay for all SSP consumed clocks atm - see above */
1950 /* ssp_wait_delay(PLATFORM_SSP_DELAY); */
1951 k_busy_wait(DAI_INTEL_SSP_PLATFORM_DELAY_US);
1952 break;
1953 }
1954
1955 k_spin_unlock(&dp->lock, key);
1956 }
1957
1958 /* stop the SSP for either playback or capture */
dai_ssp_stop(struct dai_intel_ssp * dp,int direction)1959 static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction)
1960 {
1961 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1962 k_spinlock_key_t key;
1963
1964 key = k_spin_lock(&dp->lock);
1965
1966 /*
1967 * Wait to get valid fifo status in clock consumer mode. TODO it's
1968 * uncertain which SSP clock consumer modes need the delay atm, but
1969 * these can be added here when confirmed.
1970 */
1971 switch (ssp->config.format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1972 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1973 break;
1974 default:
1975 /* delay for all SSP consumed clocks atm - see above */
1976 k_busy_wait(DAI_INTEL_SSP_PLATFORM_DELAY_US);
1977 break;
1978 }
1979
1980 /* stop Rx if neeed */
1981 if (direction == DAI_DIR_CAPTURE &&
1982 ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) {
1983 dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0);
1984 dai_ssp_empty_rx_fifo(dp);
1985 ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1986 LOG_INF("%s RX stop", __func__);
1987 }
1988
1989 /* stop Tx if needed */
1990 if (direction == DAI_DIR_PLAYBACK &&
1991 ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) {
1992 dai_ssp_empty_tx_fifo(dp);
1993 dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0);
1994 ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1995 LOG_INF("%sTX stop", __func__);
1996 }
1997
1998 /* disable SSP port if no users */
1999 if (ssp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING &&
2000 ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING) {
2001 bool clear_rse_bits = COND_CODE_1(CONFIG_INTEL_ADSP_CAVS,
2002 (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)),
2003 (true));
2004 if (clear_rse_bits) {
2005 /* clear TRSE/RSRE before SSE */
2006 dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, 0);
2007 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0);
2008 LOG_INF("%s SSE clear SSP%d", __func__, dp->index);
2009 }
2010 }
2011
2012 dai_ssp_post_stop(dp);
2013
2014 k_spin_unlock(&dp->lock, key);
2015 }
2016
dai_ssp_pause(struct dai_intel_ssp * dp,int direction)2017 static void dai_ssp_pause(struct dai_intel_ssp *dp, int direction)
2018 {
2019 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2020
2021 if (direction == DAI_DIR_CAPTURE) {
2022 LOG_INF("%s RX", __func__);
2023 } else {
2024 LOG_INF("%s TX", __func__);
2025 }
2026
2027 ssp->state[direction] = DAI_STATE_PAUSED;
2028 }
2029
dai_ssp_trigger(const struct device * dev,enum dai_dir dir,enum dai_trigger_cmd cmd)2030 static int dai_ssp_trigger(const struct device *dev, enum dai_dir dir,
2031 enum dai_trigger_cmd cmd)
2032 {
2033 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2034 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2035 int array_index = SSP_ARRAY_INDEX(dir);
2036
2037 LOG_DBG("%s cmd %d", __func__, cmd);
2038
2039 switch (cmd) {
2040 case DAI_TRIGGER_START:
2041 if (ssp->state[array_index] == DAI_STATE_PAUSED ||
2042 ssp->state[array_index] == DAI_STATE_PRE_RUNNING) {
2043 dai_ssp_start(dp, array_index);
2044 }
2045 break;
2046 case DAI_TRIGGER_STOP:
2047 dai_ssp_stop(dp, array_index);
2048 break;
2049 case DAI_TRIGGER_PAUSE:
2050 dai_ssp_pause(dp, array_index);
2051 break;
2052 case DAI_TRIGGER_PRE_START:
2053 dai_ssp_early_start(dp, array_index);
2054 break;
2055 default:
2056 break;
2057 }
2058
2059 return 0;
2060 }
2061
dai_ssp_config_get(const struct device * dev,struct dai_config * cfg,enum dai_dir dir)2062 static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, enum dai_dir dir)
2063 {
2064 struct dai_config *params = (struct dai_config *)dev->config;
2065 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2066 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2067
2068 if (!cfg) {
2069 return -EINVAL;
2070 }
2071
2072 if (!ssp) {
2073 *cfg = *params;
2074 return 0;
2075 }
2076
2077 params->rate = ssp->params.fsync_rate;
2078
2079 if (dir == DAI_DIR_PLAYBACK) {
2080 params->channels = POPCOUNT(ssp->params.tx_slots);
2081 } else {
2082 params->channels = POPCOUNT(ssp->params.rx_slots);
2083 }
2084
2085 params->word_size = ssp->params.sample_valid_bits;
2086
2087 *cfg = *params;
2088
2089 return 0;
2090 }
2091
dai_ssp_config_set(const struct device * dev,const struct dai_config * cfg,const void * bespoke_cfg)2092 static int dai_ssp_config_set(const struct device *dev, const struct dai_config *cfg,
2093 const void *bespoke_cfg)
2094 {
2095 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2096 int ret;
2097
2098 if (cfg->type == DAI_INTEL_SSP) {
2099 ret = dai_ssp_set_config_tplg(dp, cfg, bespoke_cfg);
2100 } else {
2101 ret = dai_ssp_set_config_blob(dp, cfg, bespoke_cfg);
2102 }
2103 dai_ssp_program_channel_map(dp, cfg, dp->index);
2104 return ret;
2105 }
2106
dai_ssp_get_properties(const struct device * dev,enum dai_dir dir,int stream_id)2107 static const struct dai_properties *dai_ssp_get_properties(const struct device *dev,
2108 enum dai_dir dir, int stream_id)
2109 {
2110 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2111 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2112 struct dai_properties *prop = &ssp->props;
2113 int array_index = SSP_ARRAY_INDEX(dir);
2114
2115 prop->fifo_address = dp->plat_data.fifo[array_index].offset;
2116 prop->dma_hs_id = dp->plat_data.fifo[array_index].handshake;
2117
2118 if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) {
2119 prop->reg_init_delay = 0;
2120 } else {
2121 prop->reg_init_delay = ssp->params.bclk_delay;
2122 }
2123
2124 LOG_INF("%s dai_index %u", __func__, dp->index);
2125 LOG_INF("%s fifo %u", __func__, prop->fifo_address);
2126 LOG_INF("%s handshake %u", __func__, prop->dma_hs_id);
2127 LOG_INF("%s init delay %u", __func__, prop->reg_init_delay);
2128
2129 return prop;
2130 }
2131
dai_ssp_probe(struct dai_intel_ssp * dp)2132 static int dai_ssp_probe(struct dai_intel_ssp *dp)
2133 {
2134 struct dai_intel_ssp_pdata *ssp;
2135
2136 if (dai_get_drvdata(dp)) {
2137 return -EEXIST; /* already created */
2138 }
2139
2140 /* allocate private data */
2141 ssp = k_calloc(1, sizeof(*ssp));
2142 if (!ssp) {
2143 LOG_ERR("%s alloc failed", __func__);
2144 return -ENOMEM;
2145 }
2146 dai_set_drvdata(dp, ssp);
2147
2148 ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY;
2149 ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY;
2150
2151 #if CONFIG_INTEL_MN
2152 /* Reset M/N, power-gating functions need it */
2153 dai_ssp_mn_reset_bclk_divider(dp, dp->index);
2154 #endif
2155
2156 /* Enable SSP power */
2157 dai_ssp_pm_runtime_en_ssp_power(dp, dp->index);
2158
2159 /* Disable dynamic clock gating before touching any register */
2160 dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index);
2161
2162 dai_ssp_empty_rx_fifo(dp);
2163
2164 return 0;
2165 }
2166
dai_ssp_remove(struct dai_intel_ssp * dp)2167 static int dai_ssp_remove(struct dai_intel_ssp *dp)
2168 {
2169 dai_ssp_pm_runtime_en_ssp_clk_gating(dp, dp->index);
2170
2171 dai_ssp_mclk_disable_unprepare(dp);
2172 dai_ssp_bclk_disable_unprepare(dp);
2173
2174 /* Disable SSP power */
2175 dai_ssp_pm_runtime_dis_ssp_power(dp, dp->index);
2176
2177 k_free(dai_get_drvdata(dp));
2178 dai_set_drvdata(dp, NULL);
2179
2180 return 0;
2181 }
2182
ssp_pm_action(const struct device * dev,enum pm_device_action action)2183 static int ssp_pm_action(const struct device *dev, enum pm_device_action action)
2184 {
2185 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2186 switch (action) {
2187 case PM_DEVICE_ACTION_SUSPEND:
2188 dai_ssp_remove(dp);
2189 break;
2190 case PM_DEVICE_ACTION_RESUME:
2191 dai_ssp_probe(dp);
2192 break;
2193 case PM_DEVICE_ACTION_TURN_OFF:
2194 case PM_DEVICE_ACTION_TURN_ON:
2195 /* All device pm is handled during resume and suspend */
2196 break;
2197 default:
2198 return -ENOTSUP;
2199 }
2200
2201 return 0;
2202 }
2203
ssp_init(const struct device * dev)2204 static int ssp_init(const struct device *dev)
2205 {
2206 if (pm_device_on_power_domain(dev)) {
2207 pm_device_init_off(dev);
2208 } else {
2209 pm_device_init_suspended(dev);
2210 }
2211
2212 return pm_device_runtime_enable(dev);
2213 }
2214
2215 static struct dai_driver_api dai_intel_ssp_api_funcs = {
2216 .probe = pm_device_runtime_get,
2217 .remove = pm_device_runtime_put,
2218 .config_set = dai_ssp_config_set,
2219 .config_get = dai_ssp_config_get,
2220 .trigger = dai_ssp_trigger,
2221 .get_properties = dai_ssp_get_properties,
2222 };
2223
2224 static struct dai_intel_ssp_freq_table ssp_freq_table[] = {
2225 { DT_PROP(DT_NODELABEL(audioclk), clock_frequency),
2226 DT_PROP(DT_NODELABEL(audioclk), clock_frequency) / 1000},
2227 { DT_PROP(DT_NODELABEL(sysclk), clock_frequency),
2228 DT_PROP(DT_NODELABEL(sysclk), clock_frequency) / 1000},
2229 { DT_PROP(DT_NODELABEL(pllclk), clock_frequency),
2230 DT_PROP(DT_NODELABEL(pllclk), clock_frequency) / 1000},
2231 };
2232
2233 static uint32_t ssp_freq_sources[] = {
2234 DAI_INTEL_SSP_CLOCK_AUDIO_CARDINAL,
2235 DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR,
2236 DAI_INTEL_SSP_CLOCK_PLL_FIXED,
2237 };
2238
2239 static struct dai_intel_ssp_mn ssp_mn_divider = {
2240 .base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(ssp0), 1),
2241 };
2242
2243 static const char irq_name_level5_z[] = "level5";
2244
2245 #define DAI_INTEL_SSP_DEVICE_INIT(n) \
2246 static struct dai_config dai_intel_ssp_config_##n = { \
2247 .type = DAI_INTEL_SSP, \
2248 .dai_index = n, \
2249 }; \
2250 static struct dai_intel_ssp dai_intel_ssp_data_##n = { \
2251 .index = n, \
2252 .plat_data = { \
2253 .base = DT_INST_REG_ADDR_BY_IDX(n, 0), \
2254 IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(sspbase)), \
2255 (.ip_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(sspbase), 0),))\
2256 .shim_base = DT_REG_ADDR_BY_IDX(DT_NODELABEL(shim), 0), \
2257 IF_ENABLED(DT_NODE_EXISTS(DT_NODELABEL(hdamlssp)), \
2258 (.hdamlssp_base = DT_REG_ADDR(DT_NODELABEL(hdamlssp)),))\
2259 IF_ENABLED(DT_INST_PROP_HAS_IDX(n, i2svss, 0), \
2260 (.i2svss_base = DT_INST_PROP_BY_IDX(n, i2svss, 0),))\
2261 .irq = n, \
2262 .irq_name = irq_name_level5_z, \
2263 .fifo[DAI_DIR_PLAYBACK].offset = \
2264 DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \
2265 .fifo[DAI_DIR_PLAYBACK].handshake = \
2266 DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \
2267 .fifo[DAI_DIR_CAPTURE].offset = \
2268 DT_INST_REG_ADDR_BY_IDX(n, 0) + SSDR, \
2269 .fifo[DAI_DIR_CAPTURE].handshake = \
2270 DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \
2271 .mn_inst = &ssp_mn_divider, \
2272 .ftable = ssp_freq_table, \
2273 .fsources = ssp_freq_sources, \
2274 }, \
2275 }; \
2276 \
2277 PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \
2278 \
2279 DEVICE_DT_INST_DEFINE(n, \
2280 ssp_init, PM_DEVICE_DT_INST_GET(n), \
2281 &dai_intel_ssp_data_##n, \
2282 &dai_intel_ssp_config_##n, \
2283 POST_KERNEL, 32, \
2284 &dai_intel_ssp_api_funcs);
2285
2286 DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_SSP_DEVICE_INIT)
2287