1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 
10 #include <zephyr/toolchain.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/sys/util.h>
13 
14 #include <zephyr/device.h>
15 #include <zephyr/drivers/dai.h>
16 #include <zephyr/drivers/dma.h>
17 #include <soc.h>
18 
19 /* sof ssp bespoke data */
20 struct sof_dai_ssp_params {
21 	uint32_t reserved0;
22 	uint16_t reserved1;
23 	uint16_t mclk_id;
24 
25 	uint32_t mclk_rate;
26 	uint32_t fsync_rate;
27 	uint32_t bclk_rate;
28 
29 	uint32_t tdm_slots;
30 	uint32_t rx_slots;
31 	uint32_t tx_slots;
32 
33 	uint32_t sample_valid_bits;
34 	uint16_t tdm_slot_width;
35 	uint16_t reserved2;
36 
37 	uint32_t mclk_direction;
38 
39 	uint16_t frame_pulse_width;
40 	uint16_t tdm_per_slot_padding_flag;
41 	uint32_t clks_control;
42 	uint32_t quirks;
43 	uint32_t bclk_delay;
44 } __packed;
45 
46 static const struct device *const dev_dai_ssp =
47 	DEVICE_DT_GET(DT_NODELABEL(ssp00));
48 static const struct device *const dev_dma_dw =
49 	DEVICE_DT_GET(DT_NODELABEL(lpgpdma0));
50 
51 static struct dai_config config;
52 static struct sof_dai_ssp_params ssp_config;
53 
54 #define BUF_SIZE 48
55 #define XFER_SIZE BUF_SIZE * 4
56 #define XFERS 2
57 
58 K_SEM_DEFINE(xfer_sem, 0, 1);
59 
60 static struct dma_config dma_cfg = {0};
61 static struct dma_block_config dma_block_cfgs[XFERS];
62 static struct dma_config dma_cfg_rx = {0};
63 static struct dma_block_config dma_block_cfgs_rx[XFERS];
64 
65 /* 1ms frame of 48Hz sine in 48kHz, thus 48 x 32 bit samples */
66 static int32_t sine_buf[BUF_SIZE] = {
67 	0x00000000, 0x10b5150f, 0x2120fb83, 0x30fbc54d,
68 	0x40000000, 0x4debe4fe, 0x5a82799a, 0x658c9a2d,
69 	0x6ed9eba1, 0x7641af3d, 0x7ba3751d, 0x7ee7aa4c,
70 	0x7fffffff, 0x7ee7aa4c, 0x7ba3751d, 0x7641af3d,
71 	0x6ed9eba1, 0x658c9a2d, 0x5a82799a, 0x4debe4fe,
72 	0x40000000, 0x30fbc54d, 0x2120fb83, 0x10b5150f,
73 	0x00000000, 0xef4aeaf1, 0xdedf047d, 0xcf043ab3,
74 	0xc0000000, 0xb2141b02, 0xa57d8666, 0x9a7365d3,
75 	0x9126145f, 0x89be50c3, 0x845c8ae3, 0x811855b4,
76 	0x80000000, 0x811855b4, 0x845c8ae3, 0x89be50c3,
77 	0x9126145f, 0x9a7365d3, 0xa57d8666, 0xb2141b02,
78 	0xc0000000, 0xcf043ab3, 0xdedf047d, 0xef4aeaf1,
79 };
80 
81 static __aligned(32) int32_t rx_data[XFERS][BUF_SIZE] = { { 0 } };
82 
dma_callback(const struct device * dma_dev,void * user_data,uint32_t channel,int status)83 static void dma_callback(const struct device *dma_dev, void *user_data,
84 			 uint32_t channel, int status)
85 {
86 	if (status < 0) {
87 		TC_PRINT("tx callback status %d\n", status);
88 	} else {
89 		TC_PRINT("tx giving up\n");
90 	}
91 }
92 
dma_callback_rx(const struct device * dma_dev,void * user_data,uint32_t channel,int status)93 static void dma_callback_rx(const struct device *dma_dev, void *user_data,
94 			    uint32_t channel, int status)
95 {
96 	if (status < 0) {
97 		TC_PRINT("rx callback status %d\n", status);
98 	} else {
99 		TC_PRINT("rx giving xfer_sem\n");
100 		k_sem_give(&xfer_sem);
101 	}
102 }
103 
config_output_dma(const struct dai_properties * props,uint32_t * chan_id)104 static int config_output_dma(const struct dai_properties *props, uint32_t *chan_id)
105 {
106 	dma_cfg.dma_slot = props->dma_hs_id;
107 	dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
108 	dma_cfg.dest_handshake = 0;
109 	dma_cfg.source_handshake = 0;
110 	dma_cfg.cyclic = 1;
111 	dma_cfg.source_data_size = 1;
112 	dma_cfg.dest_data_size = 1;
113 	dma_cfg.source_burst_length = 1;
114 	dma_cfg.dest_burst_length = 1;
115 	dma_cfg.user_data = NULL;
116 	dma_cfg.dma_callback = dma_callback;
117 	dma_cfg.block_count = XFERS;
118 	dma_cfg.head_block = dma_block_cfgs;
119 	dma_cfg.complete_callback_en = false; /* per block completion */
120 
121 	*chan_id = dma_request_channel(dev_dma_dw, NULL);
122 	if (*chan_id < 0) {
123 		TC_PRINT("Platform does not support dma request channel\n");
124 		return -1;
125 	}
126 
127 	memset(dma_block_cfgs, 0, sizeof(dma_block_cfgs));
128 	for (int i = 0; i < XFERS; i++) {
129 		dma_block_cfgs[i].block_size = XFER_SIZE;
130 		dma_block_cfgs[i].source_address = (uint32_t)sine_buf;
131 		dma_block_cfgs[i].dest_address = props->fifo_address;
132 		TC_PRINT("dma block %d block_size %d, source addr %x, dest addr %x\n",
133 			 i, BUF_SIZE, dma_block_cfgs[i].source_address,
134 			 dma_block_cfgs[i].dest_address);
135 		if (i < XFERS - 1) {
136 			dma_block_cfgs[i].next_block = &dma_block_cfgs[i+1];
137 			TC_PRINT("set next block pointer to %p\n", dma_block_cfgs[i].next_block);
138 		}
139 	}
140 
141 	return 0;
142 }
143 
config_input_dma(const struct dai_properties * props,uint32_t * chan_id_rx)144 static int config_input_dma(const struct dai_properties *props, uint32_t *chan_id_rx)
145 {
146 	dma_cfg_rx.dma_slot = props->dma_hs_id;
147 	dma_cfg_rx.channel_direction = PERIPHERAL_TO_MEMORY;
148 	dma_cfg_rx.dest_handshake = 0;
149 	dma_cfg_rx.source_handshake = 0;
150 	dma_cfg_rx.cyclic = 1;
151 	dma_cfg_rx.source_data_size = 1;
152 	dma_cfg_rx.dest_data_size = 1;
153 	dma_cfg_rx.source_burst_length = 1;
154 	dma_cfg_rx.dest_burst_length = 1;
155 	dma_cfg_rx.user_data = NULL;
156 	dma_cfg_rx.dma_callback = dma_callback_rx;
157 	dma_cfg_rx.block_count = XFERS;
158 	dma_cfg_rx.head_block = dma_block_cfgs_rx;
159 	dma_cfg_rx.complete_callback_en = false; /* per block completion */
160 
161 	*chan_id_rx = dma_request_channel(dev_dma_dw, NULL);
162 	if (*chan_id_rx < 0) {
163 		TC_PRINT("Platform does not support dma request channel\n");
164 		return -1;
165 	}
166 
167 	memset(dma_block_cfgs_rx, 0, sizeof(dma_block_cfgs_rx));
168 	memset(rx_data, 0, sizeof(rx_data));
169 	for (int i = 0; i < XFERS; i++) {
170 		dma_block_cfgs_rx[i].block_size = XFER_SIZE;
171 		dma_block_cfgs_rx[i].source_address = props->fifo_address;
172 		dma_block_cfgs_rx[i].dest_address = (uint32_t)rx_data[i];
173 		TC_PRINT("dma block %d block_size %d, source addr %x, dest addr %x\n",
174 			 i, BUF_SIZE, dma_block_cfgs_rx[i].source_address,
175 			 dma_block_cfgs_rx[i].dest_address);
176 		if (i < XFERS - 1) {
177 			dma_block_cfgs_rx[i].next_block = &dma_block_cfgs_rx[i+1];
178 			TC_PRINT("set next block pointer to %p\n", dma_block_cfgs_rx[i].next_block);
179 		}
180 	}
181 
182 	return 0;
183 }
184 
check_transmission(void)185 static int check_transmission(void)
186 {
187 	int32_t buffer[2 * BUF_SIZE];
188 	bool pattern_found = false;
189 	int32_t pattern[4];
190 	int start_index;
191 	int i, j;
192 
193 	TC_PRINT("Checking transmission:\n");
194 
195 	/* let's make things easier */
196 	for (i = 0; i < BUF_SIZE; i++) {
197 		buffer[i] = rx_data[0][i];
198 		buffer[BUF_SIZE + i] = rx_data[1][i];
199 	}
200 
201 	for (i = 0; i < 4; i++) {
202 		pattern[i] = sine_buf[i];
203 	}
204 
205 	TC_PRINT("tx_data (will be sent 2 times):\n");
206 	for (i = 0; i < BUF_SIZE; i += 8) {
207 		for (j = 0; j < 8; j++) {
208 			TC_PRINT("0x%08x ", sine_buf[i + j]);
209 		}
210 		TC_PRINT("\n");
211 	}
212 	TC_PRINT("\n");
213 
214 	TC_PRINT("rx_data:\n");
215 	for (i = 0; i < BUF_SIZE * 2; i += 8) {
216 		for (j = 0; j < 8; j++) {
217 			TC_PRINT("0x%08x ", buffer[i + j]);
218 		}
219 		TC_PRINT("\n");
220 	}
221 	TC_PRINT("\n");
222 
223 	/* search for pattern only on first half */
224 	for (i = 0; i < BUF_SIZE; i++) {
225 		if (buffer[i] == pattern[0] &&
226 		    buffer[i + 1] == pattern[1] &&
227 		    buffer[i + 2] == pattern[2] &&
228 		    buffer[i + 3] == pattern[3]) {
229 			pattern_found = true;
230 			start_index = i;
231 			break;
232 		}
233 	}
234 
235 	if (!pattern_found) {
236 		TC_PRINT("pattern not found in rx buffer\n");
237 		return TC_FAIL;
238 	}
239 
240 	TC_PRINT("pattern found in rx buffer an index %d value %x\n", start_index,
241 		 buffer[start_index]);
242 
243 	for (i = 0; i < BUF_SIZE; i++) {
244 		TC_PRINT("tx 0x%08x rx 0x%08x\n", buffer[start_index + i], sine_buf[i]);
245 		if (buffer[start_index + i] != sine_buf[i]) {
246 			break;
247 		}
248 	}
249 
250 	if (i < BUF_SIZE - 1) {
251 		TC_PRINT("transfer differs at index %d\n", i);
252 		return TC_FAIL;
253 	}
254 
255 	return TC_PASS;
256 }
257 
ZTEST(adsp_ssp,test_adsp_ssp_transfer)258 ZTEST(adsp_ssp, test_adsp_ssp_transfer)
259 {
260 	const struct dai_properties *props;
261 	static int chan_id_rx;
262 	static int chan_id;
263 
264 	props = dai_get_properties(dev_dai_ssp, DAI_DIR_TX, 0);
265 	if (!props) {
266 		TC_PRINT("Cannot get dai tx properties\n");
267 		return;
268 	}
269 
270 	if (config_output_dma(props, &chan_id)) {
271 		TC_PRINT("ERROR: config tx dma (%d)\n", chan_id);
272 		return;
273 	}
274 
275 	TC_PRINT("Configuring the dma tx transfer on channel %d\n", chan_id);
276 
277 	if (dma_config(dev_dma_dw, chan_id, &dma_cfg)) {
278 		TC_PRINT("ERROR: dma tx config (%d)\n", chan_id);
279 		return;
280 	}
281 
282 	props = dai_get_properties(dev_dai_ssp, DAI_DIR_RX, 0);
283 	if (!props) {
284 		TC_PRINT("Cannot get dai rx properties\n");
285 		return;
286 	}
287 
288 	if (config_input_dma(props, &chan_id_rx)) {
289 		TC_PRINT("ERROR: config rx dma (%d)\n", chan_id);
290 		return;
291 	}
292 
293 	TC_PRINT("Configuring the dma rx transfer on channel %d\n", chan_id_rx);
294 
295 	if (dma_config(dev_dma_dw, chan_id_rx, &dma_cfg_rx)) {
296 		TC_PRINT("ERROR: transfer config (%d)\n", chan_id_rx);
297 		return;
298 	}
299 
300 	TC_PRINT("Starting the transfer on channels %d and %d and waiting completion\n", chan_id,
301 		 chan_id_rx);
302 
303 	if (dai_trigger(dev_dai_ssp, DAI_DIR_RX, DAI_TRIGGER_PRE_START)) {
304 		TC_PRINT("ERROR: dai rx pre start\n");
305 		return;
306 	}
307 
308 	if (dai_trigger(dev_dai_ssp, DAI_DIR_TX, DAI_TRIGGER_PRE_START)) {
309 		TC_PRINT("ERROR: dai tx pre start\n");
310 		return;
311 	}
312 
313 	if (dma_start(dev_dma_dw, chan_id_rx)) {
314 		TC_PRINT("ERROR: dma rx transfer start (%d)\n", chan_id);
315 		return;
316 	}
317 
318 	if (dma_start(dev_dma_dw, chan_id)) {
319 		TC_PRINT("ERROR: dma tx transfer start (%d)\n", chan_id);
320 		return;
321 	}
322 
323 	if (dai_trigger(dev_dai_ssp, DAI_DIR_RX, DAI_TRIGGER_START)) {
324 		TC_PRINT("ERROR: rx dai start\n");
325 		return;
326 	}
327 
328 	if (dai_trigger(dev_dai_ssp, DAI_DIR_TX, DAI_TRIGGER_START)) {
329 		TC_PRINT("ERROR: tx dai start\n");
330 		return;
331 	}
332 
333 
334 	if (k_sem_take(&xfer_sem, K_MSEC(1000)) != 0) {
335 		TC_PRINT("timed out waiting for xfers\n");
336 		return;
337 	}
338 
339 	dma_stop(dev_dma_dw, chan_id_rx);
340 	dma_stop(dev_dma_dw, chan_id);
341 	dai_trigger(dev_dai_ssp, DAI_DIR_RX, DAI_TRIGGER_STOP);
342 	dai_trigger(dev_dai_ssp, DAI_DIR_TX, DAI_TRIGGER_STOP);
343 
344 	check_transmission();
345 }
346 
ZTEST(adsp_ssp,test_adsp_ssp_config_set)347 ZTEST(adsp_ssp, test_adsp_ssp_config_set)
348 {
349 	int ret;
350 
351 	/* generic config */
352 	config.type = DAI_INTEL_SSP;
353 	config.dai_index = 0;
354 	config.channels = 2;
355 	config.rate = 48000;
356 	/*
357 	 * 1st byte = "ssp mode" = 1 = SOF_DAI_FMT_I2S = I2S mode
358 	 * 3rd byte = "frame mode" = 0 = SOF_DAI_FMT_NB_NF = normal bit clock + frame
359 	 * 4th byte = "clocks mode" = 4 = SOF_DAI_FMT_CBC_CFC =
360 	 * codec bclk consumer & frame consumer
361 	 */
362 	config.format = 0x00004001;
363 	config.options = 0;
364 	config.word_size = 0;
365 	config.block_size = 0;
366 
367 	/* bespoke config */
368 	ssp_config.mclk_id = 0;
369 	ssp_config.mclk_rate = 24576000;
370 	ssp_config.fsync_rate = 48000;
371 	ssp_config.bclk_rate = 3072000;
372 	ssp_config.tdm_slots = 2;
373 	ssp_config.rx_slots = 3;
374 	ssp_config.tx_slots = 3;
375 	ssp_config.sample_valid_bits = 32;
376 	ssp_config.tdm_slot_width = 32;
377 	ssp_config.mclk_direction = 0;
378 	ssp_config.frame_pulse_width = 0;
379 	ssp_config.tdm_per_slot_padding_flag = 0;
380 	ssp_config.clks_control = 0;
381 	ssp_config.quirks = 1 << 6; /* loopback bit on */
382 	ssp_config.bclk_delay = 0;
383 
384 	ret = dai_config_set(dev_dai_ssp, &config, &ssp_config);
385 
386 	zassert_equal(ret, TC_PASS);
387 }
388 
test_adsp_ssp_probe(void)389 static void test_adsp_ssp_probe(void)
390 {
391 	int ret;
392 
393 	ret = dai_probe(dev_dai_ssp);
394 
395 	zassert_equal(ret, TC_PASS);
396 }
397 
adsp_ssp_setup(void)398 static void *adsp_ssp_setup(void)
399 {
400 	k_object_access_grant(dev_dai_ssp, k_current_get());
401 
402 	zassert_true(device_is_ready(dev_dai_ssp), "device SSP_0 is not ready");
403 	zassert_true(device_is_ready(dev_dma_dw), "device DMA 0 is not ready");
404 
405 	test_adsp_ssp_probe();
406 
407 	return NULL;
408 }
409 
410 
adsp_clock_source_is_supported(int source)411 bool adsp_clock_source_is_supported(int source)
412 {
413 	return true;
414 }
415 
adsp_clock_source_frequency(int source)416 uint32_t adsp_clock_source_frequency(int source)
417 {
418 	return 0;
419 }
420 
421 ZTEST_SUITE(adsp_ssp, NULL, adsp_ssp_setup, NULL, NULL, NULL);
422