• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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