Skip to content

Commit 2f552fa

Browse files
nxpfranklialexandrebelloni
authored andcommitted
i3c: master: Extend address status bit to 4 and add I3C_ADDR_SLOT_EXT_DESIRED
Extend the address status bit to 4 and introduce the I3C_ADDR_SLOT_EXT_DESIRED macro to indicate that a device prefers a specific address. This is generally set by the 'assigned-address' in the device tree source (dts) file. ┌────┬─────────────┬───┬─────────┬───┐ │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐ └────┴─────────────┴───┴─────────┴───┘ │ ┌─────────────────────────────────────────┘ │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐ └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│ └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘ Some master controllers (such as HCI) need to prepare the entire above transaction before sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated before knowing the target device's UID information. However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise, if the "init_dyn_addr" is already in use by another I3C device, the target device will not be able to switch to its desired address. If the previous step fails, fallback returning one of the remaining unassigned address, regardless of its state in the desired list. Reviewed-by: Miquel Raynal <[email protected]> Signed-off-by: Frank Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 16aed0a commit 2f552fa

File tree

2 files changed

+59
-13
lines changed

2 files changed

+59
-13
lines changed

drivers/i3c/master.c

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ const struct bus_type i3c_bus_type = {
345345
EXPORT_SYMBOL_GPL(i3c_bus_type);
346346

347347
static enum i3c_addr_slot_status
348-
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
348+
i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask)
349349
{
350350
unsigned long status;
351351
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
@@ -356,11 +356,17 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
356356
status = bus->addrslots[bitpos / BITS_PER_LONG];
357357
status >>= bitpos % BITS_PER_LONG;
358358

359-
return status & I3C_ADDR_SLOT_STATUS_MASK;
359+
return status & mask;
360360
}
361361

362-
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
363-
enum i3c_addr_slot_status status)
362+
static enum i3c_addr_slot_status
363+
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
364+
{
365+
return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK);
366+
}
367+
368+
static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr,
369+
enum i3c_addr_slot_status status, u32 mask)
364370
{
365371
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
366372
unsigned long *ptr;
@@ -369,9 +375,14 @@ static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
369375
return;
370376

371377
ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
372-
*ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK <<
373-
(bitpos % BITS_PER_LONG));
374-
*ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG);
378+
*ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG));
379+
*ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG);
380+
}
381+
382+
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
383+
enum i3c_addr_slot_status status)
384+
{
385+
i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK);
375386
}
376387

377388
static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
@@ -383,13 +394,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
383394
return status == I3C_ADDR_SLOT_FREE;
384395
}
385396

397+
/*
398+
* ┌────┬─────────────┬───┬─────────┬───┐
399+
* │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐
400+
* └────┴─────────────┴───┴─────────┴───┘ │
401+
* ┌─────────────────────────────────────────┘
402+
* │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐
403+
* └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│
404+
* └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘
405+
* Some master controllers (such as HCI) need to prepare the entire above transaction before
406+
* sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated
407+
* before knowing the target device's UID information.
408+
*
409+
* However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is
410+
* typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI
411+
* priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is
412+
* not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with
413+
* the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise,
414+
* if the "init_dyn_addr" is already in use by another I3C device, the target device will not be
415+
* able to switch to its desired address.
416+
*
417+
* If the previous step fails, fallback returning one of the remaining unassigned address,
418+
* regardless of its state in the desired list.
419+
*/
386420
static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr)
387421
{
388422
enum i3c_addr_slot_status status;
389423
u8 addr;
390424

391425
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
392-
status = i3c_bus_get_addr_slot_status(bus, addr);
426+
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
427+
I3C_ADDR_SLOT_EXT_STATUS_MASK);
428+
if (status == I3C_ADDR_SLOT_FREE)
429+
return addr;
430+
}
431+
432+
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
433+
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
434+
I3C_ADDR_SLOT_STATUS_MASK);
393435
if (status == I3C_ADDR_SLOT_FREE)
394436
return addr;
395437
}
@@ -1918,9 +1960,10 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
19181960
goto err_rstdaa;
19191961
}
19201962

1921-
i3c_bus_set_addr_slot_status(&master->bus,
1922-
i3cboardinfo->init_dyn_addr,
1923-
I3C_ADDR_SLOT_I3C_DEV);
1963+
i3c_bus_set_addr_slot_status_mask(&master->bus,
1964+
i3cboardinfo->init_dyn_addr,
1965+
I3C_ADDR_SLOT_I3C_DEV | I3C_ADDR_SLOT_EXT_DESIRED,
1966+
I3C_ADDR_SLOT_EXT_STATUS_MASK);
19241967

19251968
/*
19261969
* Only try to create/attach devices that have a static

include/linux/i3c/master.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ enum i3c_open_drain_speed {
298298
* @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device
299299
* @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device
300300
* @I3C_ADDR_SLOT_STATUS_MASK: address slot mask
301-
*
301+
* @I3C_ADDR_SLOT_EXT_DESIRED: the bitmask represents addresses that are preferred by some devices,
302+
* such as the "assigned-address" property in a device tree source.
302303
* On an I3C bus, addresses are assigned dynamically, and we need to know which
303304
* addresses are free to use and which ones are already assigned.
304305
*
@@ -311,9 +312,11 @@ enum i3c_addr_slot_status {
311312
I3C_ADDR_SLOT_I2C_DEV,
312313
I3C_ADDR_SLOT_I3C_DEV,
313314
I3C_ADDR_SLOT_STATUS_MASK = 3,
315+
I3C_ADDR_SLOT_EXT_STATUS_MASK = 7,
316+
I3C_ADDR_SLOT_EXT_DESIRED = BIT(2),
314317
};
315318

316-
#define I3C_ADDR_SLOT_STATUS_BITS 2
319+
#define I3C_ADDR_SLOT_STATUS_BITS 4
317320

318321
/**
319322
* struct i3c_bus - I3C bus object

0 commit comments

Comments
 (0)