From: Michal Simek <monstr@monstr.eu>
To: Raviteja Narayanam <raviteja.narayanam@xilinx.com>
Cc: linux-i2c@vger.kernel.org, git <git@xilinx.com>,
linux-arm <linux-arm-kernel@lists.infradead.org>,
LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] i2c: cadence: Clear HOLD bit before xfer_size register rolls over
Date: Wed, 23 Jun 2021 10:46:54 +0200 [thread overview]
Message-ID: <CAHTX3dLA1oF2v6FRgeL9kMExMXxGz=7LJBM3oo9Zf1CA2HfQFA@mail.gmail.com> (raw)
In-Reply-To: <1606203965-31595-1-git-send-email-raviteja.narayanam@xilinx.com>
út 24. 11. 2020 v 8:48 odesílatel Raviteja Narayanam
<raviteja.narayanam@xilinx.com> napsal:
>
> On Xilinx zynq SOC if the delay between address register write and
> control register write in cdns_mrecv function is more, the xfer size
> register rolls over and controller is stuck. This is an IP bug and
and the controller
> is resolved in later versions of IP.
>
> To avoid this scenario, disable the interrupts on the current processor
> core between the two register writes and enable them later. This can
> help achieve the timing constraint.
>
> Signed-off-by: Raviteja Narayanam <raviteja.narayanam@xilinx.com>
> ---
> drivers/i2c/busses/i2c-cadence.c | 48 ++++++++++++++++++++++++++++++++++------
> 1 file changed, 41 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
> index e4b7f2a..81b7c45 100644
> --- a/drivers/i2c/busses/i2c-cadence.c
> +++ b/drivers/i2c/busses/i2c-cadence.c
> @@ -578,6 +578,11 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> {
> unsigned int ctrl_reg;
> unsigned int isr_status;
> + unsigned long flags;
> + bool hold_clear = false;
> + bool irq_save = false;
> +
> + u32 addr;
>
> id->p_recv_buf = id->p_msg->buf;
> id->recv_count = id->p_msg->len;
> @@ -618,14 +623,43 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
> }
>
> - /* Set the slave address in address register - triggers operation */
> - cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
> - CDNS_I2C_ADDR_OFFSET);
> - /* Clear the bus hold flag if bytes to receive is less than FIFO size */
> + /* Determine hold_clear based on number of bytes to receive and hold flag */
> if (!id->bus_hold_flag &&
> - ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
> - (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
> - cdns_i2c_clear_bus_hold(id);
> + ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
> + (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
> + if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
> + hold_clear = true;
> + if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
> + irq_save = true;
> + }
> + }
> +
> + addr = id->p_msg->addr;
> + addr &= CDNS_I2C_ADDR_MASK;
> +
> + if (hold_clear) {
> + ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & ~CDNS_I2C_CR_HOLD;
> + /*
> + * In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size
> + * register reaches '0'. This is an IP bug which causes transfer size
> + * register overflow to 0xFF. To satisfy this timing requirement,
> + * disable the interrupts on current processor core between register
> + * writes to slave address register and control register.
> + */
> + if (irq_save)
> + local_irq_save(flags);
> +
> + cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
> + cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
> + /* Read it back to avoid bufferring and make sure write happens */
> + cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
> +
> + if (irq_save)
> + local_irq_restore(flags);
> + } else {
> + cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
> + }
> +
> cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
> }
Unfortunately we can't do anything with this on the Zynq platform. It
is better than nothing.
ZynqMP is not affected.
Acked-by: Michal Simek <michal.simek@xilinx.com>
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2021-06-23 8:49 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-24 7:46 [PATCH] i2c: cadence: Clear HOLD bit before xfer_size register rolls over Raviteja Narayanam
2021-06-23 8:46 ` Michal Simek [this message]
2021-06-23 16:18 ` Wolfram Sang
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='CAHTX3dLA1oF2v6FRgeL9kMExMXxGz=7LJBM3oo9Zf1CA2HfQFA@mail.gmail.com' \
--to=monstr@monstr.eu \
--cc=git@xilinx.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=raviteja.narayanam@xilinx.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 NNTP newsgroup(s).