Skip to content

Commit f2d549d

Browse files
XenuIsWatchingnashif
authored andcommitted
drivers: i3c: cdns: fixup attachment and addr assignment for daa
The ENTDAA does not have a way to assign DA that are with a PID. It will assign DAs that were in it's RRs in the order that they win arbitration. Assign only available addresses in to it's RRs before ENTDAA. Cleanup the attach api to no longer require a addr argument and remove the helper function `i3c_determine_default_addr`. This now looks at if it has a static address or if it already has a dynamic address (such as from DEFTGTS) and will register the address if either exist with precidence of dynamic addr over static addr. This also fixes up the look up for if a device already has a dynamic addr to find which pos of the RRs is it is in. Signed-off-by: Ryan McClelland <[email protected]>
1 parent 2c1eae2 commit f2d549d

File tree

3 files changed

+89
-130
lines changed

3 files changed

+89
-130
lines changed

drivers/i3c/i3c_cdns.c

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,7 @@ static int cdns_i3c_do_daa(const struct device *dev)
14991499
struct cdns_i3c_data *data = dev->data;
15001500
const struct cdns_i3c_config *config = dev->config;
15011501
struct i3c_config_controller *ctrl_config = &data->common.ctrl_config;
1502+
uint8_t last_addr = 0;
15021503

15031504
/* DAA should not be done by secondary controllers */
15041505
if (ctrl_config->is_secondary) {
@@ -1510,6 +1511,23 @@ static int cdns_i3c_do_daa(const struct device *dev)
15101511
/* ignore the controller register */
15111512
olddevs |= BIT(0);
15121513

1514+
/* Assign dynamic addressses to available RRs */
1515+
/* Loop through each clear bit */
1516+
for (uint8_t i = find_lsb_set(~olddevs); i <= data->max_devs; i++) {
1517+
uint8_t rr_idx = i - 1;
1518+
1519+
if (~olddevs & BIT(rr_idx)) {
1520+
/* Read RRx registers */
1521+
last_addr = i3c_addr_slots_next_free_find(
1522+
&data->common.attached_dev.addr_slots, last_addr + 1);
1523+
/* Write RRx registers */
1524+
sys_write32(prepare_rr0_dev_address(last_addr) | DEV_ID_RR0_IS_I3C,
1525+
config->base + DEV_ID_RR0(rr_idx));
1526+
sys_write32(0, config->base + DEV_ID_RR1(rr_idx));
1527+
sys_write32(0, config->base + DEV_ID_RR2(rr_idx));
1528+
}
1529+
}
1530+
15131531
/* the Cadence I3C IP will assign an address for it from the RR */
15141532
struct i3c_ccc_payload entdaa_ccc;
15151533

@@ -1915,7 +1933,10 @@ static int cdns_i3c_master_get_rr_slot(const struct device *dev, uint8_t dyn_add
19151933
{
19161934
struct cdns_i3c_data *data = dev->data;
19171935
const struct cdns_i3c_config *config = dev->config;
1936+
uint8_t rr_idx, i;
1937+
uint32_t rr, activedevs;
19181938

1939+
/* If it does not have a dynamic address, then assign it a free one */
19191940
if (dyn_addr == 0) {
19201941
if (!data->free_rr_slots) {
19211942
return -ENOSPC;
@@ -1924,62 +1945,70 @@ static int cdns_i3c_master_get_rr_slot(const struct device *dev, uint8_t dyn_add
19241945
return find_lsb_set(data->free_rr_slots) - 1;
19251946
}
19261947

1927-
uint32_t activedevs = sys_read32(config->base + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
1928-
1948+
/* Device already has a Dynamic Address, so assume it is already in the RRs */
1949+
activedevs = sys_read32(config->base + DEVS_CTRL) & DEVS_CTRL_DEVS_ACTIVE_MASK;
1950+
/* skip itself */
19291951
activedevs &= ~BIT(0);
19301952

19311953
/* loop through each set bit for new devices */
1932-
for (uint8_t i = find_lsb_set(activedevs); i <= find_msb_set(activedevs); i++) {
1933-
if (activedevs & BIT(i)) {
1934-
uint32_t rr = sys_read32(config->base + DEV_ID_RR0(i));
1935-
1936-
if (!(rr & DEV_ID_RR0_IS_I3C) || DEV_ID_RR0_GET_DEV_ADDR(rr) != dyn_addr) {
1937-
continue;
1954+
for (i = find_lsb_set(activedevs); i <= find_msb_set(activedevs); i++) {
1955+
rr_idx = i - 1;
1956+
if (activedevs & BIT(rr_idx)) {
1957+
rr = sys_read32(config->base + DEV_ID_RR0(rr_idx));
1958+
if ((rr & DEV_ID_RR0_IS_I3C) && DEV_ID_RR0_GET_DEV_ADDR(rr) == dyn_addr) {
1959+
return rr_idx;
19381960
}
1939-
return i;
19401961
}
19411962
}
19421963

19431964
return -EINVAL;
19441965
}
19451966

1946-
static int cdns_i3c_attach_device(const struct device *dev, struct i3c_device_desc *desc,
1947-
uint8_t addr)
1967+
static int cdns_i3c_attach_device(const struct device *dev, struct i3c_device_desc *desc)
19481968
{
1949-
const struct cdns_i3c_config *config = dev->config;
1950-
struct cdns_i3c_data *data = dev->data;
1951-
int slot = cdns_i3c_master_get_rr_slot(dev, desc->dynamic_addr);
1952-
1953-
if (slot < 0) {
1954-
LOG_ERR("%s: no space for i3c device: %s", dev->name, desc->dev->name);
1955-
return slot;
1956-
}
1969+
/*
1970+
* Mark Devices as active, devices that will be found and marked active during DAA,
1971+
* it will be given the exact DA programmed in it's RR, otherwise they get set as active
1972+
* here. If dynamic address is set, then it assumed that it was already initialized by the
1973+
* primary controller. When assigned through ENTDAA, the dynamic address, bcr, dcr, and pid
1974+
* are all set in the RR along with setting the device as active. If it has a static addr,
1975+
* then it is assumed that it will be programmed with SETDASA and will need to be marked
1976+
* as active before sending out SETDASA.
1977+
*/
1978+
if ((desc->static_addr != 0) || (desc->dynamic_addr != 0)) {
1979+
const struct cdns_i3c_config *config = dev->config;
1980+
struct cdns_i3c_data *data = dev->data;
19571981

1958-
k_mutex_lock(&data->bus_lock, K_FOREVER);
1982+
int slot = cdns_i3c_master_get_rr_slot(dev, desc->dynamic_addr ? desc->dynamic_addr
1983+
: desc->static_addr);
19591984

1960-
data->cdns_i3c_i2c_priv_data[slot].id = slot;
1961-
desc->controller_priv = &(data->cdns_i3c_i2c_priv_data[slot]);
1962-
data->free_rr_slots &= ~BIT(slot);
1963-
1964-
uint32_t dev_id_rr0 = DEV_ID_RR0_IS_I3C | prepare_rr0_dev_address(addr);
1965-
uint32_t dev_id_rr1 = DEV_ID_RR1_PID_MSB((desc->pid & 0xFFFFFFFF0000) >> 16);
1966-
uint32_t dev_id_rr2 = DEV_ID_RR2_PID_LSB(desc->pid & 0xFFFF);
1985+
if (slot < 0) {
1986+
LOG_ERR("%s: no space for i3c device: %s", dev->name, desc->dev->name);
1987+
return slot;
1988+
}
19671989

1968-
sys_write32(dev_id_rr0, config->base + DEV_ID_RR0(slot));
1969-
sys_write32(dev_id_rr1, config->base + DEV_ID_RR1(slot));
1970-
sys_write32(dev_id_rr2, config->base + DEV_ID_RR2(slot));
1990+
k_mutex_lock(&data->bus_lock, K_FOREVER);
19711991

1972-
/** Mark Devices as active, devices that will be found and marked active during DAA,
1973-
* it will be given the exact DA programmed in it's RR if the PID matches and marked
1974-
* as active duing ENTDAA, otherwise they get set as active here. If dynamic address
1975-
* is set, then it assumed that it was already initialized by the primary controller.
1976-
*/
1977-
if ((desc->static_addr != 0) || (desc->dynamic_addr != 0)) {
19781992
sys_write32(sys_read32(config->base + DEVS_CTRL) | DEVS_CTRL_DEV_ACTIVE(slot),
19791993
config->base + DEVS_CTRL);
1980-
}
19811994

1982-
k_mutex_unlock(&data->bus_lock);
1995+
data->cdns_i3c_i2c_priv_data[slot].id = slot;
1996+
desc->controller_priv = &(data->cdns_i3c_i2c_priv_data[slot]);
1997+
data->free_rr_slots &= ~BIT(slot);
1998+
1999+
uint32_t dev_id_rr0 =
2000+
DEV_ID_RR0_IS_I3C |
2001+
prepare_rr0_dev_address(desc->dynamic_addr ? desc->dynamic_addr
2002+
: desc->static_addr);
2003+
uint32_t dev_id_rr1 = DEV_ID_RR1_PID_MSB((desc->pid & 0xFFFFFFFF0000) >> 16);
2004+
uint32_t dev_id_rr2 = DEV_ID_RR2_PID_LSB(desc->pid & 0xFFFF);
2005+
2006+
sys_write32(dev_id_rr0, config->base + DEV_ID_RR0(slot));
2007+
sys_write32(dev_id_rr1, config->base + DEV_ID_RR1(slot));
2008+
sys_write32(dev_id_rr2, config->base + DEV_ID_RR2(slot));
2009+
2010+
k_mutex_unlock(&data->bus_lock);
2011+
}
19832012

19842013
return 0;
19852014
}

drivers/i3c/i3c_common.c

Lines changed: 21 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -234,92 +234,41 @@ struct i3c_i2c_device_desc *i3c_dev_list_i2c_addr_find(const struct device *dev,
234234
return ret;
235235
}
236236

237-
int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr)
238-
{
239-
struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
240-
241-
/* If dynamic addr is set, then it assumed that it was assigned by a primary controller */
242-
if (target->dynamic_addr == 0) {
243-
/* It is assumed that SETDASA or ENTDAA will be run after this */
244-
if (target->init_dynamic_addr != 0U) {
245-
/* initial dynamic address is requested */
246-
if (target->static_addr == 0) {
247-
/* SA is set to 0, so DA will be set with ENTDAA */
248-
if (i3c_addr_slots_is_free(&data->attached_dev.addr_slots,
249-
target->init_dynamic_addr)) {
250-
/* Set DA during ENTDAA */
251-
*addr = target->init_dynamic_addr;
252-
} else {
253-
/* address is not free, get the next one */
254-
*addr = i3c_addr_slots_next_free_find(
255-
&data->attached_dev.addr_slots, 0);
256-
}
257-
} else {
258-
/* Use the init dynamic address as it's DA, but the RR will need to
259-
* be first set with it's SA to run SETDASA, the RR address will
260-
* need be updated after SETDASA with the request dynamic address
261-
*/
262-
if (i3c_addr_slots_is_free(&data->attached_dev.addr_slots,
263-
target->static_addr)) {
264-
*addr = target->static_addr;
265-
} else {
266-
/* static address has already been taken */
267-
return -EINVAL;
268-
}
269-
}
270-
} else {
271-
/* no init dynamic address is requested */
272-
if (target->static_addr != 0) {
273-
if (i3c_addr_slots_is_free(&data->attached_dev.addr_slots,
274-
target->static_addr)) {
275-
/* static exists, set DA with same SA during SETDASA*/
276-
*addr = target->static_addr;
277-
} else {
278-
/* static address has already been taken */
279-
return -EINVAL;
280-
}
281-
} else {
282-
/* pick a DA to use */
283-
*addr = i3c_addr_slots_next_free_find(
284-
&data->attached_dev.addr_slots, 0);
285-
}
286-
}
287-
} else {
288-
*addr = target->dynamic_addr;
289-
}
290-
291-
return 0;
292-
}
293-
294237
int i3c_attach_i3c_device(struct i3c_device_desc *target)
295238
{
296239
struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
297240
const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
298-
sys_snode_t *node;
299241
uint8_t addr = 0;
300242
int status = 0;
243+
struct i3c_device_desc *i3c_desc;
301244

302245
/* check to see if the device has already been attached */
303-
if (!sys_slist_is_empty(&data->attached_dev.devices.i3c)) {
304-
SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i3c, node) {
305-
if (node == &target->node) {
306-
return -EINVAL;
307-
}
246+
I3C_BUS_FOR_EACH_I3CDEV(target->bus, i3c_desc) {
247+
if (i3c_desc == target) {
248+
return -EINVAL;
308249
}
309250
}
310251

311-
status = i3c_determine_default_addr(target, &addr);
312-
if (status != 0) {
313-
return status;
252+
addr = target->dynamic_addr ? target->dynamic_addr : target->static_addr;
253+
254+
/*
255+
* If it has a dynamic addr already assigned or a static address, check that it is free
256+
*/
257+
if (addr) {
258+
if (!i3c_addr_slots_is_free(&data->attached_dev.addr_slots, addr)) {
259+
return -EINVAL;
260+
}
314261
}
315262

316263
sys_slist_append(&data->attached_dev.devices.i3c, &target->node);
317264

318265
if (api->attach_i3c_device != NULL) {
319-
status = api->attach_i3c_device(target->bus, target, addr);
266+
status = api->attach_i3c_device(target->bus, target);
320267
}
321268

322-
i3c_addr_slots_mark_i3c(&data->attached_dev.addr_slots, addr);
269+
if (addr) {
270+
i3c_addr_slots_mark_i3c(&data->attached_dev.addr_slots, addr);
271+
}
323272

324273
return status;
325274
}
@@ -376,15 +325,13 @@ int i3c_attach_i2c_device(struct i3c_i2c_device_desc *target)
376325
{
377326
struct i3c_driver_data *data = (struct i3c_driver_data *)target->bus->data;
378327
const struct i3c_driver_api *api = (const struct i3c_driver_api *)target->bus->api;
379-
sys_snode_t *node;
380328
int status = 0;
329+
struct i3c_i2c_device_desc *i3c_i2c_desc;
381330

382331
/* check to see if the device has already been attached */
383-
if (!sys_slist_is_empty(&data->attached_dev.devices.i2c)) {
384-
SYS_SLIST_FOR_EACH_NODE(&data->attached_dev.devices.i2c, node) {
385-
if (node == &target->node) {
386-
return -EINVAL;
387-
}
332+
I3C_BUS_FOR_EACH_I2CDEV(target->bus, i3c_i2c_desc) {
333+
if (i3c_i2c_desc == target) {
334+
return -EINVAL;
388335
}
389336
}
390337

include/zephyr/drivers/i3c.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -639,13 +639,11 @@ __subsystem struct i3c_driver_api {
639639
*
640640
* @param dev Pointer to controller device driver instance.
641641
* @param target Pointer to target device descriptor.
642-
* @param addr Address to attach with
643642
*
644643
* @return See i3c_attach_i3c_device()
645644
*/
646645
int (*attach_i3c_device)(const struct device *dev,
647-
struct i3c_device_desc *target,
648-
uint8_t addr);
646+
struct i3c_device_desc *target);
649647

650648
/**
651649
* I3C Address Update
@@ -1273,21 +1271,6 @@ struct i3c_device_desc *i3c_dev_list_i3c_addr_find(const struct device *dev,
12731271
struct i3c_i2c_device_desc *i3c_dev_list_i2c_addr_find(const struct device *dev,
12741272
uint16_t addr);
12751273

1276-
/**
1277-
* @brief Helper function to find the default address an i3c device is attached with
1278-
*
1279-
* This is a helper function to find the default address the
1280-
* device will be loaded with. This could be either it's static
1281-
* address, a requested dynamic address, or just a dynamic address
1282-
* that is available
1283-
* @param[in] target The pointer of the device descriptor
1284-
* @param[out] addr Address to be assigned to target device.
1285-
*
1286-
* @retval 0 if successful.
1287-
* @retval -EINVAL if the expected default address is already in use
1288-
*/
1289-
int i3c_determine_default_addr(struct i3c_device_desc *target, uint8_t *addr);
1290-
12911274
/**
12921275
* @brief Helper function to find a usable address during ENTDAA.
12931276
*

0 commit comments

Comments
 (0)