mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] i3c: master: dw-i3c-master: HDR-BT support
@ 2026-10-13  8:04 Dineshkumar Parameswaran
  2026-10-13  8:04 ` [PATCH 1/2] i3c: Add HDR_BT mode to the I3C framework Dineshkumar Parameswaran
  2026-10-13  8:04 ` [PATCH 2/2] i3c: master: dw-i3c-master: add HDR-BT transfer support Dineshkumar Parameswaran
  0 siblings, 2 replies; 3+ messages in thread
From: Dineshkumar Parameswaran @ 2026-10-13  8:04 UTC (permalink / raw)
  To: linux-i3c
  Cc: alexandre.belloni, Frank.Li, linux-kernel, Dineshkumar Parameswaran

Hello,

This series adds HDR-BT (High Data Rate - Bulk Transport)
support to the Synopsys DesignWare I3C master driver.

The DesignWare controller provides hardware support for HDR-BT
transfers, but the current driver only supports SDR transfers.
This limitation prevents users from utilizing the higher
throughput capabilities available on supported hardware.

Patch Overview:
1. Add HDR-BT capability in the I3C framework.
2. Implement HDR-BT operation in the DesignWare master driver.

Dineshkumar Parameswaran.

Dineshkumar Parameswaran (2):
  i3c: Add HDR_BT mode to the I3C framework
  i3c: master: dw-i3c-master: add HDR-BT transfer support

 drivers/i3c/master/dw-i3c-master.c | 146 +++++++++++++++++++++--------
 include/linux/i3c/device.h         |   4 +-
 2 files changed, 109 insertions(+), 41 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] i3c: Add HDR_BT mode to the I3C framework
  2026-10-13  8:04 [PATCH 0/2] i3c: master: dw-i3c-master: HDR-BT support Dineshkumar Parameswaran
@ 2026-10-13  8:04 ` Dineshkumar Parameswaran
  2026-10-13  8:04 ` [PATCH 2/2] i3c: master: dw-i3c-master: add HDR-BT transfer support Dineshkumar Parameswaran
  1 sibling, 0 replies; 3+ messages in thread
From: Dineshkumar Parameswaran @ 2026-10-13  8:04 UTC (permalink / raw)
  To: linux-i3c
  Cc: alexandre.belloni, Frank.Li, linux-kernel, Dineshkumar Parameswaran

Enables representing HDR-BT capability in the core transfer mode
definitions.

Signed-off-by: Dineshkumar Parameswaran <parame@synopsys.com>
---
 include/linux/i3c/device.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index e30ea2cb13cb..87aa6bfab69d 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -43,13 +43,15 @@ enum i3c_error_code {
  * @I3C_HDR_DDR: DDR mode
  * @I3C_HDR_TSP: TSP mode
  * @I3C_HDR_TSL: TSL mode
+ * @I3C_HDR_BT: BT mode
  * @I3C_SDR: SDR mode (NOT HDR mode)
  */
 enum i3c_xfer_mode {
-	/* The below 3 value (I3C_HDR*) must match GETCAP1 Byte bit position */
+	/* The below 4 value (I3C_HDR*) must match GETCAP1 Byte bit position */
 	I3C_HDR_DDR = 0,
 	I3C_HDR_TSP = 1,
 	I3C_HDR_TSL = 2,
+	I3C_HDR_BT = 3,
 	/* Use for default SDR transfer mode */
 	I3C_SDR = 31,
 };
-- 
2.34.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 2/2] i3c: master: dw-i3c-master: add HDR-BT transfer support
  2026-10-13  8:04 [PATCH 0/2] i3c: master: dw-i3c-master: HDR-BT support Dineshkumar Parameswaran
  2026-10-13  8:04 ` [PATCH 1/2] i3c: Add HDR_BT mode to the I3C framework Dineshkumar Parameswaran
@ 2026-10-13  8:04 ` Dineshkumar Parameswaran
  1 sibling, 0 replies; 3+ messages in thread
From: Dineshkumar Parameswaran @ 2026-10-13  8:04 UTC (permalink / raw)
  To: linux-i3c
  Cc: alexandre.belloni, Frank.Li, linux-kernel, Dineshkumar Parameswaran

Key differences:
-Add HDR-BT support for the DesignWare I3C master by introducing the
unified command format required by HDR-BT transfers.
-The current driver builds legacy cmd_lo/cmd_hi command entries for SDR and
HDR-DDR only. HDR-BT requires a 4-DWORD unified command layout, so HDR-BT
transfers cannot be described correctly with the existing path.
- HDR BT mode uses to send data in blocks and protected using CRC.

Signed-off-by: Dineshkumar Parameswaran <parame@synopsys.com>
---
 drivers/i3c/master/dw-i3c-master.c | 146 +++++++++++++++++++++--------
 1 file changed, 106 insertions(+), 40 deletions(-)

diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 58c54746bbe5..fc58dea8fe4f 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -65,6 +65,29 @@
 #define COMMAND_PORT_DEV_COUNT(x)	(((x) << 21) & GENMASK(25, 21))
 #define COMMAND_PORT_ADDR_ASSGN_CMD	0x03
 
+#define COMMAND_PORT_UNIFIED_DWORD0_CMD			0x04
+#define COMMAND_PORT_UNIFIED_DWORD0_TID(x)		(((x) << 3) & GENMASK(6, 3))
+#define COMMAND_PORT_UNIFIED_DWORD0_RnW			BIT(8)
+#define COMMAND_PORT_UNIFIED_DWORD0_DEV_INDEX(x)	(((x) << 9) & GENMASK(13, 9))
+#define COMMAND_PORT_UNIFIED_DWORD0_SPEED_MODE(x)	(((x) << 19) & GENMASK(22, 19))
+#define COMMAND_PORT_UNIFIED_DWORD0_WROC		BIT(30)
+#define COMMAND_PORT_UNIFIED_DWORD0_TOC			BIT(31)
+
+#define COMMAND_PORT_UNIFIED_DWORD1_DATA_LENGTH(x)	((x) & GENMASK(22, 0))
+#define COMMAND_PORT_UNIFIED_DWORD1_MLANE_MODE(x)	(((x) << 24) & GENMASK(26, 24))
+#define COMMAND_PORT_UNIFIED_DWORD1_MLANE_CODE(x)	(((x) << 27) & GENMASK(29, 27))
+
+#define COMMAND_PORT_UNIFIED_DWORD2_IDB0_CCC_CMD0(x)	((x) & GENMASK(7, 0))
+#define COMMAND_PORT_UNIFIED_DWORD2_IDB1_DB_CMD1(x)	(((x) << 8) & GENMASK(15, 8))
+#define COMMAND_PORT_UNIFIED_DWORD2_IDB2_HDRCMD_CMD2(x)	(((x) << 16) & GENMASK(23, 16))
+#define COMMAND_PORT_UNIFIED_DWORD2_IDB3_CMD3(x)	(((x) << 24) & GENMASK(31, 24))
+
+#define COMMAND_PORT_UNIFIED_DWORD3_CONTROL(x)		((x) & GENMASK(7, 0))
+
+#define HDR_BT_SPD_MODE		0x8
+#define SINGLE_LANE		0x0
+#define SIZEOF_UNIFIED_CMD	4
+
 #define RESPONSE_QUEUE_PORT		0x10
 #define RESPONSE_PORT_ERR_STATUS(x)	(((x) & GENMASK(31, 28)) >> 28)
 #define RESPONSE_NO_ERROR		0
@@ -247,8 +270,15 @@
 #define DW_I3C_ACPI_SKIP_CLK_RST	BIT(3)
 
 struct dw_i3c_cmd {
-	u32 cmd_lo;
-	u32 cmd_hi;
+	bool is_unified_cmd;
+	union {
+		struct {
+			u32 cmd_lo;
+			u32 cmd_hi;
+			u32 data[2];
+		};
+		u32 unified_cmd[4];
+	} cmd_data;
 	u16 tx_len;
 	u16 rx_len;
 	u8 error;
@@ -402,7 +432,7 @@ dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds)
 static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master)
 {
 	struct dw_i3c_xfer *xfer = master->xferqueue.cur;
-	unsigned int i;
+	unsigned int i, k;
 	u32 thld_ctrl;
 
 	if (!xfer)
@@ -422,8 +452,14 @@ static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master)
 	for (i = 0; i < xfer->ncmds; i++) {
 		struct dw_i3c_cmd *cmd = &xfer->cmds[i];
 
-		writel(cmd->cmd_hi, master->regs + COMMAND_QUEUE_PORT);
-		writel(cmd->cmd_lo, master->regs + COMMAND_QUEUE_PORT);
+		if (cmd->is_unified_cmd) {
+			for (k = 0; k < SIZEOF_UNIFIED_CMD; k++)
+				writel(cmd->cmd_data.unified_cmd[k],
+				       master->regs + COMMAND_QUEUE_PORT);
+		} else {
+			writel(cmd->cmd_data.cmd_hi, master->regs + COMMAND_QUEUE_PORT);
+			writel(cmd->cmd_data.cmd_lo, master->regs + COMMAND_QUEUE_PORT);
+		}
 	}
 }
 
@@ -784,10 +820,10 @@ static int dw_i3c_ccc_set(struct dw_i3c_master *master,
 	cmd->tx_buf = ccc->dests[0].payload.data;
 	cmd->tx_len = ccc->dests[0].payload.len;
 
-	cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) |
+	cmd->cmd_data.cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) |
 		      COMMAND_PORT_TRANSFER_ARG;
 
-	cmd->cmd_lo = COMMAND_PORT_CP |
+	cmd->cmd_data.cmd_lo = COMMAND_PORT_CP |
 		      COMMAND_PORT_DEV_INDEX(pos) |
 		      COMMAND_PORT_CMD(ccc->id) |
 		      COMMAND_PORT_TOC |
@@ -823,10 +859,10 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
 	cmd->rx_buf = ccc->dests[0].payload.data;
 	cmd->rx_len = ccc->dests[0].payload.len;
 
-	cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) |
+	cmd->cmd_data.cmd_hi = COMMAND_PORT_ARG_DATA_LEN(ccc->dests[0].payload.len) |
 		      COMMAND_PORT_TRANSFER_ARG;
 
-	cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER |
+	cmd->cmd_data.cmd_lo = COMMAND_PORT_READ_TRANSFER |
 		      COMMAND_PORT_CP |
 		      COMMAND_PORT_DEV_INDEX(pos) |
 		      COMMAND_PORT_CMD(ccc->id) |
@@ -924,8 +960,8 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
 	}
 	cmd = &xfer->cmds[0];
 	cmd->rx_len = master->maxdevs;
-	cmd->cmd_hi = COMMAND_PORT_TRANSFER_ARG;
-	cmd->cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) |
+	cmd->cmd_data.cmd_hi = COMMAND_PORT_TRANSFER_ARG;
+	cmd->cmd_data.cmd_lo = COMMAND_PORT_DEV_COUNT(master->maxdevs - pos) |
 		      COMMAND_PORT_DEV_INDEX(pos) |
 		      COMMAND_PORT_CMD(I3C_CCC_ENTDAA) |
 		      COMMAND_PORT_ADDR_ASSGN_CMD |
@@ -999,33 +1035,63 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
 	for (i = 0; i < i3c_nxfers; i++) {
 		struct dw_i3c_cmd *cmd = &xfer->cmds[i];
 
-		cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) |
-			COMMAND_PORT_TRANSFER_ARG;
-
-		if (i3c_xfers[i].rnw) {
-			cmd->rx_buf = i3c_xfers[i].data.in;
-			cmd->rx_len = i3c_xfers[i].len;
-			cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER |
-				      COMMAND_PORT_SPEED(dev->info.max_read_ds);
-
+		if (mode == I3C_HDR_BT) {
+			cmd->cmd_data.unified_cmd[0] = COMMAND_PORT_UNIFIED_DWORD0_CMD |
+				COMMAND_PORT_UNIFIED_DWORD0_TID(i) |
+				COMMAND_PORT_UNIFIED_DWORD0_DEV_INDEX(data->index) |
+				COMMAND_PORT_UNIFIED_DWORD0_SPEED_MODE(HDR_BT_SPD_MODE) |
+				COMMAND_PORT_UNIFIED_DWORD0_WROC;
+			if (i3c_xfers[i].rnw) {
+				cmd->rx_buf = i3c_xfers[i].data.in;
+				cmd->rx_len = i3c_xfers[i].len;
+				cmd->cmd_data.unified_cmd[0] |= COMMAND_PORT_UNIFIED_DWORD0_RnW;
+			} else {
+				cmd->tx_buf = i3c_xfers[i].data.out;
+				cmd->tx_len = i3c_xfers[i].len;
+			}
+			cmd->cmd_data.unified_cmd[1] =
+				COMMAND_PORT_UNIFIED_DWORD1_DATA_LENGTH(i3c_xfers[i].len) |
+				COMMAND_PORT_UNIFIED_DWORD1_MLANE_CODE(SINGLE_LANE) |
+				COMMAND_PORT_UNIFIED_DWORD1_MLANE_MODE(SINGLE_LANE);
+			cmd->cmd_data.unified_cmd[2] =
+				COMMAND_PORT_UNIFIED_DWORD2_IDB0_CCC_CMD0(0x00) |
+				COMMAND_PORT_UNIFIED_DWORD2_IDB1_DB_CMD1(0x00) |
+				COMMAND_PORT_UNIFIED_DWORD2_IDB2_HDRCMD_CMD2(0x00) |
+				COMMAND_PORT_UNIFIED_DWORD2_IDB3_CMD3(0x00);
+			cmd->cmd_data.unified_cmd[3] = COMMAND_PORT_UNIFIED_DWORD3_CONTROL(0);
+			if (i == (i3c_nxfers - 1))
+				cmd->cmd_data.unified_cmd[0] |= COMMAND_PORT_UNIFIED_DWORD0_TOC;
+			cmd->is_unified_cmd = true;
 		} else {
-			cmd->tx_buf = i3c_xfers[i].data.out;
-			cmd->tx_len = i3c_xfers[i].len;
-			cmd->cmd_lo =
-				COMMAND_PORT_SPEED(dev->info.max_write_ds);
-		}
 
-		cmd->cmd_lo |= COMMAND_PORT_TID(i) |
-			       COMMAND_PORT_DEV_INDEX(data->index) |
-			       COMMAND_PORT_ROC;
-
-		if (mode == I3C_HDR_DDR)
-			cmd->cmd_lo |= COMMAND_PORT_CP |
-				COMMAND_PORT_CMD(I3C_CCC_ENTHDR(0)) |
-				COMMAND_PORT_SPEED(DW_I3C_HDR_DDR_SPEED);
-
-		if (i == (i3c_nxfers - 1))
-			cmd->cmd_lo |= COMMAND_PORT_TOC;
+			cmd->cmd_data.cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) |
+				COMMAND_PORT_TRANSFER_ARG;
+
+			if (i3c_xfers[i].rnw) {
+				cmd->rx_buf = i3c_xfers[i].data.in;
+				cmd->rx_len = i3c_xfers[i].len;
+				cmd->cmd_data.cmd_lo = COMMAND_PORT_READ_TRANSFER |
+					COMMAND_PORT_SPEED(dev->info.max_read_ds);
+
+			} else {
+				cmd->tx_buf = i3c_xfers[i].data.out;
+				cmd->tx_len = i3c_xfers[i].len;
+				cmd->cmd_data.cmd_lo =
+					COMMAND_PORT_SPEED(dev->info.max_write_ds);
+			}
+
+			cmd->cmd_data.cmd_lo |= COMMAND_PORT_TID(i) |
+				COMMAND_PORT_DEV_INDEX(data->index) |
+				COMMAND_PORT_ROC;
+
+			if (mode == I3C_HDR_DDR)
+				cmd->cmd_data.cmd_lo |= COMMAND_PORT_CP |
+					COMMAND_PORT_CMD(I3C_CCC_ENTHDR(0)) |
+					COMMAND_PORT_SPEED(DW_I3C_HDR_DDR_SPEED);
+
+			if (i == (i3c_nxfers - 1))
+				cmd->cmd_data.cmd_lo |= COMMAND_PORT_TOC;
+		}
 	}
 
 	dw_i3c_master_enqueue_xfer(master, xfer);
@@ -1162,15 +1228,15 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
 	for (i = 0; i < i2c_nxfers; i++) {
 		struct dw_i3c_cmd *cmd = &xfer->cmds[i];
 
-		cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i2c_xfers[i].len) |
+		cmd->cmd_data.cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i2c_xfers[i].len) |
 			COMMAND_PORT_TRANSFER_ARG;
 
-		cmd->cmd_lo = COMMAND_PORT_TID(i) |
+		cmd->cmd_data.cmd_lo = COMMAND_PORT_TID(i) |
 			      COMMAND_PORT_DEV_INDEX(data->index) |
 			      COMMAND_PORT_ROC;
 
 		if (i2c_xfers[i].flags & I2C_M_RD) {
-			cmd->cmd_lo |= COMMAND_PORT_READ_TRANSFER;
+			cmd->cmd_data.cmd_lo |= COMMAND_PORT_READ_TRANSFER;
 			cmd->rx_buf = i2c_xfers[i].buf;
 			cmd->rx_len = i2c_xfers[i].len;
 		} else {
@@ -1179,7 +1245,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
 		}
 
 		if (i == (i2c_nxfers - 1))
-			cmd->cmd_lo |= COMMAND_PORT_TOC;
+			cmd->cmd_data.cmd_lo |= COMMAND_PORT_TOC;
 	}
 
 	dw_i3c_master_enqueue_xfer(master, xfer);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-13  8:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-13  8:04 [PATCH 0/2] i3c: master: dw-i3c-master: HDR-BT support Dineshkumar Parameswaran
2026-10-13  8:04 ` [PATCH 1/2] i3c: Add HDR_BT mode to the I3C framework Dineshkumar Parameswaran
2026-10-13  8:04 ` [PATCH 2/2] i3c: master: dw-i3c-master: add HDR-BT transfer support Dineshkumar Parameswaran

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®