1 /*
2  * Copyright (c) 2022-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 "device_resource_if.h"
10 #include "hdf_base.h"
11 #include "hdf_log.h"
12 #include "osal_mem.h"
13 #include "osal_sem.h"
14 #include "osal_spinlock.h"
15 #include "spi/spi_core.h"
16 
17 #define HDF_LOG_TAG           spi_virtual
18 #define DEFAULT_BUS_NUM       255
19 #define FIFO_SIZE_MAX         256
20 #define WAIT_TIMEOUT          1000 // ms
21 #define DEFAULT_SPEED         2000000U
22 #define BYTES_PER_WORD        2U
23 #define BITS_PER_WORD_MIN     4U
24 #define BITS_PER_WORD_EIGHT   8U
25 #define BITS_PER_WORD_MAX     16U
26 
27 struct VirtualSpi {
28     struct SpiCntlr *cntlr;
29     struct OsalSem sem;
30     OsalSpinlock lock;
31     uint32_t busNum;
32     uint32_t speed;
33     uint32_t fifoSize;
34     uint32_t numCs;
35     uint16_t waterline;
36     uint16_t wp;
37     uint16_t rp;
38     uint16_t validSize;
39     uint16_t *ringBuffer;
40     struct SpiCfg cfg;
41 };
42 
NextByte(uint32_t fifoSize,uint16_t curByte)43 static inline uint16_t NextByte(uint32_t fifoSize, uint16_t curByte)
44 {
45     if (curByte >= fifoSize - 1) {
46         return 0;
47     } else {
48         return ++curByte;
49     }
50 }
51 
RingBufferReadWord(struct VirtualSpi * virtual,uint16_t * word)52 static bool RingBufferReadWord(struct VirtualSpi *virtual, uint16_t *word)
53 {
54     uint16_t pos = NextByte(virtual->fifoSize, virtual->rp);
55 
56     (void)OsalSpinLock(&virtual->lock);
57     if (pos == virtual->wp || virtual->validSize == 0) {
58         (void)OsalSpinUnlock(&virtual->lock);
59         return false;
60     }
61     *word = virtual->ringBuffer[pos];
62     virtual->rp = pos;
63     virtual->validSize--;
64     (void)OsalSpinUnlock(&virtual->lock);
65     return true;
66 }
67 
RingBufferWriteWord(struct VirtualSpi * virtual,uint16_t word)68 static bool RingBufferWriteWord(struct VirtualSpi *virtual, uint16_t word)
69 {
70     (void)OsalSpinLock(&virtual->lock);
71     if (virtual->wp == virtual->rp || virtual->validSize == virtual->fifoSize - 1) {
72         (void)OsalSpinUnlock(&virtual->lock);
73         return false;
74     }
75     virtual->ringBuffer[virtual->wp] = word;
76     virtual->wp = NextByte(virtual->fifoSize, virtual->wp);
77     virtual->validSize++;
78     if (virtual->validSize == virtual->waterline) {
79         (void)OsalSemPost(&virtual->sem);
80     }
81     (void)OsalSpinUnlock(&virtual->lock);
82     return true;
83 }
84 
RingBufferFlush(struct VirtualSpi * virtual)85 static void RingBufferFlush(struct VirtualSpi *virtual)
86 {
87     (void)OsalSpinLock(&virtual->lock);
88     virtual->wp = 0;
89     virtual->rp = virtual->fifoSize - 1;
90     virtual->validSize = 0;
91     (void)OsalSpinUnlock(&virtual->lock);
92 }
93 
RingBufferConfig(struct VirtualSpi * virtual)94 static int32_t RingBufferConfig(struct VirtualSpi *virtual)
95 {
96     if (virtual->fifoSize == 0 || virtual->fifoSize > FIFO_SIZE_MAX) {
97         HDF_LOGE("RingBufferConfig, invalid fifoSize!");
98         return HDF_ERR_INVALID_PARAM;
99     }
100 
101     if ((virtual->cfg.mode & SPI_MODE_LOOP) != 0 && virtual->ringBuffer == NULL) {
102         virtual->ringBuffer = OsalMemAlloc(virtual->fifoSize * BYTES_PER_WORD);
103         if (virtual->ringBuffer == NULL) {
104             HDF_LOGE("RingBufferConfig: malloc ringBuffer fail!");
105             return HDF_ERR_MALLOC_FAIL;
106         }
107     } else if ((virtual->cfg.mode & SPI_MODE_LOOP) == 0) {
108         OsalMemFree(virtual->ringBuffer);
109         virtual->ringBuffer = NULL;
110     }
111     RingBufferFlush(virtual);
112     return HDF_SUCCESS;
113 }
114 
115 #define ONE_BYTE 1
116 #define TWO_BYTE 2
117 
VirtualSpiToByteWidth(uint8_t bitsPerWord)118 static inline uint8_t VirtualSpiToByteWidth(uint8_t bitsPerWord)
119 {
120     if (bitsPerWord <= BITS_PER_WORD_EIGHT) {
121         return ONE_BYTE;
122     } else {
123         return TWO_BYTE;
124     }
125 }
126 
VirtualSpiWriteFifo(struct VirtualSpi * virtual,const uint8_t * tx,uint32_t count)127 static bool VirtualSpiWriteFifo(struct VirtualSpi *virtual, const uint8_t *tx, uint32_t count)
128 {
129     uint16_t value;
130     uint8_t bytes = VirtualSpiToByteWidth(virtual->cfg.bitsPerWord);
131 
132     if ((virtual->cfg.mode & SPI_MODE_LOOP) == 0 || virtual->ringBuffer == NULL) {
133         /* open loop mode */
134         return true;
135     }
136 
137     for (value = 0; count >= bytes; count -= bytes) {
138         if (tx != NULL) {
139             value = (bytes == ONE_BYTE) ? *tx : *((uint16_t *)tx);
140             tx += bytes;
141         }
142         if (!RingBufferWriteWord(virtual, value)) {
143             return false;
144         }
145     }
146     return true;
147 }
148 
VirtualSpiReadFifo(struct VirtualSpi * virtual,uint8_t * rx,uint32_t count)149 static bool VirtualSpiReadFifo(struct VirtualSpi *virtual, uint8_t *rx, uint32_t count)
150 {
151     uint16_t value;
152     uint8_t bytes = VirtualSpiToByteWidth(virtual->cfg.bitsPerWord);
153 
154     if ((virtual->cfg.mode & SPI_MODE_LOOP) == 0 || virtual->ringBuffer == NULL) {
155         /* open loop mode */
156         return true;
157     }
158 
159     for (value = 0; count >= bytes; count -= bytes) {
160         if (!RingBufferReadWord(virtual, &value)) {
161             return false;
162         }
163 
164         if (rx == NULL) {
165             continue;
166         }
167         if (bytes == ONE_BYTE) {
168             *rx = (uint8_t)value;
169         } else {
170             *((uint16_t *)rx) = value;
171         }
172         rx += bytes;
173     }
174     return true;
175 }
176 
VirtualSpiTxRx(struct VirtualSpi * virtual,const struct SpiMsg * msg)177 static int32_t VirtualSpiTxRx(struct VirtualSpi *virtual, const struct SpiMsg *msg)
178 {
179     int32_t ret;
180     uint32_t tmpLen;
181     uint32_t len;
182     const uint8_t *tx = msg->wbuf;
183     uint8_t *rx = msg->rbuf;
184     uint32_t burstSize = virtual->fifoSize >> 1; // burstSize = fifoSzie / 2
185 
186     if (tx == NULL && rx == NULL) {
187         return HDF_ERR_INVALID_PARAM;
188     }
189 
190     for (tmpLen = 0, len = msg->len; len > 0; len -= tmpLen) {
191         tmpLen = (len > burstSize) ? burstSize : len;
192         if (!VirtualSpiWriteFifo(virtual, tx, tmpLen)) {
193             HDF_LOGE("VirtualSpiTxRx: write fifo fail!");
194             return HDF_FAILURE;
195         }
196         tx = (tx == NULL) ? NULL : (tx + tmpLen);
197         if (tmpLen == burstSize) {
198             ret = OsalSemWait((struct OsalSem *)(&virtual->sem), WAIT_TIMEOUT);
199             if (ret != HDF_SUCCESS) {
200                 HDF_LOGE("VirtualSpiTxRx: sem wait timeout, ret: %d!", ret);
201                 return ret;
202             }
203         }
204 
205         if (!VirtualSpiReadFifo(virtual, rx, tmpLen)) {
206             HDF_LOGE("VirtualSpiTxRx: read fifo fail!");
207             return HDF_FAILURE;
208         }
209         rx = (rx == NULL) ? NULL : (rx + tmpLen);
210     }
211     return HDF_SUCCESS;
212 }
213 
VirtualSpiFindDeviceByCsNum(const struct VirtualSpi * virtual,uint32_t cs)214 static inline bool VirtualSpiFindDeviceByCsNum(const struct VirtualSpi *virtual, uint32_t cs)
215 {
216     if (virtual == NULL || virtual->numCs <= cs) {
217         return false;
218     }
219 
220     return true;
221 }
222 
VirtualSpiSetCfg(struct SpiCntlr * cntlr,struct SpiCfg * cfg)223 static int32_t VirtualSpiSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
224 {
225     struct VirtualSpi *virtual = NULL;
226 
227     if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
228         HDF_LOGE("VirtualSpiSetCfg: cntlr priv or cfg is null!");
229         return HDF_ERR_INVALID_PARAM;
230     }
231     virtual = (struct VirtualSpi *)cntlr->priv;
232     if (!VirtualSpiFindDeviceByCsNum(virtual, cntlr->curCs)) {
233         HDF_LOGE("VirtualSpiSetCfg: invalid cs %u!", cntlr->curCs);
234         return HDF_ERR_INVALID_PARAM;
235     }
236     virtual->cfg = *cfg;
237     return HDF_SUCCESS;
238 }
239 
VirtualSpiGetCfg(struct SpiCntlr * cntlr,struct SpiCfg * cfg)240 static int32_t VirtualSpiGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
241 {
242     struct VirtualSpi *virtual = NULL;
243 
244     if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
245         HDF_LOGE("VirtualSpiGetCfg: cntlr priv or cfg is null!");
246         return HDF_ERR_INVALID_PARAM;
247     }
248     virtual = (struct VirtualSpi *)cntlr->priv;
249     if (!VirtualSpiFindDeviceByCsNum(virtual, cntlr->curCs)) {
250         HDF_LOGE("VirtualSpiGetCfg: invalid cs %u!", cntlr->curCs);
251         return HDF_ERR_INVALID_PARAM;
252     }
253     *cfg = virtual->cfg;
254     return HDF_SUCCESS;
255 }
256 
VirtualSpiTransferOneMessage(struct VirtualSpi * virtual,struct SpiMsg * msg)257 static int32_t VirtualSpiTransferOneMessage(struct VirtualSpi *virtual, struct SpiMsg *msg)
258 {
259     int32_t ret;
260 
261     if (msg == NULL || (msg->rbuf == NULL && msg->wbuf == NULL)) {
262         HDF_LOGE("VirtualSpiTransferOneMessage: invalid parameter!");
263         return HDF_ERR_INVALID_PARAM;
264     }
265     virtual->speed = (msg->speed) == 0 ? DEFAULT_SPEED : msg->speed;
266 
267     ret = RingBufferConfig(virtual);
268     if (ret != HDF_SUCCESS) {
269         return ret;
270     }
271 
272     return VirtualSpiTxRx(virtual, msg);
273 }
274 
VirtualSpiTransfer(struct SpiCntlr * cntlr,struct SpiMsg * msg,uint32_t count)275 static int32_t VirtualSpiTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count)
276 {
277     int32_t ret;
278     uint32_t i;
279     struct VirtualSpi *virtual = NULL;
280 
281     if (cntlr == NULL || cntlr->priv == NULL) {
282         HDF_LOGE("VirtualSpiTransfer: invalid controller!");
283         return HDF_ERR_INVALID_OBJECT;
284     }
285     if (msg == NULL || count == 0) {
286         HDF_LOGE("VirtualSpiTransfer: invalid parameter!");
287         return HDF_ERR_INVALID_PARAM;
288     }
289 
290     virtual = (struct VirtualSpi *)cntlr->priv;
291     if (!VirtualSpiFindDeviceByCsNum(virtual, cntlr->curCs)) {
292         HDF_LOGE("VirtualSpiTransfer: invalid cs %u!", cntlr->curCs);
293         return HDF_FAILURE;
294     }
295     for (i = 0; i < count; i++) {
296         ret = VirtualSpiTransferOneMessage(virtual, &(msg[i]));
297         if (ret != 0) {
298             HDF_LOGE("VirtualSpiTransfer: transfer error, ret: %d!", ret);
299             return ret;
300         }
301     }
302     return HDF_SUCCESS;
303 }
304 
VirtualSpiOpen(struct SpiCntlr * cntlr)305 int32_t VirtualSpiOpen(struct SpiCntlr *cntlr)
306 {
307     (void)cntlr;
308     return HDF_SUCCESS;
309 }
310 
VirtualSpiClose(struct SpiCntlr * cntlr)311 int32_t VirtualSpiClose(struct SpiCntlr *cntlr)
312 {
313     (void)cntlr;
314     return HDF_SUCCESS;
315 }
316 
317 static struct SpiCntlrMethod g_method = {
318     .Transfer = VirtualSpiTransfer,
319     .SetCfg = VirtualSpiSetCfg,
320     .GetCfg = VirtualSpiGetCfg,
321     .Open = VirtualSpiOpen,
322     .Close = VirtualSpiClose,
323 };
324 
SpiGetCfgFromHcs(struct VirtualSpi * virtual,const struct DeviceResourceNode * node)325 static int32_t SpiGetCfgFromHcs(struct VirtualSpi *virtual, const struct DeviceResourceNode *node)
326 {
327     struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
328 
329     if (iface == NULL || iface->GetUint32 == NULL || iface->GetUint16 == NULL || iface->GetUint8 == NULL) {
330         HDF_LOGE("SpiGetCfgFromHcs: face is invalid!");
331         return HDF_FAILURE;
332     }
333     if (iface->GetUint32(node, "busNum", &virtual->busNum, DEFAULT_BUS_NUM) != HDF_SUCCESS) {
334         HDF_LOGE("SpiGetCfgFromHcs: read busNum fail!");
335         return HDF_FAILURE;
336     }
337     if (iface->GetUint32(node, "numCs", &virtual->numCs, 0) != HDF_SUCCESS) {
338         HDF_LOGE("SpiGetCfgFromHcs: read numCs fail!");
339         return HDF_FAILURE;
340     }
341     if (iface->GetUint32(node, "speed", &virtual->speed, 0) != HDF_SUCCESS) {
342         HDF_LOGE("SpiGetCfgFromHcs: read speed fail!");
343         return HDF_FAILURE;
344     }
345     if (iface->GetUint32(node, "fifoSize", &virtual->fifoSize, 0) != HDF_SUCCESS) {
346         HDF_LOGE("SpiGetCfgFromHcs: read fifoSize fail!");
347         return HDF_FAILURE;
348     }
349     if (iface->GetUint16(node, "mode", &virtual->cfg.mode, 0) != HDF_SUCCESS) {
350         HDF_LOGE("SpiGetCfgFromHcs: read mode fail!");
351         return HDF_FAILURE;
352     }
353     if (iface->GetUint8(node, "bitsPerWord", &virtual->cfg.bitsPerWord, 0) != HDF_SUCCESS) {
354         HDF_LOGE("SpiGetCfgFromHcs: read bitsPerWord fail!");
355         return HDF_FAILURE;
356     }
357     if (iface->GetUint8(node, "transferMode", &virtual->cfg.transferMode, 0) != HDF_SUCCESS) {
358         HDF_LOGE("SpiGetCfgFromHcs: read transferMode fail!");
359         return HDF_FAILURE;
360     }
361     if (iface->GetUint32(node, "maxSpeedHz", &virtual->cfg.maxSpeedHz, 0) != HDF_SUCCESS) {
362         HDF_LOGE("SpiGetCfgFromHcs: read maxSpeedHz fail!");
363         return HDF_FAILURE;
364     }
365     if (iface->GetUint16(node, "waterline", &virtual->waterline, 0) != HDF_SUCCESS) {
366         HDF_LOGE("SpiGetCfgFromHcs: read waterline fail!");
367         return HDF_FAILURE;
368     }
369     return HDF_SUCCESS;
370 }
371 
VirtualSpiInit(struct SpiCntlr * cntlr,const struct HdfDeviceObject * device)372 static int32_t VirtualSpiInit(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
373 {
374     int32_t ret;
375     struct VirtualSpi *virtual = NULL;
376 
377     if (device->property == NULL) {
378         HDF_LOGE("VirtualSpiInit: property is null!");
379         return HDF_ERR_INVALID_PARAM;
380     }
381 
382     virtual = (struct VirtualSpi *)OsalMemCalloc(sizeof(*virtual));
383     if (virtual == NULL) {
384         HDF_LOGE("VirtualSpiInit: OsalMemCalloc error!");
385         return HDF_FAILURE;
386     }
387     ret = SpiGetCfgFromHcs(virtual, device->property);
388     if (ret != HDF_SUCCESS) {
389         HDF_LOGE("VirtualSpiInit: SpiGetCfgFromHcs error, ret: %d!", ret);
390         OsalMemFree(virtual);
391         return ret;
392     }
393 
394     virtual->cntlr = cntlr;
395     cntlr->priv = (void *)virtual;
396     cntlr->method = &g_method;
397     ret = OsalSemInit(&virtual->sem, 0);
398     if (ret != HDF_SUCCESS) {
399         return ret;
400     }
401     if (OsalSpinInit(&virtual->lock) != HDF_SUCCESS) {
402         HDF_LOGE("VirtualSpiInit: init lock fail!");
403         return HDF_FAILURE;
404     }
405 
406     return HDF_SUCCESS;
407 }
408 
VirtualSpiDeviceBind(struct HdfDeviceObject * device)409 static int32_t VirtualSpiDeviceBind(struct HdfDeviceObject *device)
410 {
411     HDF_LOGI("VirtualSpiDeviceBind: entry!");
412     if (device == NULL) {
413         return HDF_ERR_INVALID_OBJECT;
414     }
415     return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
416 }
417 
VirtualSpiDeviceInit(struct HdfDeviceObject * device)418 static int32_t VirtualSpiDeviceInit(struct HdfDeviceObject *device)
419 {
420     int32_t ret;
421     struct SpiCntlr *cntlr = NULL;
422 
423     if (device == NULL) {
424         HDF_LOGE("VirtualSpiDeviceInit: device is null!");
425         return HDF_ERR_INVALID_OBJECT;
426     }
427     cntlr = SpiCntlrFromDevice(device);
428     if (cntlr == NULL) {
429         HDF_LOGE("VirtualSpiDeviceInit: cntlr is null!");
430         return HDF_FAILURE;
431     }
432 
433     ret = VirtualSpiInit(cntlr, device);
434     if (ret != HDF_SUCCESS) {
435         HDF_LOGE("VirtualSpiDeviceInit: error init, ret: %d!", ret);
436         return ret;
437     }
438     ret = RingBufferConfig((struct VirtualSpi *)cntlr->priv);
439     if (ret != HDF_SUCCESS) {
440         HDF_LOGE("VirtualSpiDeviceInit: RingBufferConfig error!");
441     } else {
442         HDF_LOGI("VirtualSpiDeviceInit: spi device init success!");
443     }
444 
445     return ret;
446 }
447 
VirtualSpiDeviceRelease(struct HdfDeviceObject * device)448 static void VirtualSpiDeviceRelease(struct HdfDeviceObject *device)
449 {
450     struct SpiCntlr *cntlr = NULL;
451     struct VirtualSpi *virtual = NULL;
452 
453     HDF_LOGI("VirtualSpiDeviceRelease: entry!");
454     if (device == NULL) {
455         HDF_LOGE("VirtualSpiDeviceRelease: device is null!");
456         return;
457     }
458     cntlr = SpiCntlrFromDevice(device);
459     if (cntlr == NULL || cntlr->priv == NULL) {
460         HDF_LOGE("VirtualSpiDeviceRelease: cntlr or priv is null!");
461         return;
462     }
463     SpiCntlrDestroy(cntlr);
464     virtual = (struct VirtualSpi *)cntlr->priv;
465     (void)OsalSpinDestroy(&(virtual->lock));
466     (void)OsalSemDestroy(&virtual->sem);
467     OsalMemFree(virtual->ringBuffer);
468     OsalMemFree(virtual);
469 }
470 
471 static const struct HdfDriverEntry g_virtualSpiDevice = {
472     .moduleVersion = 1,
473     .moduleName = "virtual_spi_driver",
474     .Bind = VirtualSpiDeviceBind,
475     .Init = VirtualSpiDeviceInit,
476     .Release = VirtualSpiDeviceRelease,
477 };
478 
479 HDF_INIT(g_virtualSpiDevice);
480