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