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[%#x]=%#x, waited for: mask %#x, val %#x, us %u", reg,
747 sys_read32(reg), mask, val, (uint32_t)us);
748 return -EIO;
749 }
750
751 return 0;
752 }
753
dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp * dp,uint32_t ssp_index)754 static inline void dai_ssp_pm_runtime_dis_ssp_clk_gating(struct dai_intel_ssp *dp,
755 uint32_t ssp_index)
756 {
757 #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING
758 uint32_t shim_reg;
759
760 shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) |
761 (ssp_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ?
762 SHIM_CLKCTL_I2SFDCGB(ssp_index) :
763 SHIM_CLKCTL_I2SEFDCGB(ssp_index -
764 CONFIG_DAI_INTEL_SSP_NUM_BASE));
765
766 sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL);
767
768 LOG_INF("ssp_index %d CLKCTL %08x", ssp_index, shim_reg);
769 #endif
770 }
771
dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp * dp,uint32_t ssp_index)772 static inline void dai_ssp_pm_runtime_en_ssp_clk_gating(struct dai_intel_ssp *dp,
773 uint32_t ssp_index)
774 {
775 #if CONFIG_DAI_SSP_CLK_FORCE_DYNAMIC_CLOCK_GATING
776 uint32_t shim_reg;
777
778 shim_reg = sys_read32(dai_shim_base(dp) + SHIM_CLKCTL) &
779 ~(ssp_index < CONFIG_DAI_INTEL_SSP_NUM_BASE ?
780 SHIM_CLKCTL_I2SFDCGB(ssp_index) :
781 SHIM_CLKCTL_I2SEFDCGB(ssp_index -
782 CONFIG_DAI_INTEL_SSP_NUM_BASE));
783
784 sys_write32(shim_reg, dai_shim_base(dp) + SHIM_CLKCTL);
785
786 LOG_INF("ssp_index %d CLKCTL %08x", ssp_index, shim_reg);
787 #endif
788 }
789
dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp * dp,uint32_t ssp_index)790 static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t ssp_index)
791 {
792 #if CONFIG_DAI_SSP_HAS_POWER_CONTROL
793 int ret;
794
795 LOG_INF("SSP%d", ssp_index);
796 #if SSP_IP_VER < SSP_IP_VER_2_0
797 sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) | I2SLCTL_SPA(ssp_index),
798 dai_ip_base(dp) + I2SLCTL_OFFSET);
799
800 /* Check if powered on. */
801 ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
802 I2SLCTL_CPA(ssp_index), I2SLCTL_CPA(ssp_index),
803 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
804 #elif SSP_IP_VER > SSP_IP_VER_1_5
805 sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) |
806 I2SLCTL_SPA(ssp_index),
807 dai_hdamlssp_base(dp) + I2SLCTL_OFFSET);
808 /* Check if powered on. */
809 ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET,
810 I2SLCTL_CPA(ssp_index), I2SLCTL_CPA(ssp_index),
811 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
812 #else
813 #error need to define SOC
814 #endif
815 if (ret) {
816 LOG_WRN("SSP%d: timeout", ssp_index);
817 }
818 #else
819 ARG_UNUSED(dp);
820 ARG_UNUSED(ssp_index);
821 #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
822 }
823
dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp * dp,uint32_t ssp_index)824 static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t ssp_index)
825 {
826 #if CONFIG_DAI_SSP_HAS_POWER_CONTROL
827 int ret;
828
829 LOG_INF("SSP%d", ssp_index);
830 #if SSP_IP_VER < SSP_IP_VER_2_0
831 sys_write32(sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(ssp_index)),
832 dai_ip_base(dp) + I2SLCTL_OFFSET);
833
834 /* Check if powered off. */
835 ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET,
836 I2SLCTL_CPA(ssp_index), 0,
837 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
838
839 #elif SSP_IP_VER > SSP_IP_VER_1_5
840 sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(ssp_index)),
841 dai_hdamlssp_base(dp) + I2SLCTL_OFFSET);
842
843 /* Check if powered off. */
844 ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET,
845 I2SLCTL_CPA(ssp_index), 0,
846 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
847 #else
848 #error need to define SOC
849 #endif
850 if (ret) {
851 LOG_WRN("SSP%d: timeout", ssp_index);
852 }
853 #else
854 ARG_UNUSED(dp);
855 ARG_UNUSED(ssp_index);
856 #endif /* CONFIG_DAI_SSP_HAS_POWER_CONTROL */
857 }
858
dai_ssp_program_channel_map(struct dai_intel_ssp * dp,const struct dai_config * cfg,uint32_t ssp_index,const void * spec_config)859 static void dai_ssp_program_channel_map(struct dai_intel_ssp *dp,
860 const struct dai_config *cfg, uint32_t ssp_index, const void *spec_config)
861 {
862 #if defined(CONFIG_SOC_INTEL_ACE20_LNL)
863 ARG_UNUSED(spec_config);
864 uint16_t pcmsycm = cfg->link_config;
865 /* Set upper slot number from configuration */
866 pcmsycm = pcmsycm | (dp->ssp_plat_data->params.tdm_slots - 1) << 4;
867
868 if (IS_BIT_SET(cfg->link_config, 15)) {
869 uint32_t reg_add = dai_ip_base(dp) + 0x1000 * ssp_index + PCMS0CM_OFFSET;
870 /* Program HDA output stream parameters */
871 sys_write16((pcmsycm & 0xffff), reg_add);
872 } else {
873 uint32_t reg_add = dai_ip_base(dp) + 0x1000 * ssp_index + PCMS1CM_OFFSET;
874 /* Program HDA input stream parameters */
875 sys_write16((pcmsycm & 0xffff), reg_add);
876 }
877 #elif SSP_IP_VER > SSP_IP_VER_2_0
878 const struct dai_intel_ipc4_ssp_configuration_blob_ver_3_0 *blob30 = spec_config;
879 const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config;
880 uint64_t time_slot_map = 0;
881 uint16_t pcmsycm = cfg->link_config;
882 uint8_t slot_count = 0;
883
884 if (IS_BIT_SET(cfg->link_config, 15)) {
885 if (blob30->version == SSP_BLOB_VER_3_0) {
886 time_slot_map =
887 blob30->i2s_ssp_config.ssmidytsa[cfg->tdm_slot_group];
888 } else {
889 time_slot_map =
890 blob->i2s_driver_config.i2s_config.ssmidytsa[cfg->tdm_slot_group];
891 }
892 slot_count = POPCOUNT(time_slot_map >> 32) + POPCOUNT(time_slot_map & 0xFFFFFFFF);
893 pcmsycm = cfg->link_config | (slot_count - 1) << 4;
894 uint32_t reg_add = dai_ip_base(dp) + 0x1000 * ssp_index +
895 PCMSyCM_OFFSET(cfg->tdm_slot_group);
896
897 /* Program HDA output stream parameters */
898 sys_write16((pcmsycm & 0xffff), reg_add);
899
900 } else {
901 if (blob30->version == SSP_BLOB_VER_3_0) {
902 time_slot_map =
903 blob30->i2s_ssp_config.ssmodytsa[cfg->tdm_slot_group];
904 } else {
905 time_slot_map =
906 blob->i2s_driver_config.i2s_config.ssmodytsa[cfg->tdm_slot_group];
907 }
908 slot_count = POPCOUNT(time_slot_map >> 32) + POPCOUNT(time_slot_map & 0xFFFFFFFF);
909 pcmsycm = cfg->link_config | (slot_count - 1) << 4;
910 uint32_t reg_add = dai_ip_base(dp) + 0x1000 * ssp_index +
911 PCMSyCM_OFFSET(cfg->tdm_slot_group + I2SOPCMC);
912
913 /* Program HDA input stream parameters */
914 sys_write16((pcmsycm & 0xffff), reg_add);
915 }
916 #else
917 ARG_UNUSED(dp);
918 ARG_UNUSED(cfg);
919 ARG_UNUSED(ssp_index);
920 ARG_UNUSED(spec_config);
921 #endif /* CONFIG_SOC_INTEL_ACE20_LNL */
922 }
923
924 /* empty SSP transmit FIFO */
dai_ssp_empty_tx_fifo(struct dai_intel_ssp * dp)925 static void dai_ssp_empty_tx_fifo(struct dai_intel_ssp *dp)
926 {
927 int ret;
928 uint32_t sssr;
929
930 /*
931 * SSSR_TNF is cleared when TX FIFO is empty or full,
932 * so wait for set TNF then for TFL zero - order matter.
933 */
934 #if SSP_IP_VER > SSP_IP_VER_2_0
935 ret = dai_ssp_poll_for_register_delay(dai_base(dp) + SSMODyCS(dp->tdm_slot_group),
936 SSMODyCS_TNF, SSMODyCS_TNF,
937 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
938
939 ret |= dai_ssp_poll_for_register_delay(dai_base(dp) + SSMODyCS(dp->tdm_slot_group),
940 SSMODyCS_TFL, 0,
941 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE *
942 (DAI_INTEL_SSP_FIFO_DEPTH - 1) / 2);
943 #else
944 ret = dai_ssp_poll_for_register_delay(dai_base(dp) + SSSR, SSSR_TNF, SSSR_TNF,
945 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE);
946 ret |= dai_ssp_poll_for_register_delay(dai_base(dp) + SSCR3, SSCR3_TFL_MASK, 0,
947 DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE *
948 (DAI_INTEL_SSP_FIFO_DEPTH - 1) / 2);
949 #endif
950
951 if (ret) {
952 LOG_WRN("timeout");
953 }
954
955 sssr = sys_read32(dai_base(dp) + SSSR);
956
957 /* clear interrupt */
958 if (sssr & SSSR_TUR) {
959 sys_write32(sssr, dai_base(dp) + SSSR);
960 }
961 }
962
963 #if SSP_IP_VER > SSP_IP_VER_2_0
ssp_empty_rx_fifo_on_start(struct dai_intel_ssp * dp)964 static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp)
965 {
966 uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX;
967 uint32_t i, sssr;
968
969 sssr = sys_read32(dai_base(dp) + SSSR);
970
971 if (sssr & SSSR_ROR) {
972 /* The RX FIFO is in overflow condition, empty it */
973 for (uint32_t idx = 0; idx < I2SIPCMC; ++idx) {
974 for (i = 0; i < DAI_INTEL_SSP_FIFO_DEPTH; i++) {
975 sys_read32(dai_base(dp) + SSMIDyD(idx));
976 }
977 }
978
979 /* Clear the overflow status */
980 dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR);
981 /* Re-read the SSSR register */
982 sssr = sys_read32(dai_base(dp) + SSSR);
983 }
984
985 for (uint32_t idx = 0; idx < I2SIPCMC; ++idx) {
986 while ((sys_read32(dai_base(dp) + SSMIDyCS(idx)) & SSMIDyCS_RNE) && retry--) {
987 uint32_t entries = SSMIDyCS_RFL_VAL(sys_read32(dai_base(dp) +
988 SSMIDyCS(idx)));
989
990 /* Empty the RX FIFO (the DMA is not running at this point) */
991 for (i = 0; i < entries + 1; i++) {
992 sys_read32(dai_base(dp) + SSMIDyD(idx));
993 }
994
995 sssr = sys_read32(dai_base(dp) + SSSR);
996 }
997 }
998 }
999
ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp * dp)1000 static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp)
1001 {
1002 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1003 uint64_t sample_ticks = ssp_plat_data->params.fsync_rate ?
1004 1000000 / ssp_plat_data->params.fsync_rate : 0;
1005 uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX;
1006 uint32_t i, sssr, ssmidycs;
1007 uint32_t entries[2];
1008
1009 sssr = sys_read32(dai_base(dp) + SSSR);
1010
1011 entries[0] = SSMIDyCS_RFL_VAL(sys_read32(dai_base(dp) + SSMIDyCS(dp->tdm_slot_group)));
1012
1013 while ((sys_read32(dai_base(dp) + SSMIDyCS(dp->tdm_slot_group)) &
1014 SSMIDyCS_RNE) && retry--) {
1015 /* Wait one sample time */
1016 k_busy_wait(sample_ticks);
1017
1018 entries[1] = SSMIDyCS_RFL_VAL(sys_read32(dai_base(dp) +
1019 SSMIDyCS(dp->tdm_slot_group)));
1020 sssr = sys_read32(dai_base(dp) + SSSR);
1021 ssmidycs = sys_read32(dai_base(dp) + SSMIDyCS(dp->tdm_slot_group));
1022
1023 if (entries[0] > entries[1]) {
1024 /*
1025 * The DMA is reading the FIFO, check the status in the
1026 * next loop
1027 */
1028 entries[0] = entries[1];
1029 } else if (!(ssmidycs & SSMIDyCS_RFS)) {
1030 /*
1031 * The DMA request is not asserted, read the FIFO
1032 * directly, otherwise let the next loop iteration to
1033 * check the status
1034 */
1035 for (i = 0; i < entries[1] + 1; i++) {
1036 sys_read32(dai_base(dp) + SSMIDyD(dp->tdm_slot_group));
1037 }
1038 }
1039 sssr = sys_read32(dai_base(dp) + SSSR);
1040 }
1041
1042 /* Just in case clear the overflow status */
1043 dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR);
1044 }
1045
1046 #else
ssp_empty_rx_fifo_on_start(struct dai_intel_ssp * dp)1047 static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp)
1048 {
1049 uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX;
1050 uint32_t i, sssr;
1051
1052 sssr = sys_read32(dai_base(dp) + SSSR);
1053
1054 if (sssr & SSSR_ROR) {
1055 /* The RX FIFO is in overflow condition, empty it */
1056 for (i = 0; i < DAI_INTEL_SSP_FIFO_DEPTH; i++) {
1057 sys_read32(dai_base(dp) + SSDR);
1058 }
1059
1060 /* Clear the overflow status */
1061 dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR);
1062 /* Re-read the SSSR register */
1063 sssr = sys_read32(dai_base(dp) + SSSR);
1064 }
1065
1066 while ((sssr & SSSR_RNE) && retry--) {
1067 uint32_t entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
1068
1069 /* Empty the RX FIFO (the DMA is not running at this point) */
1070 for (i = 0; i < entries + 1; i++) {
1071 sys_read32(dai_base(dp) + SSDR);
1072 }
1073
1074 sssr = sys_read32(dai_base(dp) + SSSR);
1075 }
1076 }
1077
ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp * dp)1078 static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp)
1079 {
1080 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1081 uint64_t sample_ticks = ssp_plat_data->params.fsync_rate ?
1082 1000000 / ssp_plat_data->params.fsync_rate : 0;
1083 uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX;
1084 uint32_t entries[2];
1085 uint32_t i, sssr;
1086
1087 sssr = sys_read32(dai_base(dp) + SSSR);
1088 entries[0] = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
1089
1090 while ((sssr & SSSR_RNE) && retry--) {
1091 /* Wait one sample time */
1092 k_busy_wait(sample_ticks);
1093
1094 entries[1] = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3));
1095 sssr = sys_read32(dai_base(dp) + SSSR);
1096
1097 if (entries[0] > entries[1]) {
1098 /*
1099 * The DMA is reading the FIFO, check the status in the
1100 * next loop
1101 */
1102 entries[0] = entries[1];
1103 } else if (!(sssr & SSSR_RFS)) {
1104 /*
1105 * The DMA request is not asserted, read the FIFO
1106 * directly, otherwise let the next loop iteration to
1107 * check the status
1108 */
1109 for (i = 0; i < entries[1] + 1; i++) {
1110 sys_read32(dai_base(dp) + SSDR);
1111 }
1112 }
1113
1114 sssr = sys_read32(dai_base(dp) + SSSR);
1115 }
1116
1117 /* Just in case clear the overflow status */
1118 dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR);
1119 }
1120
1121 #endif
1122
dai_ssp_mclk_prepare_enable(struct dai_intel_ssp * dp)1123 static int dai_ssp_mclk_prepare_enable(struct dai_intel_ssp *dp)
1124 {
1125 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1126 int ret;
1127
1128 if (ssp_plat_data->clk_active & SSP_CLK_MCLK_ACTIVE) {
1129 return 0;
1130 }
1131
1132 /* MCLK config */
1133 ret = dai_ssp_mn_set_mclk(dp, ssp_plat_data->params.mclk_id,
1134 ssp_plat_data->params.mclk_rate);
1135 if (ret < 0) {
1136 LOG_ERR("invalid mclk_rate = %d for mclk_id = %d", ssp_plat_data->params.mclk_rate,
1137 ssp_plat_data->params.mclk_id);
1138 } else {
1139 ssp_plat_data->clk_active |= SSP_CLK_MCLK_ACTIVE;
1140 }
1141
1142 return ret;
1143 }
1144
dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp * dp)1145 static void dai_ssp_mclk_disable_unprepare(struct dai_intel_ssp *dp)
1146 {
1147 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1148
1149 if (!(ssp_plat_data->clk_active & SSP_CLK_MCLK_ACTIVE)) {
1150 return;
1151 }
1152
1153 dai_ssp_mn_release_mclk(dp, ssp_plat_data->params.mclk_id);
1154
1155 ssp_plat_data->clk_active &= ~SSP_CLK_MCLK_ACTIVE;
1156 }
1157
dai_ssp_bclk_prepare_enable(struct dai_intel_ssp * dp)1158 static int dai_ssp_bclk_prepare_enable(struct dai_intel_ssp *dp)
1159 {
1160 #if SSP_IP_VER != SSP_IP_VER_1_0
1161 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
1162 #endif
1163 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1164 uint32_t sscr0;
1165 uint32_t mdiv;
1166 int ret = 0;
1167
1168 if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) {
1169 return 0;
1170 }
1171
1172 sscr0 = sys_read32(dai_base(dp) + SSCR0);
1173
1174 #if SSP_IP_VER == SSP_IP_VER_1_0
1175 bool need_ecs = false;
1176 /* BCLK config */
1177 ret = dai_ssp_mn_set_bclk(dp, dp->dai_index, ssp_plat_data->params.bclk_rate,
1178 &mdiv, &need_ecs);
1179 if (ret < 0) {
1180 LOG_ERR("invalid bclk_rate = %d for ssp_index = %d",
1181 ssp_plat_data->params.bclk_rate, dp->dai_index);
1182 goto out;
1183 }
1184 #else
1185 if (ft[DAI_INTEL_SSP_DEFAULT_IDX].freq % ssp_plat_data->params.bclk_rate != 0) {
1186 LOG_ERR("invalid bclk_rate = %d for ssp_index = %d",
1187 ssp_plat_data->params.bclk_rate, dp->dai_index);
1188 ret = -EINVAL;
1189 goto out;
1190 }
1191
1192 mdiv = ft[DAI_INTEL_SSP_DEFAULT_IDX].freq / ssp_plat_data->params.bclk_rate;
1193 #endif
1194
1195 #if SSP_IP_VER == SSP_IP_VER_1_0
1196 if (need_ecs) {
1197 sscr0 |= SSCR0_ECS;
1198 }
1199 #endif
1200
1201 /* clock divisor is SCR + 1 */
1202 mdiv -= 1;
1203
1204 /* divisor must be within SCR range */
1205 if (mdiv > (SSCR0_SCR_MASK >> 8)) {
1206 LOG_ERR("divisor %d is not within SCR range", mdiv);
1207 ret = -EINVAL;
1208 goto out;
1209 }
1210
1211 /* set the SCR divisor */
1212 sscr0 &= ~SSCR0_SCR_MASK;
1213 sscr0 |= SSCR0_SCR(mdiv);
1214
1215 sys_write32(sscr0, dai_base(dp) + SSCR0);
1216
1217 LOG_INF("sscr0 = 0x%08x", sscr0);
1218 out:
1219 if (!ret) {
1220 ssp_plat_data->clk_active |= SSP_CLK_BCLK_ACTIVE;
1221 }
1222
1223 return ret;
1224 }
1225
dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp * dp)1226 static void dai_ssp_bclk_disable_unprepare(struct dai_intel_ssp *dp)
1227 {
1228 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1229
1230 if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE)) {
1231 return;
1232 }
1233 #if SSP_IP_VER == SSP_IP_VER_1_0
1234 dai_ssp_mn_release_bclk(dp, ssp_plat_data->ssp_index);
1235 #endif
1236 ssp_plat_data->clk_active &= ~SSP_CLK_BCLK_ACTIVE;
1237 }
1238
dai_ssp_log_ssp_data(struct dai_intel_ssp * dp)1239 static void dai_ssp_log_ssp_data(struct dai_intel_ssp *dp)
1240 {
1241 LOG_INF("dai index: %u", dp->dai_index);
1242 LOG_INF("plat_data base: %u", dp->ssp_plat_data->base);
1243 LOG_INF("plat_data irq: %u", dp->ssp_plat_data->irq);
1244 LOG_INF("plat_data fifo playback offset: %u",
1245 dp->ssp_plat_data->fifo[DAI_DIR_PLAYBACK].offset);
1246 LOG_INF("plat_data fifo playback handshake: %u",
1247 dp->ssp_plat_data->fifo[DAI_DIR_PLAYBACK].handshake);
1248 LOG_INF("plat_data fifo capture offset: %u",
1249 dp->ssp_plat_data->fifo[DAI_DIR_CAPTURE].offset);
1250 LOG_INF("plat_data fifo capture handshake: %u",
1251 dp->ssp_plat_data->fifo[DAI_DIR_CAPTURE].handshake);
1252 }
1253
1254 /* Digital Audio interface formatting */
dai_ssp_set_config_tplg(struct dai_intel_ssp * dp,const struct dai_config * config,const void * bespoke_cfg)1255 static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_config *config,
1256 const void *bespoke_cfg)
1257 {
1258 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
1259 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
1260 struct dai_intel_ssp_freq_table *ft = dai_get_ftable(dp);
1261 uint32_t sscr0;
1262 uint32_t sscr1;
1263 uint32_t sscr2;
1264 uint32_t sscr3;
1265 uint32_t sspsp;
1266 uint32_t sspsp2;
1267 uint32_t sstsa;
1268 uint32_t ssrsa;
1269 uint32_t ssto;
1270 uint32_t ssioc;
1271 uint32_t bdiv;
1272 uint32_t data_size;
1273 uint32_t frame_end_padding;
1274 uint32_t slot_end_padding;
1275 uint32_t frame_len = 0;
1276 uint32_t bdiv_min;
1277 uint32_t tft;
1278 uint32_t rft;
1279 uint32_t active_tx_slots = 2;
1280 uint32_t active_rx_slots = 2;
1281 uint32_t sample_width = 2;
1282
1283 bool inverted_bclk = false;
1284 bool inverted_frame = false;
1285 bool cfs = false;
1286 bool start_delay = false;
1287 k_spinlock_key_t key;
1288 int ret = 0;
1289
1290 dai_ssp_log_ssp_data(dp);
1291
1292 key = k_spin_lock(&dp->lock);
1293
1294 /* ignore config if SSP is already configured */
1295 if (dp->state[DAI_DIR_PLAYBACK] > DAI_STATE_READY ||
1296 dp->state[DAI_DIR_CAPTURE] > DAI_STATE_READY) {
1297 if (!memcmp(&ssp_plat_data->params, bespoke_cfg,
1298 sizeof(struct dai_intel_ipc3_ssp_params))) {
1299 LOG_INF("Already configured. Ignore config");
1300 goto clk;
1301 }
1302
1303 if (ssp_plat_data->clk_active &
1304 (SSP_CLK_MCLK_ACTIVE | SSP_CLK_BCLK_ACTIVE)) {
1305 LOG_WRN("SSP active, cannot change config");
1306 goto clk;
1307 }
1308
1309 /* safe to proceed and change HW config */
1310 }
1311
1312 LOG_INF("SSP%d", dp->dai_index);
1313
1314 /* reset SSP settings */
1315 /* sscr0 dynamic settings are DSS, EDSS, SCR, FRDC, ECS */
1316 /*
1317 * FIXME: MOD, ACS, NCS are not set,
1318 * no support for network mode for now
1319 */
1320 sscr0 = SSCR0_PSP | SSCR0_RIM | SSCR0_TIM;
1321
1322 /* sscr1 dynamic settings are SFRMDIR, SCLKDIR, SCFR, RSRE, TSRE */
1323 sscr1 = SSCR1_TTE | SSCR1_TTELP | SSCR1_TRAIL;
1324
1325 /* sscr2 dynamic setting is LJDFD */
1326 sscr2 = SSCR2_SDFD | SSCR2_TURM1;
1327
1328 /* sscr3 dynamic settings are TFT, RFT */
1329 sscr3 = 0;
1330
1331 /* sspsp dynamic settings are SCMODE, SFRMP, DMYSTRT, SFRMWDTH */
1332 sspsp = 0;
1333
1334 ssp->config = *config;
1335 memcpy(&ssp_plat_data->params, bespoke_cfg, sizeof(struct dai_intel_ipc3_ssp_params));
1336
1337 /* sspsp2 no dynamic setting */
1338 sspsp2 = 0x0;
1339
1340 /* ssioc dynamic setting is SFCR */
1341 ssioc = SSIOC_SCOE;
1342
1343 /* ssto no dynamic setting */
1344 ssto = 0x0;
1345
1346 /* sstsa dynamic setting is TTSA, default 2 slots */
1347 sstsa = SSTSA_SSTSA(ssp_plat_data->params.tx_slots);
1348
1349 /* ssrsa dynamic setting is RTSA, default 2 slots */
1350 ssrsa = SSRSA_SSRSA(ssp_plat_data->params.rx_slots);
1351
1352 switch (config->format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
1353 case DAI_INTEL_IPC3_SSP_FMT_CBP_CFP:
1354 sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
1355 break;
1356 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
1357 sscr1 |= SSCR1_SCFR;
1358 cfs = true;
1359 break;
1360 case DAI_INTEL_IPC3_SSP_FMT_CBP_CFC:
1361 sscr1 |= SSCR1_SCLKDIR;
1362 /* FIXME: this mode has not been tested */
1363
1364 cfs = true;
1365 break;
1366 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFP:
1367 sscr1 |= SSCR1_SCFR | SSCR1_SFRMDIR;
1368 /* FIXME: this mode has not been tested */
1369 break;
1370 default:
1371 LOG_ERR("format & PROVIDER_MASK EINVAL");
1372 ret = -EINVAL;
1373 goto out;
1374 }
1375
1376 /* clock signal polarity */
1377 switch (config->format & DAI_INTEL_IPC3_SSP_FMT_INV_MASK) {
1378 case DAI_INTEL_IPC3_SSP_FMT_NB_NF:
1379 break;
1380 case DAI_INTEL_IPC3_SSP_FMT_NB_IF:
1381 inverted_frame = true; /* handled later with format */
1382 break;
1383 case DAI_INTEL_IPC3_SSP_FMT_IB_IF:
1384 inverted_bclk = true; /* handled later with bclk idle */
1385 inverted_frame = true; /* handled later with format */
1386 break;
1387 case DAI_INTEL_IPC3_SSP_FMT_IB_NF:
1388 inverted_bclk = true; /* handled later with bclk idle */
1389 break;
1390 default:
1391 LOG_ERR("format & INV_MASK EINVAL");
1392 ret = -EINVAL;
1393 goto out;
1394 }
1395
1396 /* supporting bclk idle state */
1397 if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_IDLE_HIGH) {
1398 /* bclk idle state high */
1399 sspsp |= SSPSP_SCMODE((inverted_bclk ^ 0x3) & 0x3);
1400 } else {
1401 /* bclk idle state low */
1402 sspsp |= SSPSP_SCMODE(inverted_bclk);
1403 }
1404
1405 sscr0 |= SSCR0_MOD | SSCR0_ACS;
1406
1407 /* Additional hardware settings */
1408
1409 /* Receiver Time-out Interrupt Disabled/Enabled */
1410 sscr1 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_TINTE) ?
1411 SSCR1_TINTE : 0;
1412
1413 /* Peripheral Trailing Byte Interrupts Disable/Enable */
1414 sscr1 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PINTE) ?
1415 SSCR1_PINTE : 0;
1416
1417 /* Enable/disable internal loopback. Output of transmit serial
1418 * shifter connected to input of receive serial shifter, internally.
1419 */
1420 sscr1 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) ?
1421 SSCR1_LBM : 0;
1422
1423 if (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_LBM) {
1424 LOG_INF("going for loopback!");
1425 } else {
1426 LOG_INF("no loopback!");
1427 }
1428
1429 /* Transmit data are driven at the same/opposite clock edge specified
1430 * in SSPSP.SCMODE[1:0]
1431 */
1432 sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_SMTATF) ?
1433 SSCR2_SMTATF : 0;
1434
1435 /* Receive data are sampled at the same/opposite clock edge specified
1436 * in SSPSP.SCMODE[1:0]
1437 */
1438 sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_MMRATF) ?
1439 SSCR2_MMRATF : 0;
1440
1441 /* Enable/disable the fix for PSP consumer mode TXD wait for frame
1442 * de-assertion before starting the second channel
1443 */
1444 sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSTWFDFD) ?
1445 SSCR2_PSPSTWFDFD : 0;
1446
1447 /* Enable/disable the fix for PSP provider mode FSRT with dummy stop &
1448 * frame end padding capability
1449 */
1450 sscr2 |= (ssp_plat_data->params.quirks & DAI_INTEL_IPC3_SSP_QUIRK_PSPSRWFDFD) ?
1451 SSCR2_PSPSRWFDFD : 0;
1452
1453 if (!ssp_plat_data->params.mclk_rate ||
1454 ssp_plat_data->params.mclk_rate > ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq) {
1455 LOG_ERR("invalid MCLK = %d Hz (valid < %d)", ssp_plat_data->params.mclk_rate,
1456 ft[DAI_INTEL_SSP_MAX_FREQ_INDEX].freq);
1457 ret = -EINVAL;
1458 goto out;
1459 }
1460
1461 if (!ssp_plat_data->params.bclk_rate ||
1462 ssp_plat_data->params.bclk_rate > ssp_plat_data->params.mclk_rate) {
1463 LOG_ERR("BCLK %d Hz = 0 or > MCLK %d Hz", ssp_plat_data->params.bclk_rate,
1464 ssp_plat_data->params.mclk_rate);
1465 ret = -EINVAL;
1466 goto out;
1467 }
1468
1469 /* calc frame width based on BCLK and rate - must be divisible */
1470 if (ssp_plat_data->params.bclk_rate % ssp_plat_data->params.fsync_rate) {
1471 LOG_ERR("BCLK %d is not divisible by rate %d", ssp_plat_data->params.bclk_rate,
1472 ssp_plat_data->params.fsync_rate);
1473 ret = -EINVAL;
1474 goto out;
1475 }
1476
1477 /* must be enough BCLKs for data */
1478 bdiv = ssp_plat_data->params.bclk_rate / ssp_plat_data->params.fsync_rate;
1479 if (bdiv < ssp_plat_data->params.tdm_slot_width * ssp_plat_data->params.tdm_slots) {
1480 LOG_ERR("not enough BCLKs need %d",
1481 ssp_plat_data->params.tdm_slot_width * ssp_plat_data->params.tdm_slots);
1482 ret = -EINVAL;
1483 goto out;
1484 }
1485
1486 /* tdm_slot_width must be <= 38 for SSP */
1487 if (ssp_plat_data->params.tdm_slot_width > 38) {
1488 LOG_ERR("tdm_slot_width %d > 38", ssp_plat_data->params.tdm_slot_width);
1489 ret = -EINVAL;
1490 goto out;
1491 }
1492
1493 bdiv_min = ssp_plat_data->params.tdm_slots *
1494 (ssp_plat_data->params.tdm_per_slot_padding_flag ?
1495 ssp_plat_data->params.tdm_slot_width : ssp_plat_data->params.sample_valid_bits);
1496 if (bdiv < bdiv_min) {
1497 LOG_ERR("bdiv(%d) < bdiv_min(%d)", bdiv, bdiv_min);
1498 ret = -EINVAL;
1499 goto out;
1500 }
1501
1502 frame_end_padding = bdiv - bdiv_min;
1503 if (frame_end_padding > SSPSP2_FEP_MASK) {
1504 LOG_ERR("frame_end_padding too big: %u", frame_end_padding);
1505 ret = -EINVAL;
1506 goto out;
1507 }
1508
1509 /* format */
1510 switch (config->format & DAI_INTEL_IPC3_SSP_FMT_FORMAT_MASK) {
1511 case DAI_INTEL_IPC3_SSP_FMT_I2S:
1512
1513 start_delay = true;
1514
1515 sscr0 |= SSCR0_FRDC(ssp_plat_data->params.tdm_slots);
1516
1517 if (bdiv % 2) {
1518 LOG_ERR("bdiv %d is not divisible by 2", bdiv);
1519 ret = -EINVAL;
1520 goto out;
1521 }
1522
1523 /* set asserted frame length to half frame length */
1524 frame_len = bdiv / 2;
1525
1526 /*
1527 * handle frame polarity, I2S default is falling/active low,
1528 * non-inverted(inverted_frame=0) -- active low(SFRMP=0),
1529 * inverted(inverted_frame=1) -- rising/active high(SFRMP=1),
1530 * so, we should set SFRMP to inverted_frame.
1531 */
1532 sspsp |= SSPSP_SFRMP(inverted_frame);
1533
1534 /*
1535 * for I2S/LEFT_J, the padding has to happen at the end
1536 * of each slot
1537 */
1538 if (frame_end_padding % 2) {
1539 LOG_ERR("frame_end_padding %d is not divisible by 2", frame_end_padding);
1540 ret = -EINVAL;
1541 goto out;
1542 }
1543
1544 slot_end_padding = frame_end_padding / 2;
1545
1546 if (slot_end_padding > DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) {
1547 /* too big padding */
1548 LOG_ERR("slot_end_padding > %d", DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX);
1549 ret = -EINVAL;
1550 goto out;
1551 }
1552
1553 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1554 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1555 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1556
1557 break;
1558
1559 case DAI_INTEL_IPC3_SSP_FMT_LEFT_J:
1560
1561 /* default start_delay value is set to false */
1562
1563 sscr0 |= SSCR0_FRDC(ssp_plat_data->params.tdm_slots);
1564
1565 /* LJDFD enable */
1566 sscr2 &= ~SSCR2_LJDFD;
1567
1568 if (bdiv % 2) {
1569 LOG_ERR("bdiv %d is not divisible by 2", bdiv);
1570 ret = -EINVAL;
1571 goto out;
1572 }
1573
1574 /* set asserted frame length to half frame length */
1575 frame_len = bdiv / 2;
1576
1577 /*
1578 * handle frame polarity, LEFT_J default is rising/active high,
1579 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
1580 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
1581 * so, we should set SFRMP to !inverted_frame.
1582 */
1583 sspsp |= SSPSP_SFRMP(!inverted_frame);
1584
1585 /*
1586 * for I2S/LEFT_J, the padding has to happen at the end
1587 * of each slot
1588 */
1589 if (frame_end_padding % 2) {
1590 LOG_ERR("frame_end_padding %d is not divisible by 2", frame_end_padding);
1591 ret = -EINVAL;
1592 goto out;
1593 }
1594
1595 slot_end_padding = frame_end_padding / 2;
1596
1597 if (slot_end_padding > 15) {
1598 /* can't handle padding over 15 bits */
1599 LOG_ERR("slot_end_padding %d > 15 bits", slot_end_padding);
1600 ret = -EINVAL;
1601 goto out;
1602 }
1603
1604 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1605 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1606 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1607
1608 break;
1609 case DAI_INTEL_IPC3_SSP_FMT_DSP_A:
1610
1611 start_delay = true;
1612
1613 /* fallthrough */
1614
1615 case DAI_INTEL_IPC3_SSP_FMT_DSP_B:
1616
1617 /* default start_delay value is set to false */
1618
1619 sscr0 |= SSCR0_MOD | SSCR0_FRDC(ssp_plat_data->params.tdm_slots);
1620
1621 /* set asserted frame length */
1622 frame_len = 1; /* default */
1623
1624 if (cfs && ssp_plat_data->params.frame_pulse_width > 0 &&
1625 ssp_plat_data->params.frame_pulse_width <=
1626 DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) {
1627 frame_len = ssp_plat_data->params.frame_pulse_width;
1628 }
1629
1630 /* frame_pulse_width must less or equal 38 */
1631 if (ssp_plat_data->params.frame_pulse_width >
1632 DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX) {
1633 LOG_ERR("frame_pulse_width > %d", DAI_INTEL_IPC3_SSP_FRAME_PULSE_WIDTH_MAX);
1634 ret = -EINVAL;
1635 goto out;
1636 }
1637 /*
1638 * handle frame polarity, DSP_B default is rising/active high,
1639 * non-inverted(inverted_frame=0) -- active high(SFRMP=1),
1640 * inverted(inverted_frame=1) -- falling/active low(SFRMP=0),
1641 * so, we should set SFRMP to !inverted_frame.
1642 */
1643 sspsp |= SSPSP_SFRMP(!inverted_frame);
1644
1645 active_tx_slots = POPCOUNT(ssp_plat_data->params.tx_slots);
1646 active_rx_slots = POPCOUNT(ssp_plat_data->params.rx_slots);
1647
1648 /*
1649 * handle TDM mode, TDM mode has padding at the end of
1650 * each slot. The amount of padding is equal to result of
1651 * subtracting slot width and valid bits per slot.
1652 */
1653 if (ssp_plat_data->params.tdm_per_slot_padding_flag) {
1654 frame_end_padding = bdiv - ssp_plat_data->params.tdm_slots *
1655 ssp_plat_data->params.tdm_slot_width;
1656
1657 slot_end_padding = ssp_plat_data->params.tdm_slot_width -
1658 ssp_plat_data->params.sample_valid_bits;
1659
1660 if (slot_end_padding >
1661 DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX) {
1662 LOG_ERR("slot_end_padding > %d",
1663 DAI_INTEL_IPC3_SSP_SLOT_PADDING_MAX);
1664 ret = -EINVAL;
1665 goto out;
1666 }
1667
1668 sspsp |= SSPSP_DMYSTOP(slot_end_padding);
1669 slot_end_padding >>= SSPSP_DMYSTOP_BITS;
1670 sspsp |= SSPSP_EDMYSTOP(slot_end_padding);
1671 }
1672
1673 sspsp2 |= (frame_end_padding & SSPSP2_FEP_MASK);
1674
1675 break;
1676 default:
1677 LOG_ERR("invalid format 0x%04x", config->format);
1678 ret = -EINVAL;
1679 goto out;
1680 }
1681
1682 if (start_delay) {
1683 sspsp |= SSPSP_FSRT;
1684 }
1685
1686 sspsp |= SSPSP_SFRMWDTH(frame_len);
1687
1688 data_size = ssp_plat_data->params.sample_valid_bits;
1689
1690 if (data_size > 16) {
1691 sscr0 |= (SSCR0_EDSS | SSCR0_DSIZE(data_size - 16));
1692 } else {
1693 sscr0 |= SSCR0_DSIZE(data_size);
1694 }
1695
1696 /* setting TFT and RFT */
1697 switch (ssp_plat_data->params.sample_valid_bits) {
1698 case 16:
1699 /* use 2 bytes for each slot */
1700 sample_width = 2;
1701 break;
1702 case 24:
1703 case 32:
1704 /* use 4 bytes for each slot */
1705 sample_width = 4;
1706 break;
1707 default:
1708 LOG_ERR("sample_valid_bits %d", ssp_plat_data->params.sample_valid_bits);
1709 ret = -EINVAL;
1710 goto out;
1711 }
1712
1713 tft = MIN(DAI_INTEL_SSP_FIFO_DEPTH - DAI_INTEL_SSP_FIFO_WATERMARK,
1714 sample_width * active_tx_slots);
1715 rft = MIN(DAI_INTEL_SSP_FIFO_DEPTH - DAI_INTEL_SSP_FIFO_WATERMARK,
1716 sample_width * active_rx_slots);
1717
1718 sscr3 |= SSCR3_TX(tft) | SSCR3_RX(rft);
1719
1720 sys_write32(sscr0, dai_base(dp) + SSCR0);
1721 sys_write32(sscr1, dai_base(dp) + SSCR1);
1722 sys_write32(sscr2, dai_base(dp) + SSCR2);
1723 sys_write32(sscr3, dai_base(dp) + SSCR3);
1724 sys_write32(sspsp, dai_base(dp) + SSPSP);
1725 sys_write32(sspsp2, dai_base(dp) + SSPSP2);
1726 sys_write32(ssioc, dai_base(dp) + SSIOC);
1727 sys_write32(ssto, dai_base(dp) + SSTO);
1728
1729 #if SSP_IP_VER > SSP_IP_VER_2_0
1730 for (uint32_t idx = 0; idx < I2SIPCMC; ++idx) {
1731 sys_write64(sstsa, dai_base(dp) + SSMODyTSA(idx));
1732 }
1733
1734 for (uint32_t idx = 0; idx < I2SOPCMC; ++idx) {
1735 sys_write64(ssrsa, dai_base(dp) + SSMIDyTSA(idx));
1736 }
1737 #else
1738 sys_write32(sstsa, dai_base(dp) + SSTSA);
1739 sys_write32(ssrsa, dai_base(dp) + SSRSA);
1740 #endif
1741
1742 LOG_INF("sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
1743 sscr0, sscr1, ssto, sspsp);
1744 LOG_INF("sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x, ssioc = 0x%08x",
1745 sscr2, sspsp2, sscr3, ssioc);
1746 LOG_INF("ssrsa = 0x%08x, sstsa = 0x%08x",
1747 ssrsa, sstsa);
1748
1749 dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
1750 dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
1751
1752 clk:
1753 switch (config->options & DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_CMD_MASK) {
1754 case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_PARAMS:
1755 if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) {
1756 ret = dai_ssp_mclk_prepare_enable(dp);
1757 if (ret < 0) {
1758 goto out;
1759 }
1760
1761 ssp_plat_data->clk_active |= SSP_CLK_MCLK_ES_REQ;
1762
1763 LOG_INF("hw_params stage: enabled MCLK clocks for SSP%d...",
1764 dp->dai_index);
1765 }
1766
1767 if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) {
1768 bool enable_sse = false;
1769
1770 if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE)) {
1771 enable_sse = true;
1772 }
1773
1774 ret = dai_ssp_bclk_prepare_enable(dp);
1775 if (ret < 0) {
1776 goto out;
1777 }
1778
1779 ssp_plat_data->clk_active |= SSP_CLK_BCLK_ES_REQ;
1780
1781 if (enable_sse) {
1782
1783 #if SSP_IP_VER > SSP_IP_VER_2_0
1784 dai_ssp_update_bits(dp, SSMIDyCS(dp->tdm_slot_group),
1785 SSMIDyCS_RSRE, SSMIDyCS_RSRE);
1786 dai_ssp_update_bits(dp, SSMODyCS(dp->tdm_slot_group),
1787 SSMODyCS_TSRE, SSMODyCS_TSRE);
1788 #endif
1789 /* enable port */
1790 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
1791
1792 LOG_INF("SSE set for SSP%d", ssp_plat_data->ssp_index);
1793 }
1794
1795 LOG_INF("hw_params stage: enabled BCLK clocks for SSP%d...",
1796 ssp_plat_data->ssp_index);
1797 }
1798 break;
1799 case DAI_INTEL_IPC3_SSP_CONFIG_FLAGS_HW_FREE:
1800 /* disable SSP port if no users */
1801 if (dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING ||
1802 dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) {
1803 LOG_INF("hw_free stage: ignore since SSP%d still in use",
1804 dp->dai_index);
1805 break;
1806 }
1807
1808 if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_BCLK_ES) {
1809 LOG_INF("hw_free stage: releasing BCLK clocks for SSP%d...",
1810 dp->dai_index);
1811 if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) {
1812
1813 #if SSP_IP_VER > SSP_IP_VER_2_0
1814 for (uint32_t idx = 0; idx < I2SOPCMC; ++idx) {
1815 dai_ssp_update_bits(dp, SSMODyCS(idx), SSMODyCS_TSRE, 0);
1816 }
1817
1818 for (uint32_t idx = 0; idx < I2SIPCMC; ++idx) {
1819 dai_ssp_update_bits(dp, SSMIDyCS(idx), SSMIDyCS_RSRE, 0);
1820 }
1821 #endif
1822 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0);
1823 LOG_INF("SSE clear for SSP%d", dp->dai_index);
1824 }
1825 dai_ssp_bclk_disable_unprepare(dp);
1826 ssp_plat_data->clk_active &= ~SSP_CLK_BCLK_ES_REQ;
1827 }
1828 if (ssp_plat_data->params.clks_control & DAI_INTEL_IPC3_SSP_CLKCTRL_MCLK_ES) {
1829 LOG_INF("hw_free stage: releasing MCLK clocks for SSP%d...",
1830 dp->dai_index);
1831 dai_ssp_mclk_disable_unprepare(dp);
1832 ssp_plat_data->clk_active &= ~SSP_CLK_MCLK_ES_REQ;
1833 }
1834 break;
1835 default:
1836 break;
1837 }
1838 out:
1839
1840 k_spin_unlock(&dp->lock, key);
1841
1842 return ret;
1843 }
1844
dai_ssp_check_aux_data(struct ssp_intel_aux_tlv * aux_tlv,int aux_len,int parsed_len)1845 static int dai_ssp_check_aux_data(struct ssp_intel_aux_tlv *aux_tlv, int aux_len, int parsed_len)
1846 {
1847 struct ssp_intel_sync_ctl *sync;
1848 int size, size_left;
1849
1850 switch (aux_tlv->type) {
1851 case SSP_MN_DIVIDER_CONTROLS:
1852 size = sizeof(struct ssp_intel_mn_ctl);
1853 break;
1854 case SSP_DMA_CLK_CONTROLS:
1855 size = sizeof(struct ssp_intel_clk_ctl);
1856 break;
1857 case SSP_DMA_TRANSMISSION_START:
1858 case SSP_DMA_TRANSMISSION_STOP:
1859 size = sizeof(struct ssp_intel_tr_ctl);
1860 case SSP_DMA_ALWAYS_RUNNING_MODE:
1861 size = sizeof(struct ssp_intel_run_ctl);
1862 break;
1863 case SSP_DMA_SYNC_DATA:
1864 size = sizeof(struct ssp_intel_sync_ctl);
1865 sync = (struct ssp_intel_sync_ctl *)&aux_tlv->val;
1866 size += sync->count * sizeof(struct ssp_intel_node_ctl);
1867 break;
1868 case SSP_DMA_CLK_CONTROLS_EXT:
1869 size = sizeof(struct ssp_intel_ext_ctl);
1870 break;
1871 case SSP_LINK_CLK_SOURCE:
1872 #if SSP_IP_VER >= SSP_IP_VER_1_5
1873 size = sizeof(struct ssp_intel_link_ctl);
1874 break;
1875 #else
1876 return 0;
1877 #endif
1878 default:
1879 LOG_ERR("undefined aux data type %u", aux_tlv->type);
1880 return -EINVAL;
1881 }
1882
1883 /* check for malformed struct, size greater than aux_data or described in tlv */
1884 size_left = aux_len - parsed_len - sizeof(struct ssp_intel_aux_tlv);
1885 if (size > size_left || size != aux_tlv->size) {
1886 LOG_ERR("malformed struct, size %d, size_left %d, tlv_size %d", size,
1887 size_left, aux_tlv->size);
1888 return -EINVAL;
1889 }
1890
1891 return 0;
1892 }
1893
1894 /**
1895 * This function checks if the provided buffer contains valid DMA control
1896 * TLV (Type-Length-Value) entries. It ensures that only specific types
1897 * of DMA control settings are allowed to be modified at runtime.
1898 */
dai_ssp_check_dma_control(const uint8_t * aux_ptr,int aux_len)1899 static int dai_ssp_check_dma_control(const uint8_t *aux_ptr, int aux_len)
1900 {
1901 int hop;
1902 struct ssp_intel_aux_tlv *aux_tlv;
1903
1904 for (int i = 0; i < aux_len; i += hop) {
1905 aux_tlv = (struct ssp_intel_aux_tlv *)(aux_ptr);
1906 switch (aux_tlv->type) {
1907 case SSP_DMA_CLK_CONTROLS:
1908 case SSP_DMA_TRANSMISSION_START:
1909 case SSP_DMA_TRANSMISSION_STOP:
1910 case SSP_DMA_ALWAYS_RUNNING_MODE:
1911 case SSP_DMA_SYNC_DATA:
1912 case SSP_DMA_CLK_CONTROLS_EXT:
1913 case SSP_LINK_CLK_SOURCE:
1914 break;
1915 default:
1916 LOG_ERR("incorect config type %u", aux_tlv->type);
1917 return -EINVAL;
1918 }
1919
1920 hop = aux_tlv->size + sizeof(struct ssp_intel_aux_tlv);
1921 aux_ptr += hop;
1922 }
1923
1924 return 0;
1925 }
1926
dai_ssp_parse_tlv(struct dai_intel_ssp * dp,const uint8_t * aux_ptr,size_t aux_len)1927 static int dai_ssp_parse_tlv(struct dai_intel_ssp *dp, const uint8_t *aux_ptr, size_t aux_len)
1928 {
1929 int hop, i, j;
1930 struct ssp_intel_aux_tlv *aux_tlv;
1931 struct ssp_intel_mn_ctl *mn;
1932 struct ssp_intel_clk_ctl *clk;
1933 struct ssp_intel_tr_ctl *tr;
1934 struct ssp_intel_run_ctl *run;
1935 struct ssp_intel_node_ctl *node;
1936 struct ssp_intel_sync_ctl *sync;
1937 struct ssp_intel_ext_ctl *ext;
1938 #if SSP_IP_VER >= SSP_IP_VER_1_5
1939 struct ssp_intel_link_ctl *link;
1940 #if SSP_IP_VER > SSP_IP_VER_1_5
1941 struct dai_intel_ssp_plat_data *ssp = dai_get_plat_data(dp);
1942 #endif
1943 #endif
1944
1945 for (i = 0; i < aux_len; i += hop) {
1946 aux_tlv = (struct ssp_intel_aux_tlv *)(aux_ptr);
1947 if (dai_ssp_check_aux_data(aux_tlv, aux_len, i)) {
1948 return -EINVAL;
1949 }
1950 switch (aux_tlv->type) {
1951 case SSP_MN_DIVIDER_CONTROLS:
1952 mn = (struct ssp_intel_mn_ctl *)&aux_tlv->val;
1953 LOG_INF("mn div_m %u, div_n %u", mn->div_m, mn->div_n);
1954 break;
1955 case SSP_DMA_CLK_CONTROLS:
1956 clk = (struct ssp_intel_clk_ctl *)&aux_tlv->val;
1957 LOG_INF("clk start %u, stop %u", clk->start, clk->stop);
1958 break;
1959 case SSP_DMA_TRANSMISSION_START:
1960 case SSP_DMA_TRANSMISSION_STOP:
1961 tr = (struct ssp_intel_tr_ctl *)&aux_tlv->val;
1962 LOG_INF("tr sampling frequency %u, bit_depth %u, channel_map %u,",
1963 tr->sampling_frequency, tr->bit_depth, tr->channel_map);
1964 LOG_INF("channel_config %u, interleaving_style %u, format %u",
1965 tr->channel_config, tr->interleaving_style, tr->format);
1966 break;
1967 case SSP_DMA_ALWAYS_RUNNING_MODE:
1968 run = (struct ssp_intel_run_ctl *)&aux_tlv->val;
1969 LOG_INF("run enabled %u", run->enabled);
1970 break;
1971 case SSP_DMA_SYNC_DATA:
1972 sync = (struct ssp_intel_sync_ctl *)&aux_tlv->val;
1973 LOG_INF("sync sync_denominator %u, count %u",
1974 sync->sync_denominator, sync->count);
1975 node = (struct ssp_intel_node_ctl *)((uint8_t *)sync +
1976 sizeof(struct ssp_intel_sync_ctl));
1977 for (j = 0; j < sync->count; j++) {
1978 LOG_INF("node node_id %u, sampling_rate %u",
1979 node->node_id, node->sampling_rate);
1980 node++;
1981 }
1982 break;
1983 case SSP_DMA_CLK_CONTROLS_EXT:
1984 ext = (struct ssp_intel_ext_ctl *)&aux_tlv->val;
1985 LOG_INF("ext ext_data %u", ext->ext_data);
1986 break;
1987 case SSP_LINK_CLK_SOURCE:
1988 #if SSP_IP_VER >= SSP_IP_VER_1_5
1989 link = (struct ssp_intel_link_ctl *)&aux_tlv->val;
1990 #if SSP_IP_VER < SSP_IP_VER_2_0
1991 sys_write32((sys_read32(dai_ip_base(dp) + I2SLCTL_OFFSET) &
1992 ~I2CLCTL_MLCS(0x7)) |
1993 I2CLCTL_MLCS(link->clock_source), dai_ip_base(dp) +
1994 I2SLCTL_OFFSET);
1995 #elif SSP_IP_VER > SSP_IP_VER_1_5
1996 ssp->link_clock = link->clock_source;
1997 sys_write32((sys_read32(dai_i2svss_base(dp) + I2SLCTL_OFFSET) &
1998 ~I2CLCTL_MLCS(0x7)) |
1999 I2CLCTL_MLCS(link->clock_source),
2000 dai_i2svss_base(dp) + I2SLCTL_OFFSET);
2001 #endif
2002 LOG_INF("link clock_source %u", link->clock_source);
2003 #endif
2004 break;
2005 default:
2006 LOG_ERR("undefined aux data type %u", aux_tlv->type);
2007 return -EINVAL;
2008 }
2009
2010 hop = aux_tlv->size + sizeof(struct ssp_intel_aux_tlv);
2011 aux_ptr += hop;
2012 }
2013
2014 return 0;
2015 }
2016
dai_ssp_parse_aux_data(struct dai_intel_ssp * dp,const void * spec_config)2017 static int dai_ssp_parse_aux_data(struct dai_intel_ssp *dp, const void *spec_config)
2018 {
2019 const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config;
2020 const struct dai_intel_ipc4_ssp_configuration_blob_ver_3_0 *blob30 = spec_config;
2021 int cfg_len, pre_aux_len, aux_len;
2022 uint8_t *aux_ptr;
2023
2024 if (blob15->version == SSP_BLOB_VER_1_5) {
2025 cfg_len = blob15->size;
2026 pre_aux_len = sizeof(*blob15) +
2027 blob15->i2s_mclk_control.mdivrcnt * sizeof(uint32_t);
2028 aux_len = cfg_len - pre_aux_len;
2029 aux_ptr = (uint8_t *)blob15 + pre_aux_len;
2030 } else if (blob30->version == SSP_BLOB_VER_3_0) {
2031 cfg_len = blob30->size;
2032 pre_aux_len = sizeof(*blob30) +
2033 blob30->i2s_mclk_control.mdivrcnt * sizeof(uint32_t);
2034 aux_len = cfg_len - pre_aux_len;
2035 aux_ptr = (uint8_t *)blob30 + pre_aux_len;
2036 } else {
2037 LOG_ERR("unsupported blob version");
2038 return -EINVAL;
2039 }
2040
2041 if (aux_len <= 0) {
2042 return 0;
2043 }
2044
2045 return dai_ssp_parse_tlv(dp, aux_ptr, aux_len);
2046 }
2047
dai_ssp_set_clock_control_ver_1_5(struct dai_intel_ssp * dp,const struct dai_intel_ipc4_ssp_mclk_config_2 * cc)2048 static int dai_ssp_set_clock_control_ver_1_5(struct dai_intel_ssp *dp,
2049 const struct dai_intel_ipc4_ssp_mclk_config_2 *cc)
2050 {
2051 /* currently we only support 1 divider */
2052 if (cc->mdivrcnt != 1) {
2053 LOG_ERR("bad clock divider count %u", cc->mdivrcnt);
2054 return -EINVAL;
2055 }
2056
2057 /* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
2058 * mclk and bclk at this time.
2059 */
2060 dai_ssp_mn_set_mclk_blob(dp, cc->mdivctlr, cc->mdivr[0]);
2061
2062 return 0;
2063 }
2064
dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp * dp,const struct dai_intel_ipc4_ssp_mclk_config * cc)2065 static int dai_ssp_set_clock_control_ver_1(struct dai_intel_ssp *dp,
2066 const struct dai_intel_ipc4_ssp_mclk_config *cc)
2067 {
2068 /* ssp blob is set by pcm_hw_params for ipc4 stream, so enable
2069 * mclk and bclk at this time.
2070 */
2071 dai_ssp_mn_set_mclk_blob(dp, cc->mdivc, cc->mdivr);
2072
2073 return 0;
2074 }
2075
2076 #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)2077 static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg,
2078 const void *spec_config)
2079 {
2080 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2081 const struct dai_intel_ipc4_ssp_config_ver_3_0 *regs = spec_config;
2082 uint32_t sscr1 = 0;
2083 uint32_t ssc0 = regs->ssc0;
2084 sscr1 = regs->ssc1 & ~(SSCR1_RSVD21);
2085
2086 LOG_INF("SSP%d configuration:", dp->dai_index);
2087
2088 sys_write32(ssc0, dai_base(dp) + SSCR0);
2089 sys_write32(regs->ssc2 & ~SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
2090 sys_write32(sscr1, dai_base(dp) + SSCR1);
2091 sys_write32(regs->ssc2 | SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
2092 sys_write32(regs->ssc2, dai_base(dp) + SSCR2);
2093 sys_write32(regs->sspsp, dai_base(dp) + SSPSP);
2094 sys_write32(regs->sspsp2, dai_base(dp) + SSPSP2);
2095 sys_write32(regs->ssioc, dai_base(dp) + SSIOC);
2096 sys_write32(regs->sscto, dai_base(dp) + SSTO);
2097
2098 for (uint32_t idx = 0; idx < I2SIPCMC; ++idx) {
2099 sys_write64(regs->ssmidytsa[idx], dai_base(dp) + SSMIDyTSA(idx));
2100 }
2101
2102 for (uint32_t idx = 0; idx < I2SOPCMC; ++idx) {
2103 sys_write64(regs->ssmodytsa[idx], dai_base(dp) + SSMODyTSA(idx));
2104 }
2105
2106 LOG_INF(" sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
2107 ssc0, sscr1, regs->sscto, regs->sspsp);
2108 LOG_INF(" sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x",
2109 regs->ssc2, regs->sspsp2, regs->ssc3);
2110 LOG_INF(" ssioc = 0x%08x", regs->ssioc);
2111
2112 ssp_plat_data->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0);
2113 if (ssc0 & SSCR0_EDSS) {
2114 ssp_plat_data->params.sample_valid_bits += 16;
2115 }
2116
2117 ssp_plat_data->params.tx_slots = regs->ssmodytsa[dp->tdm_slot_group];
2118 ssp_plat_data->params.rx_slots = regs->ssmidytsa[dp->tdm_slot_group];
2119
2120 ssp_plat_data->params.fsync_rate = cfg->rate;
2121 dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
2122 dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
2123 }
2124 #else
dai_ssp_set_reg_config(struct dai_intel_ssp * dp,const struct dai_config * cfg,const void * spec_config)2125 static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_config *cfg,
2126 const void *spec_config)
2127 {
2128 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2129 const struct dai_intel_ipc4_ssp_config *regs = spec_config;
2130 uint32_t sscr1 = 0;
2131 uint32_t sstsa = 0;
2132 uint32_t ssrsa = 0;
2133 uint32_t ssc0 = regs->ssc0;
2134
2135 sscr1 = regs->ssc1 & ~(SSCR1_RSRE | SSCR1_TSRE);
2136 sstsa = SSTSA_GET(regs->sstsa);
2137 ssrsa = SSRSA_GET(regs->ssrsa);
2138
2139 LOG_INF("SSP%d configuration:", dp->dai_index);
2140
2141 if (regs->sstsa & SSTSA_TXEN || regs->ssrsa & SSRSA_RXEN ||
2142 regs->ssc1 & (SSCR1_RSRE | SSCR1_TSRE)) {
2143 LOG_INF(" Ignoring %s%s%s%sfrom blob",
2144 regs->sstsa & SSTSA_TXEN ? "SSTSA:TXEN " : "",
2145 regs->ssrsa & SSRSA_RXEN ? "SSRSA:RXEN " : "",
2146 regs->ssc1 & SSCR1_TSRE ? "SSCR1:TSRE " : "",
2147 regs->ssc1 & SSCR1_RSRE ? "SSCR1:RSRE " : "");
2148 }
2149
2150 sys_write32(ssc0, dai_base(dp) + SSCR0);
2151 sys_write32(regs->ssc2 & ~SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
2152 sys_write32(sscr1, dai_base(dp) + SSCR1);
2153 sys_write32(regs->ssc2 | SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */
2154 sys_write32(regs->ssc2, dai_base(dp) + SSCR2);
2155 sys_write32(regs->ssc3, dai_base(dp) + SSCR3);
2156 sys_write32(regs->sspsp, dai_base(dp) + SSPSP);
2157 sys_write32(regs->sspsp2, dai_base(dp) + SSPSP2);
2158 sys_write32(regs->ssioc, dai_base(dp) + SSIOC);
2159 sys_write32(regs->sscto, dai_base(dp) + SSTO);
2160 sys_write32(sstsa, dai_base(dp) + SSTSA);
2161 sys_write32(ssrsa, dai_base(dp) + SSRSA);
2162
2163 LOG_INF(" sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x",
2164 ssc0, sscr1, regs->sscto, regs->sspsp);
2165 LOG_INF(" sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x",
2166 regs->ssc2, regs->sspsp2, regs->ssc3);
2167 LOG_INF(" ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x",
2168 regs->ssioc, ssrsa, sstsa);
2169
2170 ssp_plat_data->params.sample_valid_bits = SSCR0_DSIZE_GET(ssc0);
2171 if (ssc0 & SSCR0_EDSS) {
2172 ssp_plat_data->params.sample_valid_bits += 16;
2173 }
2174
2175 ssp_plat_data->params.tdm_slots = SSCR0_FRDC_GET(ssc0);
2176 ssp_plat_data->params.tx_slots = SSTSA_GET(sstsa);
2177 ssp_plat_data->params.rx_slots = SSRSA_GET(ssrsa);
2178 ssp_plat_data->params.fsync_rate = cfg->rate;
2179 dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
2180 dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
2181 }
2182 #endif
2183
dai_ssp_set_config_blob(struct dai_intel_ssp * dp,const struct dai_config * cfg,const void * spec_config)2184 static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_config *cfg,
2185 const void *spec_config)
2186 {
2187 const struct dai_intel_ipc4_ssp_configuration_blob_ver_1_5 *blob15 = spec_config;
2188 const struct dai_intel_ipc4_ssp_configuration_blob_ver_3_0 *blob30 = spec_config;
2189 const struct dai_intel_ipc4_ssp_configuration_blob *blob = spec_config;
2190 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2191 int err;
2192
2193 #if SSP_IP_VER > SSP_IP_VER_2_0
2194 dp->tdm_slot_group = cfg->tdm_slot_group;
2195 #endif
2196
2197 /* set config only once for playback or capture */
2198 if (ssp_plat_data->is_initialized) {
2199 dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
2200 dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
2201 return 0;
2202 }
2203
2204 if (blob15->version == SSP_BLOB_VER_1_5) {
2205 err = dai_ssp_parse_aux_data(dp, spec_config);
2206 if (err) {
2207 return err;
2208 }
2209 dai_ssp_set_reg_config(dp, cfg, (void *)&blob15->i2s_ssp_config);
2210 err = dai_ssp_set_clock_control_ver_1_5(dp, &blob15->i2s_mclk_control);
2211 if (err) {
2212 return err;
2213 }
2214 } else if (blob30->version == SSP_BLOB_VER_3_0) {
2215 err = dai_ssp_parse_aux_data(dp, spec_config);
2216 if (err) {
2217 return err;
2218 }
2219 dai_ssp_set_reg_config(dp, cfg, (void *)&blob30->i2s_ssp_config);
2220 err = dai_ssp_set_clock_control_ver_1_5(dp, &blob30->i2s_mclk_control);
2221 if (err) {
2222 return err;
2223 }
2224 } else {
2225 dai_ssp_set_reg_config(dp, cfg, (void *)&blob->i2s_driver_config.i2s_config);
2226 err = dai_ssp_set_clock_control_ver_1(dp, &blob->i2s_driver_config.mclk_config);
2227 if (err) {
2228 return err;
2229 }
2230 }
2231
2232 ssp_plat_data->clk_active |= SSP_CLK_MCLK_ES_REQ;
2233
2234 /* enable port */
2235 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
2236 ssp_plat_data->clk_active |= SSP_CLK_BCLK_ES_REQ;
2237 ssp_plat_data->is_initialized = true;
2238
2239 return 0;
2240 }
2241
2242 /*
2243 * Portion of the SSP configuration should be applied just before the
2244 * SSP dai is activated, for either power saving or params runtime
2245 * configurable flexibility.
2246 */
dai_ssp_pre_start(struct dai_intel_ssp * dp)2247 static int dai_ssp_pre_start(struct dai_intel_ssp *dp)
2248 {
2249 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2250 int ret = 0;
2251
2252 /*
2253 * We will test if mclk/bclk is configured in
2254 * ssp_mclk/bclk_prepare_enable/disable functions
2255 */
2256 if (!(ssp_plat_data->clk_active & SSP_CLK_MCLK_ES_REQ)) {
2257 /* MCLK config */
2258 ret = dai_ssp_mclk_prepare_enable(dp);
2259 if (ret < 0) {
2260 return ret;
2261 }
2262 }
2263
2264 if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) {
2265 ret = dai_ssp_bclk_prepare_enable(dp);
2266 }
2267
2268 return ret;
2269 }
2270
2271 /*
2272 * For power saving, we should do kinds of power release when the SSP
2273 * dai is changed to inactive, though the runtime param configuration
2274 * don't have to be reset.
2275 */
dai_ssp_post_stop(struct dai_intel_ssp * dp)2276 static void dai_ssp_post_stop(struct dai_intel_ssp *dp)
2277 {
2278 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2279
2280 /* release clocks if SSP is inactive */
2281 if (dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_RUNNING &&
2282 dp->state[DAI_DIR_CAPTURE] != DAI_STATE_RUNNING) {
2283 if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) {
2284 LOG_INF("releasing BCLK clocks for SSP%d...", dp->dai_index);
2285 dai_ssp_bclk_disable_unprepare(dp);
2286 }
2287 if (!(ssp_plat_data->clk_active & SSP_CLK_MCLK_ES_REQ)) {
2288 LOG_INF("releasing MCLK clocks for SSP%d...", dp->dai_index);
2289 dai_ssp_mclk_disable_unprepare(dp);
2290 }
2291 }
2292 }
2293
dai_ssp_early_start(struct dai_intel_ssp * dp,int direction)2294 static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction)
2295 {
2296 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2297 k_spinlock_key_t key;
2298
2299 key = k_spin_lock(&dp->lock);
2300
2301 /* RX fifo must be cleared before start */
2302 if (direction == DAI_DIR_CAPTURE) {
2303 LOG_INF("SSP%d RX", dp->dai_index);
2304 ssp_empty_rx_fifo_on_start(dp);
2305 } else {
2306 LOG_INF("SSP%d TX", dp->dai_index);
2307 }
2308
2309 /* request mclk/bclk */
2310 dai_ssp_pre_start(dp);
2311
2312 if (!(ssp_plat_data->clk_active & SSP_CLK_BCLK_ES_REQ)) {
2313 /* enable port */
2314 LOG_INF("SSP%d: set SSE", dp->dai_index);
2315 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE);
2316 }
2317
2318 k_spin_unlock(&dp->lock, key);
2319 }
2320
2321 /* start the SSP for either playback or capture */
dai_ssp_start(struct dai_intel_ssp * dp,int direction)2322 static void dai_ssp_start(struct dai_intel_ssp *dp, int direction)
2323 {
2324 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2325 k_spinlock_key_t key;
2326
2327 key = k_spin_lock(&dp->lock);
2328
2329
2330 /* enable DMA */
2331 if (direction == DAI_DIR_PLAYBACK) {
2332 LOG_INF("SSP%d TX", dp->dai_index);
2333 #if SSP_IP_VER > SSP_IP_VER_2_0
2334 dai_ssp_update_bits(dp, SSMODyCS(dp->tdm_slot_group),
2335 SSMODyCS_TSRE, SSMODyCS_TSRE);
2336 dai_ssp_update_bits(dp, SSMODyCS(dp->tdm_slot_group),
2337 SSMODyCS_TXEN, SSMODyCS_TXEN);
2338 #else
2339 dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, SSCR1_TSRE);
2340 dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN);
2341 #endif
2342 } else {
2343 LOG_INF("SSP%d RX", dp->dai_index);
2344 #if SSP_IP_VER > SSP_IP_VER_2_0
2345 dai_ssp_update_bits(dp, SSMIDyCS(dp->tdm_slot_group),
2346 SSMIDyCS_RSRE, SSMIDyCS_RSRE);
2347 dai_ssp_update_bits(dp, SSMIDyCS(dp->tdm_slot_group),
2348 SSMIDyCS_RXEN, SSMIDyCS_RXEN);
2349 #else
2350 dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, SSCR1_RSRE);
2351 dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN);
2352 #endif
2353 }
2354
2355 dp->state[direction] = DAI_STATE_RUNNING;
2356
2357 /*
2358 * Wait to get valid fifo status in clock consumer mode. TODO it's
2359 * uncertain which SSP clock consumer modes need the delay atm, but
2360 * these can be added here when confirmed.
2361 */
2362 switch (ssp->config.format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
2363 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
2364 break;
2365 default:
2366 /* delay for all SSP consumed clocks atm - see above */
2367 /* ssp_wait_delay(PLATFORM_SSP_DELAY); */
2368 k_busy_wait(DAI_INTEL_SSP_PLATFORM_DELAY_US);
2369 break;
2370 }
2371
2372 k_spin_unlock(&dp->lock, key);
2373 }
2374
2375 /* stop the SSP for either playback or capture */
dai_ssp_stop(struct dai_intel_ssp * dp,int direction)2376 static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction)
2377 {
2378 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2379 k_spinlock_key_t key;
2380
2381 key = k_spin_lock(&dp->lock);
2382
2383 /*
2384 * Wait to get valid fifo status in clock consumer mode. TODO it's
2385 * uncertain which SSP clock consumer modes need the delay atm, but
2386 * these can be added here when confirmed.
2387 */
2388 switch (ssp->config.format & DAI_INTEL_IPC3_SSP_FMT_CLOCK_PROVIDER_MASK) {
2389 case DAI_INTEL_IPC3_SSP_FMT_CBC_CFC:
2390 break;
2391 default:
2392 /* delay for all SSP consumed clocks atm - see above */
2393 k_busy_wait(DAI_INTEL_SSP_PLATFORM_DELAY_US);
2394 break;
2395 }
2396
2397 /* stop Rx if neeed */
2398 if (direction == DAI_DIR_CAPTURE &&
2399 dp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) {
2400 LOG_INF("SSP%d RX", dp->dai_index);
2401
2402 #if SSP_IP_VER > SSP_IP_VER_2_0
2403 dai_ssp_update_bits(dp, SSMIDyCS(dp->tdm_slot_group), SSMIDyCS_RXEN, 0);
2404 dai_ssp_update_bits(dp, SSMIDyCS(dp->tdm_slot_group), SSMIDyCS_RSRE, 0);
2405 #else
2406 dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0);
2407 dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, 0);
2408 #endif
2409 ssp_empty_rx_fifo_on_stop(dp);
2410 dp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING;
2411 }
2412
2413 /* stop Tx if needed */
2414 if (direction == DAI_DIR_PLAYBACK &&
2415 dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) {
2416 LOG_INF("SSP%d TX", dp->dai_index);
2417
2418 #if SSP_IP_VER > SSP_IP_VER_2_0
2419 dai_ssp_update_bits(dp, SSMODyCS(dp->tdm_slot_group), SSMODyCS_TSRE, 0);
2420 dai_ssp_empty_tx_fifo(dp);
2421 dai_ssp_update_bits(dp, SSMODyCS(dp->tdm_slot_group), SSMODyCS_TXEN, 0);
2422 #else
2423 dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, 0);
2424 dai_ssp_empty_tx_fifo(dp);
2425 dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0);
2426 #endif
2427 dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING;
2428 }
2429
2430 k_spin_unlock(&dp->lock, key);
2431 }
2432
dai_ssp_pause(struct dai_intel_ssp * dp,int direction)2433 static void dai_ssp_pause(struct dai_intel_ssp *dp, int direction)
2434 {
2435 if (direction == DAI_DIR_CAPTURE) {
2436 LOG_INF("SSP%d RX", dp->dai_index);
2437 } else {
2438 LOG_INF("SSP%d TX", dp->dai_index);
2439 }
2440
2441 dp->state[direction] = DAI_STATE_PAUSED;
2442 }
2443
dai_ssp_trigger(const struct device * dev,enum dai_dir dir,enum dai_trigger_cmd cmd)2444 static int dai_ssp_trigger(const struct device *dev, enum dai_dir dir,
2445 enum dai_trigger_cmd cmd)
2446 {
2447 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2448 int array_index = SSP_ARRAY_INDEX(dir);
2449
2450 LOG_DBG("SSP%d: cmd %d", dp->dai_index, cmd);
2451
2452 switch (cmd) {
2453 case DAI_TRIGGER_START:
2454 if (dp->state[array_index] == DAI_STATE_PAUSED ||
2455 dp->state[array_index] == DAI_STATE_PRE_RUNNING) {
2456 dai_ssp_start(dp, array_index);
2457 }
2458 break;
2459 case DAI_TRIGGER_STOP:
2460 dai_ssp_stop(dp, array_index);
2461 break;
2462 case DAI_TRIGGER_PAUSE:
2463 dai_ssp_pause(dp, array_index);
2464 break;
2465 case DAI_TRIGGER_PRE_START:
2466 dai_ssp_early_start(dp, array_index);
2467 break;
2468 default:
2469 break;
2470 }
2471
2472 return 0;
2473 }
2474
dai_ssp_config_get(const struct device * dev,struct dai_config * cfg,enum dai_dir dir)2475 static int dai_ssp_config_get(const struct device *dev, struct dai_config *cfg, enum dai_dir dir)
2476 {
2477 struct dai_config *params = (struct dai_config *)dev->config;
2478 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2479 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2480 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2481
2482 if (!cfg) {
2483 return -EINVAL;
2484 }
2485
2486 if (!ssp) {
2487 *cfg = *params;
2488 return 0;
2489 }
2490
2491 params->rate = ssp_plat_data->params.fsync_rate;
2492
2493 if (dir == DAI_DIR_PLAYBACK) {
2494 params->channels = POPCOUNT(ssp_plat_data->params.tx_slots);
2495 } else {
2496 params->channels = POPCOUNT(ssp_plat_data->params.rx_slots);
2497 }
2498
2499 params->word_size = ssp_plat_data->params.sample_valid_bits;
2500
2501 *cfg = *params;
2502
2503 return 0;
2504 }
2505
dai_ssp_config_set(const struct device * dev,const struct dai_config * cfg,const void * bespoke_cfg)2506 static int dai_ssp_config_set(const struct device *dev, const struct dai_config *cfg,
2507 const void *bespoke_cfg)
2508 {
2509 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2510 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2511 int ret;
2512
2513 if (cfg->type == DAI_INTEL_SSP) {
2514 ret = dai_ssp_set_config_tplg(dp, cfg, bespoke_cfg);
2515 } else {
2516 ret = dai_ssp_set_config_blob(dp, cfg, bespoke_cfg);
2517 }
2518 dai_ssp_program_channel_map(dp, cfg, ssp_plat_data->ssp_index, bespoke_cfg);
2519
2520 return ret;
2521 }
2522
dai_ssp_get_properties(const struct device * dev,enum dai_dir dir,int stream_id)2523 static const struct dai_properties *dai_ssp_get_properties(const struct device *dev,
2524 enum dai_dir dir, int stream_id)
2525 {
2526 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2527 struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp);
2528 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2529 struct dai_properties *prop = &ssp->props;
2530 int array_index = SSP_ARRAY_INDEX(dir);
2531
2532 prop->fifo_address = ssp_plat_data->fifo[array_index].offset;
2533 prop->dma_hs_id = ssp_plat_data->fifo[array_index].handshake;
2534
2535 if (ssp_plat_data->clk_active & SSP_CLK_BCLK_ACTIVE) {
2536 prop->reg_init_delay = 0;
2537 } else {
2538 prop->reg_init_delay = ssp_plat_data->params.bclk_delay;
2539 }
2540
2541 LOG_INF("SSP%u: fifo %u, handshake %u, init delay %u", dp->dai_index, prop->fifo_address,
2542 prop->dma_hs_id, prop->reg_init_delay);
2543
2544 return prop;
2545 }
2546
ssp_acquire_ip(struct dai_intel_ssp * dp)2547 static void ssp_acquire_ip(struct dai_intel_ssp *dp)
2548 {
2549 struct dai_intel_ssp_plat_data *ssp = dai_get_plat_data(dp);
2550
2551 ssp->acquire_count++;
2552
2553 if (ssp->acquire_count == 1) {
2554 /* Enable SSP power */
2555 dai_ssp_pm_runtime_en_ssp_power(dp, ssp->ssp_index);
2556
2557 /* Disable dynamic clock gating before touching any register */
2558 dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, ssp->ssp_index);
2559
2560 #if SSP_IP_VER >= SSP_IP_VER_2_0
2561 /* Switch to selected clock source */
2562 sys_write32((sys_read32(dai_i2svss_base(dp) + I2SLCTL_OFFSET) &
2563 ~I2CLCTL_MLCS(0x7)) |
2564 I2CLCTL_MLCS(ssp->link_clock),
2565 dai_i2svss_base(dp) + I2SLCTL_OFFSET);
2566 #endif
2567 }
2568 }
2569
ssp_release_ip(struct dai_intel_ssp * dp)2570 static void ssp_release_ip(struct dai_intel_ssp *dp)
2571 {
2572 struct dai_intel_ssp_plat_data *ssp = dai_get_plat_data(dp);
2573
2574 if (ssp->acquire_count == 0) {
2575 return;
2576 }
2577
2578 --ssp->acquire_count;
2579
2580 if (ssp->acquire_count == 0) {
2581 /* disable SSP port if no users */
2582 if (dp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING &&
2583 dp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING &&
2584 COND_CODE_1(CONFIG_INTEL_ADSP_CAVS,
2585 (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) {
2586 dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0);
2587 LOG_INF("%s SSE clear SSP%d", __func__, ssp->ssp_index);
2588 }
2589
2590 dai_ssp_post_stop(dp);
2591
2592 #if SSP_IP_VER >= SSP_IP_VER_2_0
2593 /* Restore default XTAL clock source */
2594 sys_write32((sys_read32(dai_i2svss_base(dp) + I2SLCTL_OFFSET) &
2595 ~I2CLCTL_MLCS(0x7)) |
2596 I2CLCTL_MLCS(DAI_INTEL_SSP_CLOCK_XTAL_OSCILLATOR),
2597 dai_i2svss_base(dp) + I2SLCTL_OFFSET);
2598 #endif
2599
2600 dai_ssp_pm_runtime_en_ssp_clk_gating(dp, ssp->ssp_index);
2601
2602 dai_ssp_mclk_disable_unprepare(dp);
2603 dai_ssp_bclk_disable_unprepare(dp);
2604
2605 /* Disable SSP power */
2606 dai_ssp_pm_runtime_dis_ssp_power(dp, ssp->ssp_index);
2607 ssp->is_initialized = false;
2608 }
2609 }
2610
dai_ssp_probe(struct dai_intel_ssp * dp)2611 static int dai_ssp_probe(struct dai_intel_ssp *dp)
2612 {
2613 struct dai_intel_ssp_plat_data *ssp_plat_data = dai_get_plat_data(dp);
2614 struct dai_intel_ssp_pdata *ssp;
2615
2616 if (dai_get_drvdata(dp)) {
2617 return -EEXIST; /* already created */
2618 }
2619
2620 /* allocate private data */
2621 ssp = k_calloc(1, sizeof(*ssp));
2622 if (!ssp) {
2623 LOG_ERR("SSP%d: alloc failed", ssp_plat_data->ssp_index);
2624 return -ENOMEM;
2625 }
2626 dai_set_drvdata(dp, ssp);
2627
2628 dp->state[DAI_DIR_PLAYBACK] = DAI_STATE_READY;
2629 dp->state[DAI_DIR_CAPTURE] = DAI_STATE_READY;
2630
2631 #if SSP_IP_VER == SSP_IP_VER_1_0
2632 /* Reset M/N, power-gating functions need it */
2633 dai_ssp_mn_reset_bclk_divider(dp, ssp_plat_data->ssp_index);
2634 #endif
2635
2636 ssp_acquire_ip(dp);
2637
2638 return 0;
2639 }
2640
dai_ssp_remove(struct dai_intel_ssp * dp)2641 static int dai_ssp_remove(struct dai_intel_ssp *dp)
2642 {
2643 ssp_release_ip(dp);
2644
2645 k_free(dai_get_drvdata(dp));
2646 dai_set_drvdata(dp, NULL);
2647
2648 return 0;
2649 }
2650
ssp_pm_action(const struct device * dev,enum pm_device_action action)2651 static int ssp_pm_action(const struct device *dev, enum pm_device_action action)
2652 {
2653 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2654
2655 switch (action) {
2656 case PM_DEVICE_ACTION_SUSPEND:
2657 dai_ssp_remove(dp);
2658 break;
2659 case PM_DEVICE_ACTION_RESUME:
2660 dai_ssp_probe(dp);
2661 break;
2662 case PM_DEVICE_ACTION_TURN_OFF:
2663 case PM_DEVICE_ACTION_TURN_ON:
2664 /* All device pm is handled during resume and suspend */
2665 break;
2666 default:
2667 return -ENOTSUP;
2668 }
2669
2670 return 0;
2671 }
2672
dai_intel_ssp_init_device(const struct device * dev)2673 static int dai_intel_ssp_init_device(const struct device *dev)
2674 {
2675 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2676
2677 dp->ssp_plat_data = ssp_get_device_instance(dp->ssp_index);
2678
2679 return 0;
2680 };
2681
ssp_init(const struct device * dev)2682 static int ssp_init(const struct device *dev)
2683 {
2684 dai_intel_ssp_init_device(dev);
2685 return pm_device_driver_init(dev, ssp_pm_action);
2686 }
2687
dai_ssp_dma_control_set(const struct device * dev,const void * bespoke_cfg,size_t size)2688 static int dai_ssp_dma_control_set(const struct device *dev,
2689 const void *bespoke_cfg,
2690 size_t size)
2691 {
2692 struct dai_intel_ssp *dp = (struct dai_intel_ssp *)dev->data;
2693
2694 LOG_INF("SSP%d: tlv addr = 0x%x, tlv size = %d",
2695 dp->dai_index, (uint32_t)bespoke_cfg, size);
2696 if (size < sizeof(struct ssp_intel_aux_tlv)) {
2697 return -EINVAL;
2698 }
2699
2700 if (dp->state[DAI_DIR_PLAYBACK] != DAI_STATE_READY ||
2701 dp->state[DAI_DIR_CAPTURE] != DAI_STATE_READY) {
2702 return -EIO;
2703 }
2704
2705 if (dai_ssp_check_dma_control(bespoke_cfg, size)) {
2706 return -EINVAL;
2707 }
2708
2709 return dai_ssp_parse_tlv(dp, bespoke_cfg, size);
2710 }
2711
2712 static DEVICE_API(dai, dai_intel_ssp_api_funcs) = {
2713 .probe = pm_device_runtime_get,
2714 .remove = pm_device_runtime_put,
2715 .config_set = dai_ssp_config_set,
2716 .config_get = dai_ssp_config_get,
2717 .trigger = dai_ssp_trigger,
2718 .get_properties = dai_ssp_get_properties,
2719 .config_update = dai_ssp_dma_control_set,
2720 };
2721
2722
2723 #define DT_DRV_COMPAT intel_ssp_dai
2724
2725 #define DAI_INTEL_SSP_DEVICE_INIT(n) \
2726 static struct dai_config dai_intel_ssp_config_##n = { \
2727 .type = DAI_INTEL_SSP, \
2728 .dai_index = DT_INST_REG_ADDR(n), \
2729 }; \
2730 static struct dai_intel_ssp dai_intel_ssp_data_##n = { \
2731 .dai_index = DT_INST_REG_ADDR(n), \
2732 .ssp_index = DT_PROP(DT_INST_PARENT(n), ssp_index), \
2733 .tdm_slot_group = 0, \
2734 }; \
2735 \
2736 PM_DEVICE_DT_INST_DEFINE(n, ssp_pm_action); \
2737 \
2738 DEVICE_DT_INST_DEFINE(n, \
2739 ssp_init, PM_DEVICE_DT_INST_GET(n), \
2740 &dai_intel_ssp_data_##n, \
2741 &dai_intel_ssp_config_##n, \
2742 POST_KERNEL, 42, \
2743 &dai_intel_ssp_api_funcs);
2744
2745 DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_SSP_DEVICE_INIT)
2746