1 /*
2 * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "spi_test.h"
10 #include "securec.h"
11 #include "device_resource_if.h"
12 #include "hdf_io_service_if.h"
13 #include "hdf_base.h"
14 #include "hdf_log.h"
15 #include "osal_mem.h"
16 #include "osal_time.h"
17 #include "spi_if.h"
18
19 #define HDF_LOG_TAG spi_test_c
20
21 #define SPI_TEST_4BITS 4
22 #define SPI_TEST_8BITS 8
23 #define SPI_TEST_16BITS 16
24
SpiTestGetConfig(struct SpiTestConfig * config)25 static int32_t SpiTestGetConfig(struct SpiTestConfig *config)
26 {
27 int32_t ret;
28 struct HdfSBuf *reply = NULL;
29 struct HdfIoService *service = NULL;
30 struct SpiTestConfig *cfg = NULL;
31 const void *buf = NULL;
32 uint32_t len;
33
34 service = HdfIoServiceBind("SPI_TEST");
35 if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) {
36 HDF_LOGE("SpiTestGetConfig: fail to bind service!");
37 return HDF_ERR_NOT_SUPPORT;
38 }
39
40 do {
41 reply = HdfSbufObtainDefaultSize();
42 if (reply == NULL) {
43 HDF_LOGE("SpiTestGetConfig: fail to obtain reply!");
44 ret = HDF_ERR_MALLOC_FAIL;
45 break;
46 }
47
48 ret = service->dispatcher->Dispatch(&service->object, 0, NULL, reply);
49 if (ret != HDF_SUCCESS) {
50 HDF_LOGE("SpiTestGetConfig: remote dispatch fail, ret: %d", ret);
51 break;
52 }
53
54 if (!HdfSbufReadBuffer(reply, (const void **)&cfg, &len)) {
55 HDF_LOGE("SpiTestGetConfig: read buf fail!");
56 ret = HDF_ERR_IO;
57 break;
58 }
59
60 if (len != sizeof(*cfg)) {
61 HDF_LOGE("SpiTestGetConfig: cfg size:%zu, read size:%u!", sizeof(*cfg), len);
62 ret = HDF_ERR_IO;
63 break;
64 }
65
66 if (memcpy_s(config, sizeof(*config), cfg, sizeof(*cfg)) != EOK) {
67 HDF_LOGE("SpiTestGetConfig: memcpy config fail!");
68 ret = HDF_ERR_IO;
69 break;
70 }
71
72 if (!HdfSbufReadBuffer(reply, (const void **)&buf, &len)) {
73 HDF_LOGE("SpiTestGetConfig: read buf fail!");
74 ret = HDF_ERR_IO;
75 break;
76 }
77
78 if (len != config->len) {
79 HDF_LOGE("SpiTestGetConfig: buffer size:%zu, read size:%u!", config->len, len);
80 ret = HDF_ERR_IO;
81 break;
82 }
83
84 config->wbuf = NULL;
85 config->wbuf = (uint8_t *)OsalMemCalloc(config->len);
86 if (config->wbuf == NULL) {
87 HDF_LOGE("SpiTestGetConfig: malloc wbuf fail!");
88 ret = HDF_ERR_MALLOC_FAIL;
89 break;
90 }
91
92 if (memcpy_s(config->wbuf, config->len, buf, len) != EOK) {
93 HDF_LOGE("SpiTestGetConfig: memcpy config fail!");
94 ret = HDF_ERR_IO;
95 break;
96 }
97 ret = HDF_SUCCESS;
98 } while (0);
99 HdfSbufRecycle(reply);
100 HdfIoServiceRecycle(service);
101 return ret;
102 }
103
SpiTesterGet(void)104 static struct SpiTester *SpiTesterGet(void)
105 {
106 int32_t ret;
107 struct SpiDevInfo info;
108 static struct SpiTester tester;
109
110 HDF_LOGE("SpiTesterGet: enter");
111 ret = SpiTestGetConfig(&tester.config);
112 if (ret != HDF_SUCCESS) {
113 HDF_LOGE("SpiTesterGet: read config fail, ret: %d!", ret);
114 return NULL;
115 }
116
117 tester.config.rbuf = (uint8_t *)OsalMemCalloc(tester.config.len);
118 if (tester.config.rbuf == NULL) {
119 HDF_LOGE("SpiTesterGet: malloc rbuf fail!");
120 return NULL;
121 }
122
123 info.busNum = tester.config.bus;
124 info.csNum = tester.config.cs;
125
126 tester.handle = SpiOpen(&info);
127 if (tester.handle == NULL) {
128 HDF_LOGE("SpiTesterGet: open spi: %u, cs: %u fail!", tester.config.bus, tester.config.cs);
129 return NULL;
130 }
131
132 return &tester;
133 }
134
SpiTesterPut(struct SpiTester * tester)135 static void SpiTesterPut(struct SpiTester *tester)
136 {
137 if (tester == NULL || tester->handle == NULL) {
138 HDF_LOGE("SpiTesterPut: tester or handle is null!");
139 return;
140 }
141 SpiClose(tester->handle);
142 if (tester->config.rbuf != NULL) {
143 OsalMemFree(tester->config.rbuf);
144 tester->config.rbuf = NULL;
145 }
146 if (tester->config.wbuf != NULL) {
147 OsalMemFree(tester->config.wbuf);
148 tester->config.wbuf = NULL;
149 }
150 tester->handle = NULL;
151 }
152
153 #define BITS_PER_WORD_DEFAULT 8
154 #define BITS_PER_WORD_8BITS 8
155 #define BITS_PER_WORD_10BITS 10
156 #define MAX_SPEED_HZ 10000000
157
158 static struct SpiCfg g_spiCfg = {
159 .mode = SPI_CLK_PHASE | SPI_MODE_LOOP,
160 .bitsPerWord = BITS_PER_WORD_DEFAULT,
161 .maxSpeedHz = MAX_SPEED_HZ,
162 .transferMode = SPI_POLLING_TRANSFER,
163 };
164
165 #define SPI_TEST_ONE_BYTE 1
166 #define SPI_TEST_TWO_BYTE 2
167
SpiCmpMemByBits(uint8_t * wbuf,uint8_t * rbuf,uint32_t len,uint8_t bits)168 static int32_t SpiCmpMemByBits(uint8_t *wbuf, uint8_t *rbuf, uint32_t len, uint8_t bits)
169 {
170 uint32_t i;
171 uint16_t vw;
172 uint16_t vr;
173
174 if (bits < SPI_TEST_4BITS) {
175 bits = SPI_TEST_4BITS;
176 } else if (bits > SPI_TEST_16BITS) {
177 bits = SPI_TEST_16BITS;
178 }
179
180 for (i = 0; i < len;) {
181 if (bits <= SPI_TEST_8BITS) {
182 vw = *((uint8_t *)(wbuf + i)) & (~(0xFFFF << bits));
183 vr = *((uint8_t *)(rbuf + i)) & (~(0xFFFF << bits));
184 } else {
185 vw = *((uint16_t *)(wbuf + i)) & (~(0xFFFF << bits));
186 vr = *((uint16_t *)(rbuf + i)) & (~(0xFFFF << bits));
187 }
188 if (vw != vr) {
189 HDF_LOGE("SpiCmpMemByBits: compare mem fail(i=%u, vw=%hu, vr=%hu, bits = %hhu, len=%u)",
190 i, vw, vr, bits, len);
191 return HDF_FAILURE;
192 }
193 i += (bits <= SPI_TEST_8BITS) ? SPI_TEST_ONE_BYTE : SPI_TEST_TWO_BYTE;
194 }
195 HDF_LOGD("SpiCmpMemByBits: mem size(%u) compare success!", len);
196 return HDF_SUCCESS;
197 }
198
SpiDoTransferTest(struct SpiTester * tester,struct SpiCfg * cfg,struct SpiMsg * msg)199 static int32_t SpiDoTransferTest(struct SpiTester *tester, struct SpiCfg *cfg, struct SpiMsg *msg)
200 {
201 int32_t ret;
202
203 ret = SpiSetCfg(tester->handle, cfg);
204 if (ret != HDF_SUCCESS) {
205 HDF_LOGE("SpiDoTransferTest: set config fail, ret: %d", ret);
206 return ret;
207 }
208
209 ret = SpiTransfer(tester->handle, msg, 1);
210 if (ret != HDF_SUCCESS) {
211 HDF_LOGE("SpiDoTransferTest: spi transfer err, ret: %d", ret);
212 return ret;
213 }
214
215 ret = SpiCmpMemByBits(msg->wbuf, msg->rbuf, msg->len, g_spiCfg.bitsPerWord);
216 if (ret != HDF_SUCCESS) {
217 return ret;
218 }
219
220 ret = SpiWrite(tester->handle, msg->wbuf, msg->len);
221 if (ret != HDF_SUCCESS) {
222 HDF_LOGE("SpiDoTransferTest: spi write err, ret: %d", ret);
223 return ret;
224 }
225
226 ret = SpiRead(tester->handle, msg->rbuf, msg->len);
227 if (ret != HDF_SUCCESS) {
228 HDF_LOGE("SpiDoTransferTest: spi read err, ret: %d", ret);
229 return ret;
230 }
231
232 HDF_LOGD("SpiDoTransferTest: success!");
233 return HDF_SUCCESS;
234 }
235
SpiTransferTest(struct SpiTester * tester)236 static int32_t SpiTransferTest(struct SpiTester *tester)
237 {
238 int32_t ret;
239 struct SpiMsg msg;
240
241 g_spiCfg.bitsPerWord = BITS_PER_WORD_8BITS;
242 g_spiCfg.transferMode = SPI_POLLING_TRANSFER;
243
244 msg.rbuf = tester->config.rbuf;
245 msg.wbuf = tester->config.wbuf;
246 msg.len = tester->config.len;
247 msg.keepCs = 0; // switch off the CS after transfer
248 msg.delayUs = 0;
249 msg.speed = 0; // use default speed
250
251 ret = SpiDoTransferTest(tester, &g_spiCfg, &msg);
252 if (ret != HDF_SUCCESS) {
253 HDF_LOGE("SpiTransferTest: fail, bitsPerWord = %u, ret = %d!", g_spiCfg.bitsPerWord, ret);
254 return ret;
255 }
256
257 g_spiCfg.bitsPerWord = BITS_PER_WORD_10BITS;
258 ret = SpiDoTransferTest(tester, &g_spiCfg, &msg);
259 if (ret != HDF_SUCCESS) {
260 HDF_LOGE("SpiTransferTest: fail, bitsPerWord = %u, ret = %d!", g_spiCfg.bitsPerWord, ret);
261 return ret;
262 }
263
264 return HDF_SUCCESS;
265 }
266
267 #define SPI_TEST_MSG_NUM 3
268 #define SPI_TEST_MSG_0 0
269 #define SPI_TEST_MSG_1 1
270 #define SPI_TEST_MSG_2 2
271
SpiMultiTransferTest(struct SpiTester * tester)272 static int32_t SpiMultiTransferTest(struct SpiTester *tester)
273 {
274 int32_t ret;
275 struct SpiMsg msgs[SPI_TEST_MSG_NUM];
276
277 g_spiCfg.bitsPerWord = BITS_PER_WORD_8BITS;
278 g_spiCfg.transferMode = SPI_POLLING_TRANSFER;
279
280 msgs[SPI_TEST_MSG_0].rbuf = tester->config.rbuf;
281 msgs[SPI_TEST_MSG_0].wbuf = tester->config.wbuf;
282 msgs[SPI_TEST_MSG_0].len = tester->config.len;
283 msgs[SPI_TEST_MSG_0].delayUs = 0;
284 msgs[SPI_TEST_MSG_0].speed = 0; // use default speed
285
286 msgs[SPI_TEST_MSG_1].wbuf = tester->config.wbuf;
287 msgs[SPI_TEST_MSG_1].rbuf = NULL;
288 msgs[SPI_TEST_MSG_1].len = tester->config.len;
289 msgs[SPI_TEST_MSG_1].speed = 0;
290
291 msgs[SPI_TEST_MSG_2].wbuf = NULL;
292 msgs[SPI_TEST_MSG_2].rbuf = tester->config.rbuf;
293 msgs[SPI_TEST_MSG_2].len = tester->config.len;
294 msgs[SPI_TEST_MSG_2].speed = 0;
295 msgs[SPI_TEST_MSG_2].keepCs = 0; // switch off the CS after transfer
296
297 ret = SpiSetCfg(tester->handle, &g_spiCfg);
298 if (ret != HDF_SUCCESS) {
299 HDF_LOGE("SpiMultiTransferTest: set config fail, ret: %d", ret);
300 return ret;
301 }
302
303 ret = SpiTransfer(tester->handle, (struct SpiMsg *)&msgs, SPI_TEST_MSG_NUM);
304 if (ret != HDF_SUCCESS) {
305 HDF_LOGE("SpiMultiTransferTest: multi transfer test fail, ret: %d", ret);
306 return ret;
307 }
308
309 return HDF_SUCCESS;
310 }
311
312 #define DMA_TRANSFER_SINGLE_MAX (1024 * 64 - 1)
313 #define DMA_TRANSFER_SIZE_TOTAL (DMA_TRANSFER_SINGLE_MAX * 2 + 65532)
314 #define DMA_TRANSFER_BUF_SEED 0x5A
315 #define DMA_ALIGN_SIZE 64
316 #ifdef CONFIG_IMX8MM_SPI_TEST
317 #define DMA_TRANSFER_SIZE_TOTAL_NXP (60)
318 #endif // CONFIG_IMX8MM_SPI_TEST
SpiSetDmaIntMsg(struct SpiMsg * msg,uint32_t len)319 static int32_t SpiSetDmaIntMsg(struct SpiMsg *msg, uint32_t len)
320 {
321 uint32_t i;
322 uint8_t *wbuf = NULL;
323 uint8_t *rbuf = NULL;
324
325 msg->wbuf = msg->rbuf = NULL;
326
327 wbuf = (uint8_t *)OsalMemAllocAlign(DMA_ALIGN_SIZE, len);
328 if (wbuf == NULL) {
329 return HDF_ERR_MALLOC_FAIL;
330 }
331 rbuf = (uint8_t *)OsalMemAllocAlign(DMA_ALIGN_SIZE, len);
332 if (rbuf == NULL) {
333 OsalMemFree(wbuf);
334 return HDF_ERR_MALLOC_FAIL;
335 }
336
337 wbuf[0] = DMA_TRANSFER_BUF_SEED;
338 for (i = 1; i < len; i++) {
339 wbuf[i] = wbuf[i - 1] + 1;
340 rbuf[i] = 0;
341 }
342 msg->wbuf = wbuf;
343 msg->rbuf = rbuf;
344 msg->len = len;
345 msg->keepCs = 0, // switch off the CS after transfer
346 msg->delayUs = 0;
347 msg->speed = 0; // using default speed
348 return HDF_SUCCESS;
349 }
350
SpiUnsetDmaIntMsg(struct SpiMsg * msg)351 static void SpiUnsetDmaIntMsg(struct SpiMsg *msg)
352 {
353 if (msg != NULL) {
354 OsalMemFree(msg->wbuf);
355 OsalMemFree(msg->rbuf);
356 msg->wbuf = NULL;
357 msg->rbuf = NULL;
358 }
359 }
360
SpiDmaTransferTest(struct SpiTester * tester)361 static int32_t SpiDmaTransferTest(struct SpiTester *tester)
362 {
363 int32_t ret;
364 struct SpiMsg msg;
365
366 g_spiCfg.transferMode = SPI_DMA_TRANSFER;
367 g_spiCfg.bitsPerWord = BITS_PER_WORD_8BITS;
368
369 if (tester->config.testDma == 0) {
370 HDF_LOGI("SpiDmaTransferTest: testDma not set!");
371 return HDF_SUCCESS;
372 }
373
374 ret = SpiSetDmaIntMsg(&msg, DMA_TRANSFER_SIZE_TOTAL);
375 if (ret != HDF_SUCCESS) {
376 HDF_LOGE("SpiDmaTransferTest: set dma int msg fail, ret: %d", ret);
377 return ret;
378 }
379
380 ret = SpiDoTransferTest(tester, &g_spiCfg, &msg);
381 if (ret != HDF_SUCCESS) {
382 SpiUnsetDmaIntMsg(&msg);
383 HDF_LOGE("SpiDmaTransferTest: fail, bitsPerWord = %u, ret = %d!", g_spiCfg.bitsPerWord, ret);
384 return ret;
385 }
386
387 g_spiCfg.bitsPerWord = BITS_PER_WORD_10BITS;
388 ret = SpiDoTransferTest(tester, &g_spiCfg, &msg);
389 if (ret != HDF_SUCCESS) {
390 SpiUnsetDmaIntMsg(&msg);
391 HDF_LOGE("SpiDmaTransferTest: fail, bitsPerWord = %u, ret = %d!", g_spiCfg.bitsPerWord, ret);
392 return ret;
393 }
394
395 SpiUnsetDmaIntMsg(&msg);
396 return HDF_SUCCESS;
397 }
398
SpiIntTransferTest(struct SpiTester * tester)399 static int32_t SpiIntTransferTest(struct SpiTester *tester)
400 {
401 int32_t ret;
402 struct SpiMsg msg;
403
404 g_spiCfg.transferMode = SPI_INTERRUPT_TRANSFER;
405 g_spiCfg.bitsPerWord = BITS_PER_WORD_8BITS;
406 #ifdef CONFIG_IMX8MM_SPI_TEST
407 ret = SpiSetDmaIntMsg(&msg, DMA_TRANSFER_SIZE_TOTAL_NXP);
408 #else // CONFIG_IMX8MM_SPI_TEST
409 ret = SpiSetDmaIntMsg(&msg, DMA_TRANSFER_SIZE_TOTAL);
410 #endif // CONFIG_IMX8MM_SPI_TEST
411 if (ret != HDF_SUCCESS) {
412 return ret;
413 }
414
415 ret = SpiDoTransferTest(tester, &g_spiCfg, &msg);
416 if (ret != HDF_SUCCESS) {
417 SpiUnsetDmaIntMsg(&msg);
418 HDF_LOGE("SpiIntTransferTest: fail, bitsPerWord = %u, ret = %d!", g_spiCfg.bitsPerWord, ret);
419 return ret;
420 }
421
422 g_spiCfg.bitsPerWord = BITS_PER_WORD_10BITS;
423 ret = SpiDoTransferTest(tester, &g_spiCfg, &msg);
424 if (ret != HDF_SUCCESS) {
425 SpiUnsetDmaIntMsg(&msg);
426 HDF_LOGE("SpiIntTransferTest: fail, bitsPerWord = %u, ret = %d!", g_spiCfg.bitsPerWord, ret);
427 return ret;
428 }
429
430 SpiUnsetDmaIntMsg(&msg);
431 return HDF_SUCCESS;
432 }
433
SpiReliabilityTest(struct SpiTester * tester)434 static int32_t SpiReliabilityTest(struct SpiTester *tester)
435 {
436 struct SpiCfg cfg = {0};
437 struct SpiMsg msg = {0};
438
439 (void)SpiSetCfg(tester->handle, &cfg);
440 (void)SpiSetCfg(tester->handle, NULL);
441 (void)SpiTransfer(tester->handle, &msg, 1);
442 (void)SpiTransfer(tester->handle, NULL, -1);
443 (void)SpiWrite(tester->handle, tester->config.wbuf, tester->config.len);
444 (void)SpiWrite(tester->handle, NULL, -1);
445 (void)SpiRead(tester->handle, tester->config.rbuf, tester->config.len);
446 (void)SpiRead(tester->handle, NULL, -1);
447
448 (void)tester;
449 HDF_LOGE("SpiReliabilityTest: success!");
450 return HDF_SUCCESS;
451 }
452
SpiTestAll(struct SpiTester * tester)453 static int32_t SpiTestAll(struct SpiTester *tester)
454 {
455 int32_t total = 0;
456 int32_t error = 0;
457
458 if (SpiTransferTest(tester) != HDF_SUCCESS) {
459 error++;
460 }
461 total++;
462
463 if (SpiDmaTransferTest(tester) != HDF_SUCCESS) {
464 error++;
465 }
466 total++;
467
468 if (SpiIntTransferTest(tester) != HDF_SUCCESS) {
469 error++;
470 }
471 total++;
472
473 if (SpiReliabilityTest(tester) != HDF_SUCCESS) {
474 error++;
475 }
476 total++;
477
478 HDF_LOGE("SpiTestAll: spi tester total %d error %d", total, error);
479 return HDF_SUCCESS;
480 }
481
SpiIfPerformanceTest(struct SpiTester * tester)482 static int32_t SpiIfPerformanceTest(struct SpiTester *tester)
483 {
484 #ifdef __LITEOS__
485 // liteos the accuracy of the obtained time is too large and inaccurate.
486 if (tester == NULL || tester->handle == NULL) {
487 HDF_LOGE("SpiIfPerformanceTest: tester or handle is null!");
488 return HDF_FAILURE;
489 }
490 return HDF_SUCCESS;
491 #endif
492 int32_t ret;
493 struct SpiCfg cfg = {0};
494 uint64_t startMs;
495 uint64_t endMs;
496 uint64_t useTime; // ms
497
498 startMs = OsalGetSysTimeMs();
499 ret = SpiGetCfg(tester->handle, &cfg);
500 endMs = OsalGetSysTimeMs();
501
502 if (ret == HDF_SUCCESS) {
503 useTime = endMs - startMs;
504 HDF_LOGI("SpiIfPerformanceTest: ----->interface performance test:[start - end] < 1ms[%s]\r\n",
505 useTime < 1 ? "yes" : "no");
506 return HDF_SUCCESS;
507 }
508 return HDF_FAILURE;
509 }
510
511 struct SpiTestFunc {
512 int cmd;
513 int32_t (*func)(struct SpiTester *tester);
514 const char *name;
515 };
516
517 static struct SpiTestFunc g_spiTestEntry[] = {
518 {SPI_TRANSFER_TEST, SpiTransferTest, "SpiTransferTest"},
519 {SPI_MULTI_TRANSFER_TEST, SpiMultiTransferTest, "SpiMultiTransferTest"},
520 {SPI_DMA_TRANSFER_TEST, SpiDmaTransferTest, "SpiDmaTransferTest"},
521 {SPI_INT_TRANSFER_TEST, SpiIntTransferTest, "SpiIntTransferTest"},
522 {SPI_RELIABILITY_TEST, SpiReliabilityTest, "SpiReliabilityTest"},
523 {SPI_PERFORMANCE_TEST, SpiIfPerformanceTest, "SpiIfPerformanceTest"},
524 {SPI_TEST_ALL, SpiTestAll, "SpiTestAll"},
525 };
526
SpiTestExecute(int cmd)527 int32_t SpiTestExecute(int cmd)
528 {
529 uint32_t i;
530 int32_t ret = HDF_ERR_NOT_SUPPORT;
531 struct SpiTester *tester = NULL;
532
533 HDF_LOGE("SpiTestExecute: enter cmd %d!", cmd);
534 if (cmd > SPI_TEST_CMD_MAX) {
535 HDF_LOGE("SpiTestExecute: invalid cmd: %d!", cmd);
536 ret = HDF_ERR_INVALID_OBJECT;
537 goto EXIT;
538 }
539
540 tester = SpiTesterGet();
541 if (tester == NULL || tester->handle == NULL) {
542 HDF_LOGE("SpiTestExecute: get tester fail!");
543 ret = HDF_ERR_NOT_SUPPORT;
544 goto EXIT;
545 }
546
547 for (i = 0; i < sizeof(g_spiTestEntry) / sizeof(g_spiTestEntry[0]); i++) {
548 if (g_spiTestEntry[i].cmd != cmd || g_spiTestEntry[i].func == NULL) {
549 continue;
550 }
551 ret = g_spiTestEntry[i].func(tester);
552 break;
553 }
554 EXIT:
555 HDF_LOGE("[SpiTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
556 SpiTesterPut(tester);
557 return ret;
558 }
559