Message ID | 20240117225009.2931699-1-Frank.Li@nxp.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | [1/1] i3c: master: svc: add support for read len bigger than 255 | expand |
On Wed, Jan 17, 2024 at 05:50:09PM -0500, Frank Li wrote: > 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> Sorry, please hold. I found failure at corner case. will improve and send next version later. Frank > --- > 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 >
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)
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(-)