diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index b0ff0e1..7099f5f 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -24,7 +24,8 @@
 #define DEVICE_CTRL			0x0
 #define DEV_CTRL_ENABLE			BIT(31)
 #define DEV_CTRL_RESUME			BIT(30)
-#define DEV_CTRL_HOT_JOIN_NACK		BIT(8)
+#define ADAPTIVE_I2C_I3C		BIT(27)
+#define DEV_CTRL_HJ_NACK		BIT(8)
 #define DEV_CTRL_I2C_SLAVE_PRESENT	BIT(7)
 
 #define DEVICE_ADDR			0x4
@@ -74,7 +75,17 @@
 
 #define RX_TX_DATA_PORT			0x14
 #define IBI_QUEUE_STATUS		0x18
+#define IBI_QUEUE_IBI_ID(x)		(((x) & GENMASK(15, 8)) >> 8)
+#define IBI_QUEUE_IBI_ADDR(x)		((x) >> 1)
+#define IBI_TYPE_HJ(x)			\
+	(IBI_QUEUE_IBI_ADDR((x)) == I3C_HOT_JOIN_ADDR && !((x) & BIT(0)))
+#define IBI_TYPE_MR(x)			\
+	(IBI_QUEUE_IBI_ADDR((x)) != I3C_HOT_JOIN_ADDR && !((x) & BIT(0)))
+#define IBI_TYPE_SIR(x)			\
+	(IBI_QUEUE_IBI_ADDR((x)) != I3C_HOT_JOIN_ADDR && ((x) & BIT(0)))
+
 #define QUEUE_THLD_CTRL			0x1c
+#define QUEUE_THLD_CTRL_IBI_STS_MASK	GENMASK(31, 24)
 #define QUEUE_THLD_CTRL_RESP_BUF_MASK	GENMASK(15, 8)
 #define QUEUE_THLD_CTRL_RESP_BUF(x)	(((x) - 1) << 8)
 
@@ -85,6 +96,8 @@
 #define IBI_MR_REQ_REJECT		0x2C
 #define IBI_SIR_REQ_REJECT		0x30
 #define IBI_REQ_REJECT_ALL		GENMASK(31, 0)
+#define IBI_SIR_REQ_ID(x)		((((x) & GENMASK(6, 5)) >> 5) + \
+					((x) & GENMASK(4, 0)))
 
 #define RESET_CTRL			0x34
 #define RESET_CTRL_IBI_QUEUE		BIT(5)
@@ -95,6 +108,12 @@
 #define RESET_CTRL_SOFT			BIT(0)
 
 #define SLV_EVENT_CTRL			0x38
+#define SLV_EVENT_MWL_UPDATED		BIT(7)
+#define SLV_EVENT_MRL_UPDATED		BIT(6)
+#define SLV_EVENT_HJ_INTR_REQ		BIT(3)
+#define SLV_EVENT_MASTER_INTR_REQ	BIT(1)
+#define SLV_EVENT_SLAVE_INTR_REQ	BIT(0)
+
 #define INTR_STATUS			0x3c
 #define INTR_STATUS_EN			0x40
 #define INTR_SIGNAL_EN			0x44
@@ -126,8 +145,15 @@
 					INTR_TX_THLD_STAT |		\
 					INTR_RX_THLD_STAT)
 
-#define INTR_MASTER_MASK		(INTR_TRANSFER_ERR_STAT |	\
-					 INTR_RESP_READY_STAT)
+#define INTR_MASTER_MASK		(INTR_BUSOWNER_UPDATE_STAT |	\
+					 INTR_TRANSFER_ERR_STAT |	\
+					 INTR_RESP_READY_STAT |		\
+					 INTR_IBI_THLD_STAT)
+
+#define INTR_SLAVE_MASK			(INTR_BUSOWNER_UPDATE_STAT |	\
+					 INTR_DEFSLV_STAT |		\
+					 INTR_TRANSFER_ERR_STAT |	\
+					 INTR_CCC_UPDATED_STAT)
 
 #define QUEUE_STATUS_LEVEL		0x4c
 #define QUEUE_STATUS_IBI_STATUS_CNT(x)	(((x) & GENMASK(28, 24)) >> 24)
@@ -140,20 +166,34 @@
 
 #define PRESENT_STATE			0x54
 #define CCC_DEVICE_STATUS		0x58
-#define DEVICE_ADDR_TABLE_POINTER	0x5c
-#define DEVICE_ADDR_TABLE_DEPTH(x)	(((x) & GENMASK(31, 16)) >> 16)
-#define DEVICE_ADDR_TABLE_ADDR(x)	((x) & GENMASK(7, 0))
+#define DEV_ADDR_TABLE_POINTER		0x5c
+#define DEV_ADDR_TABLE_DEPTH(x)		(((x) & GENMASK(31, 16)) >> 16)
+#define DEV_ADDR_TABLE_ADDR(x)		((x) & GENMASK(15, 0))
 
 #define DEV_CHAR_TABLE_POINTER		0x60
+#define DEV_CHAR_TABLE_RST_INDEX	(~GENMASK(24, 19))
+#define DEV_CHAR_TABLE_DEPTH(x)		(((x) & GENMASK(18, 12)) >> 12)
+#define DEV_CHAR_TABLE_ADDR(x)		((x) & GENMASK(11, 0))
+
 #define VENDOR_SPECIFIC_REG_POINTER	0x6c
 #define SLV_PID_VALUE			0x74
 #define SLV_CHAR_CTRL			0x78
+#define SLV_CHAR_CTRL_HDR_CAP(x)	(((x) & GENMASK(23, 16)) >> 16)
+#define SLV_CHAR_CTRL_DCR(x)		(((x) & GENMASK(15, 8)) >> 8)
+#define SLV_CHAR_CTRL_BCR(x)		((x) & GENMASK(7, 0))
+
 #define SLV_MAX_LEN			0x7c
 #define MAX_READ_TURNAROUND		0x80
 #define MAX_DATA_SPEED			0x84
 #define SLV_DEBUG_STATUS		0x88
+
 #define SLV_INTR_REQ			0x8c
+#define SLV_INTR_REQ_MIR		BIT(3)
+#define SLV_INTR_REQ_SIR		BIT(0)
+
 #define DEVICE_CTRL_EXTENDED		0xb0
+#define DEV_OP_MODE_SLAVE	BIT(0)
+
 #define SCL_I3C_OD_TIMING		0xb4
 #define SCL_I3C_PP_TIMING		0xb8
 #define SCL_I3C_TIMING_HCNT(x)		(((x) << 16) & GENMASK(23, 16))
@@ -176,9 +216,12 @@
 
 #define SCL_EXT_TERMN_LCNT_TIMING	0xcc
 #define BUS_FREE_TIMING			0xd4
+#define BUS_IBI_FREE(x)			(((x) << 16) & GENMASK(31, 16))
 #define BUS_I3C_MST_FREE(x)		((x) & GENMASK(15, 0))
 
 #define BUS_IDLE_TIMING			0xd8
+#define BUS_IDLE_TIME(x)		((x) & GENMASK(19, 0))
+
 #define I3C_VER_ID			0xe0
 #define I3C_VER_TYPE			0xe4
 #define EXTENDED_CAPABILITY		0xe8
@@ -189,8 +232,16 @@
 #define DEV_ADDR_TABLE_STATIC_ADDR(x)	((x) & GENMASK(6, 0))
 #define DEV_ADDR_TABLE_LOC(start, idx)	((start) + ((idx) << 2))
 
+#define DEV_CHAR_TABLE_LOC(start, idx, loc) \
+	((start) + ((idx) << 4) + ((loc) << 2))
+
+#define SEC_DEV_CHAR_TABLE_LOC(start, idx) \
+	((start) + ((idx) << 2))
+
 #define MAX_DEVS 32
 
+#define I3C_BUS_AVAIL_TIME_NS		1000
+#define I3C_BUS_IDLE_TIME_NS		1000000
 #define I3C_BUS_SDR1_SCL_RATE		8000000
 #define I3C_BUS_SDR2_SCL_RATE		6000000
 #define I3C_BUS_SDR3_SCL_RATE		4000000
@@ -201,7 +252,18 @@
 
 #define XFER_TIMEOUT (msecs_to_jiffies(1000))
 
+struct dw_i3c_defslvs_dct {
+	u8 static_addr;
+	u8 bcr;
+	u8 dcr_lvr;
+	u8 dyn_addr;
+};
+
 struct dw_i3c_master_caps {
+	u16 datstartaddr;
+	u16 datdepth;
+	u16 dctstartaddr;
+	u8 dctdepth;
 	u8 cmdfifodepth;
 	u8 datafifodepth;
 };
@@ -224,16 +286,32 @@ struct dw_i3c_xfer {
 	struct dw_i3c_cmd cmds[0];
 };
 
+enum type {
+	REQUEST = 1,
+	DELIVER,
+	HANDOFF,
+	TAKEOVER,
+};
+
 struct dw_i3c_master {
 	struct i3c_master_controller base;
-	u16 maxdevs;
-	u16 datstartaddr;
+	struct work_struct hj_work;
+	enum i3c_dr_mode dr_mode;
+	struct {
+		struct work_struct mr_work;
+		enum type type;
+		u8 addr;
+	} mastership;
 	u32 free_pos;
 	struct {
 		struct list_head list;
 		struct dw_i3c_xfer *cur;
 		spinlock_t lock;
 	} xferqueue;
+	struct {
+		struct i3c_dev_desc *slots[MAX_DEVS];
+		spinlock_t lock; /* spinlock for ibi handling */
+	} ibi;
 	struct dw_i3c_master_caps caps;
 	void __iomem *regs;
 	struct reset_control *core_rst;
@@ -244,7 +322,9 @@ struct dw_i3c_master {
 };
 
 struct dw_i3c_i2c_dev_data {
+	struct i3c_generic_ibi_pool *ibi_pool;
 	u8 index;
+	s8 ibi;
 };
 
 static u8 even_parity(u8 p)
@@ -276,6 +356,7 @@ static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
 	case I3C_CCC_SETMRL(true):
 	case I3C_CCC_SETMRL(false):
 	case I3C_CCC_ENTHDR(0):
+	case I3C_CCC_DEFSLVS:
 	case I3C_CCC_SETDASA:
 	case I3C_CCC_SETNEWDA:
 	case I3C_CCC_GETMWL:
@@ -283,6 +364,7 @@ static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
 	case I3C_CCC_GETPID:
 	case I3C_CCC_GETBCR:
 	case I3C_CCC_GETDCR:
+	case I3C_CCC_GETACCMST:
 	case I3C_CCC_GETSTATUS:
 	case I3C_CCC_GETMXDS:
 	case I3C_CCC_GETHDRCAP:
@@ -314,7 +396,7 @@ static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr)
 {
 	int pos;
 
-	for (pos = 0; pos < master->maxdevs; pos++) {
+	for (pos = 0; pos < master->caps.datdepth; pos++) {
 		if (addr == master->addrs[pos])
 			return pos;
 	}
@@ -324,12 +406,37 @@ static int dw_i3c_master_get_addr_pos(struct dw_i3c_master *master, u8 addr)
 
 static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master)
 {
-	if (!(master->free_pos & GENMASK(master->maxdevs - 1, 0)))
+	if (!(master->free_pos & GENMASK(master->caps.datdepth - 1, 0)))
 		return -ENOSPC;
 
 	return ffs(master->free_pos) - 1;
 }
 
+static void
+dw_i3c_master_add_defslvs(struct dw_i3c_master *master, int ndevs)
+{
+	struct i3c_ccc_dev_desc defslvs;
+	struct dw_i3c_defslvs_dct dct;
+	u32 *ptr = (u32 *)&dct;
+	int i;
+
+	for (i = 0; i < ndevs; i++) {
+		*ptr = readl(master->regs +
+			SEC_DEV_CHAR_TABLE_LOC(master->caps.dctstartaddr, i));
+
+		defslvs.dyn_addr = dct.dyn_addr >> 1;
+		if (dct.dyn_addr)
+			defslvs.dcr = dct.dcr_lvr;
+		else
+			defslvs.lvr = dct.dcr_lvr;
+
+		defslvs.bcr = dct.bcr;
+		defslvs.static_addr = dct.static_addr >> 1;
+
+		defslvs_populate_i3c_bus(&master->base, defslvs);
+	}
+}
+
 static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master,
 				     const u8 *bytes, int nbytes)
 {
@@ -539,7 +646,8 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
 	writel(scl_timing, master->regs + SCL_I3C_PP_TIMING);
 
 	if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT))
-		writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
+		writel(readl(master->regs + BUS_FREE_TIMING) |
+		       BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
 
 	lcnt = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period);
 	scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
@@ -582,7 +690,8 @@ static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
 		     SCL_I2C_FM_TIMING_LCNT(lcnt);
 	writel(scl_timing, master->regs + SCL_I2C_FM_TIMING);
 
-	writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
+	writel(readl(master->regs + BUS_FREE_TIMING) |
+	       BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
 	writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_I2C_SLAVE_PRESENT,
 	       master->regs + DEVICE_CTRL);
 
@@ -594,9 +703,11 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 	struct dw_i3c_master *master = to_dw_i3c_master(m);
 	struct i3c_bus *bus = i3c_master_get_bus(m);
 	struct i3c_device_info info = { };
-	u32 thld_ctrl;
+	u32 thld_ctrl, char_ctrl;
 	int ret;
 
+	dw_i3c_master_disable(master);
+
 	switch (bus->mode) {
 	case I3C_BUS_MODE_MIXED_FAST:
 	case I3C_BUS_MODE_MIXED_LIMITED:
@@ -613,38 +724,43 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
 		return -EINVAL;
 	}
 
-	thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
-	thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK;
-	writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
+	if (!m->secondary) {
+		thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
+		thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK &
+			     ~QUEUE_THLD_CTRL_IBI_STS_MASK;
+		writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
 
-	thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL);
-	thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF;
-	writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL);
+		thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL);
+		thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF;
+		writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL);
 
-	writel(INTR_ALL, master->regs + INTR_STATUS);
-	writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
-	writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
+		writel(INTR_ALL, master->regs + INTR_STATUS);
+		writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
+		writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
 
-	ret = i3c_master_get_free_addr(m, 0);
-	if (ret < 0)
-		return ret;
+		ret = i3c_master_get_free_addr(m, 0);
+		if (ret < 0)
+			return ret;
 
-	writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
-	       master->regs + DEVICE_ADDR);
+		writel(DEV_ADDR_DYNAMIC_ADDR_VALID | DEV_ADDR_DYNAMIC(ret),
+		       master->regs + DEVICE_ADDR);
+	}
+
+	if (!(readl(master->regs + DEVICE_ADDR) & DEV_ADDR_DYNAMIC_ADDR_VALID))
+		return -EINVAL;
 
 	memset(&info, 0, sizeof(info));
-	info.dyn_addr = ret;
+	char_ctrl = readl(master->regs + SLV_CHAR_CTRL);
+	info.hdr_cap = SLV_CHAR_CTRL_HDR_CAP(char_ctrl);
+	info.dcr = SLV_CHAR_CTRL_DCR(char_ctrl);
+	info.bcr = SLV_CHAR_CTRL_BCR(char_ctrl);
+	info.dyn_addr = readl(master->regs + DEVICE_ADDR) >> 16 & GENMASK(6, 0);
 
 	ret = i3c_master_set_info(&master->base, &info);
 	if (ret)
 		return ret;
 
 	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_SIR_REQ_REJECT);
-	writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
-
-	/* For now don't support Hot-Join */
-	writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
-	       master->regs + DEVICE_CTRL);
 
 	dw_i3c_master_enable(master);
 
@@ -770,7 +886,7 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
 	olddevs = ~(master->free_pos);
 
 	/* Prepare DAT before launching DAA. */
-	for (pos = 0; pos < master->maxdevs; pos++) {
+	for (pos = 0; pos < master->caps.datdepth; pos++) {
 		if (olddevs & BIT(pos))
 			continue;
 
@@ -785,7 +901,7 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
 
 		writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(ret),
 		       master->regs +
-		       DEV_ADDR_TABLE_LOC(master->datstartaddr, pos));
+		       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr, pos));
 	}
 
 	xfer = dw_i3c_master_alloc_xfer(master, 1);
@@ -795,7 +911,7 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
 	pos = dw_i3c_master_get_free_pos(master);
 	cmd = &xfer->cmds[0];
 	cmd->cmd_hi = 0x1;
-	cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) |
+	cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->caps.datdepth - pos) |
 		      COMMAND_PORT_DEV_INDEX(pos) |
 		      COMMAND_PORT_CMD(I3C_CCC_ENTDAA) |
 		      COMMAND_PORT_ADDR_ASSGN_CMD |
@@ -806,20 +922,20 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
 	if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
 		dw_i3c_master_dequeue_xfer(master, xfer);
 
-	newdevs = GENMASK(master->maxdevs - cmd->rx_len - 1, 0);
+	newdevs = GENMASK(master->caps.datdepth - cmd->rx_len - 1, 0);
 	newdevs &= ~olddevs;
 
-	for (pos = 0; pos < master->maxdevs; pos++) {
+	for (pos = 0; pos < master->caps.datdepth; pos++) {
 		if (newdevs & BIT(pos))
 			i3c_master_add_i3c_dev_locked(m, master->addrs[pos]);
 	}
 
 	dw_i3c_master_free_xfer(xfer);
 
-	i3c_master_disec_locked(m, I3C_BROADCAST_ADDR,
+	i3c_master_defslvs_locked(&master->base);
+	i3c_master_enec_locked(m, I3C_BROADCAST_ADDR,
 				I3C_CCC_EVENT_HJ |
-				I3C_CCC_EVENT_MR |
-				I3C_CCC_EVENT_SIR);
+				I3C_CCC_EVENT_MR);
 
 	return 0;
 }
@@ -899,10 +1015,27 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
 	struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct dw_i3c_master *master = to_dw_i3c_master(m);
+	int pos;
+
+	pos = dw_i3c_master_get_free_pos(master);
+
+	if (data->index > pos && pos > 0) {
+		writel(0,
+		       master->regs +
+		       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr,
+					  data->index));
+
+		master->addrs[data->index] = 0;
+		master->free_pos |= BIT(data->index);
+
+		data->index = pos;
+		master->addrs[pos] = dev->info.dyn_addr;
+		master->free_pos &= ~BIT(pos);
+	}
 
 	writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr),
 	       master->regs +
-	       DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+	       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr, data->index));
 
 	master->addrs[data->index] = dev->info.dyn_addr;
 
@@ -931,7 +1064,7 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
 
 	writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->addrs[pos]),
 	       master->regs +
-	       DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+	       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr, data->index));
 
 	return 0;
 }
@@ -944,7 +1077,7 @@ static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
 
 	writel(0,
 	       master->regs +
-	       DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+	       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr, data->index));
 
 	i3c_dev_set_master_data(dev, NULL);
 	master->addrs[data->index] = 0;
@@ -1040,7 +1173,7 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
 	writel(DEV_ADDR_TABLE_LEGACY_I2C_DEV |
 	       DEV_ADDR_TABLE_STATIC_ADDR(dev->addr),
 	       master->regs +
-	       DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+	       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr, data->index));
 
 	return 0;
 }
@@ -1053,7 +1186,7 @@ static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
 
 	writel(0,
 	       master->regs +
-	       DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
+	       DEV_ADDR_TABLE_LOC(master->caps.datstartaddr, data->index));
 
 	i2c_dev_set_master_data(dev, NULL);
 	master->addrs[data->index] = 0;
@@ -1061,7 +1194,153 @@ static void dw_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
 	kfree(data);
 }
 
-static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id)
+static void dw_i3c_master_handle_sir(struct dw_i3c_master *master, u8 addr)
+{
+	struct dw_i3c_i2c_dev_data *data;
+	struct i3c_dev_desc *dev;
+	struct i3c_ibi_slot *slot;
+	int pos;
+
+	pos = dw_i3c_master_get_addr_pos(master, addr);
+	if (pos < 0)
+		return;
+
+	dev = master->ibi.slots[pos];
+
+	spin_lock(&master->ibi.lock);
+	data = i3c_dev_get_master_data(dev);
+	slot = i3c_generic_ibi_get_free_slot(data->ibi_pool);
+	if (!slot) {
+		spin_unlock(&master->ibi.lock);
+		return;
+	}
+	i3c_master_queue_ibi(dev, slot);
+	spin_unlock(&master->ibi.lock);
+}
+
+static void dw_i3c_master_demux_ibis(struct dw_i3c_master *master)
+{
+	u32 nibis;
+	int i;
+
+	nibis = readl(master->regs + QUEUE_STATUS_LEVEL);
+	nibis = QUEUE_STATUS_IBI_BUF_BLR(nibis);
+
+	for (i = 0; i < nibis; i++) {
+		u32 ibir = readl(master->regs + IBI_QUEUE_STATUS);
+		u8 id = IBI_QUEUE_IBI_ID(ibir);
+
+		if (IBI_TYPE_HJ(id))
+			queue_work(master->base.wq, &master->hj_work);
+		else if (IBI_TYPE_SIR(id))
+			dw_i3c_master_handle_sir(master,
+						 IBI_QUEUE_IBI_ADDR(id));
+		else if (IBI_TYPE_MR(id)) {
+			master->mastership.addr = IBI_QUEUE_IBI_ADDR(id);
+			master->mastership.type = DELIVER;
+			queue_work(master->base.wq,
+				   &master->mastership.mr_work);
+		}
+	}
+}
+
+static void dw_i3c_master_bus_handoff(struct dw_i3c_master *master)
+{
+	u32 thld_ctrl;
+
+	writel(RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO |
+	       RESET_CTRL_RESP_QUEUE | RESET_CTRL_CMD_QUEUE,
+	       master->regs + RESET_CTRL);
+
+	thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
+	thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK;
+	writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
+
+	writel(INTR_ALL, master->regs + INTR_STATUS);
+	writel(INTR_SLAVE_MASK, master->regs + INTR_STATUS_EN);
+	writel(INTR_SLAVE_MASK, master->regs + INTR_SIGNAL_EN);
+
+	writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME,
+	       master->regs + DEVICE_CTRL);
+
+	master->mastership.type = HANDOFF;
+	queue_work(master->base.wq, &master->mastership.mr_work);
+}
+
+static void dw_i3c_sec_master_bus_takeover(struct dw_i3c_master *master)
+{
+	u32 thld_ctrl;
+
+	writel(RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO |
+	       RESET_CTRL_RESP_QUEUE | RESET_CTRL_CMD_QUEUE,
+	       master->regs + RESET_CTRL);
+
+	thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
+	thld_ctrl &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK &
+		     ~QUEUE_THLD_CTRL_IBI_STS_MASK;
+	writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
+
+	thld_ctrl = readl(master->regs + DATA_BUFFER_THLD_CTRL);
+	thld_ctrl &= ~DATA_BUFFER_THLD_CTRL_RX_BUF;
+	writel(thld_ctrl, master->regs + DATA_BUFFER_THLD_CTRL);
+
+	writel(INTR_ALL, master->regs + INTR_STATUS);
+	writel(INTR_MASTER_MASK, master->regs + INTR_STATUS_EN);
+	writel(INTR_MASTER_MASK, master->regs + INTR_SIGNAL_EN);
+
+	writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME,
+	       master->regs + DEVICE_CTRL);
+
+	master->mastership.type = TAKEOVER;
+	queue_work(master->base.wq, &master->mastership.mr_work);
+}
+
+static void
+dw_i3c_sec_master_irq_handler(struct dw_i3c_master *master, u32 status)
+{
+	bool do_mr = false;
+	u32 ret;
+
+	if (status & INTR_TRANSFER_ERR_STAT)
+		writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS);
+
+	if (status & INTR_DEFSLV_STAT) {
+		ret = readl(master->regs + RESPONSE_QUEUE_PORT);
+		dw_i3c_master_add_defslvs(master, RESPONSE_PORT_DATA_LEN(ret));
+		writel(INTR_DEFSLV_STAT, master->regs + INTR_STATUS);
+		do_mr = true;
+	}
+
+	if (status & INTR_CCC_UPDATED_STAT) {
+		do_mr = true;
+		writel(INTR_CCC_UPDATED_STAT, master->regs + INTR_STATUS);
+	}
+
+	if (status & INTR_BUSOWNER_UPDATE_STAT) {
+		dw_i3c_master_bus_handoff(master);
+		writel(INTR_BUSOWNER_UPDATE_STAT, master->regs + INTR_STATUS);
+	}
+
+	if (!list_empty(&master->base.defslvs) && do_mr &&
+	    (readl(master->regs + SLV_EVENT_CTRL) & SLV_EVENT_MASTER_INTR_REQ)) {
+		master->mastership.type = REQUEST;
+		queue_work(master->base.wq, &master->mastership.mr_work);
+	}
+}
+
+static void
+dw_i3c_master_irq_handler(struct dw_i3c_master *master, u32 status)
+{
+	if (status & INTR_IBI_THLD_STAT)
+		dw_i3c_master_demux_ibis(master);
+
+	if (status & INTR_BUSOWNER_UPDATE_STAT) {
+		dw_i3c_sec_master_bus_takeover(master);
+		writel(INTR_BUSOWNER_UPDATE_STAT, master->regs + INTR_STATUS);
+	}
+}
+
+static irqreturn_t dw_i3c_irq_handler(int irq, void *dev_id)
 {
 	struct dw_i3c_master *master = dev_id;
 	u32 status;
@@ -1079,9 +1358,143 @@ static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id)
 		writel(INTR_TRANSFER_ERR_STAT, master->regs + INTR_STATUS);
 	spin_unlock(&master->xferqueue.lock);
 
+	if (readl(master->regs + DEVICE_CTRL_EXTENDED) & DEV_OP_MODE_SLAVE)
+		dw_i3c_sec_master_irq_handler(master, status);
+	else
+		dw_i3c_master_irq_handler(master, status);
+
 	return IRQ_HANDLED;
 }
 
+static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
+{
+	struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+	struct i3c_master_controller *m = i3c_dev_get_master(dev);
+	struct dw_i3c_master *master = to_dw_i3c_master(m);
+	unsigned long flags;
+	u32 sirmap;
+	int ret;
+
+	ret = i3c_master_disec_locked(m, dev->info.dyn_addr,
+				      I3C_CCC_EVENT_SIR);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&master->ibi.lock, flags);
+	sirmap = readl(master->regs + IBI_SIR_REQ_REJECT);
+	sirmap |= BIT(data->ibi);
+	writel(sirmap, master->regs + IBI_SIR_REQ_REJECT);
+	spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+	return ret;
+}
+
+static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
+{
+	struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+	struct i3c_master_controller *m = i3c_dev_get_master(dev);
+	struct dw_i3c_master *master = to_dw_i3c_master(m);
+	unsigned long flags;
+	u32 sirmap;
+	int ret;
+
+	spin_lock_irqsave(&master->ibi.lock, flags);
+	sirmap = readl(master->regs + IBI_SIR_REQ_REJECT);
+	sirmap &= ~BIT(data->ibi);
+	writel(sirmap, master->regs + IBI_SIR_REQ_REJECT);
+	spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+	ret = i3c_master_enec_locked(m, dev->info.dyn_addr,
+				     I3C_CCC_EVENT_SIR);
+	if (ret) {
+		spin_lock_irqsave(&master->ibi.lock, flags);
+		sirmap = readl(master->regs + IBI_SIR_REQ_REJECT);
+		sirmap |= BIT(data->ibi);
+		writel(sirmap, master->regs + IBI_SIR_REQ_REJECT);
+		spin_unlock_irqrestore(&master->ibi.lock, flags);
+	}
+
+	return ret;
+}
+
+static int dw_i3c_master_request_ibi(struct i3c_dev_desc *dev,
+				     const struct i3c_ibi_setup *req)
+{
+	struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+	struct i3c_master_controller *m = i3c_dev_get_master(dev);
+	struct dw_i3c_master *master = to_dw_i3c_master(m);
+	unsigned long flags;
+
+	if (req->max_payload_len > 0)
+		return -ENOTSUPP;
+
+	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
+	if (IS_ERR(data->ibi_pool))
+		return PTR_ERR(data->ibi_pool);
+
+	spin_lock_irqsave(&master->ibi.lock, flags);
+	data->ibi = IBI_SIR_REQ_ID(dev->info.dyn_addr);
+	master->ibi.slots[data->index] = dev;
+	spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+	return 0;
+}
+
+static void dw_i3c_master_free_ibi(struct i3c_dev_desc *dev)
+{
+	struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+	struct i3c_master_controller *m = i3c_dev_get_master(dev);
+	struct dw_i3c_master *master = to_dw_i3c_master(m);
+	unsigned long flags;
+
+	spin_lock_irqsave(&master->ibi.lock, flags);
+	master->ibi.slots[data->index] = NULL;
+	data->ibi = -1;
+	spin_unlock_irqrestore(&master->ibi.lock, flags);
+
+	i3c_generic_ibi_free_pool(data->ibi_pool);
+}
+
+static void dw_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
+					   struct i3c_ibi_slot *slot)
+{
+	struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+
+	i3c_generic_ibi_recycle_slot(data->ibi_pool, slot);
+}
+
+static int
+dw_i3c_sec_master_request_mastership(struct i3c_master_controller *m)
+{
+	struct dw_i3c_master *master = to_dw_i3c_master(m);
+	u32 status;
+	int ret;
+
+	if (!m->secondary)
+		return -EINVAL;
+
+	if (!(readl(master->regs + DEVICE_ADDR) & DEV_ADDR_DYNAMIC_ADDR_VALID))
+		return -EINVAL;
+
+	if (!(readl(master->regs + SLV_EVENT_CTRL) & SLV_EVENT_MASTER_INTR_REQ))
+		return -EINVAL;
+
+	writel(readl(master->regs + SLV_INTR_REQ) |
+	       SLV_INTR_REQ_MIR, master->regs + SLV_INTR_REQ);
+
+	ret = readl_poll_timeout(master->regs + SLV_INTR_REQ, status,
+				 ((status & BIT(8)) && !(status & BIT(9))),
+				 100, 1000000);
+
+	return ret;
+}
+
+static int
+dw_i3c_master_deliver_mastership(struct i3c_master_controller *m, u8 addr)
+{
+	return i3c_master_getaccmst_locked(m, addr);
+}
+
 static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
 	.bus_init = dw_i3c_master_bus_init,
 	.bus_cleanup = dw_i3c_master_bus_cleanup,
@@ -1095,12 +1508,74 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
 	.attach_i2c_dev = dw_i3c_master_attach_i2c_dev,
 	.detach_i2c_dev = dw_i3c_master_detach_i2c_dev,
 	.i2c_xfers = dw_i3c_master_i2c_xfers,
+	.enable_ibi = dw_i3c_master_enable_ibi,
+	.disable_ibi = dw_i3c_master_disable_ibi,
+	.request_ibi = dw_i3c_master_request_ibi,
+	.free_ibi = dw_i3c_master_free_ibi,
+	.recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot,
+	.request_mastership = dw_i3c_sec_master_request_mastership,
+	.deliver_mastership = dw_i3c_master_deliver_mastership,
 };
 
+static void dw_i3c_master_hj(struct work_struct *work)
+{
+	struct dw_i3c_master *master = container_of(work, struct dw_i3c_master,
+						    hj_work);
+
+	i3c_master_do_daa(&master->base);
+}
+
+static void dw_i3c_master_mr(struct work_struct *work)
+{
+	struct dw_i3c_master *master = container_of(work,
+						   struct dw_i3c_master,
+						   mastership.mr_work);
+
+	switch (master->mastership.type) {
+	case REQUEST:
+		i3c_sec_master_request_mastership(&master->base);
+		break;
+	case DELIVER:
+		i3c_master_deliver_mastership(&master->base,
+					      master->mastership.addr);
+		break;
+	case HANDOFF:
+		i3c_master_switch_operation_mode(&master->base, true);
+		break;
+	case TAKEOVER:
+		i3c_master_switch_operation_mode(&master->base, false);
+		break;
+	default:
+		break;
+	}
+}
+
+static int dw_i3c_sec_master_init(struct dw_i3c_master *master)
+{
+	u32 ret;
+
+	ret = readl(master->regs + QUEUE_THLD_CTRL);
+	ret &= ~QUEUE_THLD_CTRL_RESP_BUF_MASK;
+	writel(ret, master->regs + QUEUE_THLD_CTRL);
+
+	writel(INTR_SLAVE_MASK, master->regs + INTR_STATUS_EN);
+	writel(INTR_SLAVE_MASK, master->regs + INTR_SIGNAL_EN);
+
+	writel(ADAPTIVE_I2C_I3C, master->regs + DEVICE_CTRL);
+	writel(DEV_OP_MODE_SLAVE, master->regs + DEVICE_CTRL_EXTENDED);
+
+	dw_i3c_master_enable(master);
+
+	return 0;
+}
+
 static int dw_i3c_probe(struct platform_device *pdev)
 {
+	unsigned long core_rate, core_period;
 	struct dw_i3c_master *master;
 	struct resource *res;
+	u16 avail_timing;
+	u32 idle_timing;
 	int ret, irq;
 
 	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
@@ -1127,13 +1602,16 @@ static int dw_i3c_probe(struct platform_device *pdev)
 
 	reset_control_deassert(master->core_rst);
 
+	spin_lock_init(&master->ibi.lock);
 	spin_lock_init(&master->xferqueue.lock);
 	INIT_LIST_HEAD(&master->xferqueue.list);
+	INIT_WORK(&master->hj_work, dw_i3c_master_hj);
+	INIT_WORK(&master->mastership.mr_work, dw_i3c_master_mr);
 
 	writel(INTR_ALL, master->regs + INTR_STATUS);
 	irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(&pdev->dev, irq,
-			       dw_i3c_master_irq_handler, 0,
+			       dw_i3c_irq_handler, 0,
 			       dev_name(&pdev->dev), master);
 	if (ret)
 		goto err_assert_rst;
@@ -1147,15 +1625,44 @@ static int dw_i3c_probe(struct platform_device *pdev)
 	ret = readl(master->regs + DATA_BUFFER_STATUS_LEVEL);
 	master->caps.datafifodepth = DATA_BUFFER_STATUS_LEVEL_TX(ret);
 
-	ret = readl(master->regs + DEVICE_ADDR_TABLE_POINTER);
-	master->datstartaddr = ret;
-	master->maxdevs = ret >> 16;
-	master->free_pos = GENMASK(master->maxdevs - 1, 0);
+	ret = readl(master->regs + DEV_ADDR_TABLE_POINTER);
+	master->caps.datstartaddr = DEV_ADDR_TABLE_ADDR(ret);
+	master->caps.datdepth = DEV_ADDR_TABLE_DEPTH(ret);
 
-	ret = i3c_master_register(&master->base, &pdev->dev,
-				  &dw_mipi_i3c_ops, false);
-	if (ret)
-		goto err_assert_rst;
+	ret = readl(master->regs + DEV_CHAR_TABLE_POINTER);
+	master->caps.dctstartaddr = DEV_CHAR_TABLE_ADDR(ret);
+	master->caps.dctdepth = DEV_CHAR_TABLE_DEPTH(ret);
+
+	master->free_pos = GENMASK(master->caps.datdepth - 1, 0);
+
+	core_rate = clk_get_rate(master->core_clk);
+	if (!core_rate)
+		return -EINVAL;
+
+	core_period = DIV_ROUND_UP(1000000000, core_rate);
+
+	avail_timing = DIV_ROUND_UP(I3C_BUS_AVAIL_TIME_NS, core_period);
+	writel(readl(master->regs + BUS_FREE_TIMING) |
+	       BUS_IBI_FREE(avail_timing), master->regs + BUS_FREE_TIMING);
+
+	idle_timing = DIV_ROUND_UP(I3C_BUS_IDLE_TIME_NS, core_period);
+	writel(readl(master->regs + BUS_IDLE_TIMING) |
+	       BUS_IDLE_TIME(idle_timing), master->regs + BUS_IDLE_TIMING);
+
+	master->dr_mode = i3c_get_dr_mode(&pdev->dev);
+
+	if (master->dr_mode == I3C_DR_MODE_MASTER) {
+		if (i3c_master_register(&master->base, &pdev->dev,
+					&dw_mipi_i3c_ops, false))
+			goto err_assert_rst;
+	} else {
+		if (dw_i3c_sec_master_init(master))
+			goto err_assert_rst;
+
+		if (i3c_master_register(&master->base, &pdev->dev,
+					&dw_mipi_i3c_ops, true))
+			goto err_assert_rst;
+	}
 
 	return 0;
 
