1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/spi.h>
11 #include <zephyr/linker/devicetree_regions.h>
12 #include <zephyr/ztest.h>
13
14 #if CONFIG_TESTED_SPI_MODE == 0
15 #define SPI_MODE (SPI_WORD_SET(8) | SPI_LINES_SINGLE | SPI_TRANSFER_LSB)
16 #elif CONFIG_TESTED_SPI_MODE == 1
17 #define SPI_MODE (SPI_WORD_SET(8) | SPI_LINES_SINGLE | SPI_TRANSFER_MSB | SPI_MODE_CPHA)
18 #elif CONFIG_TESTED_SPI_MODE == 2
19 #define SPI_MODE (SPI_WORD_SET(8) | SPI_LINES_SINGLE | SPI_TRANSFER_LSB | SPI_MODE_CPOL)
20 #elif CONFIG_TESTED_SPI_MODE == 3
21 #define SPI_MODE (SPI_WORD_SET(8) | SPI_LINES_SINGLE | SPI_TRANSFER_MSB | SPI_MODE_CPHA \
22 | SPI_MODE_CPOL)
23 #endif
24
25 #define SPIM_OP (SPI_OP_MODE_MASTER | SPI_MODE)
26 #define SPIS_OP (SPI_OP_MODE_SLAVE | SPI_MODE)
27
28 static struct spi_dt_spec spim = SPI_DT_SPEC_GET(DT_NODELABEL(dut_spi_dt), SPIM_OP, 0);
29 static const struct device *spis_dev = DEVICE_DT_GET(DT_NODELABEL(dut_spis));
30 static const struct spi_config spis_config = {
31 .operation = SPIS_OP
32 };
33
34 static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
35 static struct k_poll_event async_evt =
36 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &async_sig);
37
38 static struct k_poll_signal async_sig_spim = K_POLL_SIGNAL_INITIALIZER(async_sig_spim);
39 static struct k_poll_event async_evt_spim =
40 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &async_sig_spim);
41
42 #define MEMORY_SECTION(node) \
43 COND_CODE_1(DT_NODE_HAS_PROP(node, memory_regions), \
44 (__attribute__((__section__( \
45 LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(node, memory_regions)))))), \
46 ())
47
48 static uint8_t spim_buffer[32] MEMORY_SECTION(DT_BUS(DT_NODELABEL(dut_spi_dt)));
49 static uint8_t spis_buffer[32] MEMORY_SECTION(DT_NODELABEL(dut_spis));
50
51 struct test_data {
52 struct k_work_delayable test_work;
53 struct k_sem sem;
54 int spim_alloc_idx;
55 int spis_alloc_idx;
56 struct spi_buf_set sets[4];
57 struct spi_buf_set *mtx_set;
58 struct spi_buf_set *mrx_set;
59 struct spi_buf_set *stx_set;
60 struct spi_buf_set *srx_set;
61 struct spi_buf bufs[8];
62 bool async;
63 };
64
65 static struct test_data tdata;
66
67 /* Allocate buffer from spim or spis space. */
buf_alloc(size_t len,bool spim)68 static uint8_t *buf_alloc(size_t len, bool spim)
69 {
70 int *idx = spim ? &tdata.spim_alloc_idx : &tdata.spis_alloc_idx;
71 uint8_t *buf = spim ? spim_buffer : spis_buffer;
72 size_t total = spim ? sizeof(spim_buffer) : sizeof(spis_buffer);
73 uint8_t *rv;
74
75 if (*idx + len > total) {
76 zassert_false(true);
77
78 return NULL;
79 }
80
81 rv = &buf[*idx];
82 *idx += len;
83
84 return rv;
85 }
86
work_handler(struct k_work * work)87 static void work_handler(struct k_work *work)
88 {
89 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
90 struct test_data *td = CONTAINER_OF(dwork, struct test_data, test_work);
91 int rv;
92
93 if (!td->async) {
94 rv = spi_transceive_dt(&spim, td->mtx_set, td->mrx_set);
95 if (rv == 0) {
96 k_sem_give(&td->sem);
97 }
98 } else {
99 rv = spi_transceive_signal(spim.bus, &spim.config, td->mtx_set, td->mrx_set,
100 &async_sig_spim);
101 zassert_equal(rv, 0);
102
103 rv = k_poll(&async_evt_spim, 1, K_MSEC(200));
104 zassert_false(rv, "one or more events are not ready");
105
106 rv = async_evt_spim.signal->result;
107 zassert_equal(rv, 0);
108
109 /* Reinitializing for next call */
110 async_evt_spim.signal->signaled = 0U;
111 async_evt_spim.state = K_POLL_STATE_NOT_READY;
112
113 k_sem_give(&td->sem);
114 }
115 }
116
117 /** Copies data from buffers in the set to a single buffer which makes it easier
118 * to compare transmitted and received data.
119 *
120 * @param buf Output buffer.
121 * @param len Buffer length.
122 * @param set Set of buffers.
123 *
124 * @return Number of bytes copied.
125 */
cpy_data(uint8_t * buf,size_t len,struct spi_buf_set * set)126 static int cpy_data(uint8_t *buf, size_t len, struct spi_buf_set *set)
127 {
128 int idx = 0;
129
130 for (size_t i = 0; i < set->count; i++) {
131 size_t l = set->buffers[i].len;
132
133 if (len - idx >= l) {
134 memcpy(&buf[idx], set->buffers[i].buf, l);
135 idx += l;
136 } else {
137 return -1;
138 }
139 }
140
141 return idx;
142 }
143
144 /** Compare two sets.
145 *
146 * @param tx_set TX set.
147 * @param rx_set RX set.
148 * @param same_size True if it is expected to have the same amount of data in both sets.
149 *
150 * @return 0 if data is the same and other value indicate that check failed.
151 */
check_buffers(struct spi_buf_set * tx_set,struct spi_buf_set * rx_set,bool same_size)152 static int check_buffers(struct spi_buf_set *tx_set, struct spi_buf_set *rx_set, bool same_size)
153 {
154 static uint8_t tx_data[256];
155 static uint8_t rx_data[256];
156 int rx_len;
157 int tx_len;
158
159 if (!tx_set || !rx_set) {
160 return 0;
161 }
162
163 rx_len = cpy_data(rx_data, sizeof(rx_data), rx_set);
164 tx_len = cpy_data(tx_data, sizeof(tx_data), tx_set);
165 if (same_size && (rx_len != tx_len)) {
166 return -1;
167 }
168
169 return memcmp(tx_data, rx_data, rx_len);
170 }
171
172 /** Calculate expected number of received bytes by the SPI peripheral.
173 *
174 * It is used to check if SPI API call for peripheral SPI device returns correct value.
175 * @param tx_set TX set.
176 * @param rx_set RX set.
177 *
178 * @return Expected amount of received bytes.
179 */
peripheral_rx_len(struct spi_buf_set * tx_set,struct spi_buf_set * rx_set)180 static int peripheral_rx_len(struct spi_buf_set *tx_set, struct spi_buf_set *rx_set)
181 {
182 size_t tx_len = 0;
183 size_t rx_len = 0;
184
185 if (!tx_set || !rx_set) {
186 return 0;
187 }
188
189 for (size_t i = 0; i < tx_set->count; i++) {
190 tx_len += tx_set->buffers[i].len;
191 }
192
193 for (size_t i = 0; i < rx_set->count; i++) {
194 rx_len += rx_set->buffers[i].len;
195 }
196
197 return MIN(rx_len, tx_len);
198 }
199
200 /** Generic function which runs the test with sets prepared in the test data structure. */
run_test(bool m_same_size,bool s_same_size,bool async)201 static void run_test(bool m_same_size, bool s_same_size, bool async)
202 {
203 int rv;
204 int periph_rv;
205 int srx_len;
206
207 tdata.async = async;
208 rv = k_work_schedule(&tdata.test_work, K_MSEC(10));
209 zassert_equal(rv, 1);
210
211 if (!async) {
212 periph_rv = spi_transceive(spis_dev, &spis_config, tdata.stx_set, tdata.srx_set);
213 if (periph_rv == -ENOTSUP) {
214 ztest_test_skip();
215 }
216 } else {
217 rv = spi_transceive_signal(spis_dev, &spis_config, tdata.stx_set, tdata.srx_set,
218 &async_sig);
219 if (rv == -ENOTSUP) {
220 ztest_test_skip();
221 }
222 zassert_equal(rv, 0);
223
224 /* Transfer not finished yet */
225 rv = k_sem_take(&tdata.sem, K_NO_WAIT);
226 zassert_equal(rv, -EBUSY);
227
228 rv = k_poll(&async_evt, 1, K_MSEC(200));
229 zassert_false(rv, "one or more events are not ready");
230
231 periph_rv = async_evt.signal->result;
232
233 /* Reinitializing for next call */
234 async_evt.signal->signaled = 0U;
235 async_evt.state = K_POLL_STATE_NOT_READY;
236 }
237
238 rv = k_sem_take(&tdata.sem, K_MSEC(100));
239 zassert_equal(rv, 0);
240
241 srx_len = peripheral_rx_len(tdata.mtx_set, tdata.srx_set);
242
243 zassert_equal(periph_rv, srx_len, "Got: %d but expected:%d", periph_rv, srx_len);
244
245 rv = check_buffers(tdata.mtx_set, tdata.srx_set, m_same_size);
246 zassert_equal(rv, 0);
247
248 rv = check_buffers(tdata.stx_set, tdata.mrx_set, s_same_size);
249 zassert_equal(rv, 0);
250 }
251
252 /** Basic test where SPI controller and SPI peripheral have RX and TX sets which contains only one
253 * same size buffer.
254 */
test_basic(bool async)255 static void test_basic(bool async)
256 {
257 size_t len = 16;
258
259 for (int i = 0; i < 4; i++) {
260 tdata.bufs[i].buf = buf_alloc(len, i < 2);
261 tdata.bufs[i].len = len;
262 tdata.sets[i].buffers = &tdata.bufs[i];
263 tdata.sets[i].count = 1;
264 }
265
266 tdata.mtx_set = &tdata.sets[0];
267 tdata.mrx_set = &tdata.sets[1];
268 tdata.stx_set = &tdata.sets[2];
269 tdata.srx_set = &tdata.sets[3];
270
271 run_test(true, true, async);
272 }
273
ZTEST(spi_controller_peripheral,test_basic)274 ZTEST(spi_controller_peripheral, test_basic)
275 {
276 test_basic(false);
277 }
278
ZTEST(spi_controller_peripheral,test_basic_async)279 ZTEST(spi_controller_peripheral, test_basic_async)
280 {
281 test_basic(true);
282 }
283
284 /** Basic test with zero length buffers.
285 */
test_basic_zero_len(bool async)286 void test_basic_zero_len(bool async)
287 {
288 size_t len = 8;
289
290 /* SPIM */
291 tdata.bufs[0].buf = buf_alloc(len, true);
292 tdata.bufs[0].len = len;
293 tdata.bufs[1].buf = buf_alloc(len, true);
294 /* Intentionally len was set to 0 - second buffer "is empty". */
295 tdata.bufs[1].len = 0;
296 tdata.sets[0].buffers = &tdata.bufs[0];
297 tdata.sets[0].count = 2;
298 tdata.mtx_set = &tdata.sets[0];
299
300 tdata.bufs[2].buf = buf_alloc(len, true);
301 tdata.bufs[2].len = len;
302 tdata.bufs[3].buf = buf_alloc(len, true);
303 /* Intentionally len was set to 0 - second buffer "is empty". */
304 tdata.bufs[3].len = 0;
305 tdata.sets[1].buffers = &tdata.bufs[2];
306 tdata.sets[1].count = 2;
307 tdata.mrx_set = &tdata.sets[1];
308
309 /* SPIS */
310 tdata.bufs[4].buf = buf_alloc(len, false);
311 tdata.bufs[4].len = len;
312 tdata.sets[2].buffers = &tdata.bufs[4];
313 tdata.sets[2].count = 1;
314 tdata.stx_set = &tdata.sets[2];
315
316 tdata.bufs[6].buf = buf_alloc(len, false);
317 tdata.bufs[6].len = len;
318 tdata.sets[3].buffers = &tdata.bufs[6];
319 tdata.sets[3].count = 1;
320 tdata.srx_set = &tdata.sets[3];
321
322 run_test(true, true, async);
323 }
324
ZTEST(spi_controller_peripheral,test_basic_zero_len)325 ZTEST(spi_controller_peripheral, test_basic_zero_len)
326 {
327 test_basic_zero_len(false);
328 }
329
ZTEST(spi_controller_peripheral,test_basic_zero_len_async)330 ZTEST(spi_controller_peripheral, test_basic_zero_len_async)
331 {
332 test_basic_zero_len(true);
333 }
334
335 /** Setup a transfer where RX buffer on SPI controller and SPI peripheral are
336 * shorter than TX buffers. RX buffers shall contain beginning of TX data
337 * and last TX bytes that did not fit in the RX buffers shall be lost.
338 */
test_short_rx(bool async)339 static void test_short_rx(bool async)
340 {
341 size_t len = 16;
342
343 tdata.bufs[0].buf = buf_alloc(len, true);
344 tdata.bufs[0].len = len;
345 tdata.bufs[1].buf = buf_alloc(len, true);
346 tdata.bufs[1].len = len - 3; /* RX buffer */
347 tdata.bufs[2].buf = buf_alloc(len, false);
348 tdata.bufs[2].len = len;
349 tdata.bufs[3].buf = buf_alloc(len, false);
350 tdata.bufs[3].len = len - 4; /* RX buffer */
351
352 for (int i = 0; i < 4; i++) {
353 tdata.sets[i].buffers = &tdata.bufs[i];
354 tdata.sets[i].count = 1;
355 }
356
357 tdata.mtx_set = &tdata.sets[0];
358 tdata.mrx_set = &tdata.sets[1];
359 tdata.stx_set = &tdata.sets[2];
360 tdata.srx_set = &tdata.sets[3];
361
362 run_test(false, false, async);
363 }
364
ZTEST(spi_controller_peripheral,test_short_rx)365 ZTEST(spi_controller_peripheral, test_short_rx)
366 {
367 test_short_rx(false);
368 }
369
ZTEST(spi_controller_peripheral,test_short_rx_async)370 ZTEST(spi_controller_peripheral, test_short_rx_async)
371 {
372 test_short_rx(true);
373 }
374
375 /** Test where only master transmits. */
test_only_tx(bool async)376 static void test_only_tx(bool async)
377 {
378 size_t len = 16;
379
380 /* MTX buffer */
381 tdata.bufs[0].buf = buf_alloc(len, true);
382 tdata.bufs[0].len = len;
383 tdata.sets[0].buffers = &tdata.bufs[0];
384 tdata.sets[0].count = 1;
385 tdata.mtx_set = &tdata.sets[0];
386 tdata.mrx_set = NULL;
387
388 /* STX buffer */
389 tdata.bufs[1].buf = buf_alloc(len, false);
390 tdata.bufs[1].len = len;
391 tdata.sets[1].buffers = &tdata.bufs[1];
392 tdata.sets[1].count = 1;
393 tdata.srx_set = &tdata.sets[1];
394 tdata.stx_set = NULL;
395
396 run_test(true, true, async);
397 }
398
ZTEST(spi_controller_peripheral,test_only_tx)399 ZTEST(spi_controller_peripheral, test_only_tx)
400 {
401 test_only_tx(false);
402 }
403
ZTEST(spi_controller_peripheral,test_only_tx_async)404 ZTEST(spi_controller_peripheral, test_only_tx_async)
405 {
406 test_only_tx(true);
407 }
408
409 /** Test where only SPI controller transmits and SPI peripheral receives in chunks. */
test_only_tx_in_chunks(bool async)410 static void test_only_tx_in_chunks(bool async)
411 {
412 size_t len1 = 7;
413 size_t len2 = 8;
414
415 /* MTX buffer */
416 tdata.bufs[0].buf = buf_alloc(len1 + len2, true);
417 tdata.bufs[0].len = len1 + len2;
418 tdata.sets[0].buffers = &tdata.bufs[0];
419 tdata.sets[0].count = 1;
420 tdata.mtx_set = &tdata.sets[0];
421 tdata.mrx_set = NULL;
422
423 /* STX buffer */
424 tdata.bufs[1].buf = buf_alloc(len1, false);
425 tdata.bufs[1].len = len1;
426 tdata.bufs[2].buf = buf_alloc(len2, false);
427 tdata.bufs[2].len = len2;
428 tdata.sets[1].buffers = &tdata.bufs[1];
429 tdata.sets[1].count = 2;
430 tdata.srx_set = &tdata.sets[1];
431 tdata.stx_set = NULL;
432
433 run_test(true, true, async);
434 }
435
ZTEST(spi_controller_peripheral,test_only_tx_in_chunks)436 ZTEST(spi_controller_peripheral, test_only_tx_in_chunks)
437 {
438 test_only_tx_in_chunks(false);
439 }
440
ZTEST(spi_controller_peripheral,test_only_tx_in_chunks_async)441 ZTEST(spi_controller_peripheral, test_only_tx_in_chunks_async)
442 {
443 test_only_tx_in_chunks(true);
444 }
445
446 /** Test where only SPI peripheral transmits. */
test_only_rx(bool async)447 static void test_only_rx(bool async)
448 {
449 size_t len = 16;
450
451 /* MTX buffer */
452 tdata.bufs[0].buf = buf_alloc(len, true);
453 tdata.bufs[0].len = len;
454 tdata.sets[0].buffers = &tdata.bufs[0];
455 tdata.sets[0].count = 1;
456 tdata.mrx_set = &tdata.sets[0];
457 tdata.mtx_set = NULL;
458
459 /* STX buffer */
460 tdata.bufs[1].buf = buf_alloc(len, false);
461 tdata.bufs[1].len = len;
462 tdata.sets[1].buffers = &tdata.bufs[1];
463 tdata.sets[1].count = 1;
464 tdata.stx_set = &tdata.sets[1];
465 tdata.srx_set = NULL;
466
467 run_test(true, true, async);
468 }
469
ZTEST(spi_controller_peripheral,test_only_rx)470 ZTEST(spi_controller_peripheral, test_only_rx)
471 {
472 test_only_rx(false);
473 }
474
ZTEST(spi_controller_peripheral,test_only_rx_async)475 ZTEST(spi_controller_peripheral, test_only_rx_async)
476 {
477 test_only_rx(true);
478 }
479
480 /** Test where only SPI peripheral transmits in chunks. */
test_only_rx_in_chunks(bool async)481 static void test_only_rx_in_chunks(bool async)
482 {
483 size_t len1 = 7;
484 size_t len2 = 9;
485
486 /* MTX buffer */
487 tdata.bufs[0].buf = buf_alloc(len1 + len2, true);
488 tdata.bufs[0].len = len1 + len2;
489 tdata.sets[0].buffers = &tdata.bufs[0];
490 tdata.sets[0].count = 1;
491 tdata.mrx_set = &tdata.sets[0];
492 tdata.mtx_set = NULL;
493
494 /* STX buffer */
495 tdata.bufs[1].buf = buf_alloc(len1, false);
496 tdata.bufs[1].len = len1;
497 tdata.bufs[2].buf = buf_alloc(len2, false);
498 tdata.bufs[2].len = len2;
499 tdata.sets[1].buffers = &tdata.bufs[1];
500 tdata.sets[1].count = 2;
501 tdata.stx_set = &tdata.sets[1];
502 tdata.srx_set = NULL;
503
504 run_test(true, true, async);
505 }
506
ZTEST(spi_controller_peripheral,test_only_rx_in_chunks)507 ZTEST(spi_controller_peripheral, test_only_rx_in_chunks)
508 {
509 test_only_rx_in_chunks(false);
510 }
511
ZTEST(spi_controller_peripheral,test_only_rx_in_chunks_async)512 ZTEST(spi_controller_peripheral, test_only_rx_in_chunks_async)
513 {
514 test_only_rx_in_chunks(true);
515 }
516
before(void * not_used)517 static void before(void *not_used)
518 {
519 ARG_UNUSED(not_used);
520
521 memset(&tdata, 0, sizeof(tdata));
522 for (size_t i = 0; i < sizeof(spim_buffer); i++) {
523 spim_buffer[i] = (uint8_t)i;
524 }
525 for (size_t i = 0; i < sizeof(spis_buffer); i++) {
526 spis_buffer[i] = (uint8_t)(i + 0x80);
527 }
528
529 k_work_init_delayable(&tdata.test_work, work_handler);
530 k_sem_init(&tdata.sem, 0, 1);
531 }
532
suite_setup(void)533 static void *suite_setup(void)
534 {
535 return NULL;
536 }
537
538 ZTEST_SUITE(spi_controller_peripheral, NULL, suite_setup, before, NULL, NULL);
539