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