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