1 /*
2 * Copyright (c) 2021-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 "i3c/i3c_core.h"
10 #include "device_resource_if.h"
11 #include "osal_mem.h"
12 #include "osal_time.h"
13
14 #define HDF_LOG_TAG i3c_virtual
15
16 #define VIRTUAL_I3C_DELAY 50
17 #define VIRTUAL_I3C_HOT_JOIN_TEST_ADDR 0x3f
18
19 #define VIRTUAL_I3C_TEST_STR_LEN 11
20 #define VIRTUAL_I3C_TEST_STR "Hello I3C!"
21
22 struct VirtualI3cCntlr {
23 struct I3cCntlr cntlr;
24 OsalSpinlock spin;
25 uint16_t busId;
26 uint16_t busMode;
27 uint16_t IrqNum;
28 uint32_t i3cMaxRate;
29 uint32_t i3cRate;
30 uint32_t i2cFmRate;
31 uint32_t i2cFmPlusRate;
32 };
33
34 struct VirtualI3cTransferData {
35 struct I3cMsg *msgs;
36 int16_t index;
37 int16_t count;
38 };
39
40 struct VirtualI3cIbiSimulator {
41 uint16_t ibiAddr;
42 uint16_t deviceAddr;
43 };
44
45 static struct VirtualI3cIbiSimulator g_ibiSimulator;
46
VirtualI3cSetIbiSimulator(uint16_t addr,uint16_t deviceAddr)47 static inline void VirtualI3cSetIbiSimulator(uint16_t addr, uint16_t deviceAddr)
48 {
49 g_ibiSimulator.ibiAddr = addr;
50 g_ibiSimulator.deviceAddr = deviceAddr;
51 }
52
VirtualI3cGetIbiAddr(void)53 static inline uint16_t VirtualI3cGetIbiAddr(void)
54 {
55 return g_ibiSimulator.ibiAddr;
56 }
57
VirtualI3cGetIbiDeviceAddr(void)58 static inline uint16_t VirtualI3cGetIbiDeviceAddr(void)
59 {
60 return g_ibiSimulator.deviceAddr;
61 }
62
VirtualI3cXferI2cOneMsgPolling(const struct VirtualI3cCntlr * virtual,const struct VirtualI3cTransferData * td)63 static int32_t VirtualI3cXferI2cOneMsgPolling(const struct VirtualI3cCntlr *virtual,
64 const struct VirtualI3cTransferData *td)
65 {
66 struct I3cMsg *msg = &td->msgs[td->index];
67
68 (void)virtual;
69 (void)msg;
70 HDF_LOGV("VirtualI3cXferI2cOneMsgPolling: flags:0x%x, len=%d", msg->flags, msg->len);
71
72 return HDF_SUCCESS;
73 }
74
VirtualI3cCntlrInit(struct VirtualI3cCntlr * virtual)75 static inline void VirtualI3cCntlrInit(struct VirtualI3cCntlr *virtual)
76 {
77 HDF_LOGI("VirtualI3cCntlrInit: cntlr:%u init done!", virtual->busId);
78 }
79
VirtualSendCccCmd(struct I3cCntlr * cntlr,struct I3cCccCmd * ccc)80 static int32_t VirtualSendCccCmd(struct I3cCntlr *cntlr, struct I3cCccCmd *ccc)
81 {
82 (void)cntlr;
83 HDF_LOGI("VirtualSendCccCmd: enter, destination: %x!", ccc->dest);
84
85 return HDF_SUCCESS;
86 }
87
VirtualI3cTransfer(struct I3cCntlr * cntlr,struct I3cMsg * msgs,int16_t count)88 static int32_t VirtualI3cTransfer(struct I3cCntlr *cntlr, struct I3cMsg *msgs, int16_t count)
89 {
90 if (cntlr == NULL || cntlr->priv == NULL) {
91 HDF_LOGE("VirtualI3cTransfer: cntlr or virtual is null!");
92 return HDF_ERR_INVALID_OBJECT;
93 }
94
95 if (msgs == NULL || count <= 0) {
96 HDF_LOGE("VirtualI3cTransfer: err params! count:%d!", count);
97 return HDF_ERR_INVALID_PARAM;
98 }
99
100 return count;
101 }
102
VirtualI3cCntlrI2cTransfer(struct I3cCntlr * cntlr,struct I3cMsg * msgs,int16_t count)103 static int32_t VirtualI3cCntlrI2cTransfer(struct I3cCntlr *cntlr, struct I3cMsg *msgs, int16_t count)
104 {
105 int32_t ret;
106 int irqSave;
107 struct VirtualI3cCntlr *virtual = NULL;
108 struct VirtualI3cTransferData td;
109
110 if (cntlr == NULL || cntlr->priv == NULL) {
111 HDF_LOGE("VirtualI3cCntlrI2cTransfer: cntlr or virtual is null!");
112 return HDF_ERR_INVALID_OBJECT;
113 }
114 virtual = (struct VirtualI3cCntlr *)cntlr;
115
116 if (msgs == NULL || count <= 0) {
117 HDF_LOGE("VirtualI3cCntlrI2cTransfer: err params! count:%d!", count);
118 return HDF_ERR_INVALID_PARAM;
119 }
120 td.msgs = msgs;
121 td.count = count;
122 td.index = 0;
123
124 irqSave = LOS_IntLock();
125 while (td.index < td.count) {
126 ret = VirtualI3cXferI2cOneMsgPolling(virtual, &td);
127 if (ret != 0) {
128 break;
129 }
130 td.index++;
131 }
132 LOS_IntRestore(irqSave);
133 return (td.index > 0) ? td.index : ret;
134 }
135
VirtualI3cSetConfig(struct I3cCntlr * cntlr,struct I3cConfig * config)136 static int32_t VirtualI3cSetConfig(struct I3cCntlr *cntlr, struct I3cConfig *config)
137 {
138 (void)cntlr;
139 (void)config;
140 HDF_LOGI("VirtualI3cSetConfig: done!");
141 return HDF_SUCCESS;
142 }
143
VirtualI3cGetConfig(struct I3cCntlr * cntlr,struct I3cConfig * config)144 static int32_t VirtualI3cGetConfig(struct I3cCntlr *cntlr, struct I3cConfig *config)
145 {
146 (void)cntlr;
147 (void)config;
148 HDF_LOGI("VirtualI3cGetConfig: done!");
149 return HDF_SUCCESS;
150 }
151
VirtualI3cRequestIbi(struct I3cDevice * dev)152 static int32_t VirtualI3cRequestIbi(struct I3cDevice *dev)
153 {
154 (void)dev;
155 HDF_LOGI("VirtualI3cRequestIbi: done!");
156
157 return HDF_SUCCESS;
158 }
159
VirtualI3cFreeIbi(struct I3cDevice * dev)160 static void VirtualI3cFreeIbi(struct I3cDevice *dev)
161 {
162 (void)dev;
163 HDF_LOGI("VirtualI3cFreeIbi: done!");
164 }
165
166 static const struct I3cMethod g_method = {
167 .sendCccCmd = VirtualSendCccCmd,
168 .i2cTransfer = VirtualI3cCntlrI2cTransfer,
169 .Transfer = VirtualI3cTransfer,
170 .setConfig = VirtualI3cSetConfig,
171 .getConfig = VirtualI3cGetConfig,
172 .requestIbi = VirtualI3cRequestIbi,
173 .freeIbi = VirtualI3cFreeIbi,
174 };
175
VirtualI3cHotJoin(struct VirtualI3cCntlr * virtual)176 static void VirtualI3cHotJoin(struct VirtualI3cCntlr *virtual)
177 {
178 uint16_t deviceAddr;
179 struct I3cDevice *device = NULL;
180 int32_t ret;
181
182 deviceAddr = VirtualI3cGetIbiDeviceAddr();
183 device = (struct I3cDevice *)OsalMemCalloc(sizeof(*device));
184 if (device == NULL) {
185 HDF_LOGE("VirtualI3cHotJoin: device is null!");
186 return;
187 }
188 device->cntlr = &virtual->cntlr;
189 device->addr = deviceAddr;
190 device->type = I3C_CNTLR_I3C_DEVICE;
191 device->supportIbi = I3C_DEVICE_SUPPORT_IBI;
192 ret = I3cDeviceAdd(device);
193 if (ret != HDF_SUCCESS) {
194 HDF_LOGE("VirtualI3cHotJoin: add i3c device fail!");
195 return;
196 }
197 HDF_LOGI("VirtualI3cHotJoin: done!");
198 }
199
VirtualI3cReservedAddrWorker(struct VirtualI3cCntlr * virtual,uint16_t addr)200 static int32_t VirtualI3cReservedAddrWorker(struct VirtualI3cCntlr *virtual, uint16_t addr)
201 {
202 (void)virtual;
203 switch (addr) {
204 case I3C_HOT_JOIN_ADDR:
205 VirtualI3cHotJoin(virtual);
206 break;
207 case I3C_RESERVED_ADDR_7H3E:
208 case I3C_RESERVED_ADDR_7H5E:
209 case I3C_RESERVED_ADDR_7H6E:
210 case I3C_RESERVED_ADDR_7H76:
211 case I3C_RESERVED_ADDR_7H7A:
212 case I3C_RESERVED_ADDR_7H7C:
213 case I3C_RESERVED_ADDR_7H7F:
214 /* All cases of broadcast address single bit error detect */
215 HDF_LOGW("VirtualI3cReservedAddrWorker: broadcast Address single bit error!");
216 break;
217 default:
218 HDF_LOGD("VirtualI3cReservedAddrWorker: Reserved address which is not support!");
219 break;
220 }
221
222 return HDF_SUCCESS;
223 }
224
I3cIbiHandle(uint32_t irq,void * data)225 static int32_t I3cIbiHandle(uint32_t irq, void *data)
226 {
227 struct VirtualI3cCntlr *virtual = NULL;
228 struct I3cDevice *device = NULL;
229 uint16_t ibiAddr;
230 char *testStr = VIRTUAL_I3C_TEST_STR;
231
232 (void)irq;
233 if (data == NULL) {
234 HDF_LOGW("I3cIbiHandle: data is null!");
235 return HDF_ERR_INVALID_PARAM;
236 }
237 virtual = (struct VirtualI3cCntlr *)data;
238 ibiAddr = VirtualI3cGetIbiAddr();
239 if (I3cCheckReservedAddr(ibiAddr) == I3C_ADDR_RESERVED) {
240 HDF_LOGD("I3cIbiHandle: Calling VirtualI3cResAddrWorker...");
241 return VirtualI3cReservedAddrWorker(virtual, ibiAddr);
242 } else {
243 HDF_LOGD("I3cIbiHandle: Calling I3cCntlrIbiCallback...");
244 device = I3cGetDeviceByAddr(&virtual->cntlr, ibiAddr);
245 if (device == NULL) {
246 HDF_LOGE("I3cIbiHandle: device is null!");
247 return HDF_ERR_MALLOC_FAIL;
248 }
249 if (device->ibi->payload > VIRTUAL_I3C_TEST_STR_LEN) {
250 /* Put the string "Hello I3C!" into IBI buffer */
251 *device->ibi->data = *testStr;
252 }
253 return I3cCntlrIbiCallback(device);
254 }
255
256 return HDF_SUCCESS;
257 }
258
259 /* Soft calling is used here to simulate in-band interrupt */
SoftInterruptTrigger(struct VirtualI3cCntlr * virtual,uint16_t ibiDeviceAddr)260 static inline void SoftInterruptTrigger(struct VirtualI3cCntlr *virtual, uint16_t ibiDeviceAddr)
261 {
262 VirtualI3cSetIbiSimulator(I3C_HOT_JOIN_ADDR, ibiDeviceAddr);
263 HDF_LOGE("SoftInterruptTrigger: IrqNum: %d!", virtual->IrqNum);
264
265 /* Simulate soft interrupt through direct call */
266 if (I3cIbiHandle(virtual->IrqNum, (void *)virtual) != HDF_SUCCESS) {
267 HDF_LOGE("SoftInterruptTrigger: Call I3cIbiHandle fail!");
268 }
269 }
270
VirtualI3cHotJoinSimulator(void)271 static int32_t VirtualI3cHotJoinSimulator(void)
272 {
273 uint16_t busId;
274 struct I3cCntlr *cntlr = NULL;
275 struct VirtualI3cCntlr *virtual = NULL;
276
277 for (busId = 0; busId < I3C_CNTLR_MAX; busId++) {
278 cntlr = I3cCntlrGet(busId);
279 if (cntlr == NULL) {
280 continue;
281 }
282
283 virtual = (struct VirtualI3cCntlr *)cntlr;
284 OsalMDelay(VIRTUAL_I3C_DELAY);
285 SoftInterruptTrigger(virtual, VIRTUAL_I3C_HOT_JOIN_TEST_ADDR);
286 }
287
288 return HDF_SUCCESS;
289 }
290
VirtualI3cReadDrs(struct VirtualI3cCntlr * virtual,const struct DeviceResourceNode * node)291 static int32_t VirtualI3cReadDrs(struct VirtualI3cCntlr *virtual, const struct DeviceResourceNode *node)
292 {
293 struct DeviceResourceIface *drsOps = NULL;
294
295 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
296 if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL) {
297 HDF_LOGE("VirtualI3cReadDrs: invalid drs ops fail!");
298 return HDF_FAILURE;
299 }
300 if (drsOps->GetUint16(node, "busId", &virtual->busId, 0) != HDF_SUCCESS) {
301 HDF_LOGE("VirtualI3cReadDrs: read busId fail!");
302 return HDF_ERR_IO;
303 }
304 if (drsOps->GetUint16(node, "busMode", &virtual->busMode, 0) != HDF_SUCCESS) {
305 HDF_LOGE("VirtualI3cReadDrs: read busMode fail!");
306 return HDF_ERR_IO;
307 }
308 if (drsOps->GetUint16(node, "IrqNum", &virtual->IrqNum, 0) != HDF_SUCCESS) {
309 HDF_LOGE("VirtualI3cReadDrs: read IrqNum fail!");
310 return HDF_ERR_IO;
311 }
312 if (drsOps->GetUint32(node, "i3cMaxRate", &virtual->i3cMaxRate, 0) != HDF_SUCCESS) {
313 HDF_LOGE("VirtualI3cReadDrs: read i3cMaxRate fail!");
314 return HDF_ERR_IO;
315 }
316 if (drsOps->GetUint32(node, "i3cRate", &virtual->i3cRate, 0) != HDF_SUCCESS) {
317 HDF_LOGE("VirtualI3cReadDrs: read i3cRate fail!");
318 return HDF_ERR_IO;
319 }
320 if (drsOps->GetUint32(node, "i2cFmRate", &virtual->i2cFmRate, 0) != HDF_SUCCESS) {
321 HDF_LOGE("VirtualI3cReadDrs: read i2cFmRate fail!");
322 return HDF_ERR_IO;
323 }
324 if (drsOps->GetUint32(node, "i2cFmPlusRate", &virtual->i2cFmPlusRate, 0) != HDF_SUCCESS) {
325 HDF_LOGE("VirtualI3cReadDrs: read i2cFmPlusRate fail!");
326 return HDF_ERR_IO;
327 }
328
329 return HDF_SUCCESS;
330 }
331
VirtualI3cParseAndInit(struct HdfDeviceObject * device,const struct DeviceResourceNode * node)332 static int32_t VirtualI3cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
333 {
334 int32_t ret;
335 struct VirtualI3cCntlr *virtual = NULL;
336 (void)device;
337
338 virtual = (struct VirtualI3cCntlr *)OsalMemCalloc(sizeof(*virtual));
339 if (virtual == NULL) {
340 HDF_LOGE("VirtualI3cParseAndInit: malloc virtual fail!");
341 return HDF_ERR_MALLOC_FAIL;
342 }
343
344 ret = VirtualI3cReadDrs(virtual, node);
345 if (ret != HDF_SUCCESS) {
346 HDF_LOGE("VirtualI3cParseAndInit: read drs fail, ret: %d!", ret);
347 OsalMemFree(virtual);
348 virtual = NULL;
349 return ret;
350 }
351
352 VirtualI3cCntlrInit(virtual);
353 virtual->cntlr.priv = (void *)node;
354 virtual->cntlr.busId = (int16_t)virtual->busId;
355 virtual->cntlr.ops = &g_method;
356 (void)OsalSpinInit(&virtual->spin);
357 ret = I3cCntlrAdd(&virtual->cntlr);
358 if (ret != HDF_SUCCESS) {
359 HDF_LOGE("VirtualI3cParseAndInit: add i3c controller fail, ret = %d!", ret);
360 (void)OsalSpinDestroy(&virtual->spin);
361 OsalMemFree(virtual);
362 virtual = NULL;
363 return ret;
364 }
365
366 return HDF_SUCCESS;
367 }
368
VirtualI3cInit(struct HdfDeviceObject * device)369 static int32_t VirtualI3cInit(struct HdfDeviceObject *device)
370 {
371 int32_t ret;
372 const struct DeviceResourceNode *childNode = NULL;
373
374 HDF_LOGD("VirtualI3cInit: enter!");
375 if (device == NULL || device->property == NULL) {
376 HDF_LOGE("VirtualI3cInit: device or property is null!");
377 return HDF_ERR_INVALID_OBJECT;
378 }
379
380 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
381 ret = VirtualI3cParseAndInit(device, childNode);
382 if (ret != HDF_SUCCESS) {
383 break;
384 }
385 }
386 return VirtualI3cHotJoinSimulator();
387 }
388
VirtualI3cRemoveByNode(const struct DeviceResourceNode * node)389 static void VirtualI3cRemoveByNode(const struct DeviceResourceNode *node)
390 {
391 int32_t ret;
392 int16_t busId;
393 struct I3cCntlr *cntlr = NULL;
394 struct VirtualI3cCntlr *virtual = NULL;
395 struct DeviceResourceIface *drsOps = NULL;
396
397 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
398 if (drsOps == NULL || drsOps->GetUint32 == NULL) {
399 HDF_LOGE("VirtualI3cRemoveByNode: invalid drs ops fail!");
400 return;
401 }
402
403 ret = drsOps->GetUint16(node, "busId", (uint16_t *)&busId, 0);
404 if (ret != HDF_SUCCESS) {
405 HDF_LOGE("VirtualI3cRemoveByNode: read busId fail, ret: %d!", ret);
406 return;
407 }
408
409 cntlr = I3cCntlrGet(busId);
410 if (cntlr != NULL && cntlr->priv == node) {
411 I3cCntlrPut(cntlr);
412 I3cCntlrRemove(cntlr);
413 virtual = (struct VirtualI3cCntlr *)cntlr;
414 (void)OsalSpinDestroy(&virtual->spin);
415 OsalMemFree(virtual);
416 }
417 return;
418 }
419
VirtualI3cRelease(struct HdfDeviceObject * device)420 static void VirtualI3cRelease(struct HdfDeviceObject *device)
421 {
422 const struct DeviceResourceNode *childNode = NULL;
423
424 HDF_LOGI("VirtualI3cRelease: enter!");
425
426 if (device == NULL || device->property == NULL) {
427 HDF_LOGE("VirtualI3cRelease: device or property is null!");
428 return;
429 }
430
431 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
432 VirtualI3cRemoveByNode(childNode);
433 }
434 }
435
436 struct HdfDriverEntry g_i3cDriverEntry = {
437 .moduleVersion = 1,
438 .Init = VirtualI3cInit,
439 .Release = VirtualI3cRelease,
440 .moduleName = "virtual_i3c_driver",
441 };
442 HDF_INIT(g_i3cDriverEntry);
443