From: Andre Przywara <andre.przywara@arm.com>
To: Jagan Teki <jagan@amarulasolutions.com>,
George Hilliard <thirtythreeforty@gmail.com>,
qianfan Zhao <qianfanguijin@163.com>
Cc: Jesse Taube <mr.bossman075@gmail.com>,
Icenowy Zheng <icenowy@aosc.io>, Yifan Gu <me@yifangu.com>,
Giulio Benetti <giulio.benetti@benettiengineering.com>,
Samuel Holland <samuel@sholland.org>,
Jernej Skrabec <jernej.skrabec@gmail.com>,
linux-sunxi@lists.linux.dev, u-boot@lists.denx.de
Subject: Re: [PATCH 2/7] spi: sunxi: refactor SPI speed/mode programming
Date: Tue, 28 Jun 2022 01:31:57 +0100 [thread overview]
Message-ID: <20220628013157.129f4d64@slackpad.lan> (raw)
In-Reply-To: <20220503212040.27884-3-andre.przywara@arm.com>
On Tue, 3 May 2022 22:20:35 +0100
Andre Przywara <andre.przywara@arm.com> wrote:
Hi,
> As George rightfully pointed out [1], the spi-sunxi driver programs the
> speed and mode settings only when the respective functions are called,
> but this gets lost over a call to release_bus(). That asserts the
> reset line, thus forces each SPI register back to its default value.
> Adding to that, trying to program SPI_CCR and SPI_TCR might be pointless
> in the first place, when the reset line is still asserted (before
> claim_bus()), so those setting won't apply most of the time. In reality
> I see two nested claim_bus() calls for the first use, so settings between
> the two would work (for instance for the initial "sf probe"). However
> later on the speed setting is not programmed into the hardware anymore.
So this issue was addressed with patches by both George (earlier, in a
different way) and Qianfan (later, in a very similar way).
Can someone (Jagan?) please have a look at this change from the U-Boot
SPI perspective? And also the other changes in this series?
I pushed them to the sunxi/next branch:
https://source.denx.de/u-boot/custodians/u-boot-sunxi/-/commits/next/
So can people please test this and report whether this now works as
expected?
Thanks,
Andre
> So far we get away with that default frequency, because that is a rather
> tame 24 MHz, which most SPI flash chips can handle just fine.
>
> Move the actual register programming into a separate function, and use
> .set_speed and .set_mode just to set the variables in our priv structure.
> Then we only call this new function in claim_bus(), when we are sure
> that register accesses actually work and are preserved.
>
> [1] https://lore.kernel.org/u-boot/20210725231636.879913-17-me@yifangu.com/
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reported-by: George Hilliard <thirtythreeforty@gmail.com>
> ---
> drivers/spi/spi-sunxi.c | 95 ++++++++++++++++++++++-------------------
> 1 file changed, 52 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
> index b6cd7ddafad..d6b2dd09514 100644
> --- a/drivers/spi/spi-sunxi.c
> +++ b/drivers/spi/spi-sunxi.c
> @@ -221,6 +221,56 @@ err_ahb:
> return ret;
> }
>
> +static void sun4i_spi_set_speed_mode(struct udevice *dev)
> +{
> + struct sun4i_spi_priv *priv = dev_get_priv(dev);
> + unsigned int div;
> + u32 reg;
> +
> + /*
> + * Setup clock divider.
> + *
> + * We have two choices there. Either we can use the clock
> + * divide rate 1, which is calculated thanks to this formula:
> + * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
> + * Or we can use CDR2, which is calculated with the formula:
> + * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
> + * Whether we use the former or the latter is set through the
> + * DRS bit.
> + *
> + * First try CDR2, and if we can't reach the expected
> + * frequency, fall back to CDR1.
> + */
> +
> + div = SUN4I_SPI_MAX_RATE / (2 * priv->freq);
> + reg = readl(SPI_REG(priv, SPI_CCR));
> +
> + if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
> + if (div > 0)
> + div--;
> +
> + reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
> + reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
> + } else {
> + div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(priv->freq);
> + reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
> + reg |= SUN4I_CLK_CTL_CDR1(div);
> + }
> +
> + writel(reg, SPI_REG(priv, SPI_CCR));
> +
> + reg = readl(SPI_REG(priv, SPI_TCR));
> + reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
> +
> + if (priv->mode & SPI_CPOL)
> + reg |= SPI_BIT(priv, SPI_TCR_CPOL);
> +
> + if (priv->mode & SPI_CPHA)
> + reg |= SPI_BIT(priv, SPI_TCR_CPHA);
> +
> + writel(reg, SPI_REG(priv, SPI_TCR));
> +}
> +
> static int sun4i_spi_claim_bus(struct udevice *dev)
> {
> struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
> @@ -240,6 +290,8 @@ static int sun4i_spi_claim_bus(struct udevice *dev)
> setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
> SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
>
> + sun4i_spi_set_speed_mode(dev->parent);
> +
> return 0;
> }
>
> @@ -329,46 +381,14 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
> {
> struct sun4i_spi_plat *plat = dev_get_plat(dev);
> struct sun4i_spi_priv *priv = dev_get_priv(dev);
> - unsigned int div;
> - u32 reg;
>
> if (speed > plat->max_hz)
> speed = plat->max_hz;
>
> if (speed < SUN4I_SPI_MIN_RATE)
> speed = SUN4I_SPI_MIN_RATE;
> - /*
> - * Setup clock divider.
> - *
> - * We have two choices there. Either we can use the clock
> - * divide rate 1, which is calculated thanks to this formula:
> - * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
> - * Or we can use CDR2, which is calculated with the formula:
> - * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
> - * Whether we use the former or the latter is set through the
> - * DRS bit.
> - *
> - * First try CDR2, and if we can't reach the expected
> - * frequency, fall back to CDR1.
> - */
> -
> - div = SUN4I_SPI_MAX_RATE / (2 * speed);
> - reg = readl(SPI_REG(priv, SPI_CCR));
> -
> - if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
> - if (div > 0)
> - div--;
> -
> - reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
> - reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
> - } else {
> - div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(speed);
> - reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
> - reg |= SUN4I_CLK_CTL_CDR1(div);
> - }
>
> priv->freq = speed;
> - writel(reg, SPI_REG(priv, SPI_CCR));
>
> return 0;
> }
> @@ -376,19 +396,8 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
> static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
> {
> struct sun4i_spi_priv *priv = dev_get_priv(dev);
> - u32 reg;
> -
> - reg = readl(SPI_REG(priv, SPI_TCR));
> - reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
> -
> - if (mode & SPI_CPOL)
> - reg |= SPI_BIT(priv, SPI_TCR_CPOL);
> -
> - if (mode & SPI_CPHA)
> - reg |= SPI_BIT(priv, SPI_TCR_CPHA);
>
> priv->mode = mode;
> - writel(reg, SPI_REG(priv, SPI_TCR));
>
> return 0;
> }
next prev parent reply other threads:[~2022-06-28 0:44 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-03 21:20 [PATCH 0/7] sunxi: F1C100s: enable MMC and SPI in U-Boot proper Andre Przywara
2022-05-03 21:20 ` [PATCH 1/7] clk: sunxi: implement clock driver for suniv f1c100s Andre Przywara
2022-05-24 16:10 ` Andre Przywara
2022-05-03 21:20 ` [PATCH 2/7] spi: sunxi: refactor SPI speed/mode programming Andre Przywara
2022-06-28 0:31 ` Andre Przywara [this message]
2022-06-28 3:43 ` Jesse Taube
2022-07-18 10:17 ` Andre Przywara
2022-06-30 3:25 ` Jesse Taube
2022-05-03 21:20 ` [PATCH 3/7] spi: sunxi: improve SPI clock calculation Andre Przywara
2022-05-03 21:20 ` [PATCH 4/7] spi: sunxi: Add support for F1C100s SPI controller Andre Przywara
2022-05-03 21:20 ` [PATCH 5/7] sunxi: F1C100s: update DT files from Linux Andre Przywara
2022-05-05 11:26 ` Jesse Taube
2022-05-24 16:11 ` Andre Przywara
2022-05-03 21:20 ` [PATCH 6/7] Revert "sunxi: f1c100s: Drop SYSRESET to enable reset functionality" Andre Przywara
2022-05-24 16:11 ` Andre Przywara
2022-05-03 21:20 ` [PATCH 7/7] sunxi: licheepi_nano: enable SPI flash Andre Przywara
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=20220628013157.129f4d64@slackpad.lan \
--to=andre.przywara@arm.com \
--cc=giulio.benetti@benettiengineering.com \
--cc=icenowy@aosc.io \
--cc=jagan@amarulasolutions.com \
--cc=jernej.skrabec@gmail.com \
--cc=linux-sunxi@lists.linux.dev \
--cc=me@yifangu.com \
--cc=mr.bossman075@gmail.com \
--cc=qianfanguijin@163.com \
--cc=samuel@sholland.org \
--cc=thirtythreeforty@gmail.com \
--cc=u-boot@lists.denx.de \
/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).