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