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