mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Dineshkumar Parameswaran <Dineshkumar.Parameswaran@synopsys.com>
To: linux-i3c@lists.infradead.org
Cc: alexandre.belloni@bootlin.com, Frank.Li@nxp.com,
	linux-kernel@vger.kernel.org,
	Dineshkumar Parameswaran <Dineshkumar.Parameswaran@synopsys.com>
Subject: [PATCH 2/2] i3c: master: dw-i3c-master: add HDR-BT transfer support
Date: Tue, 13 Oct 2026 13:34:13 +0530	[thread overview]
Message-ID: <20261013080413.7470-3-parame@synopsys.com> (raw)
In-Reply-To: <20261013080413.7470-1-parame@synopsys.com>

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


      parent reply	other threads:[~2026-10-13  8:06 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261013080413.7470-3-parame@synopsys.com \
    --to=dineshkumar.parameswaran@synopsys.com \
    --cc=Frank.Li@nxp.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=linux-i3c@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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®