public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Jesse Taube <mr.bossman075@gmail.com>
To: Andre Przywara <andre.przywara@arm.com>,
	Jagan Teki <jagan@amarulasolutions.com>,
	George Hilliard <thirtythreeforty@gmail.com>,
	qianfan Zhao <qianfanguijin@163.com>
Cc: 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: Wed, 29 Jun 2022 23:25:55 -0400	[thread overview]
Message-ID: <9d7a7ba7-13d7-6f7f-19ea-5fc2a08e67a5@gmail.com> (raw)
In-Reply-To: <20220628013157.129f4d64@slackpad.lan>



On 6/27/22 20:31, Andre Przywara wrote:
> 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/
Tested-by: Jesse Taube <Mr.Bossman075@gmail.com>

I talked to Icenowy who also tested and said it worked with spi-nand.

There is one issue but not related to this set, the SPI max clock is 1Mhz.

Another note disabling the clock gates in `sun4i_spi_set_clock` will 
stop you from dumping the memory of the peripheral.

It would also be nice if i was kept in CC for other SUNIV patches.

Thanks,
Jesse
> 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;
>>   }
> 

  parent reply	other threads:[~2022-06-30  3:26 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
2022-06-28  3:43     ` Jesse Taube
2022-07-18 10:17       ` Andre Przywara
2022-06-30  3:25     ` Jesse Taube [this message]
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=9d7a7ba7-13d7-6f7f-19ea-5fc2a08e67a5@gmail.com \
    --to=mr.bossman075@gmail.com \
    --cc=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=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