* [PATCH v3 0/3] i3c: master: amd: Add IBI and hot-join support
@ 2026-09-08 9:42 Shubham Patil
2026-09-08 9:42 ` [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties Shubham Patil
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Shubham Patil @ 2026-09-08 9:42 UTC (permalink / raw)
To: alexandre.belloni, Frank.Li, robh, krzk+dt, conor+dt
Cc: linux-i3c, devicetree, linux-kernel, git, Shubham Patil
This series adds In-Band Interrupt (IBI) and Hot-Join support to the AMD
AXI I3C master controller driver.
An In-Band Interrupt (IBI) replaces the dedicated interrupt pin an I2C
slave would otherwise need. When the bus is idle, a target wanting
attention pulls SDA low to generate a START, then drives its own dynamic
address with RnW=1 during the arbitrated address header. The controller
either ACKs the request, accepting the interrupt and optionally reading a
Mandatory Data Byte and payload, or NACKs it. The interrupt therefore
travels in band on SDA/SCL, saving a wire per device.
Hot-Join (HJ) lets a target that was not present at boot join a running
bus, after being powered up later or physically attached. Having no
dynamic address yet, it arbitrates using the reserved Hot-Join address;
the controller ACKs that and runs dynamic address assignment to enumerate
it. The same hardware arbitrates and ACKs it as an IBI.
This series adds optional In-Band Interrupt (IBI) and Hot-Join support
to the Xilinx AXI I3C master driver. The controller is soft IP
synthesized into FPGA fabric, not fixed SoC hardware. IBI and Hot-Join
are Vivado synthesis-time options, so two bitstreams — or two instances
in the same design — can share the same IP version and compatible
string yet differ in which features are enabled. A single device may
contain multiple instances in mixed configurations. The compatible
string identifies the IP and its version, but not the capabilities of a
particular instance.
Patch 1 adds two boolean properties, in-band-interrupt-capable and
hot-join-capable, in the common i3c.yaml schema. Hot-Join requests are
ACKed by the IBI machinery, so hot-join-capable depends on
in-band-interrupt-capable. The AMD binding still requires interrupts when
IBI is present. The driver assembles its ops at probe from these flags.
Patch 2 adds IBI support. The IBI ACK enable and its interrupt mask are
controller-wide rather than per-target, so they are armed on the first
target to enable IBIs and disarmed on the last to disable them, with
per-target control left on the bus via ENEC/DISEC. IBIs also share the
response and read FIFOs with normal transfers and are distinguished only
by the reserved TID 0x0F, so the controller stops ACKing IBIs for the
duration of a transfer and a target retries instead. One ACKed just
before that takes effect is found by TID while the transfer waits for
its own response, and is delivered through the normal IBI path.
Patch 3 adds Hot-Join. ENTDAA needs bus traffic and can sleep, so it
cannot run in the hard IRQ handler; the Hot-Join event is handed to the
i3c core with i3c_master_queue_hotjoin(), which runs the re-enumeration
from the core workqueue.
Changes in v3:
- Patch 1: Move in-band-interrupt-capable and hot-join-capable into
i3c.yaml and drop the xlnx, prefix. Keep the HJ-depends-on-IBI and
IBI-requires-interrupts constraints in the AMD binding.
- Patch 2: In xi3c_xfer_resp_available(), read IBI_TARGET_ADDR before
popping RESP_STATUS_FIFO so a raced IBI is not paired with the next
address. Call i3c_dev_set_master_data() before publishing the IBI.
- Patch 3: Probe the generic hot-join-capable property.
Changes in v2:
- Patch 1: Renamed the properties to "xlnx,in-band-interrupt-capable"
and "xlnx,hot-join-capable" and expanded their descriptions; expressed
the interrupt requirement with dependencies: instead of an
allOf/if-then clause.
- Patch 2: Do not lose an IBI raced with a transfer - the IBI ACK is now
held off for the duration of a transfer so the target retries, and one
accepted just before that is delivered through the normal IBI path
instead of being drained, which could also consume the transfer's read
data. disable_ibi() returns early on DISEC failure instead of
disarming and desyncing ibi.enabled_count from the core. Added
synchronize_irq() before disable_ibi() returns and before free_ibi()
frees the pool. Reworded commit message accordingly.
- Patch 3: Use the core's i3c_master_queue_hotjoin() instead of a
private work item, and only queue when the design is hot-join capable;
the core owns the work and cancels it on unregister. Reworded commit
message accordingly.
v1:
https://lore.kernel.org/all/20260814115155.3974988-1-
shubhamsanjay.patil@amd.com/
v2:
https://lore.kernel.org/all/20260824044835.2924141-1-
shubhamsanjay.patil@amd.com/
Shubham Patil (3):
dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties
i3c: master: amd: Add support for in-band interrupts
i3c: master: amd: Add hot-join support
.../devicetree/bindings/i3c/i3c.yaml | 15 +
.../bindings/i3c/xlnx,axi-i3c-1.0.yaml | 6 +
drivers/i3c/master/amd-i3c-master.c | 656 +++++++++++++++++-
3 files changed, 657 insertions(+), 20 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties
2026-09-08 9:42 [PATCH v3 0/3] i3c: master: amd: Add IBI and hot-join support Shubham Patil
@ 2026-09-08 9:42 ` Shubham Patil
2026-09-08 17:54 ` Conor Dooley
2026-09-08 9:42 ` [PATCH v3 2/3] i3c: master: amd: Add support for in-band interrupts Shubham Patil
2026-09-08 9:42 ` [PATCH v3 3/3] i3c: master: amd: Add hot-join support Shubham Patil
2 siblings, 1 reply; 8+ messages in thread
From: Shubham Patil @ 2026-09-08 9:42 UTC (permalink / raw)
To: alexandre.belloni, Frank.Li, robh, krzk+dt, conor+dt
Cc: linux-i3c, devicetree, linux-kernel, git, Shubham Patil
In-Band Interrupt and Hot-Join are synthesis-time options of the AXI I3C
IP. Describe them with two boolean properties.
A Hot-Join request is acknowledged by the IBI machinery, so a hot-join
capable design is always IBI capable as well. Both events are reported
through the controller interrupt, which is therefore required whenever
the capability is present.
Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
---
Changes in V3:
- Move in-band-interrupt-capable and hot-join-capable into the common
i3c.yaml schema and drop the xlnx, prefix.
- Keep dependencies in the AMD binding.
- Update the commit description accordingly.
- Conor Dooley acked v2 with the xlnx,-prefixed properties in the AMD
binding [1].
That Acked-by is not carried here: the names lost the vendor prefix
and the definitions moved to i3c.yaml after Frank Li's comment.
[1]:https://lore.kernel.org/all/20260824-tightwad-impose-495476599087@spud/
Changes in V2:
- Rename the properties to "xlnx,in-band-interrupt-capable" and
"xlnx,hot-join-capable", and expand their descriptions.
- Express the interrupt requirement with dependencies: instead of an
allOf/if-then clause.
---
Documentation/devicetree/bindings/i3c/i3c.yaml | 15 +++++++++++++++
.../devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml | 6 ++++++
2 files changed, 21 insertions(+)
diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml
index e25fa72fd7857..7430394cc6b9b 100644
--- a/Documentation/devicetree/bindings/i3c/i3c.yaml
+++ b/Documentation/devicetree/bindings/i3c/i3c.yaml
@@ -61,6 +61,21 @@ properties:
Indicates that the system is accessible via this bus as an endpoint for
MCTP over I3C transport.
+ in-band-interrupt-capable:
+ type: boolean
+ description:
+ The controller supports In-Band Interrupts. A target can request
+ attention on SDA/SCL by driving its dynamic address during bus
+ arbitration, instead of using a dedicated side-band interrupt line.
+
+ hot-join-capable:
+ type: boolean
+ description:
+ The controller supports Hot-Join. A target attached or powered up
+ after the bus is already running can announce itself using the
+ reserved Hot-Join address so the controller can assign it a dynamic
+ address.
+
required:
- "#address-cells"
- "#size-cells"
diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
index 2caa245a86568..9480de3fe8e1d 100644
--- a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
+++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
@@ -37,6 +37,10 @@ required:
- reg
- clocks
+dependentRequired:
+ hot-join-capable: [ in-band-interrupt-capable ]
+ in-band-interrupt-capable: [ interrupts ]
+
allOf:
- $ref: i3c.yaml#
@@ -54,5 +58,7 @@ examples:
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <3>;
#size-cells = <0>;
+ hot-join-capable;
+ in-band-interrupt-capable;
};
...
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 2/3] i3c: master: amd: Add support for in-band interrupts
2026-09-08 9:42 [PATCH v3 0/3] i3c: master: amd: Add IBI and hot-join support Shubham Patil
2026-09-08 9:42 ` [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties Shubham Patil
@ 2026-09-08 9:42 ` Shubham Patil
2026-09-08 9:42 ` [PATCH v3 3/3] i3c: master: amd: Add hot-join support Shubham Patil
2 siblings, 0 replies; 8+ messages in thread
From: Shubham Patil @ 2026-09-08 9:42 UTC (permalink / raw)
To: alexandre.belloni, Frank.Li, robh, krzk+dt, conor+dt
Cc: linux-i3c, devicetree, linux-kernel, git, Shubham Patil
Add support for receiving and dequeueing I3C in-band interrupts.
IBI support is optional at synthesis time, so the ops are assembled at
probe from the base set plus the IBI callbacks, and the callbacks are
only registered when the "in-band-interrupt-capable" property is
present. The controller interrupt carries IBI events only, so it is
likewise only requested for such designs.
The IBI ACK enable and its interrupt mask are controller-wide rather
than per-target, so they are armed when the first target enables IBIs
and disarmed when the last one disables them. Per-target control stays
on the bus via ENEC/DISEC.
IBIs share the response and read FIFOs with normal transfers and are
tagged with the reserved TID 0x0F. Masking the interrupt for the
duration of a transfer keeps the handler from running, but does not
stop the controller from ACKing an IBI, so the ACK is held off for the
duration of a transfer as well and a target retries its request. One
ACKed just before that takes effect can still queue its response word
and payload ahead of the transfer's own. The polled transfer path
therefore demultiplexes the response FIFO by TID: an IBI response and
its payload are handed to the IBI path, and the transfer's own response
is claimed into the master state for the caller to consume.
Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
---
Changes in V3:
- In xi3c_xfer_resp_available(), read IBI_TARGET_ADDR before
popping RESP_STATUS_FIFO so a raced IBI is not paired with the next
address (or garbage).
- Call i3c_dev_set_master_data() before publishing the IBI slot so the
IRQ handler cannot see the device with NULL master data.
- Probe "in-band-interrupt-capable" instead of the xlnx, property.
- Update the commit description accordingly.
Changes in V2:
- Do not lose an IBI raced with a transfer: hold XI3C_CR_IBI_MASK off
for the duration of a transfer so the target retries.
- Deliver an IBI accepted just before that through
xi3c_master_process_ibi() instead of draining it, which could also
consume the transfer's read data.
- disable_ibi(): return early on DISEC failure instead of disarming and
desyncing ibi.enabled_count from the core.
- synchronize_irq() before disable_ibi() returns and before free_ibi()
frees the pool.
- Update the commit description accordingly.
---
drivers/i3c/master/amd-i3c-master.c | 607 +++++++++++++++++++++++++++-
1 file changed, 587 insertions(+), 20 deletions(-)
diff --git a/drivers/i3c/master/amd-i3c-master.c b/drivers/i3c/master/amd-i3c-master.c
index ef5ad5abb788c..8a8ab3cd2fa40 100644
--- a/drivers/i3c/master/amd-i3c-master.c
+++ b/drivers/i3c/master/amd-i3c-master.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i3c/master.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
@@ -19,7 +20,9 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/time.h>
#include <linux/unaligned.h>
@@ -28,6 +31,8 @@
#define XI3C_CR_OFFSET 0x08 /* Control Register */
#define XI3C_ADDRESS_OFFSET 0x0C /* Target Address Register */
#define XI3C_SR_OFFSET 0x10 /* Status Register */
+#define XI3C_INTR_STATUS_OFFSET 0x14 /* Interrupt status event (W1C) */
+#define XI3C_INTR_RE_OFFSET 0x18 /* Interrupt rising-edge enable mask */
#define XI3C_CMD_FIFO_OFFSET 0x20 /* I3C Command FIFO Register */
#define XI3C_WR_FIFO_OFFSET 0x24 /* I3C Write Data FIFO Register */
#define XI3C_RD_FIFO_OFFSET 0x28 /* I3C Read Data FIFO Register */
@@ -42,13 +47,17 @@
#define XI3C_TSU_STOP_OFFSET 0x50 /* I3C STOP Setup Register */
#define XI3C_OD_SCL_HIGH_TIME_OFFSET 0x54 /* I3C OD SCL HIGH Register */
#define XI3C_OD_SCL_LOW_TIME_OFFSET 0x58 /* I3C OD SCL LOW Register */
+#define XI3C_IBI_TARGET_ADDR_OFFSET 0x5C /* IBI source address register */
+#define XI3C_TARGET_ADDR_BCR_OFFSET 0x60 /* Per-target {DA, BCR} SPRAM */
#define XI3C_PID0_OFFSET 0x6C /* LSB 4 bytes of the PID */
#define XI3C_PID1_BCR_DCR 0x70 /* MSB 2 bytes of the PID, BCR and DCR */
#define XI3C_CR_EN_MASK BIT(0) /* Core Enable */
#define XI3C_CR_RESUME_MASK BIT(2) /* Core Resume */
+#define XI3C_CR_IBI_MASK BIT(3) /* IBI ACK enable */
#define XI3C_SR_RESP_NOT_EMPTY_MASK BIT(4) /* Resp Fifo not empty status mask */
#define XI3C_RD_FIFO_NOT_EMPTY_MASK BIT(15) /* Read Fifo not empty status mask */
+#define XI3C_INTR_IBI_MASK BIT(7) /* IBI event (INTR status/enable) */
#define XI3C_BCR_MASK GENMASK(23, 16)
#define XI3C_DCR_MASK GENMASK(31, 24)
@@ -57,6 +66,7 @@
#define XI3C_REV_NUM_MASK GENMASK(15, 8)
#define XI3C_PID1_MASK GENMASK(15, 0)
#define XI3C_FIFO_LEVEL_MASK GENMASK(15, 0)
+#define XI3C_RESP_FIFO_LEVEL_MASK GENMASK(31, 16)
#define XI3C_RESP_CODE_MASK GENMASK(8, 5)
/* Controller response codes; PG439 page 34, Table 46 */
@@ -69,7 +79,9 @@
#define XI3C_XFER_SHORT_READ 1
#define XI3C_RESP_BYTES_MASK GENMASK(20, 9) /* NUM_BYTES processed */
+#define XI3C_RESP_TID_MASK GENMASK(3, 0) /* response transfer ID */
#define XI3C_ADDR_MASK GENMASK(6, 0)
+#define XI3C_TGT_BCR_MASK GENMASK(15, 8) /* TARGET_ADDR_BCR: BCR field */
#define XI3C_FIFOS_RST_MASK GENMASK(4, 1)
/* Command FIFO word layout (bit ranges encoded in the GENMASK/BIT args) */
@@ -121,9 +133,15 @@
#define XI3C_POLL_INTERVAL_US 10
#define XI3C_I2C_MODE 0
-#define XI3C_I2C_TID 0
#define XI3C_SDR_MODE 1
+
+/*
+ * TID tags: I2C/SDR are driver-chosen for normal transfers;
+ * 0x0F is the spec-reserved IBI response TID.
+ */
+#define XI3C_I2C_TID 0
#define XI3C_SDR_TID 1
+#define XI3C_IBI_RESP_TID 0x0F
#define XI3C_WORD_LEN 4
@@ -132,6 +150,9 @@
/* Software guard: 1 s (ms, for msecs_to_jiffies) to bail out if a transfer never completes */
#define XI3C_XFER_TIMEOUT_MS 1000
+/* IBI response wait in hard-IRQ context; software-chosen safety cap. */
+#define XI3C_IBI_RESP_TIMEOUT_US 1000
+
struct xi3c_cmd {
const void *tx_buf;
void *rx_buf;
@@ -160,9 +181,33 @@ struct xi3c_xfer {
* @membase: Memory base of the HW registers.
* @pclk: Input clock driving the controller.
* @lock: Serializes transfers and CCC submission.
+ * @reg_lock: IRQ-safe lock serializing read-modify-write of the shared
+ * control (XI3C_CR_OFFSET) and interrupt-enable
+ * (XI3C_INTR_RE_OFFSET) registers.
* @daa: ENTDAA enumeration state.
* @daa.addrs: Dynamic addresses assigned in enumeration order.
* @daa.index: Number of responders enumerated so far.
+ * @xfer_resp_valid: True once the in-flight transfer's own response word has
+ * been taken from the shared response FIFO. Guarded by @lock.
+ * @ibi_capable: True when the IP was synthesized with In-Band Interrupt
+ * support ("in-band-interrupt-capable"); also the
+ * condition for the controller interrupt being present.
+ * @xfer_resp: Response word claimed for the transfer in flight; valid while
+ * @xfer_resp_valid is set. Guarded by @lock.
+ * @irq: Controller interrupt line, used for IBI events. Only valid when
+ * @ibi_capable is set.
+ * @ops: Controller ops handed to the framework, assembled at probe time from
+ * the base ops plus the callbacks the design actually supports.
+ * @ibi: In-Band Interrupt slot tracking.
+ * @ibi.lock: Protects @ibi.slots against the IBI handler.
+ * @ibi.slots: Per-device IBI registration, indexed by slot.
+ * @ibi.enabled_count: Number of devices with IBI currently enabled; the
+ * controller-wide IBI ACK/interrupt is armed on the
+ * first enable and disarmed on the last disable. Guarded
+ * by @reg_lock.
+ * @ibi.suppressed: True while a transfer holds the IBI ACK off. Arming leaves
+ * the ACK to that transfer, which restores it from
+ * @ibi.enabled_count. Guarded by @reg_lock.
*/
struct xi3c_master {
struct i3c_master_controller base;
@@ -170,10 +215,32 @@ struct xi3c_master {
void __iomem *membase;
struct clk *pclk;
struct mutex lock; /* serializes transfers and CCC submission */
+ spinlock_t reg_lock;
struct {
u8 addrs[XI3C_MAX_DEVS];
u8 index;
} daa;
+ bool xfer_resp_valid;
+ bool ibi_capable;
+ u32 xfer_resp;
+ int irq;
+ struct i3c_master_controller_ops ops;
+ struct {
+ spinlock_t lock; /* protects slots[] against the IBI handler */
+ struct i3c_dev_desc *slots[XI3C_MAX_DEVS];
+ unsigned int enabled_count;
+ bool suppressed;
+ } ibi;
+};
+
+/**
+ * struct xi3c_i3c_dev_data - Per-device controller state.
+ * @ibi_pool: Generic IBI slot pool backing this device's IBIs.
+ * @ibi_slot: Index into &xi3c_master.ibi.slots, or -1 when unregistered.
+ */
+struct xi3c_i3c_dev_data {
+ struct i3c_generic_ibi_pool *ibi_pool;
+ s16 ibi_slot;
};
static inline struct xi3c_master *
@@ -206,23 +273,89 @@ static inline bool xi3c_is_resp_available(struct xi3c_master *master)
ioread32(master->membase + XI3C_SR_OFFSET));
}
+static inline u16 xi3c_resp_fifo_level(struct xi3c_master *master)
+{
+ return FIELD_GET(XI3C_RESP_FIFO_LEVEL_MASK,
+ ioread32(master->membase + XI3C_FIFO_LVL_STATUS_1_OFFSET));
+}
+
+/*
+ * Discard an unconsumed IBI payload from the RX FIFO, keeping the FIFO
+ * aligned for the next transfer.
+ */
+static void xi3c_master_drain_ibi_fifo(struct xi3c_master *master, u16 len)
+{
+ unsigned int words = DIV_ROUND_UP(len, XI3C_WORD_LEN);
+
+ while (words--)
+ ioread32(master->membase + XI3C_RD_FIFO_OFFSET);
+}
+
+static void xi3c_master_process_ibi(struct xi3c_master *master, u32 resp, u8 da);
+
+/*
+ * Tell whether the transfer in flight has had its response posted, claiming
+ * that response into @master->xfer_resp when it has.
+ *
+ * The response and read FIFOs are shared with IBIs. A transfer stops the
+ * controller from ACKing new IBIs, but one ACKed just before that takes effect
+ * still queues its response word and its payload ahead of ours. Deliver such
+ * an IBI here rather than leaving it in the FIFOs, so a transfer cannot
+ * mistake the IBI's response code and byte count for its own, nor the IBI's
+ * payload for read data, and the event still reaches its device.
+ */
+static bool xi3c_xfer_resp_available(struct xi3c_master *master)
+{
+ u32 resp;
+ u8 da;
+
+ if (master->xfer_resp_valid)
+ return true;
+
+ while (xi3c_is_resp_available(master)) {
+ da = FIELD_GET(XI3C_ADDR_MASK,
+ ioread32(master->membase + XI3C_IBI_TARGET_ADDR_OFFSET));
+
+ resp = ioread32(master->membase + XI3C_RESP_STATUS_FIFO_OFFSET);
+
+ if (FIELD_GET(XI3C_RESP_TID_MASK, resp) != XI3C_IBI_RESP_TID) {
+ master->xfer_resp = resp;
+ master->xfer_resp_valid = true;
+ return true;
+ }
+
+ dev_dbg_ratelimited(master->dev,
+ "IBI from 0x%02x raced with transfer\n", da);
+ xi3c_master_process_ibi(master, resp, da);
+
+ /*
+ * IRQ is masked for this transfer: clear the event serviced
+ * here so it does not fire again once the IRQ is unmasked.
+ */
+ iowrite32(XI3C_INTR_IBI_MASK,
+ master->membase + XI3C_INTR_STATUS_OFFSET);
+ }
+
+ return false;
+}
+
static int xi3c_get_response(struct xi3c_master *master, struct xi3c_cmd *cmd)
{
u32 response_data;
- u32 resp_reg;
+ bool available;
u8 code;
int ret;
- ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET,
- resp_reg,
- resp_reg & XI3C_SR_RESP_NOT_EMPTY_MASK,
- XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US);
+ ret = read_poll_timeout(xi3c_xfer_resp_available, available, available,
+ XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US,
+ false, master);
if (ret) {
dev_err(master->dev, "XI3C response timeout\n");
return ret;
}
- response_data = ioread32(master->membase + XI3C_RESP_STATUS_FIFO_OFFSET);
+ response_data = master->xfer_resp;
+ master->xfer_resp_valid = false;
code = FIELD_GET(XI3C_RESP_CODE_MASK, response_data);
switch (code) {
@@ -247,6 +380,19 @@ static int xi3c_get_response(struct xi3c_master *master, struct xi3c_cmd *cmd)
}
}
+/*
+ * Wait for a response in hard-IRQ context (IBI path). Uses the atomic
+ * poll variant since the IBI handler must not sleep.
+ */
+static int xi3c_wait_resp_atomic(struct xi3c_master *master)
+{
+ u32 sr;
+
+ return readl_poll_timeout_atomic(master->membase + XI3C_SR_OFFSET, sr,
+ sr & XI3C_SR_RESP_NOT_EMPTY_MASK,
+ 0, XI3C_IBI_RESP_TIMEOUT_US);
+}
+
static inline void xi3c_writesl_be(void __iomem *addr, const void *buffer,
unsigned int count)
{
@@ -331,10 +477,28 @@ static inline void xi3c_master_disable(struct xi3c_master *master)
static inline void xi3c_master_resume(struct xi3c_master *master)
{
+ guard(spinlock_irqsave)(&master->reg_lock);
iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) |
XI3C_CR_RESUME_MASK, master->membase + XI3C_CR_OFFSET);
}
+static void xi3c_master_suppress_ibi_for_xfer(struct xi3c_master *master,
+ bool suppress)
+{
+ u32 cr;
+
+ guard(spinlock_irqsave)(&master->reg_lock);
+
+ master->ibi.suppressed = suppress;
+
+ cr = ioread32(master->membase + XI3C_CR_OFFSET);
+ if (suppress || !master->ibi.enabled_count)
+ cr &= ~XI3C_CR_IBI_MASK;
+ else
+ cr |= XI3C_CR_IBI_MASK;
+ iowrite32(cr, master->membase + XI3C_CR_OFFSET);
+}
+
static void xi3c_master_reset_fifos(struct xi3c_master *master)
{
u32 data;
@@ -356,6 +520,11 @@ static void xi3c_master_reset_fifos(struct xi3c_master *master)
static inline void xi3c_master_init(struct xi3c_master *master)
{
+ /* Mask all interrupt sources and clear any stale latched events. */
+ iowrite32(0, master->membase + XI3C_INTR_RE_OFFSET);
+ iowrite32(ioread32(master->membase + XI3C_INTR_STATUS_OFFSET),
+ master->membase + XI3C_INTR_STATUS_OFFSET);
+
/* Reset fifos */
xi3c_master_reset_fifos(master);
@@ -437,13 +606,19 @@ static int xi3c_master_read(struct xi3c_master *master, struct xi3c_cmd *cmd)
return ret;
}
- if (!(status_reg & XI3C_RD_FIFO_NOT_EMPTY_MASK))
+ /*
+ * No data queued means this read produced none, unless what is queued
+ * is an IBI response that raced with it; xi3c_xfer_resp_available()
+ * consumes that case so the wait for our own data can continue.
+ */
+ if (!(status_reg & XI3C_RD_FIFO_NOT_EMPTY_MASK) &&
+ xi3c_xfer_resp_available(master))
return 0;
timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS);
/* Read data from rx fifo */
- while (cmd->rx_len > 0 && !xi3c_is_resp_available(master)) {
+ while (cmd->rx_len > 0 && !xi3c_xfer_resp_available(master)) {
if (time_after(jiffies, timeout)) {
dev_err(master->dev, "XI3C read timeout\n");
return -EIO;
@@ -503,7 +678,7 @@ static int xi3c_master_write(struct xi3c_master *master, struct xi3c_cmd *cmd)
timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS);
/* Fill if any remaining data to tx fifo */
- while (cmd->tx_len > 0 && !xi3c_is_resp_available(master)) {
+ while (cmd->tx_len > 0 && !xi3c_xfer_resp_available(master)) {
if (time_after(jiffies, timeout)) {
dev_err(master->dev, "XI3C write timeout\n");
return -EIO;
@@ -547,22 +722,38 @@ static int xi3c_master_common_xfer(struct xi3c_master *master,
struct xi3c_xfer *xfer)
{
unsigned int i;
- int ret;
+ int ret = 0;
guard(mutex)(&master->lock);
+ /*
+ * IBIs share the response/read FIFOs; stop the controller from ACKing
+ * new ones and mask the IRQ so the handler cannot take this transfer's
+ * response.
+ */
+ if (master->ibi_capable) {
+ xi3c_master_suppress_ibi_for_xfer(master, true);
+ disable_irq(master->irq);
+ }
+
+ /* Discard any response claimed but not consumed by an aborted transfer. */
+ master->xfer_resp_valid = false;
+
for (i = 0; i < xfer->ncmds; i++) {
ret = xi3c_master_xfer(master, &xfer->cmds[i]);
- if (ret) {
- /* Count commands sent on the bus; the rest never ran */
- xfer->nissued = i + 1;
- return ret;
- }
+ if (ret)
+ break;
}
- xfer->nissued = xfer->ncmds;
+ if (master->ibi_capable) {
+ enable_irq(master->irq);
+ xi3c_master_suppress_ibi_for_xfer(master, false);
+ }
- return 0;
+ /* On failure @i is the command that failed; the rest never ran. */
+ xfer->nissued = (i < xfer->ncmds) ? i + 1 : xfer->ncmds;
+
+ return ret;
}
static int xi3c_master_do_daa(struct i3c_master_controller *m)
@@ -1052,9 +1243,338 @@ static void xi3c_master_bus_cleanup(struct i3c_master_controller *m)
{
struct xi3c_master *master = to_xi3c_master(m);
+ /*
+ * Disarm all interrupt sources and the IBI ACK so the controller can't
+ * assert once disabled; reset the refcount that tracks them.
+ */
+ scoped_guard(spinlock_irqsave, &master->reg_lock) {
+ iowrite32(0, master->membase + XI3C_INTR_RE_OFFSET);
+ iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) &
+ ~XI3C_CR_IBI_MASK, master->membase + XI3C_CR_OFFSET);
+ master->ibi.enabled_count = 0;
+ }
+
xi3c_master_disable(master);
}
+static int xi3c_master_request_ibi(struct i3c_dev_desc *dev,
+ const struct i3c_ibi_setup *req)
+{
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct xi3c_master *master = to_xi3c_master(m);
+ struct xi3c_i3c_dev_data *data;
+ unsigned long flags;
+ unsigned int i;
+
+ data = kzalloc_obj(*data, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->ibi_slot = -1;
+ data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
+ if (IS_ERR(data->ibi_pool)) {
+ int ret = PTR_ERR(data->ibi_pool);
+
+ kfree(data);
+ return ret;
+ }
+
+ i3c_dev_set_master_data(dev, data);
+
+ spin_lock_irqsave(&master->ibi.lock, flags);
+ for (i = 0; i < ARRAY_SIZE(master->ibi.slots); i++) {
+ if (!master->ibi.slots[i]) {
+ data->ibi_slot = i;
+ master->ibi.slots[i] = dev;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+ if (data->ibi_slot < 0) {
+ dev_err(master->dev, "IBI: no free slot for addr 0x%02x\n",
+ dev->info.dyn_addr);
+ i3c_dev_set_master_data(dev, NULL);
+ i3c_generic_ibi_free_pool(data->ibi_pool);
+ kfree(data);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static void xi3c_master_free_ibi(struct i3c_dev_desc *dev)
+{
+ struct xi3c_i3c_dev_data *data = i3c_dev_get_master_data(dev);
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct xi3c_master *master = to_xi3c_master(m);
+ unsigned long flags;
+
+ spin_lock_irqsave(&master->ibi.lock, flags);
+ master->ibi.slots[data->ibi_slot] = NULL;
+ spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+ /*
+ * Clearing the slot above keeps the IBI handler from finding this
+ * device, but a handler already running may be copying a payload into
+ * the pool. Wait for it to finish before the pool is freed below.
+ */
+ synchronize_irq(master->irq);
+
+ i3c_generic_ibi_free_pool(data->ibi_pool);
+ i3c_dev_set_master_data(dev, NULL);
+ kfree(data);
+}
+
+/*
+ * Arm the controller-wide IBI ACK enable and event interrupt on the first
+ * device to enable IBIs. Per-device SIR control is still done on the bus via
+ * ENEC/DISEC; this only gates whether the controller reacts to IBIs at all.
+ */
+static void xi3c_master_ibi_arm(struct xi3c_master *master)
+{
+ guard(spinlock_irqsave)(&master->reg_lock);
+
+ if (master->ibi.enabled_count++)
+ return;
+
+ /* A transfer holding the ACK off restores it once it completes. */
+ if (!master->ibi.suppressed)
+ iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) |
+ XI3C_CR_IBI_MASK,
+ master->membase + XI3C_CR_OFFSET);
+ iowrite32(ioread32(master->membase + XI3C_INTR_RE_OFFSET) |
+ XI3C_INTR_IBI_MASK, master->membase + XI3C_INTR_RE_OFFSET);
+}
+
+/* Disarm the controller-wide IBI enable once the last device disables IBIs. */
+static void xi3c_master_ibi_disarm(struct xi3c_master *master)
+{
+ guard(spinlock_irqsave)(&master->reg_lock);
+
+ if (WARN_ON(!master->ibi.enabled_count))
+ return;
+
+ if (--master->ibi.enabled_count)
+ return;
+
+ iowrite32(ioread32(master->membase + XI3C_INTR_RE_OFFSET) &
+ ~XI3C_INTR_IBI_MASK, master->membase + XI3C_INTR_RE_OFFSET);
+ iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) & ~XI3C_CR_IBI_MASK,
+ master->membase + XI3C_CR_OFFSET);
+}
+
+static int xi3c_master_enable_ibi(struct i3c_dev_desc *dev)
+{
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct xi3c_master *master = to_xi3c_master(m);
+ u32 val;
+ int ret;
+
+ /*
+ * Program {DA, BCR} into the IBI SPRAM; the DA field self-selects the
+ * row, so a plain write keeps the entry fresh after DAA reassigns the
+ * address.
+ */
+ val = FIELD_PREP(XI3C_ADDR_MASK, dev->info.dyn_addr) |
+ FIELD_PREP(XI3C_TGT_BCR_MASK, dev->info.bcr);
+ iowrite32(val, master->membase + XI3C_TARGET_ADDR_BCR_OFFSET);
+
+ /* Arm the controller IBI path before allowing this device to SIR. */
+ xi3c_master_ibi_arm(master);
+
+ ret = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+ if (ret) {
+ dev_err(master->dev, "IBI: ENEC failed addr 0x%02x (%d)\n",
+ dev->info.dyn_addr, ret);
+ xi3c_master_ibi_disarm(master);
+ }
+
+ return ret;
+}
+
+static int xi3c_master_disable_ibi(struct i3c_dev_desc *dev)
+{
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct xi3c_master *master = to_xi3c_master(m);
+ int ret;
+
+ /*
+ * Keep the controller armed if DISEC failed: the core still counts this
+ * device as enabled, and the target may still raise IBIs.
+ */
+ ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+ if (ret)
+ return ret;
+
+ xi3c_master_ibi_disarm(master);
+
+ /*
+ * The core samples the pending IBI count as soon as this returns, so
+ * wait for an in-flight handler to queue its slot; otherwise the count
+ * reads zero and the pool is freed while the handler still holds it.
+ */
+ synchronize_irq(master->irq);
+
+ return 0;
+}
+
+static void xi3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
+ struct i3c_ibi_slot *slot)
+{
+ struct xi3c_i3c_dev_data *data = i3c_dev_get_master_data(dev);
+
+ i3c_generic_ibi_recycle_slot(data->ibi_pool, slot);
+}
+
+static void xi3c_master_handle_ibi(struct xi3c_master *master)
+{
+ u32 ibi_reg, resp;
+ u8 da, code;
+ u16 len;
+
+ ibi_reg = ioread32(master->membase + XI3C_IBI_TARGET_ADDR_OFFSET);
+ da = FIELD_GET(XI3C_ADDR_MASK, ibi_reg);
+
+ if (xi3c_wait_resp_atomic(master)) {
+ dev_err_ratelimited(master->dev, "XI3C IBI response timeout\n");
+ /* Controller parks in STOP on failure; RESUME to recover (PG439). */
+ xi3c_master_resume(master);
+ return;
+ }
+
+ resp = ioread32(master->membase + XI3C_RESP_STATUS_FIFO_OFFSET);
+ code = FIELD_GET(XI3C_RESP_CODE_MASK, resp);
+ len = FIELD_GET(XI3C_RESP_BYTES_MASK, resp);
+
+ /*
+ * TID 0x0F marks an IBI response. A transfer masks this interrupt and
+ * demuxes the response FIFO itself, so its response must never reach
+ * here; draining one would eat that transfer's read data.
+ */
+ if (FIELD_GET(XI3C_RESP_TID_MASK, resp) != XI3C_IBI_RESP_TID) {
+ WARN_ONCE(1, "XI3C: transfer response in IBI handler, dropping %u bytes\n",
+ len);
+ xi3c_master_drain_ibi_fifo(master, len);
+ /* A non-success stray response parks the controller in STOP (PG439). */
+ if (code != XI3C_RESP_CODE_SUCCESS)
+ xi3c_master_resume(master);
+ return;
+ }
+
+ xi3c_master_process_ibi(master, resp, da);
+}
+
+/*
+ * Hand an IBI whose response word has already been taken from the response
+ * FIFO to its device, consuming the payload that goes with it. Runs from the
+ * IRQ handler, and from transfer context for an IBI the controller ACKed just
+ * before the transfer suppressed them.
+ */
+static void xi3c_master_process_ibi(struct xi3c_master *master, u32 resp, u8 da)
+{
+ struct xi3c_i3c_dev_data *data;
+ struct i3c_ibi_slot *slot;
+ struct i3c_dev_desc *dev;
+ unsigned long flags;
+ unsigned int id;
+ u8 code;
+ u16 len;
+
+ code = FIELD_GET(XI3C_RESP_CODE_MASK, resp);
+ len = FIELD_GET(XI3C_RESP_BYTES_MASK, resp);
+
+ if (code != XI3C_RESP_CODE_SUCCESS) {
+ dev_dbg_ratelimited(master->dev,
+ "IBI: non-success code %u, dropping %u bytes\n",
+ code, len);
+ xi3c_master_drain_ibi_fifo(master, len);
+ xi3c_master_resume(master);
+ return;
+ }
+
+ spin_lock_irqsave(&master->ibi.lock, flags);
+
+ for (id = 0; id < ARRAY_SIZE(master->ibi.slots); id++)
+ if (master->ibi.slots[id] &&
+ master->ibi.slots[id]->info.dyn_addr == da)
+ break;
+
+ if (id == ARRAY_SIZE(master->ibi.slots)) {
+ dev_dbg_ratelimited(master->dev,
+ "IBI: no registered device for addr 0x%02x\n",
+ da);
+ goto err_drain;
+ }
+
+ dev = master->ibi.slots[id];
+
+ if (!dev->ibi) {
+ dev_dbg_ratelimited(master->dev,
+ "IBI: addr 0x%02x not fully set up\n", da);
+ goto err_drain;
+ }
+
+ if (len > dev->ibi->max_payload_len) {
+ dev_dbg_ratelimited(master->dev,
+ "IBI: payload %u > max %u for addr 0x%02x\n",
+ len, dev->ibi->max_payload_len, da);
+ goto err_drain;
+ }
+
+ data = i3c_dev_get_master_data(dev);
+ slot = i3c_generic_ibi_get_free_slot(data->ibi_pool);
+ if (!slot) {
+ dev_dbg_ratelimited(master->dev,
+ "IBI: no free pool slot for addr 0x%02x\n",
+ da);
+ goto err_drain;
+ }
+
+ slot->len = 0;
+ if (len) {
+ xi3c_readl_fifo(master->membase + XI3C_RD_FIFO_OFFSET,
+ slot->data, len);
+ slot->len = len;
+ }
+
+ i3c_master_queue_ibi(dev, slot);
+ spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+ return;
+
+err_drain:
+ /*
+ * Reached only with code == SUCCESS, so the controller is not parked in
+ * STOP; no resume needed (PG439).
+ */
+ spin_unlock_irqrestore(&master->ibi.lock, flags);
+ xi3c_master_drain_ibi_fifo(master, len);
+}
+
+static irqreturn_t xi3c_master_irq_handler(int irq, void *dev_id)
+{
+ struct xi3c_master *master = dev_id;
+ u32 status;
+
+ status = ioread32(master->membase + XI3C_INTR_STATUS_OFFSET);
+ if (!status)
+ return IRQ_NONE;
+
+ /* Write-1-to-clear the latched events before servicing them. */
+ iowrite32(status, master->membase + XI3C_INTR_STATUS_OFFSET);
+
+ /* Event latches once; drain the queued IBI responses (TID checked per entry). */
+ if (status & XI3C_INTR_IBI_MASK) {
+ u16 pending = xi3c_resp_fifo_level(master);
+
+ while (pending-- && xi3c_is_resp_available(master))
+ xi3c_master_handle_ibi(master);
+ }
+
+ return IRQ_HANDLED;
+}
+
static const struct i3c_master_controller_ops xi3c_master_ops = {
.bus_init = xi3c_master_bus_init,
.bus_cleanup = xi3c_master_bus_cleanup,
@@ -1065,6 +1585,15 @@ static const struct i3c_master_controller_ops xi3c_master_ops = {
.i2c_xfers = xi3c_master_i2c_xfers,
};
+static void xi3c_master_init_ibi_ops(struct xi3c_master *master)
+{
+ master->ops.request_ibi = xi3c_master_request_ibi;
+ master->ops.free_ibi = xi3c_master_free_ibi;
+ master->ops.enable_ibi = xi3c_master_enable_ibi;
+ master->ops.disable_ibi = xi3c_master_disable_ibi;
+ master->ops.recycle_ibi_slot = xi3c_master_recycle_ibi_slot;
+}
+
static int xi3c_master_probe(struct platform_device *pdev)
{
struct xi3c_master *master;
@@ -1090,16 +1619,54 @@ static int xi3c_master_probe(struct platform_device *pdev)
if (ret)
return ret;
+ master->ops = xi3c_master_ops;
+
+ spin_lock_init(&master->ibi.lock);
+ spin_lock_init(&master->reg_lock);
+
+ master->ibi_capable =
+ device_property_read_bool(master->dev,
+ "in-band-interrupt-capable");
+
+ /*
+ * The interrupt only carries IBI events, so it is only described for
+ * designs synthesized with that feature.
+ */
+ if (master->ibi_capable) {
+ xi3c_master_init_ibi_ops(master);
+
+ master->irq = platform_get_irq(pdev, 0);
+ if (master->irq < 0)
+ return master->irq;
+
+ ret = devm_request_irq(master->dev, master->irq,
+ xi3c_master_irq_handler, IRQF_NO_AUTOEN,
+ dev_name(master->dev), master);
+ if (ret)
+ return dev_err_probe(master->dev, ret,
+ "Failed to request IRQ\n");
+ }
+
platform_set_drvdata(pdev, master);
- return i3c_master_register(&master->base, master->dev,
- &xi3c_master_ops, false);
+ ret = i3c_master_register(&master->base, master->dev, &master->ops,
+ false);
+ if (ret)
+ return ret;
+
+ if (master->ibi_capable)
+ enable_irq(master->irq);
+
+ return 0;
}
static void xi3c_master_remove(struct platform_device *pdev)
{
struct xi3c_master *master = platform_get_drvdata(pdev);
+ if (master->ibi_capable)
+ disable_irq(master->irq);
+
i3c_master_unregister(&master->base);
}
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 3/3] i3c: master: amd: Add hot-join support
2026-09-08 9:42 [PATCH v3 0/3] i3c: master: amd: Add IBI and hot-join support Shubham Patil
2026-09-08 9:42 ` [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties Shubham Patil
2026-09-08 9:42 ` [PATCH v3 2/3] i3c: master: amd: Add support for in-band interrupts Shubham Patil
@ 2026-09-08 9:42 ` Shubham Patil
2 siblings, 0 replies; 8+ messages in thread
From: Shubham Patil @ 2026-09-08 9:42 UTC (permalink / raw)
To: alexandre.belloni, Frank.Li, robh, krzk+dt, conor+dt
Cc: linux-i3c, devicetree, linux-kernel, git, Shubham Patil
Add hot-join support for the AMD AXI I3C master controller.
By default, the hot-join acknowledgment is disabled. Users can use the
sysfs entry to enable it. A hot-join event is handed to the i3c core
with i3c_master_queue_hotjoin(), which runs DAA from the core workqueue
so the new device is enumerated.
Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
---
Changes in V3:
- Probe "hot-join-capable" instead of the xlnx, property.
- Update the commit description accordingly.
Changes in V2:
- Use the core's i3c_master_queue_hotjoin() instead of a private work
item, and only queue when hj_capable is set; the core owns the work
and cancels it on unregister.
- Update the commit description accordingly.
---
drivers/i3c/master/amd-i3c-master.c | 67 +++++++++++++++++++++++++----
1 file changed, 58 insertions(+), 9 deletions(-)
diff --git a/drivers/i3c/master/amd-i3c-master.c b/drivers/i3c/master/amd-i3c-master.c
index 8a8ab3cd2fa40..6214fef14081f 100644
--- a/drivers/i3c/master/amd-i3c-master.c
+++ b/drivers/i3c/master/amd-i3c-master.c
@@ -55,9 +55,11 @@
#define XI3C_CR_EN_MASK BIT(0) /* Core Enable */
#define XI3C_CR_RESUME_MASK BIT(2) /* Core Resume */
#define XI3C_CR_IBI_MASK BIT(3) /* IBI ACK enable */
+#define XI3C_CR_HJ_MASK BIT(4) /* Hot-Join ACK enable */
#define XI3C_SR_RESP_NOT_EMPTY_MASK BIT(4) /* Resp Fifo not empty status mask */
#define XI3C_RD_FIFO_NOT_EMPTY_MASK BIT(15) /* Read Fifo not empty status mask */
#define XI3C_INTR_IBI_MASK BIT(7) /* IBI event (INTR status/enable) */
+#define XI3C_INTR_HJ_MASK BIT(8) /* Hot-Join event */
#define XI3C_BCR_MASK GENMASK(23, 16)
#define XI3C_DCR_MASK GENMASK(31, 24)
@@ -190,12 +192,15 @@ struct xi3c_xfer {
* @xfer_resp_valid: True once the in-flight transfer's own response word has
* been taken from the shared response FIFO. Guarded by @lock.
* @ibi_capable: True when the IP was synthesized with In-Band Interrupt
- * support ("in-band-interrupt-capable"); also the
- * condition for the controller interrupt being present.
+ * support ("in-band-interrupt-capable"). Since Hot-Join
+ * requests are ACKed by the IBI machinery, this is also the
+ * condition for the controller interrupt being present at all.
+ * @hj_capable: True when the IP was synthesized with Hot-Join support
+ * ("hot-join-capable"); implies @ibi_capable.
* @xfer_resp: Response word claimed for the transfer in flight; valid while
* @xfer_resp_valid is set. Guarded by @lock.
- * @irq: Controller interrupt line, used for IBI events. Only valid when
- * @ibi_capable is set.
+ * @irq: Controller interrupt line, used for IBI/Hot-Join events. Only valid
+ * when @ibi_capable is set.
* @ops: Controller ops handed to the framework, assembled at probe time from
* the base ops plus the callbacks the design actually supports.
* @ibi: In-Band Interrupt slot tracking.
@@ -222,6 +227,7 @@ struct xi3c_master {
} daa;
bool xfer_resp_valid;
bool ibi_capable;
+ bool hj_capable;
u32 xfer_resp;
int irq;
struct i3c_master_controller_ops ops;
@@ -1244,13 +1250,14 @@ static void xi3c_master_bus_cleanup(struct i3c_master_controller *m)
struct xi3c_master *master = to_xi3c_master(m);
/*
- * Disarm all interrupt sources and the IBI ACK so the controller can't
- * assert once disabled; reset the refcount that tracks them.
+ * Disarm the interrupts and the IBI/Hot-Join ACKs so nothing is left
+ * armed for a later bus_init(); reset the refcount that tracks them.
*/
scoped_guard(spinlock_irqsave, &master->reg_lock) {
iowrite32(0, master->membase + XI3C_INTR_RE_OFFSET);
iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) &
- ~XI3C_CR_IBI_MASK, master->membase + XI3C_CR_OFFSET);
+ ~(XI3C_CR_IBI_MASK | XI3C_CR_HJ_MASK),
+ master->membase + XI3C_CR_OFFSET);
master->ibi.enabled_count = 0;
}
@@ -1552,6 +1559,32 @@ static void xi3c_master_process_ibi(struct xi3c_master *master, u32 resp, u8 da)
xi3c_master_drain_ibi_fifo(master, len);
}
+static int xi3c_master_enable_hotjoin(struct i3c_master_controller *m)
+{
+ struct xi3c_master *master = to_xi3c_master(m);
+
+ guard(spinlock_irqsave)(&master->reg_lock);
+ iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) | XI3C_CR_HJ_MASK,
+ master->membase + XI3C_CR_OFFSET);
+ iowrite32(ioread32(master->membase + XI3C_INTR_RE_OFFSET) |
+ XI3C_INTR_HJ_MASK, master->membase + XI3C_INTR_RE_OFFSET);
+
+ return 0;
+}
+
+static int xi3c_master_disable_hotjoin(struct i3c_master_controller *m)
+{
+ struct xi3c_master *master = to_xi3c_master(m);
+
+ guard(spinlock_irqsave)(&master->reg_lock);
+ iowrite32(ioread32(master->membase + XI3C_INTR_RE_OFFSET) &
+ ~XI3C_INTR_HJ_MASK, master->membase + XI3C_INTR_RE_OFFSET);
+ iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) & ~XI3C_CR_HJ_MASK,
+ master->membase + XI3C_CR_OFFSET);
+
+ return 0;
+}
+
static irqreturn_t xi3c_master_irq_handler(int irq, void *dev_id)
{
struct xi3c_master *master = dev_id;
@@ -1572,6 +1605,9 @@ static irqreturn_t xi3c_master_irq_handler(int irq, void *dev_id)
xi3c_master_handle_ibi(master);
}
+ if (master->hj_capable && (status & XI3C_INTR_HJ_MASK))
+ i3c_master_queue_hotjoin(&master->base);
+
return IRQ_HANDLED;
}
@@ -1592,6 +1628,11 @@ static void xi3c_master_init_ibi_ops(struct xi3c_master *master)
master->ops.enable_ibi = xi3c_master_enable_ibi;
master->ops.disable_ibi = xi3c_master_disable_ibi;
master->ops.recycle_ibi_slot = xi3c_master_recycle_ibi_slot;
+
+ if (master->hj_capable) {
+ master->ops.enable_hotjoin = xi3c_master_enable_hotjoin;
+ master->ops.disable_hotjoin = xi3c_master_disable_hotjoin;
+ }
}
static int xi3c_master_probe(struct platform_device *pdev)
@@ -1627,10 +1668,18 @@ static int xi3c_master_probe(struct platform_device *pdev)
master->ibi_capable =
device_property_read_bool(master->dev,
"in-band-interrupt-capable");
+ master->hj_capable =
+ device_property_read_bool(master->dev,
+ "hot-join-capable");
+
+ /* Hot-Join requests are ACKed by the IBI machinery. */
+ if (master->hj_capable && !master->ibi_capable)
+ return dev_err_probe(master->dev, -EINVAL,
+ "hot-join-capable requires in-band-interrupt-capable\n");
/*
- * The interrupt only carries IBI events, so it is only described for
- * designs synthesized with that feature.
+ * The interrupt only carries IBI and Hot-Join events, so it is only
+ * described for designs synthesized with those features.
*/
if (master->ibi_capable) {
xi3c_master_init_ibi_ops(master);
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties
2026-09-08 9:42 ` [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties Shubham Patil
@ 2026-09-08 17:54 ` Conor Dooley
2026-09-09 16:21 ` Frank Li
0 siblings, 1 reply; 8+ messages in thread
From: Conor Dooley @ 2026-09-08 17:54 UTC (permalink / raw)
To: Shubham Patil
Cc: alexandre.belloni, Frank.Li, robh, krzk+dt, conor+dt, linux-i3c,
devicetree, linux-kernel, git
[-- Attachment #1: Type: text/plain, Size: 3794 bytes --]
On Tue, Sep 08, 2026 at 03:12:55PM +0530, Shubham Patil wrote:
> In-Band Interrupt and Hot-Join are synthesis-time options of the AXI I3C
> IP. Describe them with two boolean properties.
>
> A Hot-Join request is acknowledged by the IBI machinery, so a hot-join
> capable design is always IBI capable as well. Both events are reported
> through the controller interrupt, which is therefore required whenever
> the capability is present.
>
> Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
> ---
> Changes in V3:
> - Move in-band-interrupt-capable and hot-join-capable into the common
> i3c.yaml schema and drop the xlnx, prefix.
> - Keep dependencies in the AMD binding.
> - Update the commit description accordingly.
> - Conor Dooley acked v2 with the xlnx,-prefixed properties in the AMD
> binding [1].
> That Acked-by is not carried here: the names lost the vendor prefix
> and the definitions moved to i3c.yaml after Frank Li's comment.
> [1]:https://lore.kernel.org/all/20260824-tightwad-impose-495476599087@spud/
I disagree with Frank. These properties make sense for Xilinx because it
is an FPGA IP and synthesis options impact this. For other devices, this
should be determined from the compatible.
Please revert to how things were done in v2, especially as no rationale
was provided for why these should be common.
pw-bot: changes-requested
Thanks,
Conor.
>
> Changes in V2:
> - Rename the properties to "xlnx,in-band-interrupt-capable" and
> "xlnx,hot-join-capable", and expand their descriptions.
> - Express the interrupt requirement with dependencies: instead of an
> allOf/if-then clause.
> ---
> Documentation/devicetree/bindings/i3c/i3c.yaml | 15 +++++++++++++++
> .../devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml | 6 ++++++
> 2 files changed, 21 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml
> index e25fa72fd7857..7430394cc6b9b 100644
> --- a/Documentation/devicetree/bindings/i3c/i3c.yaml
> +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml
> @@ -61,6 +61,21 @@ properties:
> Indicates that the system is accessible via this bus as an endpoint for
> MCTP over I3C transport.
>
> + in-band-interrupt-capable:
> + type: boolean
> + description:
> + The controller supports In-Band Interrupts. A target can request
> + attention on SDA/SCL by driving its dynamic address during bus
> + arbitration, instead of using a dedicated side-band interrupt line.
> +
> + hot-join-capable:
> + type: boolean
> + description:
> + The controller supports Hot-Join. A target attached or powered up
> + after the bus is already running can announce itself using the
> + reserved Hot-Join address so the controller can assign it a dynamic
> + address.
> +
> required:
> - "#address-cells"
> - "#size-cells"
> diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> index 2caa245a86568..9480de3fe8e1d 100644
> --- a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> +++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> @@ -37,6 +37,10 @@ required:
> - reg
> - clocks
>
> +dependentRequired:
> + hot-join-capable: [ in-band-interrupt-capable ]
> + in-band-interrupt-capable: [ interrupts ]
> +
> allOf:
> - $ref: i3c.yaml#
>
> @@ -54,5 +58,7 @@ examples:
> interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
> #address-cells = <3>;
> #size-cells = <0>;
> + hot-join-capable;
> + in-band-interrupt-capable;
> };
> ...
> --
> 2.34.1
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties
2026-09-08 17:54 ` Conor Dooley
@ 2026-09-09 16:21 ` Frank Li
2026-09-10 11:36 ` Conor Dooley
0 siblings, 1 reply; 8+ messages in thread
From: Frank Li @ 2026-09-09 16:21 UTC (permalink / raw)
To: Conor Dooley
Cc: Shubham Patil, alexandre.belloni, Frank.Li, robh, krzk+dt,
conor+dt, linux-i3c, devicetree, linux-kernel, git
On Tue, Sep 08, 2026 at 06:54:31PM +0100, Conor Dooley wrote:
> On Tue, Sep 08, 2026 at 03:12:55PM +0530, Shubham Patil wrote:
> > In-Band Interrupt and Hot-Join are synthesis-time options of the AXI I3C
> > IP. Describe them with two boolean properties.
> >
> > A Hot-Join request is acknowledged by the IBI machinery, so a hot-join
> > capable design is always IBI capable as well. Both events are reported
> > through the controller interrupt, which is therefore required whenever
> > the capability is present.
> >
> > Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
> > ---
> > Changes in V3:
> > - Move in-band-interrupt-capable and hot-join-capable into the common
> > i3c.yaml schema and drop the xlnx, prefix.
> > - Keep dependencies in the AMD binding.
> > - Update the commit description accordingly.
> > - Conor Dooley acked v2 with the xlnx,-prefixed properties in the AMD
> > binding [1].
> > That Acked-by is not carried here: the names lost the vendor prefix
> > and the definitions moved to i3c.yaml after Frank Li's comment.
> > [1]:https://lore.kernel.org/all/20260824-tightwad-impose-495476599087@spud/
>
> I disagree with Frank. These properties make sense for Xilinx because it
> is an FPGA IP and synthesis options impact this. For other devices, this
> should be determined from the compatible.
> Please revert to how things were done in v2, especially as no rationale
> was provided for why these should be common.
It is common problems, when IP intergrate by SOC, which may defeature some
part, It is not appeared now just because IBI and HJ have not enabled
widely.
IBI and HJ is optional features of I3C. Ideally it should be indicated by
some registers. But not all vendor implement provide this CAP registers.
IBI and HJ depend on some slow clocks, which monitor SDA line change.
Some instances of IP may not have such slow clocks. Some IP's IBI and HJ
use seperate IRQ line, but these irq line may not connect of difference
instances.
like previous SPI vendor customized property, we takes efforts to convert
to common one and also meet back compatiblity problem at convert. I don't
want to do it again. This kind property is most likely as below.
default: decide by comaptible string or hardware cap
force-disabled: force disable for some reason, like, miss connect irq line
or missed some clock, or IP bugs, or board desgin's some level shift chip
broken IBI/HJ timing requirements.
Frank
>
> pw-bot: changes-requested
>
> Thanks,
> Conor.
>
> >
> > Changes in V2:
> > - Rename the properties to "xlnx,in-band-interrupt-capable" and
> > "xlnx,hot-join-capable", and expand their descriptions.
> > - Express the interrupt requirement with dependencies: instead of an
> > allOf/if-then clause.
> > ---
> > Documentation/devicetree/bindings/i3c/i3c.yaml | 15 +++++++++++++++
> > .../devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml | 6 ++++++
> > 2 files changed, 21 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml
> > index e25fa72fd7857..7430394cc6b9b 100644
> > --- a/Documentation/devicetree/bindings/i3c/i3c.yaml
> > +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml
> > @@ -61,6 +61,21 @@ properties:
> > Indicates that the system is accessible via this bus as an endpoint for
> > MCTP over I3C transport.
> >
> > + in-band-interrupt-capable:
> > + type: boolean
> > + description:
> > + The controller supports In-Band Interrupts. A target can request
> > + attention on SDA/SCL by driving its dynamic address during bus
> > + arbitration, instead of using a dedicated side-band interrupt line.
> > +
> > + hot-join-capable:
> > + type: boolean
> > + description:
> > + The controller supports Hot-Join. A target attached or powered up
> > + after the bus is already running can announce itself using the
> > + reserved Hot-Join address so the controller can assign it a dynamic
> > + address.
> > +
> > required:
> > - "#address-cells"
> > - "#size-cells"
> > diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > index 2caa245a86568..9480de3fe8e1d 100644
> > --- a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > +++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > @@ -37,6 +37,10 @@ required:
> > - reg
> > - clocks
> >
> > +dependentRequired:
> > + hot-join-capable: [ in-band-interrupt-capable ]
> > + in-band-interrupt-capable: [ interrupts ]
> > +
> > allOf:
> > - $ref: i3c.yaml#
> >
> > @@ -54,5 +58,7 @@ examples:
> > interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
> > #address-cells = <3>;
> > #size-cells = <0>;
> > + hot-join-capable;
> > + in-band-interrupt-capable;
> > };
> > ...
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties
2026-09-09 16:21 ` Frank Li
@ 2026-09-10 11:36 ` Conor Dooley
2026-09-10 15:44 ` Frank Li
0 siblings, 1 reply; 8+ messages in thread
From: Conor Dooley @ 2026-09-10 11:36 UTC (permalink / raw)
To: Frank Li
Cc: Shubham Patil, alexandre.belloni, Frank.Li, robh, krzk+dt,
conor+dt, linux-i3c, devicetree, linux-kernel, git
[-- Attachment #1: Type: text/plain, Size: 6280 bytes --]
On Wed, Sep 09, 2026 at 11:21:41AM -0500, Frank Li wrote:
> On Tue, Sep 08, 2026 at 06:54:31PM +0100, Conor Dooley wrote:
> > On Tue, Sep 08, 2026 at 03:12:55PM +0530, Shubham Patil wrote:
> > > In-Band Interrupt and Hot-Join are synthesis-time options of the AXI I3C
> > > IP. Describe them with two boolean properties.
> > >
> > > A Hot-Join request is acknowledged by the IBI machinery, so a hot-join
> > > capable design is always IBI capable as well. Both events are reported
> > > through the controller interrupt, which is therefore required whenever
> > > the capability is present.
> > >
> > > Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
> > > ---
> > > Changes in V3:
> > > - Move in-band-interrupt-capable and hot-join-capable into the common
> > > i3c.yaml schema and drop the xlnx, prefix.
> > > - Keep dependencies in the AMD binding.
> > > - Update the commit description accordingly.
> > > - Conor Dooley acked v2 with the xlnx,-prefixed properties in the AMD
> > > binding [1].
> > > That Acked-by is not carried here: the names lost the vendor prefix
> > > and the definitions moved to i3c.yaml after Frank Li's comment.
> > > [1]:https://lore.kernel.org/all/20260824-tightwad-impose-495476599087@spud/
> >
> > I disagree with Frank. These properties make sense for Xilinx because it
> > is an FPGA IP and synthesis options impact this. For other devices, this
> > should be determined from the compatible.
> > Please revert to how things were done in v2, especially as no rationale
> > was provided for why these should be common.
>
> It is common problems, when IP intergrate by SOC, which may defeature some
> part, It is not appeared now just because IBI and HJ have not enabled
> widely.
>
> IBI and HJ is optional features of I3C. Ideally it should be indicated by
> some registers. But not all vendor implement provide this CAP registers.
>
> IBI and HJ depend on some slow clocks, which monitor SDA line change.
> Some instances of IP may not have such slow clocks. Some IP's IBI and HJ
> use seperate IRQ line, but these irq line may not connect of difference
> instances.
All of this should be able to be dealt with by appropriate use of
specific compatibles.
> like previous SPI vendor customized property, we takes efforts to convert
> to common one and also meet back compatiblity problem at convert. I don't
> want to do it again. This kind property is most likely as below.
What SPI controller specific properties are you talking about here?
There are relatively few properties in spi-controller.yaml, and none of
them deal with these kinds of capabilities.
>
> default: decide by comaptible string or hardware cap
> force-disabled: force disable for some reason, like, miss connect irq line
> or missed some clock, or IP bugs, or board desgin's some level shift chip
> broken IBI/HJ timing requirements.
Of these, only the last would be a valid reason for having a property
for it. Missing interrupts, clocks or IP bugs should all be dealt with
using device specific compatibles.
If board wiring causes the breakage, the property may be more
appropriate at the i3c device level rather than the controller given
that wiring to some devices on the bus may not have the problems?
That said, I think that problem should be dealt with when it arises,
rather than starting a trend of adding capabilities properties at the
controller level when I am not convinced that there's going to be other
users in the same vein.
Thanks,
Conor.
>
> Frank
>
> >
> > pw-bot: changes-requested
> >
> > Thanks,
> > Conor.
> >
> > >
> > > Changes in V2:
> > > - Rename the properties to "xlnx,in-band-interrupt-capable" and
> > > "xlnx,hot-join-capable", and expand their descriptions.
> > > - Express the interrupt requirement with dependencies: instead of an
> > > allOf/if-then clause.
> > > ---
> > > Documentation/devicetree/bindings/i3c/i3c.yaml | 15 +++++++++++++++
> > > .../devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml | 6 ++++++
> > > 2 files changed, 21 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml
> > > index e25fa72fd7857..7430394cc6b9b 100644
> > > --- a/Documentation/devicetree/bindings/i3c/i3c.yaml
> > > +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml
> > > @@ -61,6 +61,21 @@ properties:
> > > Indicates that the system is accessible via this bus as an endpoint for
> > > MCTP over I3C transport.
> > >
> > > + in-band-interrupt-capable:
> > > + type: boolean
> > > + description:
> > > + The controller supports In-Band Interrupts. A target can request
> > > + attention on SDA/SCL by driving its dynamic address during bus
> > > + arbitration, instead of using a dedicated side-band interrupt line.
> > > +
> > > + hot-join-capable:
> > > + type: boolean
> > > + description:
> > > + The controller supports Hot-Join. A target attached or powered up
> > > + after the bus is already running can announce itself using the
> > > + reserved Hot-Join address so the controller can assign it a dynamic
> > > + address.
> > > +
> > > required:
> > > - "#address-cells"
> > > - "#size-cells"
> > > diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > > index 2caa245a86568..9480de3fe8e1d 100644
> > > --- a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > > +++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > > @@ -37,6 +37,10 @@ required:
> > > - reg
> > > - clocks
> > >
> > > +dependentRequired:
> > > + hot-join-capable: [ in-band-interrupt-capable ]
> > > + in-band-interrupt-capable: [ interrupts ]
> > > +
> > > allOf:
> > > - $ref: i3c.yaml#
> > >
> > > @@ -54,5 +58,7 @@ examples:
> > > interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
> > > #address-cells = <3>;
> > > #size-cells = <0>;
> > > + hot-join-capable;
> > > + in-band-interrupt-capable;
> > > };
> > > ...
> > > --
> > > 2.34.1
> > >
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties
2026-09-10 11:36 ` Conor Dooley
@ 2026-09-10 15:44 ` Frank Li
0 siblings, 0 replies; 8+ messages in thread
From: Frank Li @ 2026-09-10 15:44 UTC (permalink / raw)
To: Conor Dooley
Cc: Shubham Patil, alexandre.belloni, Frank.Li, robh, krzk+dt,
conor+dt, linux-i3c, devicetree, linux-kernel, git
On Thu, Sep 10, 2026 at 12:36:45PM +0100, Conor Dooley wrote:
> On Wed, Sep 09, 2026 at 11:21:41AM -0500, Frank Li wrote:
> > On Tue, Sep 08, 2026 at 06:54:31PM +0100, Conor Dooley wrote:
> > > On Tue, Sep 08, 2026 at 03:12:55PM +0530, Shubham Patil wrote:
> > > > In-Band Interrupt and Hot-Join are synthesis-time options of the AXI I3C
> > > > IP. Describe them with two boolean properties.
> > > >
> > > > A Hot-Join request is acknowledged by the IBI machinery, so a hot-join
> > > > capable design is always IBI capable as well. Both events are reported
> > > > through the controller interrupt, which is therefore required whenever
> > > > the capability is present.
> > > >
> > > > Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
> > > > ---
> > > > Changes in V3:
> > > > - Move in-band-interrupt-capable and hot-join-capable into the common
> > > > i3c.yaml schema and drop the xlnx, prefix.
> > > > - Keep dependencies in the AMD binding.
> > > > - Update the commit description accordingly.
> > > > - Conor Dooley acked v2 with the xlnx,-prefixed properties in the AMD
> > > > binding [1].
> > > > That Acked-by is not carried here: the names lost the vendor prefix
> > > > and the definitions moved to i3c.yaml after Frank Li's comment.
> > > > [1]:https://lore.kernel.org/all/20260824-tightwad-impose-495476599087@spud/
> > >
> > > I disagree with Frank. These properties make sense for Xilinx because it
> > > is an FPGA IP and synthesis options impact this. For other devices, this
> > > should be determined from the compatible.
> > > Please revert to how things were done in v2, especially as no rationale
> > > was provided for why these should be common.
> >
> > It is common problems, when IP intergrate by SOC, which may defeature some
> > part, It is not appeared now just because IBI and HJ have not enabled
> > widely.
> >
> > IBI and HJ is optional features of I3C. Ideally it should be indicated by
> > some registers. But not all vendor implement provide this CAP registers.
> >
> > IBI and HJ depend on some slow clocks, which monitor SDA line change.
> > Some instances of IP may not have such slow clocks. Some IP's IBI and HJ
> > use seperate IRQ line, but these irq line may not connect of difference
> > instances.
>
> All of this should be able to be dealt with by appropriate use of
> specific compatibles.
I understand compatible can cover most cases. Need variance for property.
>
> > like previous SPI vendor customized property, we takes efforts to convert
> > to common one and also meet back compatiblity problem at convert. I don't
> > want to do it again. This kind property is most likely as below.
>
> What SPI controller specific properties are you talking about here?
> There are relatively few properties in spi-controller.yaml, and none of
> them deal with these kinds of capabilities.
num-cs vs fsl,espi-num-chipselects. Total number CS of IP is fixed, but
some instances have not route all CS to pad.
>
> >
> > default: decide by comaptible string or hardware cap
> > force-disabled: force disable for some reason, like, miss connect irq line
> > or missed some clock, or IP bugs, or board desgin's some level shift chip
> > broken IBI/HJ timing requirements.
>
> Of these, only the last would be a valid reason for having a property
> for it. Missing interrupts, clocks or IP bugs should all be dealt with
> using device specific compatibles.
> If board wiring causes the breakage, the property may be more
> appropriate at the i3c device level rather than the controller given
> that wiring to some devices on the bus may not have the problems?
I3C.yaml is for both master controller and devices now. I3C is bus, which
connect many devices, if wiring issue, whole bus can't support IBI. And
if any broken devices happen at address arbitation, whole bus can't support
IBI.
at beging, I suggest 3 state,
[default, enable, disable], but now I think IBI_broken, HJ_broken is more
reasonable to disable it, default value should be set by compatible
string or DCR of I3C regiser.
And some I3C device may be failure to work with IBI even DCR of I3C register
show it support IBI.
I don't want to appear two similar property between vendor and common, like
num-cs vs fsl,espi-num-chipselects.
such as IBI-broken can be used for controller and devices case.
> That said, I think that problem should be dealt with when it arises,
> rather than starting a trend of adding capabilities properties at the
> controller level when I am not convinced that there's going to be other
> users in the same vein.
Understand, I3C is realtive new protocal. 'IBI-broken' is more easy
understand, logically equial to in-band-interrupt-capable.
Frank
>
> Thanks,
> Conor.
>
>
> >
> > Frank
> >
> > >
> > > pw-bot: changes-requested
> > >
> > > Thanks,
> > > Conor.
> > >
> > > >
> > > > Changes in V2:
> > > > - Rename the properties to "xlnx,in-band-interrupt-capable" and
> > > > "xlnx,hot-join-capable", and expand their descriptions.
> > > > - Express the interrupt requirement with dependencies: instead of an
> > > > allOf/if-then clause.
> > > > ---
> > > > Documentation/devicetree/bindings/i3c/i3c.yaml | 15 +++++++++++++++
> > > > .../devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml | 6 ++++++
> > > > 2 files changed, 21 insertions(+)
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml
> > > > index e25fa72fd7857..7430394cc6b9b 100644
> > > > --- a/Documentation/devicetree/bindings/i3c/i3c.yaml
> > > > +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml
> > > > @@ -61,6 +61,21 @@ properties:
> > > > Indicates that the system is accessible via this bus as an endpoint for
> > > > MCTP over I3C transport.
> > > >
> > > > + in-band-interrupt-capable:
> > > > + type: boolean
> > > > + description:
> > > > + The controller supports In-Band Interrupts. A target can request
> > > > + attention on SDA/SCL by driving its dynamic address during bus
> > > > + arbitration, instead of using a dedicated side-band interrupt line.
> > > > +
> > > > + hot-join-capable:
> > > > + type: boolean
> > > > + description:
> > > > + The controller supports Hot-Join. A target attached or powered up
> > > > + after the bus is already running can announce itself using the
> > > > + reserved Hot-Join address so the controller can assign it a dynamic
> > > > + address.
> > > > +
> > > > required:
> > > > - "#address-cells"
> > > > - "#size-cells"
> > > > diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > > > index 2caa245a86568..9480de3fe8e1d 100644
> > > > --- a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > > > +++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> > > > @@ -37,6 +37,10 @@ required:
> > > > - reg
> > > > - clocks
> > > >
> > > > +dependentRequired:
> > > > + hot-join-capable: [ in-band-interrupt-capable ]
> > > > + in-band-interrupt-capable: [ interrupts ]
> > > > +
> > > > allOf:
> > > > - $ref: i3c.yaml#
> > > >
> > > > @@ -54,5 +58,7 @@ examples:
> > > > interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
> > > > #address-cells = <3>;
> > > > #size-cells = <0>;
> > > > + hot-join-capable;
> > > > + in-band-interrupt-capable;
> > > > };
> > > > ...
> > > > --
> > > > 2.34.1
> > > >
> >
> >
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-10 15:44 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-08 9:42 [PATCH v3 0/3] i3c: master: amd: Add IBI and hot-join support Shubham Patil
2026-09-08 9:42 ` [PATCH v3 1/3] dt-bindings: i3c: xlnx: Add IBI and hot-join capability properties Shubham Patil
2026-09-08 17:54 ` Conor Dooley
2026-09-09 16:21 ` Frank Li
2026-09-10 11:36 ` Conor Dooley
2026-09-10 15:44 ` Frank Li
2026-09-08 9:42 ` [PATCH v3 2/3] i3c: master: amd: Add support for in-band interrupts Shubham Patil
2026-09-08 9:42 ` [PATCH v3 3/3] i3c: master: amd: Add hot-join support Shubham Patil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®