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 #include <zephyr/sys/slist.h>
12 
13 #include <zephyr/drivers/i3c.h>
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(i3c, CONFIG_I3C_LOG_LEVEL);
17 
i3c_dump_msgs(const char * name,const struct i3c_msg * msgs,uint8_t num_msgs,struct i3c_device_desc * target)18 void i3c_dump_msgs(const char *name, const struct i3c_msg *msgs,
19 		   uint8_t num_msgs, struct i3c_device_desc *target)
20 {
21 	LOG_DBG("I3C msg: %s, addr=%x", name, target->dynamic_addr);
22 	for (unsigned int i = 0; i < num_msgs; i++) {
23 		const struct i3c_msg *msg = &msgs[i];
24 
25 		LOG_DBG("   %c len=%02x: ",
26 			msg->flags & I3C_MSG_READ ? 'R' : 'W', msg->len);
27 		if (!(msg->flags & I3C_MSG_READ)) {
28 			LOG_HEXDUMP_DBG(msg->buf, msg->len, "contents:");
29 		}
30 	}
31 }
32 
i3c_addr_slots_set(struct i3c_addr_slots * slots,uint8_t dev_addr,enum i3c_addr_slot_status status)33 void i3c_addr_slots_set(struct i3c_addr_slots *slots,
34 			uint8_t dev_addr,
35 			enum i3c_addr_slot_status status)
36 {
37 	int bitpos;
38 	int idx;
39 
40 	__ASSERT_NO_MSG(slots != NULL);
41 
42 	if (dev_addr > I3C_MAX_ADDR) {
43 		/* Invalid address. Do nothing. */
44 		return;
45 	}
46 
47 	bitpos = dev_addr * 2;
48 	idx = bitpos / BITS_PER_LONG;
49 	bitpos %= BITS_PER_LONG;
50 
51 	slots->slots[idx] &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK << bitpos);
52 	slots->slots[idx] |= status << bitpos;
53 }
54 
55 enum i3c_addr_slot_status
i3c_addr_slots_status(struct i3c_addr_slots * slots,uint8_t dev_addr)56 i3c_addr_slots_status(struct i3c_addr_slots *slots,
57 		      uint8_t dev_addr)
58 {
59 	unsigned long status;
60 	int bitpos;
61 	int idx;
62 
63 	__ASSERT_NO_MSG(slots != NULL);
64 
65 	if (dev_addr > I3C_MAX_ADDR) {
66 		/* Invalid address.
67 		 * Simply says it's reserved so it will not be
68 		 * used for anything.
69 		 */
70 		return I3C_ADDR_SLOT_STATUS_RSVD;
71 	}
72 
73 	bitpos = dev_addr * 2;
74 	idx = bitpos / BITS_PER_LONG;
75 	bitpos %= BITS_PER_LONG;
76 
77 	status = slots->slots[idx] >> bitpos;
78 	status &= I3C_ADDR_SLOT_STATUS_MASK;
79 
80 	return status;
81 }
82 
83 
i3c_addr_slots_init(const struct device * dev)84 int i3c_addr_slots_init(const struct device *dev)
85 {
86 	struct i3c_driver_data *data =
87 		(struct i3c_driver_data *)dev->data;
88 	const struct i3c_driver_config *config =
89 		(const struct i3c_driver_config *)dev->config;
90 	int i, ret = 0;
91 	struct i3c_device_desc *i3c_dev;
92 	struct i3c_i2c_device_desc *i2c_dev;
93 
94 	__ASSERT_NO_MSG(dev != NULL);
95 
96 	(void)memset(&data->attached_dev.addr_slots, 0, sizeof(data->attached_dev.addr_slots));
97 	sys_slist_init(&data->attached_dev.devices.i3c);
98 	sys_slist_init(&data->attached_dev.devices.i2c);
99 
100 	/* Address restrictions (ref 5.1.2.2.5, Specification for I3C v1.1.1) */
101 	for (i = 0; i <= 7; i++) {
102 		/* Addresses 0 to 7 are reserved */
103 		i3c_addr_slots_set(&data->attached_dev.addr_slots, i, I3C_ADDR_SLOT_STATUS_RSVD);
104 
105 		/*
106 		 * Addresses within a single bit error of broadcast address
107 		 * are also reserved.
108 		 */
109 		i3c_addr_slots_set(&data->attached_dev.addr_slots, I3C_BROADCAST_ADDR ^ BIT(i),
110 				   I3C_ADDR_SLOT_STATUS_RSVD);
111 
112 	}
113 
114 	/* The broadcast address is reserved */
115 	i3c_addr_slots_set(&data->attached_dev.addr_slots, I3C_BROADCAST_ADDR,
116 			   I3C_ADDR_SLOT_STATUS_RSVD);
117 
118 	/*
119 	 * Mark all I2C addresses first.
120 	 */
121 	for (i = 0; i < config->dev_list.num_i2c; i++) {
122 		i2c_dev = &config->dev_list.i2c[i];
123 		ret = i3c_attach_i2c_device(i2c_dev);
124 		if (ret != 0) {
125 			/* Address slot is not free */
126 			ret = -EINVAL;
127 			goto out;
128 		}
129 	}
130 
131 	/*
132 	 * If there is a static address for the I3C devices, check
133 	 * if this address is free, and there is no other devices of
134 	 * the same (pre-assigned) address on the bus.
135 	 */
136 	for (i = 0; i < config->dev_list.num_i3c; i++) {
137 		i3c_dev = &config->dev_list.i3c[i];
138 		ret = i3c_attach_i3c_device(i3c_dev);
139 		if (ret != 0) {
140 			/* Address slot is not free */
141 			ret = -EINVAL;
142 			goto out;
143 		}
144 	}
145 
146 out:
147 	return ret;
148 }
149 
i3c_addr_slots_is_free(struct i3c_addr_slots * slots,uint8_t dev_addr)150 bool i3c_addr_slots_is_free(struct i3c_addr_slots *slots,
151 			    uint8_t dev_addr)
152 {
153 	enum i3c_addr_slot_status status;
154 
155 	__ASSERT_NO_MSG(slots != NULL);
156 
157 	status = i3c_addr_slots_status(slots, dev_addr);
158 
159 	return (status == I3C_ADDR_SLOT_STATUS_FREE);
160 }
161 
i3c_addr_slots_next_free_find(struct i3c_addr_slots * slots,uint8_t start_addr)162 uint8_t i3c_addr_slots_next_free_find(struct i3c_addr_slots *slots, uint8_t start_addr)
163 {
164 	uint8_t addr;
165 	enum i3c_addr_slot_status status;
166 
167 	/* Addresses 0 to 7 are reserved. So start at 8. */
168 	for (addr = MAX(start_addr, 8); addr < I3C_MAX_ADDR; addr++) {
169 		status = i3c_addr_slots_status(slots, addr);
170 		if (status == I3C_ADDR_SLOT_STATUS_FREE) {
171 			return addr;
172 		}
173 	}
174 
175 	return 0;
176 }
177 
i3c_dev_list_find(const struct i3c_dev_list * dev_list,const struct i3c_device_id * id)178 struct i3c_device_desc *i3c_dev_list_find(const struct i3c_dev_list *dev_list,
179 					  const struct i3c_device_id *id)
180 {
181 	int i;
182 	struct i3c_device_desc *ret = NULL;
183 
184 	__ASSERT_NO_MSG(dev_list != NULL);
185 
186 	/* this only searches known I3C PIDs */
187 	for (i = 0; i < dev_list->num_i3c; i++) {
188 		struct i3c_device_desc *desc = &dev_list->i3c[i];
189 
190 		if (desc->pid == id->pid) {
191 			ret = desc;
192 			break;
193 		}
194 	}
195 
196 	return ret;
197 }
198 
i3c_dev_list_i3c_addr_find(struct i3c_dev_attached_list * dev_list,uint8_t addr)199 struct i3c_device_desc *i3c_dev_list_i3c_addr_find(struct i3c_dev_attached_list *dev_list,
200 						   uint8_t addr)
201 {
202 	sys_snode_t *node;
203 	struct i3c_device_desc *ret = NULL;
204 
205 	__ASSERT_NO_MSG(dev_list != NULL);
206 
207 	SYS_SLIST_FOR_EACH_NODE(&dev_list->devices.i3c, node) {
208 		struct i3c_device_desc *desc = (void *)node;
209 
210 		if (desc->dynamic_addr == addr) {
211 			ret = desc;
212 			break;
213 		}
214 	}
215 
216 	return ret;
217 }
218 
i3c_dev_list_i2c_addr_find(struct i3c_dev_attached_list * dev_list,uint16_t addr)219 struct i3c_i2c_device_desc *i3c_dev_list_i2c_addr_find(struct i3c_dev_attached_list *dev_list,
220 							   uint16_t addr)
221 {
222 	sys_snode_t *node;
223 	struct i3c_i2c_device_desc *ret = NULL;
224 
225 	__ASSERT_NO_MSG(dev_list != NULL);
226 
227 	SYS_SLIST_FOR_EACH_NODE(&dev_list->devices.i2c, node) {
228 		struct i3c_i2c_device_desc *desc = (void *)node;
229 
230 		if (desc->addr == addr) {
231 			ret = desc;
232 			break;
233 		}
234 	}
235 
236 	return ret;
237 }
238 
i3c_determine_default_addr(struct i3c_device_desc * target,uint8_t * addr)239 int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr)
240 {
241 	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
242 
243 	/* If dynamic addr is set, then it assumed that it was assigned by a primary controller */
244 	if (target->dynamic_addr == 0) {
245 		/* It is assumed that SETDASA or ENTDAA will be run after this */
246 		if (target->init_dynamic_addr != 0U) {
247 			/* initial dynamic address is requested */
248 			if (target->static_addr == 0) {
249 				/* SA is set to 0, so DA will be set with ENTDAA */
250 				if (i3c_addr_slots_is_free(&data->attached_dev.addr_slots,
251 							   target->init_dynamic_addr)) {
252 					/* Set DA during ENTDAA */
253 					*addr = target->init_dynamic_addr;
254 				} else {
255 					/* address is not free, get the next one */
256 					*addr = i3c_addr_slots_next_free_find(
257 						&data->attached_dev.addr_slots, 0);
258 				}
259 			} else {
260 				/* Use the init dynamic address as it's DA, but the RR will need to
261 				 * be first set with it's SA to run SETDASA, the RR address will
262 				 * need be updated after SETDASA with the request dynamic address
263 				 */
264 				if (i3c_addr_slots_is_free(&data->attached_dev.addr_slots,
265 							   target->static_addr)) {
266 					*addr = target->static_addr;
267 				} else {
268 					/* static address has already been taken */
269 					return -EINVAL;
270 				}
271 			}
272 		} else {
273 			/* no init dynamic address is requested */
274 			if (target->static_addr != 0) {
275 				if (i3c_addr_slots_is_free(&data->attached_dev.addr_slots,
276 							   target->static_addr)) {
277 					/* static exists, set DA with same SA during SETDASA*/
278 					*addr = target->static_addr;
279 				} else {
280 					/* static address has already been taken */
281 					return -EINVAL;
282 				}
283 			} else {
284 				/* pick a DA to use */
285 				*addr = i3c_addr_slots_next_free_find(
286 					&data->attached_dev.addr_slots, 0);
287 			}
288 		}
289 	} else {
290 		*addr = target->dynamic_addr;
291 	}
292 
293 	return 0;
294 }
295 
i3c_attach_i3c_device(struct i3c_device_desc * target)296 int i3c_attach_i3c_device(struct i3c_device_desc *target)
297 {
298 	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
299 	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
300 	sys_snode_t *node;
301 	uint8_t addr = 0;
302 	int status = 0;
303 
304 	/* check to see if the device has already been attached */
305 	if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) {
306 		SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) {
307 			if (node == &target->node) {
308 				return -EINVAL;
309 			}
310 		}
311 	}
312 
313 	status = i3c_determine_default_addr(target, &addr);
314 	if (status != 0) {
315 		return status;
316 	}
317 
318 	sys_slist_append(&data->attached_dev.devices.i3c, &target->node);
319 
320 	if (api->attach_i3c_device != NULL) {
321 		status = api->attach_i3c_device(target->bus, target, addr);
322 	}
323 
324 	i3c_addr_slots_mark_i3c(&data->attached_dev.addr_slots, addr);
325 
326 	return status;
327 }
328 
i3c_reattach_i3c_device(struct i3c_device_desc * target,uint8_t old_dyn_addr)329 int i3c_reattach_i3c_device(struct i3c_device_desc *target, uint8_t old_dyn_addr)
330 {
331 	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
332 	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
333 	int status = 0;
334 
335 	if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, target->dynamic_addr)) {
336 		return -EINVAL;
337 	}
338 
339 	if (api->reattach_i3c_device != NULL) {
340 		status = api->reattach_i3c_device(target->bus, target, old_dyn_addr);
341 	}
342 
343 	if (old_dyn_addr) {
344 		/* mark the old address as free */
345 		i3c_addr_slots_mark_free(&data->attached_dev.addr_slots, old_dyn_addr);
346 	}
347 
348 	i3c_addr_slots_mark_i3c(&data->attached_dev.addr_slots, target->dynamic_addr);
349 
350 	return status;
351 }
352 
i3c_detach_i3c_device(struct i3c_device_desc * target)353 int i3c_detach_i3c_device(struct i3c_device_desc *target)
354 {
355 	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
356 	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
357 	int status = 0;
358 
359 	if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) {
360 		if (!sys_slist_find_and_remove(&data->attached_dev.devices.i3c, &target->node)) {
361 			return -EINVAL;
362 		}
363 	} else {
364 		return -EINVAL;
365 	}
366 
367 	if (api->detach_i3c_device != NULL) {
368 		status = api->detach_i3c_device(target->bus, target);
369 	}
370 
371 	i3c_addr_slots_mark_free(&data->attached_dev.addr_slots,
372 				 target->dynamic_addr ? target->dynamic_addr : target->static_addr);
373 
374 	return status;
375 }
376 
i3c_attach_i2c_device(struct i3c_i2c_device_desc * target)377 int i3c_attach_i2c_device(struct i3c_i2c_device_desc *target)
378 {
379 	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
380 	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
381 	sys_snode_t *node;
382 	int status = 0;
383 
384 	/* check to see if the device has already been attached */
385 	if (!sys_slist_is_empty(&data->attached_dev.devices.i2c)) {
386 		SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i2c, node) {
387 			if (node == &target->node) {
388 				return -EINVAL;
389 			}
390 		}
391 	}
392 
393 	if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, target->addr)) {
394 		return -EINVAL;
395 	}
396 
397 	sys_slist_append(&data->attached_dev.devices.i2c, &target->node);
398 
399 	if (api->attach_i2c_device != NULL) {
400 		status = api->attach_i2c_device(target->bus, target);
401 	}
402 
403 	i3c_addr_slots_mark_i2c(&data->attached_dev.addr_slots, target->addr);
404 
405 	return status;
406 }
407 
i3c_detach_i2c_device(struct i3c_i2c_device_desc * target)408 int i3c_detach_i2c_device(struct i3c_i2c_device_desc *target)
409 {
410 	struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
411 	const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
412 	int status = 0;
413 
414 	if (!sys_slist_is_empty(&data->attached_dev.devices.i2c)) {
415 		if (!sys_slist_find_and_remove(&data->attached_dev.devices.i2c, &target->node)) {
416 			return -EINVAL;
417 		}
418 	} else {
419 		return -EINVAL;
420 	}
421 
422 	if (api->detach_i2c_device != NULL) {
423 		status = api->detach_i2c_device(target->bus, target);
424 	}
425 
426 	i3c_addr_slots_mark_free(&data->attached_dev.addr_slots, target->addr);
427 
428 	return status;
429 }
430 
i3c_dev_list_daa_addr_helper(struct i3c_addr_slots * addr_slots,const struct i3c_dev_list * dev_list,uint64_t pid,bool must_match,bool assigned_okay,struct i3c_device_desc ** target,uint8_t * addr)431 int i3c_dev_list_daa_addr_helper(struct i3c_addr_slots *addr_slots,
432 				 const struct i3c_dev_list *dev_list,
433 				 uint64_t pid, bool must_match,
434 				 bool assigned_okay,
435 				 struct i3c_device_desc **target,
436 				 uint8_t *addr)
437 {
438 	struct i3c_device_desc *desc;
439 	const uint16_t vendor_id = (uint16_t)(pid >> 32);
440 	const uint32_t part_no = (uint32_t)(pid & 0xFFFFFFFFU);
441 	uint8_t dyn_addr = 0;
442 	int ret = 0;
443 	const struct i3c_device_id i3c_id = I3C_DEVICE_ID(pid);
444 
445 	desc = i3c_dev_list_find(dev_list, &i3c_id);
446 	if (must_match && (desc == NULL)) {
447 		/*
448 		 * No device descriptor matching incoming PID and
449 		 * that we want an exact match.
450 		 */
451 		ret = -ENODEV;
452 
453 		LOG_DBG("PID 0x%04x%08x is not in registered device list",
454 			vendor_id, part_no);
455 
456 		goto out;
457 	}
458 
459 	if (desc != NULL && desc->dynamic_addr != 0U) {
460 		if (assigned_okay) {
461 			/* Return the already assigned address if desired so. */
462 			dyn_addr = desc->dynamic_addr;
463 			goto out;
464 		} else {
465 			/*
466 			 * Bail If target already has an assigned address.
467 			 * This is probably due to having the same PIDs for multiple targets
468 			 * in the device tree.
469 			 */
470 			LOG_ERR("PID 0x%04x%08x already has "
471 				"dynamic address (0x%02x) assigned",
472 				vendor_id, part_no, desc->dynamic_addr);
473 			ret = -EINVAL;
474 			goto err;
475 		}
476 	}
477 
478 	/*
479 	 * Use the desired dynamic address as the new dynamic address
480 	 * if the slot is free.
481 	 */
482 	if (desc != NULL && desc->init_dynamic_addr != 0U) {
483 		if (i3c_addr_slots_is_free(addr_slots, desc->init_dynamic_addr)) {
484 			dyn_addr = desc->init_dynamic_addr;
485 			goto out;
486 		}
487 	}
488 
489 	/*
490 	 * Find the next available address.
491 	 */
492 	dyn_addr = i3c_addr_slots_next_free_find(addr_slots, 0);
493 
494 	if (dyn_addr == 0U) {
495 		/* No free addresses available */
496 		LOG_DBG("No more free addresses available.");
497 		ret = -ENOSPC;
498 	}
499 
500 out:
501 	*addr = dyn_addr;
502 	*target = desc;
503 
504 err:
505 	return ret;
506 }
507 
i3c_device_basic_info_get(struct i3c_device_desc * target)508 int i3c_device_basic_info_get(struct i3c_device_desc *target)
509 {
510 	int ret;
511 	uint8_t tmp_bcr;
512 
513 	struct i3c_ccc_getbcr bcr = {0};
514 	struct i3c_ccc_getdcr dcr = {0};
515 	struct i3c_ccc_mrl mrl = {0};
516 	struct i3c_ccc_mwl mwl = {0};
517 	union i3c_ccc_getcaps caps = {0};
518 
519 	/*
520 	 * Since some CCC functions requires BCR to function
521 	 * correctly, we save the BCR here and update the BCR
522 	 * in the descriptor. If any following operations fails,
523 	 * we can restore the BCR.
524 	 */
525 	tmp_bcr = target->bcr;
526 
527 	/* GETBCR */
528 	ret = i3c_ccc_do_getbcr(target, &bcr);
529 	if (ret != 0) {
530 		goto out;
531 	}
532 
533 	target->bcr = bcr.bcr;
534 
535 	/* GETDCR */
536 	ret = i3c_ccc_do_getdcr(target, &dcr);
537 	if (ret != 0) {
538 		goto out;
539 	}
540 
541 	/* GETMRL */
542 	if (i3c_ccc_do_getmrl(target, &mrl) != 0) {
543 		/* GETMRL may be optionally supported if no settable limit */
544 		LOG_DBG("No settable limit for GETMRL");
545 	}
546 
547 	/* GETMWL */
548 	if (i3c_ccc_do_getmwl(target, &mwl) != 0) {
549 		/* GETMWL may be optionally supported if no settable limit */
550 		LOG_DBG("No settable limit for GETMWL");
551 	}
552 
553 	/* GETCAPS */
554 	ret = i3c_ccc_do_getcaps_fmt1(target, &caps);
555 	/*
556 	 * GETCAPS (GETHDRCAP) is required to be supported for I3C v1.0 targets that support HDR
557 	 * modes and required if the Target's I3C version is v1.1 or later, but which the version it
558 	 * supports it can't be known ahead of time. So if the BCR bit for Advanced capabilities is
559 	 * set, then it is expected for GETCAPS to always be supported. Otherwise, then it's a I3C
560 	 * v1.0 device without any HDR modes so do not treat as an error if no valid response.
561 	 */
562 	if (ret == 0) {
563 		memcpy(&target->getcaps, &caps, sizeof(target->getcaps));
564 	} else if ((ret != 0) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) {
565 		goto out;
566 	} else {
567 		ret = 0;
568 	}
569 
570 	target->dcr = dcr.dcr;
571 	target->data_length.mrl = mrl.len;
572 	target->data_length.mwl = mwl.len;
573 	target->data_length.max_ibi = mrl.ibi_len;
574 
575 out:
576 	if (ret != 0) {
577 		/* Restore BCR is any CCC fails. */
578 		target->bcr = tmp_bcr;
579 	}
580 	return ret;
581 }
582 
583 /**
584  * @brief Do SETDASA to set static address as dynamic address.
585  *
586  * @param dev Pointer to the device driver instance.
587  * @param[out] True if DAA is still needed. False if all registered
588  *             devices have static addresses.
589  *
590  * @retval 0 if successful.
591  */
i3c_bus_setdasa(const struct device * dev,const struct i3c_dev_list * dev_list,bool * need_daa)592 static int i3c_bus_setdasa(const struct device *dev,
593 			   const struct i3c_dev_list *dev_list,
594 			   bool *need_daa)
595 {
596 	int i, ret;
597 
598 	*need_daa = false;
599 
600 	/* Loop through the registered I3C devices */
601 	for (i = 0; i < dev_list->num_i3c; i++) {
602 		struct i3c_device_desc *desc = &dev_list->i3c[i];
603 
604 		/*
605 		 * A device without static address => need to do
606 		 * dynamic address assignment.
607 		 */
608 		if (desc->static_addr == 0U) {
609 			*need_daa = true;
610 			continue;
611 		}
612 
613 		LOG_DBG("SETDASA for 0x%x", desc->static_addr);
614 
615 		ret = i3c_ccc_do_setdasa(desc);
616 		if (ret == 0) {
617 			desc->dynamic_addr = (desc->init_dynamic_addr ? desc->init_dynamic_addr
618 								      : desc->static_addr);
619 			if (desc->dynamic_addr != desc->static_addr) {
620 				if (i3c_reattach_i3c_device(desc, desc->static_addr) != 0) {
621 					LOG_ERR("Failed to reattach %s (%d)", desc->dev->name, ret);
622 				}
623 			}
624 		} else {
625 			/* SETDASA failed, detach it from the controller */
626 			if (i3c_detach_i3c_device(desc) != 0) {
627 				LOG_ERR("Failed to detach %s (%d)", desc->dev->name, ret);
628 			}
629 			LOG_ERR("SETDASA error on address 0x%x (%d)",
630 				desc->static_addr, ret);
631 			continue;
632 		}
633 	}
634 
635 	return 0;
636 }
637 
i3c_bus_init(const struct device * dev,const struct i3c_dev_list * dev_list)638 int i3c_bus_init(const struct device *dev, const struct i3c_dev_list *dev_list)
639 {
640 	int i, ret = 0;
641 	bool need_daa = true;
642 	struct i3c_ccc_events i3c_events;
643 
644 #ifdef CONFIG_I3C_INIT_RSTACT
645 	/*
646 	 * Reset all connected targets. Also reset dynamic
647 	 * addresses for all devices as we have no idea what
648 	 * dynamic addresses the connected devices have
649 	 * (e.g. assigned during previous power cycle).
650 	 *
651 	 * Note that we ignore error for both RSTACT and RSTDAA
652 	 * as there may not be any connected devices responding
653 	 * to these CCCs.
654 	 */
655 	if (i3c_ccc_do_rstact_all(dev, I3C_CCC_RSTACT_RESET_WHOLE_TARGET) != 0) {
656 		/*
657 		 * Reset Whole Target support is not required so
658 		 * if there is any NACK, we want to at least reset
659 		 * the I3C peripheral of targets.
660 		 */
661 		LOG_DBG("Broadcast RSTACT (whole target) was NACK.");
662 
663 		if (i3c_ccc_do_rstact_all(dev, I3C_CCC_RSTACT_PERIPHERAL_ONLY) != 0) {
664 			LOG_DBG("Broadcast RSTACT (peripehral) was NACK.");
665 		}
666 	}
667 #endif
668 
669 	if (i3c_ccc_do_rstdaa_all(dev) != 0) {
670 		LOG_DBG("Broadcast RSTDAA was NACK.");
671 	}
672 
673 	/*
674 	 * Disable all events from targets to avoid them
675 	 * interfering with bus initialization,
676 	 * especially during DAA.
677 	 */
678 	i3c_events.events = I3C_CCC_EVT_ALL;
679 	ret = i3c_ccc_do_events_all_set(dev, false, &i3c_events);
680 	if (ret != 0) {
681 		LOG_DBG("Broadcast DISEC was NACK.");
682 	}
683 
684 	/*
685 	 * Set static addresses as dynamic addresses.
686 	 */
687 	ret = i3c_bus_setdasa(dev, dev_list, &need_daa);
688 	if (ret != 0) {
689 		goto err_out;
690 	}
691 
692 	/*
693 	 * Perform Dynamic Address Assignment if needed.
694 	 */
695 	if (need_daa) {
696 		ret = i3c_do_daa(dev);
697 		if (ret != 0) {
698 			/*
699 			 * Spec says to try once more
700 			 * if DAA fails the first time.
701 			 */
702 			ret = i3c_do_daa(dev);
703 			if (ret != 0) {
704 				/*
705 				 * Failure to finish dynamic address assignment
706 				 * is not the end of world... hopefully.
707 				 * Continue on so the devices already have
708 				 * addresses can still function.
709 				 */
710 				LOG_ERR("DAA was not successful.");
711 			}
712 		}
713 	}
714 
715 	/*
716 	 * Loop through the registered I3C devices to retrieve
717 	 * basic target information.
718 	 */
719 	for (i = 0; i < dev_list->num_i3c; i++) {
720 		struct i3c_device_desc *desc = &dev_list->i3c[i];
721 
722 		if (desc->dynamic_addr == 0U) {
723 			continue;
724 		}
725 
726 		ret = i3c_device_basic_info_get(desc);
727 		if (ret != 0) {
728 			LOG_ERR("Error getting basic device info for 0x%02x",
729 				desc->static_addr);
730 		} else {
731 			LOG_DBG("Target 0x%02x, BCR 0x%02x, DCR 0x%02x, MRL %d, MWL %d, IBI %d",
732 				desc->dynamic_addr, desc->bcr, desc->dcr,
733 				desc->data_length.mrl, desc->data_length.mwl,
734 				desc->data_length.max_ibi);
735 		}
736 	}
737 
738 	/*
739 	 * Only re-enable Hot-Join from targets.
740 	 * Target interrupts will be enabled when IBI is enabled.
741 	 * And transferring controller role is not supported so not need to
742 	 * enable the event.
743 	 */
744 	i3c_events.events = I3C_CCC_EVT_HJ;
745 	ret = i3c_ccc_do_events_all_set(dev, true, &i3c_events);
746 	if (ret != 0) {
747 		LOG_DBG("Broadcast ENEC was NACK.");
748 	}
749 
750 err_out:
751 	return ret;
752 }
753