From: Frank Li <Frank.Li@nxp.com>
To: imx@lists.linux.dev, Miquel Raynal <miquel.raynal@bootlin.com>,
Conor Culhane <conor.culhane@silvaco.com>,
Alexandre Belloni <alexandre.belloni@bootlin.com>,
linux-i3c@lists.infradead.org (moderated list:SILVACO I3C
DUAL-ROLE MASTER), linux-kernel@vger.kernel.org (open list)
Subject: [PATCH 1/1] i3c: master: svc: add support for read len bigger than 255
Date: Wed, 17 Jan 2024 17:50:09 -0500 [thread overview]
Message-ID: <20240117225009.2931699-1-Frank.Li@nxp.com> (raw)
RDTERM is 8bit. Only support max 255 read transfer for auto terminate. Use
manual terminate when read len bigger than 255.
When left data length is FIFO size + 1, issue terminate
(RDTERM(1) | REQUEST_NONE). So hardware will stop fetch data after next
data.
│ ◄────────── buff length ────────►│
│ │
│ ┌─┬─────────────┤
│ │ │ FIFO SIZE │
│ └─┴─────────────┘
▲
│
Wait FIFO Full and Issue read termniate here!!
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/i3c/master/svc-i3c-master.c | 76 ++++++++++++++++++++++++-----
1 file changed, 64 insertions(+), 12 deletions(-)
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 5ee4db68988e2..58047ad357791 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -977,7 +977,7 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
}
static int svc_i3c_master_read(struct svc_i3c_master *master,
- u8 *in, unsigned int len)
+ u8 *in, unsigned int len, bool auto_term)
{
int offset = 0, i;
u32 mdctrl, mstatus;
@@ -995,16 +995,60 @@ static int svc_i3c_master_read(struct svc_i3c_master *master,
return -ETIMEDOUT;
}
- mdctrl = readl(master->regs + SVC_I3C_MDATACTRL);
- count = SVC_I3C_MDATACTRL_RXCOUNT(mdctrl);
- if (offset + count > len) {
- dev_err(master->dev, "I3C receive length too long!\n");
- return -EINVAL;
- }
- for (i = 0; i < count; i++)
- in[offset + i] = readl(master->regs + SVC_I3C_MRDATAB);
+ if (auto_term || completed) {
+ /* auto termate or early termate by target */
+ mdctrl = readl(master->regs + SVC_I3C_MDATACTRL);
+ count = SVC_I3C_MDATACTRL_RXCOUNT(mdctrl);
+ if (offset + count > len) {
+ dev_err(master->dev, "I3C receive length too long!\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < count; i++)
+ in[offset + i] = readl(master->regs + SVC_I3C_MRDATAB);
+
+ offset += count;
- offset += count;
+ } else {
+ /*
+ * Controller will fill whole RX FIFO in manual mode. FIFO full can prevent
+ * controller continue fetch data from target.
+ *
+ * When left data length is FIFO size + 1, issue terminate
+ * (RDTERM(1) | REQUEST_NONE). So hardware will stop fetch data after next
+ * data.
+ *
+ * │ ◄────────── buff length ────────►│
+ * │ │
+ * │ ┌─┬─────────────┤
+ * │ │ │ FIFO SIZE │
+ * │ └─┴─────────────┘
+ * ▲
+ * │
+ * Wait FIFO Full and Issue read termniate here!!
+ */
+ mdctrl = readl_relaxed(master->regs + SVC_I3C_MDATACTRL);
+ count = SVC_I3C_MDATACTRL_RXCOUNT(mdctrl);
+
+ if (offset + count + SVC_I3C_FIFO_SIZE < len) {
+ for (i = 0; i < count; i++) {
+ in[offset] = readl_relaxed(master->regs + SVC_I3C_MRDATAB);
+ offset++;
+ }
+ } else {
+ if (count != SVC_I3C_FIFO_SIZE)
+ continue;
+
+ /* Issue manual read terminate at next data */
+ if (offset + SVC_I3C_FIFO_SIZE == len - 1)
+ writel_relaxed(SVC_I3C_MCTRL_REQUEST_NONE |
+ SVC_I3C_MCTRL_DIR(1) |
+ SVC_I3C_MCTRL_RDTERM(1),
+ master->regs + SVC_I3C_MCTRL);
+
+ in[offset] = readl_relaxed(master->regs + SVC_I3C_MRDATAB);
+ offset++;
+ }
+ }
}
return offset;
@@ -1042,9 +1086,17 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
u8 *in, const u8 *out, unsigned int xfer_len,
unsigned int *actual_len, bool continued)
{
+ int rdterm = 0;
u32 reg;
int ret;
+ if (rnw)
+ rdterm = xfer_len;
+
+ /* If read length > max RDTERM in MCTRL, using manual terminate */
+ if (xfer_len > 255)
+ rdterm = 0;
+
/* clean SVC_I3C_MINT_IBIWON w1c bits */
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
@@ -1053,7 +1105,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
SVC_I3C_MCTRL_IBIRESP_NACK |
SVC_I3C_MCTRL_DIR(rnw) |
SVC_I3C_MCTRL_ADDR(addr) |
- SVC_I3C_MCTRL_RDTERM(*actual_len),
+ SVC_I3C_MCTRL_RDTERM(rdterm),
master->regs + SVC_I3C_MCTRL);
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@@ -1086,7 +1138,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
}
if (rnw)
- ret = svc_i3c_master_read(master, in, xfer_len);
+ ret = svc_i3c_master_read(master, in, xfer_len, !!rdterm);
else
ret = svc_i3c_master_write(master, out, xfer_len);
if (ret < 0)
--
2.34.1
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
next reply other threads:[~2024-01-17 22:50 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-17 22:50 Frank Li [this message]
2024-01-18 20:14 ` [PATCH 1/1] i3c: master: svc: add support for read len bigger than 255 Frank Li
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=20240117225009.2931699-1-Frank.Li@nxp.com \
--to=frank.li@nxp.com \
--cc=alexandre.belloni@bootlin.com \
--cc=conor.culhane@silvaco.com \
--cc=imx@lists.linux.dev \
--cc=linux-i3c@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=miquel.raynal@bootlin.com \
/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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).