1 /*
2 * Copyright (c) 2022 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8
9 #include <zephyr/toolchain.h>
10 #include <zephyr/sys/__assert.h>
11
12 #include <zephyr/drivers/i3c.h>
13
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_DECLARE(i3c, CONFIG_I3C_LOG_LEVEL);
16
i3c_ccc_do_getbcr(struct i3c_device_desc * target,struct i3c_ccc_getbcr * bcr)17 int i3c_ccc_do_getbcr(struct i3c_device_desc *target,
18 struct i3c_ccc_getbcr *bcr)
19 {
20 struct i3c_ccc_payload ccc_payload;
21 struct i3c_ccc_target_payload ccc_tgt_payload;
22
23 __ASSERT_NO_MSG(target != NULL);
24 __ASSERT_NO_MSG(target->bus != NULL);
25 __ASSERT_NO_MSG(bcr != NULL);
26
27 ccc_tgt_payload.addr = target->dynamic_addr;
28 ccc_tgt_payload.rnw = 1;
29 ccc_tgt_payload.data = &bcr->bcr;
30 ccc_tgt_payload.data_len = sizeof(bcr->bcr);
31
32 memset(&ccc_payload, 0, sizeof(ccc_payload));
33 ccc_payload.ccc.id = I3C_CCC_GETBCR;
34 ccc_payload.targets.payloads = &ccc_tgt_payload;
35 ccc_payload.targets.num_targets = 1;
36
37 return i3c_do_ccc(target->bus, &ccc_payload);
38 }
39
i3c_ccc_do_getdcr(struct i3c_device_desc * target,struct i3c_ccc_getdcr * dcr)40 int i3c_ccc_do_getdcr(struct i3c_device_desc *target,
41 struct i3c_ccc_getdcr *dcr)
42 {
43 struct i3c_ccc_payload ccc_payload;
44 struct i3c_ccc_target_payload ccc_tgt_payload;
45
46 __ASSERT_NO_MSG(target != NULL);
47 __ASSERT_NO_MSG(target->bus != NULL);
48 __ASSERT_NO_MSG(dcr != NULL);
49
50 ccc_tgt_payload.addr = target->dynamic_addr;
51 ccc_tgt_payload.rnw = 1;
52 ccc_tgt_payload.data = &dcr->dcr;
53 ccc_tgt_payload.data_len = sizeof(dcr->dcr);
54
55 memset(&ccc_payload, 0, sizeof(ccc_payload));
56 ccc_payload.ccc.id = I3C_CCC_GETDCR;
57 ccc_payload.targets.payloads = &ccc_tgt_payload;
58 ccc_payload.targets.num_targets = 1;
59
60 return i3c_do_ccc(target->bus, &ccc_payload);
61 }
62
i3c_ccc_do_getpid(struct i3c_device_desc * target,struct i3c_ccc_getpid * pid)63 int i3c_ccc_do_getpid(struct i3c_device_desc *target,
64 struct i3c_ccc_getpid *pid)
65 {
66 struct i3c_ccc_payload ccc_payload;
67 struct i3c_ccc_target_payload ccc_tgt_payload;
68
69 __ASSERT_NO_MSG(target != NULL);
70 __ASSERT_NO_MSG(target->bus != NULL);
71 __ASSERT_NO_MSG(pid != NULL);
72
73 ccc_tgt_payload.addr = target->dynamic_addr;
74 ccc_tgt_payload.rnw = 1;
75 ccc_tgt_payload.data = &pid->pid[0];
76 ccc_tgt_payload.data_len = sizeof(pid->pid);
77
78 memset(&ccc_payload, 0, sizeof(ccc_payload));
79 ccc_payload.ccc.id = I3C_CCC_GETPID;
80 ccc_payload.targets.payloads = &ccc_tgt_payload;
81 ccc_payload.targets.num_targets = 1;
82
83 return i3c_do_ccc(target->bus, &ccc_payload);
84 }
85
i3c_ccc_do_rstact_all(const struct device * controller,enum i3c_ccc_rstact_defining_byte action)86 int i3c_ccc_do_rstact_all(const struct device *controller,
87 enum i3c_ccc_rstact_defining_byte action)
88 {
89 struct i3c_ccc_payload ccc_payload;
90 uint8_t def_byte;
91
92 __ASSERT_NO_MSG(controller != NULL);
93
94 memset(&ccc_payload, 0, sizeof(ccc_payload));
95 ccc_payload.ccc.id = I3C_CCC_RSTACT(true);
96
97 def_byte = (uint8_t)action;
98 ccc_payload.ccc.data = &def_byte;
99 ccc_payload.ccc.data_len = 1U;
100
101 return i3c_do_ccc(controller, &ccc_payload);
102 }
103
i3c_ccc_do_rstdaa_all(const struct device * controller)104 int i3c_ccc_do_rstdaa_all(const struct device *controller)
105 {
106 struct i3c_ccc_payload ccc_payload;
107
108 __ASSERT_NO_MSG(controller != NULL);
109
110 memset(&ccc_payload, 0, sizeof(ccc_payload));
111 ccc_payload.ccc.id = I3C_CCC_RSTDAA;
112
113 return i3c_do_ccc(controller, &ccc_payload);
114 }
115
i3c_ccc_do_setdasa(const struct i3c_device_desc * target)116 int i3c_ccc_do_setdasa(const struct i3c_device_desc *target)
117 {
118 struct i3c_driver_data *bus_data = (struct i3c_driver_data *)target->bus->data;
119 struct i3c_ccc_payload ccc_payload;
120 struct i3c_ccc_target_payload ccc_tgt_payload;
121 uint8_t dyn_addr;
122
123 __ASSERT_NO_MSG(target != NULL);
124 __ASSERT_NO_MSG(target->bus != NULL);
125
126 if ((target->static_addr == 0U) || (target->dynamic_addr != 0U)) {
127 return -EINVAL;
128 }
129
130 /*
131 * Note that the 7-bit address needs to start at bit 1
132 * (aka left-justified). So shift left by 1;
133 */
134 dyn_addr = (target->init_dynamic_addr ?
135 target->init_dynamic_addr : target->static_addr) << 1;
136
137 /* check that initial dynamic address is free before setting it */
138 if ((target->init_dynamic_addr != 0) &&
139 (target->init_dynamic_addr != target->static_addr)) {
140 if (!i3c_addr_slots_is_free(&bus_data->attached_dev.addr_slots, dyn_addr >> 1)) {
141 return -EINVAL;
142 }
143 }
144
145 ccc_tgt_payload.addr = target->static_addr;
146 ccc_tgt_payload.rnw = 0;
147 ccc_tgt_payload.data = &dyn_addr;
148 ccc_tgt_payload.data_len = 1;
149
150 memset(&ccc_payload, 0, sizeof(ccc_payload));
151 ccc_payload.ccc.id = I3C_CCC_SETDASA;
152 ccc_payload.targets.payloads = &ccc_tgt_payload;
153 ccc_payload.targets.num_targets = 1;
154
155 return i3c_do_ccc(target->bus, &ccc_payload);
156 }
157
i3c_ccc_do_setnewda(const struct i3c_device_desc * target,struct i3c_ccc_address new_da)158 int i3c_ccc_do_setnewda(const struct i3c_device_desc *target, struct i3c_ccc_address new_da)
159 {
160 struct i3c_driver_data *bus_data = (struct i3c_driver_data *)target->bus->data;
161 struct i3c_ccc_payload ccc_payload;
162 struct i3c_ccc_target_payload ccc_tgt_payload;
163 uint8_t new_dyn_addr;
164
165 __ASSERT_NO_MSG(target != NULL);
166 __ASSERT_NO_MSG(target->bus != NULL);
167
168 if (target->dynamic_addr == 0U) {
169 return -EINVAL;
170 }
171
172 /*
173 * Note that the 7-bit address needs to start at bit 1
174 * (aka left-justified). So shift left by 1;
175 */
176 new_dyn_addr = new_da.addr << 1;
177
178 /* check that initial dynamic address is free before setting it */
179 if (target->dynamic_addr != new_da.addr) {
180 if (!i3c_addr_slots_is_free(&bus_data->attached_dev.addr_slots, new_da.addr)) {
181 return -EINVAL;
182 }
183 }
184
185 ccc_tgt_payload.addr = target->dynamic_addr;
186 ccc_tgt_payload.rnw = 0;
187 ccc_tgt_payload.data = &new_dyn_addr;
188 ccc_tgt_payload.data_len = 1;
189
190 memset(&ccc_payload, 0, sizeof(ccc_payload));
191 ccc_payload.ccc.id = I3C_CCC_SETNEWDA;
192 ccc_payload.targets.payloads = &ccc_tgt_payload;
193 ccc_payload.targets.num_targets = 1;
194
195 return i3c_do_ccc(target->bus, &ccc_payload);
196 }
197
i3c_ccc_do_events_all_set(const struct device * controller,bool enable,struct i3c_ccc_events * events)198 int i3c_ccc_do_events_all_set(const struct device *controller,
199 bool enable, struct i3c_ccc_events *events)
200 {
201 struct i3c_ccc_payload ccc_payload;
202
203 __ASSERT_NO_MSG(controller != NULL);
204
205 memset(&ccc_payload, 0, sizeof(ccc_payload));
206
207 ccc_payload.ccc.id = enable ? I3C_CCC_ENEC(true) : I3C_CCC_DISEC(true);
208
209 ccc_payload.ccc.data = &events->events;
210 ccc_payload.ccc.data_len = sizeof(events->events);
211
212 return i3c_do_ccc(controller, &ccc_payload);
213 }
214
i3c_ccc_do_events_set(struct i3c_device_desc * target,bool enable,struct i3c_ccc_events * events)215 int i3c_ccc_do_events_set(struct i3c_device_desc *target,
216 bool enable, struct i3c_ccc_events *events)
217 {
218 struct i3c_ccc_payload ccc_payload;
219 struct i3c_ccc_target_payload ccc_tgt_payload;
220
221 __ASSERT_NO_MSG(target != NULL);
222 __ASSERT_NO_MSG(target->bus != NULL);
223
224 if (target->dynamic_addr == 0U) {
225 return -EINVAL;
226 }
227
228 ccc_tgt_payload.addr = target->dynamic_addr;
229 ccc_tgt_payload.rnw = 0;
230 ccc_tgt_payload.data = &events->events;
231 ccc_tgt_payload.data_len = sizeof(events->events);
232
233 memset(&ccc_payload, 0, sizeof(ccc_payload));
234 ccc_payload.ccc.id = enable ? I3C_CCC_ENEC(false) : I3C_CCC_DISEC(false);
235 ccc_payload.targets.payloads = &ccc_tgt_payload;
236 ccc_payload.targets.num_targets = 1;
237
238 return i3c_do_ccc(target->bus, &ccc_payload);
239 }
240
i3c_ccc_do_setmwl_all(const struct device * controller,const struct i3c_ccc_mwl * mwl)241 int i3c_ccc_do_setmwl_all(const struct device *controller,
242 const struct i3c_ccc_mwl *mwl)
243 {
244 struct i3c_ccc_payload ccc_payload;
245 uint8_t data[2];
246
247 __ASSERT_NO_MSG(controller != NULL);
248
249 memset(&ccc_payload, 0, sizeof(ccc_payload));
250
251 ccc_payload.ccc.id = I3C_CCC_SETMWL(true);
252
253 ccc_payload.ccc.data = &data[0];
254 ccc_payload.ccc.data_len = sizeof(data);
255
256 /* The actual data is MSB first. So order the data. */
257 data[0] = (uint8_t)((mwl->len & 0xFF00U) >> 8);
258 data[1] = (uint8_t)(mwl->len & 0xFFU);
259
260 return i3c_do_ccc(controller, &ccc_payload);
261 }
262
i3c_ccc_do_setmwl(const struct i3c_device_desc * target,const struct i3c_ccc_mwl * mwl)263 int i3c_ccc_do_setmwl(const struct i3c_device_desc *target,
264 const struct i3c_ccc_mwl *mwl)
265 {
266 struct i3c_ccc_payload ccc_payload;
267 struct i3c_ccc_target_payload ccc_tgt_payload;
268 uint8_t data[2];
269
270 __ASSERT_NO_MSG(target != NULL);
271 __ASSERT_NO_MSG(target->bus != NULL);
272
273 memset(&ccc_payload, 0, sizeof(ccc_payload));
274
275 ccc_tgt_payload.addr = target->dynamic_addr;
276 ccc_tgt_payload.rnw = 0;
277 ccc_tgt_payload.data = &data[0];
278 ccc_tgt_payload.data_len = sizeof(data);
279
280 ccc_payload.ccc.id = I3C_CCC_SETMWL(false);
281 ccc_payload.targets.payloads = &ccc_tgt_payload;
282 ccc_payload.targets.num_targets = 1;
283
284 /* The actual length is MSB first. So order the data. */
285 data[0] = (uint8_t)((mwl->len & 0xFF00U) >> 8);
286 data[1] = (uint8_t)(mwl->len & 0xFFU);
287
288 return i3c_do_ccc(target->bus, &ccc_payload);
289 }
290
i3c_ccc_do_getmwl(const struct i3c_device_desc * target,struct i3c_ccc_mwl * mwl)291 int i3c_ccc_do_getmwl(const struct i3c_device_desc *target,
292 struct i3c_ccc_mwl *mwl)
293 {
294 struct i3c_ccc_payload ccc_payload;
295 struct i3c_ccc_target_payload ccc_tgt_payload;
296 uint8_t data[2];
297 int ret;
298
299 __ASSERT_NO_MSG(target != NULL);
300 __ASSERT_NO_MSG(target->bus != NULL);
301 __ASSERT_NO_MSG(mwl != NULL);
302
303 ccc_tgt_payload.addr = target->dynamic_addr;
304 ccc_tgt_payload.rnw = 1;
305 ccc_tgt_payload.data = &data[0];
306 ccc_tgt_payload.data_len = sizeof(data);
307
308 memset(&ccc_payload, 0, sizeof(ccc_payload));
309 ccc_payload.ccc.id = I3C_CCC_GETMWL;
310 ccc_payload.targets.payloads = &ccc_tgt_payload;
311 ccc_payload.targets.num_targets = 1;
312
313 ret = i3c_do_ccc(target->bus, &ccc_payload);
314
315 if (ret == 0) {
316 /* The actual length is MSB first. So order the data. */
317 mwl->len = (data[0] << 8) | data[1];
318 }
319
320 return ret;
321 }
322
i3c_ccc_do_setmrl_all(const struct device * controller,const struct i3c_ccc_mrl * mrl,bool has_ibi_size)323 int i3c_ccc_do_setmrl_all(const struct device *controller,
324 const struct i3c_ccc_mrl *mrl,
325 bool has_ibi_size)
326 {
327 struct i3c_ccc_payload ccc_payload;
328 uint8_t data[3];
329
330 __ASSERT_NO_MSG(controller != NULL);
331
332 memset(&ccc_payload, 0, sizeof(ccc_payload));
333
334 ccc_payload.ccc.id = I3C_CCC_SETMRL(true);
335
336 ccc_payload.ccc.data = &data[0];
337 ccc_payload.ccc.data_len = has_ibi_size ? 3 : 2;
338
339 /* The actual length is MSB first. So order the data. */
340 data[0] = (uint8_t)((mrl->len & 0xFF00U) >> 8);
341 data[1] = (uint8_t)(mrl->len & 0xFFU);
342
343 if (has_ibi_size) {
344 data[2] = mrl->ibi_len;
345 }
346
347 return i3c_do_ccc(controller, &ccc_payload);
348 }
349
i3c_ccc_do_setmrl(const struct i3c_device_desc * target,const struct i3c_ccc_mrl * mrl)350 int i3c_ccc_do_setmrl(const struct i3c_device_desc *target,
351 const struct i3c_ccc_mrl *mrl)
352 {
353 struct i3c_ccc_payload ccc_payload;
354 struct i3c_ccc_target_payload ccc_tgt_payload;
355 uint8_t data[3];
356
357 __ASSERT_NO_MSG(target != NULL);
358 __ASSERT_NO_MSG(target->bus != NULL);
359
360 memset(&ccc_payload, 0, sizeof(ccc_payload));
361
362 ccc_tgt_payload.addr = target->dynamic_addr;
363 ccc_tgt_payload.rnw = 0;
364 ccc_tgt_payload.data = &data[0];
365
366 ccc_payload.ccc.id = I3C_CCC_SETMRL(false);
367 ccc_payload.targets.payloads = &ccc_tgt_payload;
368 ccc_payload.targets.num_targets = 1;
369
370 /* The actual length is MSB first. So order the data. */
371 data[0] = (uint8_t)((mrl->len & 0xFF00U) >> 8);
372 data[1] = (uint8_t)(mrl->len & 0xFFU);
373
374 if ((target->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE)
375 == I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE) {
376 ccc_tgt_payload.data_len = 3;
377
378 data[2] = mrl->ibi_len;
379 } else {
380 ccc_tgt_payload.data_len = 2;
381 }
382
383 return i3c_do_ccc(target->bus, &ccc_payload);
384 }
385
i3c_ccc_do_getmrl(const struct i3c_device_desc * target,struct i3c_ccc_mrl * mrl)386 int i3c_ccc_do_getmrl(const struct i3c_device_desc *target,
387 struct i3c_ccc_mrl *mrl)
388 {
389 struct i3c_ccc_payload ccc_payload;
390 struct i3c_ccc_target_payload ccc_tgt_payload;
391 uint8_t data[3];
392 bool has_ibi_sz;
393 int ret;
394
395 __ASSERT_NO_MSG(target != NULL);
396 __ASSERT_NO_MSG(target->bus != NULL);
397 __ASSERT_NO_MSG(mrl != NULL);
398
399 has_ibi_sz = (target->bcr & I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE)
400 == I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE;
401
402 ccc_tgt_payload.addr = target->dynamic_addr;
403 ccc_tgt_payload.rnw = 1;
404 ccc_tgt_payload.data = &data[0];
405 ccc_tgt_payload.data_len = has_ibi_sz ? 3 : 2;
406
407 memset(&ccc_payload, 0, sizeof(ccc_payload));
408 ccc_payload.ccc.id = I3C_CCC_GETMRL;
409 ccc_payload.targets.payloads = &ccc_tgt_payload;
410 ccc_payload.targets.num_targets = 1;
411
412 ret = i3c_do_ccc(target->bus, &ccc_payload);
413
414 if (ret == 0) {
415 /* The actual length is MSB first. So order the data. */
416 mrl->len = (data[0] << 8) | data[1];
417
418 if (has_ibi_sz) {
419 mrl->ibi_len = data[2];
420 }
421 }
422
423 return ret;
424 }
425
i3c_ccc_do_getstatus(const struct i3c_device_desc * target,union i3c_ccc_getstatus * status,enum i3c_ccc_getstatus_fmt fmt,enum i3c_ccc_getstatus_defbyte defbyte)426 int i3c_ccc_do_getstatus(const struct i3c_device_desc *target,
427 union i3c_ccc_getstatus *status,
428 enum i3c_ccc_getstatus_fmt fmt,
429 enum i3c_ccc_getstatus_defbyte defbyte)
430 {
431 struct i3c_ccc_payload ccc_payload;
432 struct i3c_ccc_target_payload ccc_tgt_payload;
433 uint8_t defining_byte;
434 uint8_t data[2];
435 int ret;
436
437 __ASSERT_NO_MSG(target != NULL);
438 __ASSERT_NO_MSG(target->bus != NULL);
439 __ASSERT_NO_MSG(status != NULL);
440
441 ccc_tgt_payload.addr = target->dynamic_addr;
442 ccc_tgt_payload.rnw = 1;
443 ccc_tgt_payload.data = &data[0];
444
445 if (fmt == GETSTATUS_FORMAT_1) {
446 ccc_tgt_payload.data_len = 2;
447 } else if (fmt == GETSTATUS_FORMAT_2) {
448 switch (defbyte) {
449 case GETSTATUS_FORMAT_2_TGTSTAT:
450 __fallthrough;
451 case GETSTATUS_FORMAT_2_PRECR:
452 ccc_tgt_payload.data_len = 2;
453 break;
454 default:
455 ret = -EINVAL;
456 goto out;
457 }
458 } else {
459 ret = -EINVAL;
460 goto out;
461 }
462
463 memset(&ccc_payload, 0, sizeof(ccc_payload));
464 ccc_payload.ccc.id = I3C_CCC_GETSTATUS;
465 ccc_payload.targets.payloads = &ccc_tgt_payload;
466 ccc_payload.targets.num_targets = 1;
467
468 if (fmt == GETSTATUS_FORMAT_2) {
469 defining_byte = (uint8_t)defbyte;
470
471 ccc_payload.ccc.data = &defining_byte;
472 ccc_payload.ccc.data_len = 1;
473 }
474
475 ret = i3c_do_ccc(target->bus, &ccc_payload);
476
477 if (ret == 0) {
478 /* Received data is MSB first. So order the data. */
479 if (fmt == GETSTATUS_FORMAT_1) {
480 status->fmt1.status = (data[0] << 8) | data[1];
481 } else if (fmt == GETSTATUS_FORMAT_2) {
482 switch (defbyte) {
483 case GETSTATUS_FORMAT_2_TGTSTAT:
484 __fallthrough;
485 case GETSTATUS_FORMAT_2_PRECR:
486 status->fmt2.raw_u16 = (data[0] << 8) | data[1];
487 break;
488 default:
489 break;
490 }
491 }
492 }
493
494 out:
495 return ret;
496 }
497