diff mbox series

net: dsa: mt7530: disable LEDs before reset

Message ID 20240305043952.21590-1-justin.swartz@risingedge.co.za (mailing list archive)
State New, archived
Headers show
Series net: dsa: mt7530: disable LEDs before reset | expand

Commit Message

Justin Swartz March 5, 2024, 4:39 a.m. UTC
Disable LEDs just before resetting the MT7530 to avoid
situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
states may cause an unintended external crystal frequency
to be selected.

The HT_XTAL_FSEL (External Crystal Frequency Selection)
field of HWTRAP (the Hardware Trap register) stores a
2-bit value that represents the state of the ESW_P4_LED_0
and ESW_P4_LED_0 pins (seemingly) sampled just after the
MT7530 has been reset, as:

    ESW_P4_LED_0    ESW_P3_LED_0    Frequency
    -----------------------------------------
    0               1               20MHz
    1               0               40MHz
    1               1               25MHz

The value of HT_XTAL_FSEL is bootstrapped by pulling
ESW_P4_LED_0 and ESW_P3_LED_0 up or down accordingly,
but:

  if a 40MHz crystal has been selected and
  the ESW_P3_LED_0 pin is high during reset,

  or a 20MHz crystal has been selected and
  the ESW_P4_LED_0 pin is high during reset,

  then the value of HT_XTAL_FSEL will indicate
  that a 25MHz crystal is present.

By default, the state of the LED pins is PHY controlled
to reflect the link state.

To illustrate, if a board has:

  5 ports with active low LED control,
  and HT_XTAL_FSEL bootstrapped for 40MHz.

When the MT7530 is powered up without any external
connection, only the LED associated with Port 3 is
illuminated as ESW_P3_LED_0 is low.

In this state, directly after mt7530_setup()'s reset
is performed, the HWTRAP register (0x7800) reflects
the intended HT_XTAL_FSEL (HWTRAP bits 10:9) of 40MHz:

  mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007dcf

  >>> bin(0x7dcf >> 9 & 0b11)
  '0b10'

But if a cable is connected to Port 3 and the link
is active before mt7530_setup()'s reset takes place,
then HT_XTAL_FSEL seems to be set for 25MHz:

  mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007fcf

  >>> bin(0x7fcf >> 9 & 0b11)
  '0b11'

Once HT_XTAL_FSEL reflects 25MHz, none of the ports
are functional until the MT7621 (or MT7530 itself)
is reset.

By disabling the LED pins just before reset, the chance
of an unintended HT_XTAL_FSEL value is reduced.

Signed-off-by: Justin Swartz <justin.swartz@risingedge.co.za>
---
 drivers/net/dsa/mt7530.c | 6 ++++++
 1 file changed, 6 insertions(+)

Comments

Daniel Golle March 8, 2024, 2:46 p.m. UTC | #1
On Fri, Mar 08, 2024 at 12:51:15PM +0300, Arınç ÜNAL wrote:
> Hey Justin.
> 
> I couldn't find anything on the MT7621 Giga Switch Programming Guide v0.3
> document regarding which pin corresponds to which bit on the HWTRAP
> register. There's only this mention on the LED controller section,
> "hardware traps and LEDs share the same pins in GSW". But page 16 of the
> schematics document for Banana Pi BPI-R2 [1] fully documents this.
> 
> The HWTRAP register is populated right after power comes back after the
> switch chip is reset [2]. This means any active link before the reset will
> go away so the high/low state of the pins will go back to being dictated by
> the bootstrapping design of the board. The HWTRAP register will be
> populated before a link can be set up.
> 
> In conclusion, I don't see any need to disable the LED controller before
> resetting the switch chip.
> 
> [1] https://wiki.banana-pi.org/Banana_Pi_BPI-R2#Documents
> 
> [2] I've tested it on my MT7621AT board with a 40MHz XTAL frequency and a
> board with standalone MT7530 with 25MHz XTAL frequency.

How many times did you repeat this test to conclude that there is no
need to disable LEDs before reset?

As Justin is decribing a probabilistic phenomenon ("[...] chance of an
unintended HT_XTAL_FSEL value is reduced.") I believe running a single
test is not enough to conlcude anything.

I have a hard time believing that he was working on this patch without
any reason to do so...


> 
> While the kernel was booting, before the DSA subdriver kicks in:
> - For the board with 40 MHz XTAL: I've connected a Vcc pin to ESW_P3_LED_0
>   to set it high.
> - For the board with 25 MHz XTAL: I've connected a GND pin to ESW_P3_LED_0
>   to set it low.
> 
> Board with 40 MHz XTAL:
> [    2.359428] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip module
> [    2.374918] mt7530-mdio mdio-bus:1f: xtal is 25MHz
> 
> Board with 25 MHz XTAL:
> [    4.324672] mt7530-mdio mdio-bus:1f: xtal is 40MHz
> 
> diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> index 51d7b816dd02..beab5e5558d0 100644
> --- a/drivers/net/dsa/mt7530.c
> +++ b/drivers/net/dsa/mt7530.c
> @@ -2216,6 +2216,15 @@ mt7530_setup(struct dsa_switch *ds)
>  		return ret;
>  	}
> +	if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_25MHZ)
> +		dev_info(priv->dev, "xtal is 25MHz\n");
> +
> +	if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_40MHZ)
> +		dev_info(priv->dev, "xtal is 40MHz\n");
> +
> +	if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ)
> +		dev_info(priv->dev, "xtal is 20MHz\n");
> +
>  	id = mt7530_read(priv, MT7530_CREV);
>  	id >>= CHIP_NAME_SHIFT;
>  	if (id != MT7530_ID) {
> 
> Arınç
> 
> On 5.03.2024 07:39, Justin Swartz wrote:
> > Disable LEDs just before resetting the MT7530 to avoid
> > situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
> > states may cause an unintended external crystal frequency
> > to be selected.
> > 
> > The HT_XTAL_FSEL (External Crystal Frequency Selection)
> > field of HWTRAP (the Hardware Trap register) stores a
> > 2-bit value that represents the state of the ESW_P4_LED_0
> > and ESW_P4_LED_0 pins (seemingly) sampled just after the
> > MT7530 has been reset, as:
> > 
> >      ESW_P4_LED_0    ESW_P3_LED_0    Frequency
> >      -----------------------------------------
> >      0               1               20MHz
> >      1               0               40MHz
> >      1               1               25MHz
> > 
> > The value of HT_XTAL_FSEL is bootstrapped by pulling
> > ESW_P4_LED_0 and ESW_P3_LED_0 up or down accordingly,
> > but:
> > 
> >    if a 40MHz crystal has been selected and
> >    the ESW_P3_LED_0 pin is high during reset,
> > 
> >    or a 20MHz crystal has been selected and
> >    the ESW_P4_LED_0 pin is high during reset,
> > 
> >    then the value of HT_XTAL_FSEL will indicate
> >    that a 25MHz crystal is present.
> > 
> > By default, the state of the LED pins is PHY controlled
> > to reflect the link state.
> > 
> > To illustrate, if a board has:
> > 
> >    5 ports with active low LED control,
> >    and HT_XTAL_FSEL bootstrapped for 40MHz.
> > 
> > When the MT7530 is powered up without any external
> > connection, only the LED associated with Port 3 is
> > illuminated as ESW_P3_LED_0 is low.
> > 
> > In this state, directly after mt7530_setup()'s reset
> > is performed, the HWTRAP register (0x7800) reflects
> > the intended HT_XTAL_FSEL (HWTRAP bits 10:9) of 40MHz:
> > 
> >    mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007dcf
> > 
> >    >>> bin(0x7dcf >> 9 & 0b11)
> >    '0b10'
> > 
> > But if a cable is connected to Port 3 and the link
> > is active before mt7530_setup()'s reset takes place,
> > then HT_XTAL_FSEL seems to be set for 25MHz:
> > 
> >    mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007fcf
> > 
> >    >>> bin(0x7fcf >> 9 & 0b11)
> >    '0b11'
> > 
> > Once HT_XTAL_FSEL reflects 25MHz, none of the ports
> > are functional until the MT7621 (or MT7530 itself)
> > is reset.
> > 
> > By disabling the LED pins just before reset, the chance
> > of an unintended HT_XTAL_FSEL value is reduced.
> > 
> > Signed-off-by: Justin Swartz <justin.swartz@risingedge.co.za>
> > ---
> >   drivers/net/dsa/mt7530.c | 6 ++++++
> >   1 file changed, 6 insertions(+)
> > 
> > diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> > index 3c1f65759..8fa113126 100644
> > --- a/drivers/net/dsa/mt7530.c
> > +++ b/drivers/net/dsa/mt7530.c
> > @@ -2238,6 +2238,12 @@ mt7530_setup(struct dsa_switch *ds)
> >   		}
> >   	}
> > +	/* Disable LEDs before reset to prevent the MT7530 sampling a
> > +	 * potentially incorrect HT_XTAL_FSEL value.
> > +	 */
> > +	mt7530_write(priv, MT7530_LED_EN, 0);
> > +	usleep_range(1000, 1100);
> > +
> >   	/* Reset whole chip through gpio pin or memory-mapped registers for
> >   	 * different type of hardware
> >   	 */
patchwork-bot+netdevbpf@kernel.org March 11, 2024, 9:10 p.m. UTC | #2
Hello:

This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Tue,  5 Mar 2024 06:39:51 +0200 you wrote:
> Disable LEDs just before resetting the MT7530 to avoid
> situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
> states may cause an unintended external crystal frequency
> to be selected.
> 
> The HT_XTAL_FSEL (External Crystal Frequency Selection)
> field of HWTRAP (the Hardware Trap register) stores a
> 2-bit value that represents the state of the ESW_P4_LED_0
> and ESW_P4_LED_0 pins (seemingly) sampled just after the
> MT7530 has been reset, as:
> 
> [...]

Here is the summary with links:
  - net: dsa: mt7530: disable LEDs before reset
    https://git.kernel.org/netdev/net-next/c/2920dd92b980

You are awesome, thank you!
Jakub Kicinski March 11, 2024, 9:58 p.m. UTC | #3
On Tue, 12 Mar 2024 00:22:48 +0300 Arınç ÜNAL wrote:
> Why was this applied? I already explained it did not achieve anything.

Daniel disagreed and you didn't reply to him.

Please don't top post.
Daniel Golle March 11, 2024, 9:58 p.m. UTC | #4
On Tue, Mar 12, 2024 at 12:22:48AM +0300, Arınç ÜNAL wrote:
> Why was this applied? I already explained it did not achieve anything.

I agree that we were still debating about it, however, I do believe
Justin that he truely observed this problem and the fix seemed
appropriate to me.

I've explained this in my previous email which you did not notice
or at least haven't repied to:

https://patchwork.kernel.org/project/netdevbpf/patch/20240305043952.21590-1-justin.swartz@risingedge.co.za/#25753421

In the end it probably depends on the electric capacity of the circuit
connecting each LED, so it may not be reproducible on all boards and/or
under all circumstances (temperature, humindity, ...).

Disabling the LEDs and waiting for around 1mS before reset seems like
a sensible thing to do, and I'm glad Justin took care of it.


> 
> Arınç
> 
> On 12.03.2024 00:10, patchwork-bot+netdevbpf@kernel.org wrote:
> > Hello:
> > 
> > This patch was applied to netdev/net-next.git (main)
> > by Jakub Kicinski <kuba@kernel.org>:
> > 
> > On Tue,  5 Mar 2024 06:39:51 +0200 you wrote:
> > > Disable LEDs just before resetting the MT7530 to avoid
> > > situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
> > > states may cause an unintended external crystal frequency
> > > to be selected.
> > > 
> > > The HT_XTAL_FSEL (External Crystal Frequency Selection)
> > > field of HWTRAP (the Hardware Trap register) stores a
> > > 2-bit value that represents the state of the ESW_P4_LED_0
> > > and ESW_P4_LED_0 pins (seemingly) sampled just after the
> > > MT7530 has been reset, as:
> > > 
> > > [...]
> > 
> > Here is the summary with links:
> >    - net: dsa: mt7530: disable LEDs before reset
> >      https://git.kernel.org/netdev/net-next/c/2920dd92b980
> > 
> > You are awesome, thank you!
Daniel Golle March 11, 2024, 11:43 p.m. UTC | #5
On Tue, Mar 12, 2024 at 02:27:25AM +0300, Arınç ÜNAL wrote:
> On 12.03.2024 00:58, Daniel Golle wrote:
> > On Tue, Mar 12, 2024 at 12:22:48AM +0300, Arınç ÜNAL wrote:
> > > Why was this applied? I already explained it did not achieve anything.
> > 
> > I agree that we were still debating about it, however, I do believe
> > Justin that he truely observed this problem and the fix seemed
> > appropriate to me.
> > 
> > I've explained this in my previous email which you did not notice
> > or at least haven't repied to:
> > 
> > https://patchwork.kernel.org/project/netdevbpf/patch/20240305043952.21590-1-justin.swartz@risingedge.co.za/#25753421
> 
> I did read that and I did not respond because you did not argue over any of
> the technical points I've made. All you said was did I repeat the test
> enough, on a technical matter that I consider adding two and two together
> and expecting a result other than four.
> 
> How I interpreted your response was: I don't know much about this, maybe
> you're wrong. Justin must've made this patch for a reason so let's have
> them elaborate further.
> 
> > 
> > In the end it probably depends on the electric capacity of the circuit
> > connecting each LED, so it may not be reproducible on all boards and/or
> > under all circumstances (temperature, humindity, ...).
> 
> I'm sorry, this makes no sense to me. I simply fail to see how this fits
> here. Could you base your argument over my points please?

Sure, will happily do so.

> 
> Do you agree that the LED controller starts manipulating the state of the
> pins used for LEDs and bootstrapping after a link is established?

Yes. But a reset may happen while a link is already up because the switch IC
was initialized and in use by the bootloader. And hence LED may be powered
by the LED controller in that moment **just before reset**.

> 
> Do you agree that after power is cut from the switch IC and then given
> back, any active link from before will go away, meaning the pins will go
> back to the state that is being dictated by the bootstrapping design of the
> board?

I don't see how this could be related. We are not talking about power cuts
here, but rather use of a RESET signal (typically a GPIO on standalone MT753x
or reset controller of the CPU-part of the MCM).

> 
> Do you agree that with power given back, the HWTRAP register will be
> populated before a link is established?

Yes sure, but see above.

> 
> > 
> > Disabling the LEDs and waiting for around 1mS before reset seems like
> > a sensible thing to do, and I'm glad Justin took care of it.
> 
> Let's ask Justin if they tested this on a standalone MT7530. Because I did.
> The switch chip won't even be powered on before the switch chip reset
> operation is done. So the operation this patch brings does not do anything
> at all for standalone MT7530.

This is not true in case the bootloader has already powered on the
switch in order to load firmware via TFTP. In this case the link may
be up (and hence LEDs may be powered on) at the moment the reset
triggerd by probe of the DSA driver kicks in.

> 
> My conclusion to this patch is Justin tested this only on an MCM MT7530
> where the switch IC still has power before the DSA subdriver kicks in. And
> assumed that disabling the LED controller before switch chip reset would
> "reduce" the possibility of having these pins continue being manipulated by
> the LED controller AFTER power is cut off and given back to the switch
> chip, where the state of these pins would be back to being dictated by the
> bootstrapping design of the board.
> 
> Jakub, please revert this. And please next time do not apply any patch that
> modifies this driver without my approval if I've already made an argument
> against it. I'm actively maintaining this driver, if there's a need to
> respond, I will do so.
> 
> This patch did not have any ACKs. It also did not have the tree described
> on the subject. More reasons as to why this shouldn't have been applied in
> its current state.

It was clearly recognizable as a fix.

However, I agree that applying it after Ack from an active maintainer
would have been better.

I don't see a need to revert it before this debate (which starts to
look like an argument over authority) has concluded.
Justin Swartz March 12, 2024, 12:07 a.m. UTC | #6
Hi Arınç

This reply will be best read with a fixed-width font.

On 2024-03-08 11:51, Arınç ÜNAL wrote:
> Hey Justin.
> 
> I couldn't find anything on the MT7621 Giga Switch Programming Guide 
> v0.3
> document regarding which pin corresponds to which bit on the HWTRAP
> register. There's only this mention on the LED controller section,
> "hardware traps and LEDs share the same pins in GSW". But page 16 of 
> the
> schematics document for Banana Pi BPI-R2 [1] fully documents this.

There is also a table in the "MT7530 Giga Switch Programming
Guide" that describes which pins correspond to the bits of
HWTRAP, but beware of typos.


> The HWTRAP register is populated right after power comes back after the
> switch chip is reset [2]. This means any active link before the reset 
> will
> go away so the high/low state of the pins will go back to being 
> dictated by
> the bootstrapping design of the board. The HWTRAP register will be
> populated before a link can be set up.

> In conclusion, I don't see any need to disable the LED controller 
> before
> resetting the switch chip.

I should have included more evidence to support my claim.


> [1] https://wiki.banana-pi.org/Banana_Pi_BPI-R2#Documents
> 
> [2] I've tested it on my MT7621AT board with a 40MHz XTAL frequency and 
> a
> board with standalone MT7530 with 25MHz XTAL frequency.
> 
> While the kernel was booting, before the DSA subdriver kicks in:
> - For the board with 40 MHz XTAL: I've connected a Vcc pin to 
> ESW_P3_LED_0
>   to set it high.

My board has a 40MHz crystal between XPTL_XI and XPTL_XO,
ESW_P4_LED_0 has a 4.7k pull up to 3.3V, and ESW_P3_LED_0
has a 4.7k pull down to GND.

For testing, I'm relying on the MT7530 itself to change the
ESW_P3_LED_0 level according to the link state.


> - For the board with 25 MHz XTAL: I've connected a GND pin to 
> ESW_P3_LED_0
>   to set it low.
> 
> Board with 40 MHz XTAL:
> [    2.359428] mt7530-mdio mdio-bus:1f: MT7530 adapts as multi-chip 
> module
> [    2.374918] mt7530-mdio mdio-bus:1f: xtal is 25MHz
> 
> Board with 25 MHz XTAL:
> [    4.324672] mt7530-mdio mdio-bus:1f: xtal is 40MHz
> 
> diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
> index 51d7b816dd02..beab5e5558d0 100644
> --- a/drivers/net/dsa/mt7530.c
> +++ b/drivers/net/dsa/mt7530.c
> @@ -2216,6 +2216,15 @@ mt7530_setup(struct dsa_switch *ds)
>  		return ret;
>  	}
>  +	if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_25MHZ)
> +		dev_info(priv->dev, "xtal is 25MHz\n");
> +
> +	if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_40MHZ)
> +		dev_info(priv->dev, "xtal is 40MHz\n");
> +
> +	if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ)
> +		dev_info(priv->dev, "xtal is 20MHz\n");
> +
>  	id = mt7530_read(priv, MT7530_CREV);
>  	id >>= CHIP_NAME_SHIFT;
>  	if (id != MT7530_ID) {
> 
> Arınç

I took a similar approach, with calls to dev_info()
throughout mt7530_setup() plus mt7530_write(), mt7530_read()
and mt7530_rmw() to get an idea of the flow of execution and
which registers were being manipulated.

Calls to dev_info() affected timing, so I switched to using
trace_printk() and then read the output from the debugfs's
tracing/trace file instead of from the console.

I attached a logic analyzer to ESW_P4_LED_0 and ESW_P3_LED_0,
and manually triggered sampling as soon as execution of the
kernel was reported on UART1.


-- Test #1 -----------------------------------------------------------

For the sake of maximal reproducability, I removed the delay
between the assertion and deassertion of reset and added
HWTRAP value tracing:

---%---
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2243,7 +2243,6 @@ mt7530_setup(struct dsa_switch *ds)
	 */
	if (priv->mcm) {
		reset_control_assert(priv->rstc);
-		usleep_range(1000, 1100);
		reset_control_deassert(priv->rstc);
	} else {
		gpiod_set_value_cansleep(priv->reset, 0);
@@ -2260,6 +2259,10 @@ mt7530_setup(struct dsa_switch *ds)
		return ret;
	}

+	static char ht_xtal_fsel[4][6] = { "?????", "20MHz", "40MHz", "25MHz" 
};
+	trace_printk("HWTRAP = %x, HT_XTAL_FSEL = %s\n",
+		val, ht_xtal_fsel[(val & HWTRAP_XTAL_MASK) >> 9]);
+
         id = mt7530_read(priv, MT7530_CREV);
         id >>= CHIP_NAME_SHIFT;
         if (id != MT7530_ID) {
---%---

(a) Without a cable connected to Port 3 (lan4) before reset, the
correct external crystal frequency is selected:

               [3]      [4]     [6]
               :        :       :
               _________         ______________________________________
ESW_P4_LED_0           |_______|
                         _______
ESW_P3_LED_0  _________|       |______________________________________

                         :     :
                         [5]...:

[3] Port 4 LED Off. Port 3 LED On.
[4] Signals inverted. (reset_control_assert; reset_control_deassert)
[5] Period of 310 usec.
[6] Signals reflect the bootstrapped configuration.


~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
     2.432646: mt7530_setup: HWTRAP = 7dcf, HT_XTAL_FSEL = 40MHz


(b) When a cable attached to an active peer is connected to
Port 3 (lan4) before reset, the incorrect crystal frequency
selection (0b11 = 25MHz) always occurs:

               [7]      [8]     [10]    [12]
               :        :       :       :
               _________         ______________________________________
ESW_P4_LED_0           |_______|
               _________         _______
ESW_P3_LED_0           |_______|       |______________________________

                         :     : :     :
                         [9]...: [11]..:

  [7] Port 4 LED Off. Port 3 LED Off.
  [8] Signals inverted. (reset_control_assert; reset_control_deassert)
  [9] Period of 320 usec.
[10] Signals inverted.
[11] Period of 300 usec.
[12] Signals reflect the bootstrapped configuration.

~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
     2.432884: mt7530_setup: HWTRAP = 7fcf, HT_XTAL_FSEL = 25MHz


-- Test #2 -----------------------------------------------------------

To attempt to determine which transitions are associated
with asserting and deasserting reset, I performed another
test with a delay of what I intended to be a 1 sec period
where the MT7530 is held in reset:

---%---
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2243,7 +2243,7 @@ mt7530_setup(struct dsa_switch *ds)
	 */
	if (priv->mcm) {
		reset_control_assert(priv->rstc);
-		usleep_range(1000, 1100);
+		usleep_range(1000000, 1000000);
		reset_control_deassert(priv->rstc);
	} else {
		gpiod_set_value_cansleep(priv->reset, 0);
@@ -2260,6 +2260,10 @@ mt7530_setup(struct dsa_switch *ds)
		return ret;
	}

+	static char ht_xtal_fsel[4][6] = { "?????", "20MHz", "40MHz", "25MHz" 
};
+	trace_printk("HWTRAP = %x, HT_XTAL_FSEL = %s\n",
+		val, ht_xtal_fsel[(val & HWTRAP_XTAL_MASK) >> 9]);
+
	id = mt7530_read(priv, MT7530_CREV);
	id >>= CHIP_NAME_SHIFT;
	if (id != MT7530_ID) {
---%---

(a) Without a cable connected to Port 3 (lan4) before reset, the
correct external crystal frequency is again selected:

               [13]     [14]    [16]
               :        :       :
               _________         ______________________________________
ESW_P4_LED_0           |_______|
                         _______
ESW_P3_LED_0  _________|       |______________________________________

                         :     :
                         [15]..:

[13] Port 4 LED Off. Port 3 LED On.
[14] Signals inverted. (reset_control_deassert?)
[15] Period of 310 usec.
[16] Signals reflect the bootstrapped configuration.


~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
     3.437461: mt7530_setup: HWTRAP = 7dcf, HT_XTAL_FSEL = 40MHz


No difference is apparent in the timing diagram, compared
to the result from Test #1a, but it is obvious that the code
which follows the reset was executed about 1 second later.


(b) With a cable from an active peer connected to Port 3
(lan4) before reset, the correct crystal frequency
(0b10 = 40MHz) is selected:

               [17]     [18]                    [20]   [22]
               :        :                       :      :
               ______________________ \ \ ______        _______________
ESW_P4_LED_0                         / /       |______|
               _________              \ \        ______
ESW_P3_LED_0           |____________ / / ______|      |_______________
                                      \ \
                         :                     : :    :
                         [19]..................: [21].:

[17] Port 4 LED Off. Port 3 LED Off.
[18] ESW_P3_LED_0 set low. (reset_control_assert?)
[19] Period of 1000.325 msec.
[20] Signals inverted. (reset_control_deassert?)
[21] Period of 310 usec.
[22] Signals reflect the bootstrapped configuration.


~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
     3.433235: mt7530_setup: HWTRAP = 7dcf, HT_XTAL_FSEL = 40MHz


So it appears that when reset is deasserted, the ESW_P4_LED_0
and ESW_P3_LED_0 levels are inverted for a period of about
300 - 310 usec in Test #1a, #1b, #2a, and #2b.

Co-incidentally, these inverted levels are the active low
representation of what ends up in HT_XTAL_FSEL. And in all
four examples, have been the inversion of what immediately
preceded reset_control_deassert().


-- Test #3 -----------------------------------------------------------

Now it seems that there is a signature that can be used
to identify when reset_control_deassert() is executed,
the time of reset_control_assert()'s execution should be
between (at most) 1100 and (at least) 1000 usec prior
based on the unmodified reset logic.

So this patch only includes the HT_XTAL_FSEL trace.

---%---
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2260,6 +2260,10 @@ mt7530_setup(struct dsa_switch *ds)
                 return ret;
         }

+       static char ht_xtal_fsel[4][6] = { "?????", "20MHz", "40MHz", 
"25MHz" };
+       trace_printk("HWTRAP = %x, HT_XTAL_FSEL = %s\n",
+               val, ht_xtal_fsel[(val & HWTRAP_XTAL_MASK) >> 9]);
+
         id = mt7530_read(priv, MT7530_CREV);
         id >>= CHIP_NAME_SHIFT;
         if (id != MT7530_ID) {
---%---

The purpose of the following examples are to show the
variance in how long it takes for ESW_P3_LED_0 to go low.

(a) With a cable from an active peer connected to Port 3
(lan4) before reset, the correct crystal frequency
(0b10 = 40MHz) is selected.

               [23]    [24]       [26]      [28]    [30]
               :       :          :         :       :
               _____________________________         __________________
ESW_P4_LED_0                               |_______|
               ___________________           _______
ESW_P3_LED_0                     |_________|       |__________________

                        :          :       : :     :
                        :          [27]....: [29]..:
                        [25]...............:

[23] Port 4 LED Off. Port 3 LED Off.
[24] Approximate point of reset_control_assert?
[25] Period of approximately 1000 - 1100 usec.
[26] ESW_P3_LED_0 finally goes low.
[27] Period of 415 usec.
[28] Signals inverted. (reset_control_deassert?)
[29] Period of 310 usec.
[30] Signals reflect the bootstrapped configuration.


(b) With a cable from an active peer connected to Port 3
(lan4) before reset, the correct crystal frequency
(0b10 = 40MHz) is selected.

               [31]    [32]            [34] [36]    [38]
               :       :                  : :       :
               _____________________________         __________________
ESW_P4_LED_0                               |_______|
               ___________________________   _______
ESW_P3_LED_0                             |_|       |__________________

                        :                  : :     :
                        :               [35] [37]..:
                        :                  :
                        [33]...............:

[31] Port 4 LED Off. Port 3 LED Off.
[32] Approximate point of reset_control_assert?
[33] Period of approximately 1000 - 1100 usec.
[34] ESW_P3_LED_0 finally goes low.
[35] Period of 50 usec.
[36] Signals inverted. (reset_control_deassert?)
[37] Period of 310 usec.
[38] Signals reflect the bootstrapped configuration.


(c) With a cable from an active peer connected to Port 3
(lan4) before reset, an incorrect crystal frequency
(0b11 = 25MHz) is selected.

               [45]    [46]                 [48]    [50]
               :       :                    :       :
               _____________________________         __________________
ESW_P4_LED_0                               |_______|
               _____________________________
ESW_P3_LED_0                               |__________________________

                        :                  : :     :
                        :                  : [49]..:
                        :                  :
                        [47]...............:

[45] Port 4 LED Off. Port 3 LED Off.
[46] Approximate point of reset_control_assert?
[47] Period of approximately 1000 - 1100 usec.
[48] Signals inverted. (reset_control_deassert?)
[49] Period of 315 usec.
[50] Signals reflect the bootstrapped configuration.

~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
     2.617819: mt7530_setup: HWTRAP = 7fcf, HT_XTAL_FSEL = 25MHz

~ # cat /proc/cmdline
console=ttyS0,57600 loglevel=7 printk.time=1 root=/dev/ram0 debug 
rdinit=/linuxrc


-- End of Tests ------------------------------------------------------

It seems that the incorrect crystal frequency is selected more
often when debugging messages are present (such as printk()
based approaches) and especially when loglevel=7 and printk.time=1
are specified on the command line.

For the sake of reference: I disabled ethernet support in my build
of (mainline) U-boot, and my kernel configuration is a very lean
selection of options suited for IP routing and a few peripherals
on the I2C and SPI buses.

My userland is confined to an initramfs built around busybox.

I also disable gmac1 because I need a few of the rgmii2 pins for
modem control signalling.

Regards
Justin

PS: Yes, I only have access to MT7621AT SoCs.


> On 5.03.2024 07:39, Justin Swartz wrote:
>> Disable LEDs just before resetting the MT7530 to avoid
>> situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
>> states may cause an unintended external crystal frequency
>> to be selected.
>> 
>> The HT_XTAL_FSEL (External Crystal Frequency Selection)
>> field of HWTRAP (the Hardware Trap register) stores a
>> 2-bit value that represents the state of the ESW_P4_LED_0
>> and ESW_P4_LED_0 pins (seemingly) sampled just after the
>> MT7530 has been reset, as:
>> 
>>      ESW_P4_LED_0    ESW_P3_LED_0    Frequency
>>      -----------------------------------------
>>      0               1               20MHz
>>      1               0               40MHz
>>      1               1               25MHz
>> 
>> The value of HT_XTAL_FSEL is bootstrapped by pulling
>> ESW_P4_LED_0 and ESW_P3_LED_0 up or down accordingly,
>> but:
>> 
>>    if a 40MHz crystal has been selected and
>>    the ESW_P3_LED_0 pin is high during reset,
>> 
>>    or a 20MHz crystal has been selected and
>>    the ESW_P4_LED_0 pin is high during reset,
>> 
>>    then the value of HT_XTAL_FSEL will indicate
>>    that a 25MHz crystal is present.
>> 
>> By default, the state of the LED pins is PHY controlled
>> to reflect the link state.
>> 
>> To illustrate, if a board has:
>> 
>>    5 ports with active low LED control,
>>    and HT_XTAL_FSEL bootstrapped for 40MHz.
>> 
>> When the MT7530 is powered up without any external
>> connection, only the LED associated with Port 3 is
>> illuminated as ESW_P3_LED_0 is low.
>> 
>> In this state, directly after mt7530_setup()'s reset
>> is performed, the HWTRAP register (0x7800) reflects
>> the intended HT_XTAL_FSEL (HWTRAP bits 10:9) of 40MHz:
>> 
>>    mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007dcf
>> 
>>    >>> bin(0x7dcf >> 9 & 0b11)
>>    '0b10'
>> 
>> But if a cable is connected to Port 3 and the link
>> is active before mt7530_setup()'s reset takes place,
>> then HT_XTAL_FSEL seems to be set for 25MHz:
>> 
>>    mt7530-mdio mdio-bus:1f: mt7530_read: 00007800 == 00007fcf
>> 
>>    >>> bin(0x7fcf >> 9 & 0b11)
>>    '0b11'
>> 
>> Once HT_XTAL_FSEL reflects 25MHz, none of the ports
>> are functional until the MT7621 (or MT7530 itself)
>> is reset.
>> 
>> By disabling the LED pins just before reset, the chance
>> of an unintended HT_XTAL_FSEL value is reduced.
>> 
>> Signed-off-by: Justin Swartz <justin.swartz@risingedge.co.za>
>> ---
>>   drivers/net/dsa/mt7530.c | 6 ++++++
>>   1 file changed, 6 insertions(+)
>> 
>> diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
>> index 3c1f65759..8fa113126 100644
>> --- a/drivers/net/dsa/mt7530.c
>> +++ b/drivers/net/dsa/mt7530.c
>> @@ -2238,6 +2238,12 @@ mt7530_setup(struct dsa_switch *ds)
>>   		}
>>   	}
>>   +	/* Disable LEDs before reset to prevent the MT7530 sampling a
>> +	 * potentially incorrect HT_XTAL_FSEL value.
>> +	 */
>> +	mt7530_write(priv, MT7530_LED_EN, 0);
>> +	usleep_range(1000, 1100);
>> +
>>   	/* Reset whole chip through gpio pin or memory-mapped registers for
>>   	 * different type of hardware
>>   	 */
Andrew Lunn March 12, 2024, 1:03 a.m. UTC | #7
> (b) When a cable attached to an active peer is connected to
> Port 3 (lan4) before reset, the incorrect crystal frequency
> selection (0b11 = 25MHz) always occurs:
> 
>               [7]      [8]     [10]    [12]
>               :        :       :       :
>               _________         ______________________________________
> ESW_P4_LED_0           |_______|
>               _________         _______
> ESW_P3_LED_0           |_______|       |______________________________
> 
>                         :     : :     :
>                         [9]...: [11]..:
> 
>  [7] Port 4 LED Off. Port 3 LED Off.
>  [8] Signals inverted. (reset_control_assert; reset_control_deassert)
>  [9] Period of 320 usec.
> [10] Signals inverted.
> [11] Period of 300 usec.
> [12] Signals reflect the bootstrapped configuration.

Shame the patch has already been accepted. The text in this email
would of made a cool commit message.

      Andrew
Paolo Abeni March 12, 2024, 10:46 a.m. UTC | #8
On Tue, 2024-03-12 at 11:38 +0300, Arınç ÜNAL wrote:
> On 12.03.2024 00:10, patchwork-bot+netdevbpf@kernel.org wrote:
> > Hello:
> > 
> > This patch was applied to netdev/net-next.git (main)
> > by Jakub Kicinski <kuba@kernel.org>:
> > 
> > On Tue,  5 Mar 2024 06:39:51 +0200 you wrote:
> > > Disable LEDs just before resetting the MT7530 to avoid
> > > situations where the ESW_P4_LED_0 and ESW_P3_LED_0 pin
> > > states may cause an unintended external crystal frequency
> > > to be selected.
> > > 
> > > The HT_XTAL_FSEL (External Crystal Frequency Selection)
> > > field of HWTRAP (the Hardware Trap register) stores a
> > > 2-bit value that represents the state of the ESW_P4_LED_0
> > > and ESW_P4_LED_0 pins (seemingly) sampled just after the
> > > MT7530 has been reset, as:
> > > 
> > > [...]
> > 
> > Here is the summary with links:
> >    - net: dsa: mt7530: disable LEDs before reset
> >      https://git.kernel.org/netdev/net-next/c/2920dd92b980
> > 
> > You are awesome, thank you!
> 
> I am once again calling for this patch to be reverted on the net-next tree
> on the basis of:
> 
> - This patch did not go through a proper reviewing process. There are
>    proposed changes on the code it changes regarding the scope and the
>    method of the patch, and improvements to be made on the patch log.
> 
> - This patch should be backported to stable releases, therefore it
>    shouldn't be on the net-next tree and should be submitted to the net tree
>    instead.

The net-next pull request is out:

https://lore.kernel.org/netdev/20240312042504.1835743-1-kuba@kernel.org/

at this point I believe we can't retract it unless there is a very
serious regression affecting most/all users. This does not look such
case.

I think the better option is follow-up on net with follow-up fixes if
any.

All the relevant patches could be sent to the stable tree later:

https://elixir.bootlin.com/linux/latest/source/Documentation/process/stable-kernel-rules.rst#L47

To try to reduce the possibilities of this kind of situation in the
future, may I kindly ask you to invest some more little time to help
the reviewers and the maintainers? e.g. trimming the replies explicitly
cutting all the unneeded parts in the quoted code/text would make the
whole conversation much easier to follow (at least to me). The netdev
volume is insane, it's very easy to get lost in a given thread and miss
relevant part of it.

Cheers,

Paolo
Justin Swartz March 12, 2024, 12:01 p.m. UTC | #9
Arınç

On 2024-03-12 04:41, Arınç ÜNAL wrote:
> On 12.03.2024 03:07, Justin Swartz wrote:
>> I took a similar approach, with calls to dev_info()
>> throughout mt7530_setup() plus mt7530_write(), mt7530_read()
>> and mt7530_rmw() to get an idea of the flow of execution and
>> which registers were being manipulated.
>> 
>> Calls to dev_info() affected timing, so I switched to using
>> trace_printk() and then read the output from the debugfs's
>> tracing/trace file instead of from the console.
>> 
>> I attached a logic analyzer to ESW_P4_LED_0 and ESW_P3_LED_0,
>> and manually triggered sampling as soon as execution of the
>> kernel was reported on UART1.
>> 
>> 
>> -- Test #1 -----------------------------------------------------------
>> 
>> For the sake of maximal reproducability, I removed the delay
>> between the assertion and deassertion of reset and added
>> HWTRAP value tracing:
>> 
>> ---%---
>> --- a/drivers/net/dsa/mt7530.c
>> +++ b/drivers/net/dsa/mt7530.c
>> @@ -2243,7 +2243,6 @@ mt7530_setup(struct dsa_switch *ds)
>>       */
>>      if (priv->mcm) {
>>          reset_control_assert(priv->rstc);
>> -        usleep_range(1000, 1100);
>>          reset_control_deassert(priv->rstc);
>>      } else {
>>          gpiod_set_value_cansleep(priv->reset, 0);
>> @@ -2260,6 +2259,10 @@ mt7530_setup(struct dsa_switch *ds)
>>          return ret;
>>      }
>> 
>> +    static char ht_xtal_fsel[4][6] = { "?????", "20MHz", "40MHz", 
>> "25MHz" };
>> +    trace_printk("HWTRAP = %x, HT_XTAL_FSEL = %s\n",
>> +        val, ht_xtal_fsel[(val & HWTRAP_XTAL_MASK) >> 9]);
>> +
>>          id = mt7530_read(priv, MT7530_CREV);
>>          id >>= CHIP_NAME_SHIFT;
>>          if (id != MT7530_ID) {
>> ---%---
>> 
>> (a) Without a cable connected to Port 3 (lan4) before reset, the
>> correct external crystal frequency is selected:
>> 
>>                [3]      [4]     [6]
>>                :        :       :
>>                _________         
>> ______________________________________
>> ESW_P4_LED_0           |_______|
>>                          _______
>> ESW_P3_LED_0  _________|       |______________________________________
>> 
>>                          :     :
>>                          [5]...:
>> 
>> [3] Port 4 LED Off. Port 3 LED On.
>> [4] Signals inverted. (reset_control_assert; reset_control_deassert)
>> [5] Period of 310 usec.
>> [6] Signals reflect the bootstrapped configuration.
>> 
>> 
>> ~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
>>      2.432646: mt7530_setup: HWTRAP = 7dcf, HT_XTAL_FSEL = 40MHz
>> 
>> 
>> (b) When a cable attached to an active peer is connected to
>> Port 3 (lan4) before reset, the incorrect crystal frequency
>> selection (0b11 = 25MHz) always occurs:
>> 
>>                [7]      [8]     [10]    [12]
>>                :        :       :       :
>>                _________         
>> ______________________________________
>> ESW_P4_LED_0           |_______|
>>                _________         _______
>> ESW_P3_LED_0           |_______|       |______________________________
>> 
>>                          :     : :     :
>>                          [9]...: [11]..:
>> 
>>   [7] Port 4 LED Off. Port 3 LED Off.
>>   [8] Signals inverted. (reset_control_assert; reset_control_deassert)
>>   [9] Period of 320 usec.
>> [10] Signals inverted.
>> [11] Period of 300 usec.
>> [12] Signals reflect the bootstrapped configuration.
>> 
>> ~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
>>      2.432884: mt7530_setup: HWTRAP = 7fcf, HT_XTAL_FSEL = 25MHz
>> 
>> 
>> -- Test #2 -----------------------------------------------------------
>> 
>> To attempt to determine which transitions are associated
>> with asserting and deasserting reset, I performed another
>> test with a delay of what I intended to be a 1 sec period
>> where the MT7530 is held in reset:
>> 
>> ---%---
>> --- a/drivers/net/dsa/mt7530.c
>> +++ b/drivers/net/dsa/mt7530.c
>> @@ -2243,7 +2243,7 @@ mt7530_setup(struct dsa_switch *ds)
>>       */
>>      if (priv->mcm) {
>>          reset_control_assert(priv->rstc);
>> -        usleep_range(1000, 1100);
>> +        usleep_range(1000000, 1000000);
>>          reset_control_deassert(priv->rstc);
>>      } else {
>>          gpiod_set_value_cansleep(priv->reset, 0);
>> @@ -2260,6 +2260,10 @@ mt7530_setup(struct dsa_switch *ds)
>>          return ret;
>>      }
>> 
>> +    static char ht_xtal_fsel[4][6] = { "?????", "20MHz", "40MHz", 
>> "25MHz" };
>> +    trace_printk("HWTRAP = %x, HT_XTAL_FSEL = %s\n",
>> +        val, ht_xtal_fsel[(val & HWTRAP_XTAL_MASK) >> 9]);
>> +
>>      id = mt7530_read(priv, MT7530_CREV);
>>      id >>= CHIP_NAME_SHIFT;
>>      if (id != MT7530_ID) {
>> ---%---
>> 
>> (a) Without a cable connected to Port 3 (lan4) before reset, the
>> correct external crystal frequency is again selected:
>> 
>>                [13]     [14]    [16]
>>                :        :       :
>>                _________         
>> ______________________________________
>> ESW_P4_LED_0           |_______|
>>                          _______
>> ESW_P3_LED_0  _________|       |______________________________________
>> 
>>                          :     :
>>                          [15]..:
>> 
>> [13] Port 4 LED Off. Port 3 LED On.
>> [14] Signals inverted. (reset_control_deassert?)
>> [15] Period of 310 usec.
>> [16] Signals reflect the bootstrapped configuration.
>> 
>> 
>> ~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
>>      3.437461: mt7530_setup: HWTRAP = 7dcf, HT_XTAL_FSEL = 40MHz
>> 
>> 
>> No difference is apparent in the timing diagram, compared
>> to the result from Test #1a, but it is obvious that the code
>> which follows the reset was executed about 1 second later.
>> 
>> 
>> (b) With a cable from an active peer connected to Port 3
>> (lan4) before reset, the correct crystal frequency
>> (0b10 = 40MHz) is selected:
>> 
>>                [17]     [18]                    [20]   [22]
>>                :        :                       :      :
>>                ______________________ \ \ ______        
>> _______________
>> ESW_P4_LED_0                         / /       |______|
>>                _________              \ \        ______
>> ESW_P3_LED_0           |____________ / / ______|      |_______________
>>                                       \ \
>>                          :                     : :    :
>>                          [19]..................: [21].:
>> 
>> [17] Port 4 LED Off. Port 3 LED Off.
>> [18] ESW_P3_LED_0 set low. (reset_control_assert?)
>> [19] Period of 1000.325 msec.
>> [20] Signals inverted. (reset_control_deassert?)
>> [21] Period of 310 usec.
>> [22] Signals reflect the bootstrapped configuration.
>> 
>> 
>> ~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
>>      3.433235: mt7530_setup: HWTRAP = 7dcf, HT_XTAL_FSEL = 40MHz
>> 
>> 
>> So it appears that when reset is deasserted, the ESW_P4_LED_0
>> and ESW_P3_LED_0 levels are inverted for a period of about
>> 300 - 310 usec in Test #1a, #1b, #2a, and #2b.
>> 
>> Co-incidentally, these inverted levels are the active low
>> representation of what ends up in HT_XTAL_FSEL. And in all
>> four examples, have been the inversion of what immediately
>> preceded reset_control_deassert().
>> 
>> 
>> -- Test #3 -----------------------------------------------------------
>> 
>> Now it seems that there is a signature that can be used
>> to identify when reset_control_deassert() is executed,
>> the time of reset_control_assert()'s execution should be
>> between (at most) 1100 and (at least) 1000 usec prior
>> based on the unmodified reset logic.
>> 
>> So this patch only includes the HT_XTAL_FSEL trace.
>> 
>> ---%---
>> --- a/drivers/net/dsa/mt7530.c
>> +++ b/drivers/net/dsa/mt7530.c
>> @@ -2260,6 +2260,10 @@ mt7530_setup(struct dsa_switch *ds)
>>                  return ret;
>>          }
>> 
>> +       static char ht_xtal_fsel[4][6] = { "?????", "20MHz", "40MHz", 
>> "25MHz" };
>> +       trace_printk("HWTRAP = %x, HT_XTAL_FSEL = %s\n",
>> +               val, ht_xtal_fsel[(val & HWTRAP_XTAL_MASK) >> 9]);
>> +
>>          id = mt7530_read(priv, MT7530_CREV);
>>          id >>= CHIP_NAME_SHIFT;
>>          if (id != MT7530_ID) {
>> ---%---
>> 
>> The purpose of the following examples are to show the
>> variance in how long it takes for ESW_P3_LED_0 to go low.
>> 
>> (a) With a cable from an active peer connected to Port 3
>> (lan4) before reset, the correct crystal frequency
>> (0b10 = 40MHz) is selected.
>> 
>>                [23]    [24]       [26]      [28]    [30]
>>                :       :          :         :       :
>>                _____________________________         
>> __________________
>> ESW_P4_LED_0                               |_______|
>>                ___________________           _______
>> ESW_P3_LED_0                     |_________|       |__________________
>> 
>>                         :          :       : :     :
>>                         :          [27]....: [29]..:
>>                         [25]...............:
>> 
>> [23] Port 4 LED Off. Port 3 LED Off.
>> [24] Approximate point of reset_control_assert?
>> [25] Period of approximately 1000 - 1100 usec.
>> [26] ESW_P3_LED_0 finally goes low.
>> [27] Period of 415 usec.
>> [28] Signals inverted. (reset_control_deassert?)
>> [29] Period of 310 usec.
>> [30] Signals reflect the bootstrapped configuration.
>> 
>> 
>> (b) With a cable from an active peer connected to Port 3
>> (lan4) before reset, the correct crystal frequency
>> (0b10 = 40MHz) is selected.
>> 
>>                [31]    [32]            [34] [36]    [38]
>>                :       :                  : :       :
>>                _____________________________         
>> __________________
>> ESW_P4_LED_0                               |_______|
>>                ___________________________   _______
>> ESW_P3_LED_0                             |_|       |__________________
>> 
>>                         :                  : :     :
>>                         :               [35] [37]..:
>>                         :                  :
>>                         [33]...............:
>> 
>> [31] Port 4 LED Off. Port 3 LED Off.
>> [32] Approximate point of reset_control_assert?
>> [33] Period of approximately 1000 - 1100 usec.
>> [34] ESW_P3_LED_0 finally goes low.
>> [35] Period of 50 usec.
>> [36] Signals inverted. (reset_control_deassert?)
>> [37] Period of 310 usec.
>> [38] Signals reflect the bootstrapped configuration.
>> 
>> 
>> (c) With a cable from an active peer connected to Port 3
>> (lan4) before reset, an incorrect crystal frequency
>> (0b11 = 25MHz) is selected.
>> 
>>                [45]    [46]                 [48]    [50]
>>                :       :                    :       :
>>                _____________________________         
>> __________________
>> ESW_P4_LED_0                               |_______|
>>                _____________________________
>> ESW_P3_LED_0                               |__________________________
>> 
>>                         :                  : :     :
>>                         :                  : [49]..:
>>                         :                  :
>>                         [47]...............:
>> 
>> [45] Port 4 LED Off. Port 3 LED Off.
>> [46] Approximate point of reset_control_assert?
>> [47] Period of approximately 1000 - 1100 usec.
>> [48] Signals inverted. (reset_control_deassert?)
>> [49] Period of 315 usec.
>> [50] Signals reflect the bootstrapped configuration.
>> 
>> ~ # sed -n -e '$s/^.*\. //p' /sys/kernel/debug/tracing/trace
>>      2.617819: mt7530_setup: HWTRAP = 7fcf, HT_XTAL_FSEL = 25MHz
>> 
>> ~ # cat /proc/cmdline
>> console=ttyS0,57600 loglevel=7 printk.time=1 root=/dev/ram0 debug 
>> rdinit=/linuxrc
>> 
>> 
>> -- End of Tests ------------------------------------------------------
>> 
>> It seems that the incorrect crystal frequency is selected more
>> often when debugging messages are present (such as printk()
>> based approaches) and especially when loglevel=7 and printk.time=1
>> are specified on the command line.
>> 
>> For the sake of reference: I disabled ethernet support in my build
>> of (mainline) U-boot, and my kernel configuration is a very lean
>> selection of options suited for IP routing and a few peripherals
>> on the I2C and SPI buses.
>> 
>> My userland is confined to an initramfs built around busybox.
>> 
>> I also disable gmac1 because I need a few of the rgmii2 pins for
>> modem control signalling.
>> 
>> Regards
>> Justin
>> 
>> PS: Yes, I only have access to MT7621AT SoCs.
> 
> Thanks for the detailed presentation. I've simplified it to this, from 
> what
> I understood.
> 
> --- Currently 
> -------------------------------------------------------------
> 
> With a cable from an active peer connected to Port 3 (lan4) before
> reset:
> 
> Test 1, the correct crystal frequency (0b10 = 40MHz) is selected.
> 
>                       [1]        [2-1]     [3]     [5]
>                       :          :         :       :
>               _____________________________         __________________
> ESW_P4_LED_0                               |_______|
>               ___________________           _______
> ESW_P3_LED_0                     |_________|       |__________________
> 
>                        :          :       : :     :
>                        :          [2-2]...: [4]...:
>                        [2]................:
> 
> [1] reset_control_assert.
> [2] Period of 1000 - 1100 usec.
> [2-1] ESW_P3_LED_0 goes low.
> [2-2] Period of 415 usec.
> [3] reset_control_deassert.
> [4] Period of 310 usec. HWTRAP register is populated with bootstrapped
>     XTAL frequency.
> [5] Signals reflect the bootstrapped configuration.
> 
> Test 2, an incorrect crystal frequency (0b11 = 25MHz) is selected.
> 
>                       [2]                  [4]     [6]
>                       :                    :       :
>               _____________________________         __________________
> ESW_P4_LED_0                               |_______|
>               _____________________________
> ESW_P3_LED_0                               |__________________________
> 
>                        :                  : :     :
>                        :                  : [5]...:
>                        :                  :
>                        [3]................:
> 
> [1] reset_control_assert.
> [2] Period of 1000 - 1100 usec.
> [3] reset_control_deassert.
> [5] Period of 315 usec. HWTRAP register is populated with incorrect
>     XTAL frequency.
> [6] Signals reflect the bootstrapped configuration.
> 
> --- 1 second delay between assert and deassert 
> ----------------------------
> 
> With a cable from an active peer connected to Port 3 (lan4) before
> reset, the correct crystal frequency (0b10 = 40MHz) is selected:
> 
>                       [1]        [2-1]     [3]     [5]
>                       :          :         :       :
>               _____________________________         __________________
> ESW_P4_LED_0                               |_______|
>               ___________________           _______
> ESW_P3_LED_0                     |_________|       |__________________
> 
>                        :          :       : :     :
>                        :          [2-2]...: [4]...:
>                        [2]................:
> 
> [1] reset_control_assert.
> [3] Period of 1000.325 msec.
> [2-1] ESW_P3_LED_0 goes low.
> [2-2] Remaining period of 1000.325 msec.
> [3] reset_control_deassert.
> [4] Period of 310 usec. HWTRAP register is populated with bootstrapped
>     XTAL frequency.
> [5] Signals reflect the bootstrapped configuration.
> 
> ---
> 
> Wouldn't it be a better idea to increase the delay between
> reset_control_assert() and reset_control_deassert(), and
> gpiod_set_value_cansleep(priv->reset, 0) and
> gpiod_set_value_cansleep(priv->reset, 1) instead of disabling the LED
> controller and delaying before reset?

I've done some additional tests to see what the difference would be
between increasing the reset hold period vs. disabling the LEDs then
sleeping before reset.


I wanted to know:

When an active link is present on Port 3 at boot, what are the
minimum, maximum and average periods between ESW_P3_LED_0
going low and the signal inversion that seems to co-incide with
reset_control_deassert() for each approach?


I created two patches:

WITH INCREASED RESET DELAY

As I submitted a patch that added an intended 1000 - 1100 usec delay
before reset, I thought it would be fair to increase the reset hold
period by the same value.

---%---
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2243,11 +2243,11 @@ mt7530_setup(struct dsa_switch *ds)
          */
         if (priv->mcm) {
                 reset_control_assert(priv->rstc);
-               usleep_range(1000, 1100);
+               usleep_range(2000, 2200);
                 reset_control_deassert(priv->rstc);
         } else {
                 gpiod_set_value_cansleep(priv->reset, 0);
-               usleep_range(1000, 1100);
+               usleep_range(2000, 2200);
                 gpiod_set_value_cansleep(priv->reset, 1);
         }
---%---


DISABLE LEDS BEFORE RESET

Reset hold period unchanged from the intended 1000 - 1100 usec.

---%---
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2238,6 +2238,12 @@ mt7530_setup(struct dsa_switch *ds)
                 }
         }

+       /* Disable LEDs before reset to prevent the MT7530 sampling a
+        * potentially incorrect HT_XTAL_FSEL value.
+        */
+       mt7530_write(priv, MT7530_LED_EN, 0);
+       usleep_range(1000, 1100);
+
         /* Reset whole chip through gpio pin or memory-mapped registers 
for
          * different type of hardware
          */
---%---


I ran 20 tests per patch, applied exclusively. 40 tests in total.

      <-- ESW_P3_LED_0 Low Period before Reset Deassertion -->

   TEST    WITH INCREASED RESET DELAY    DISABLE LEDS BEFORE RESET
      #                        (usec)                       (usec)
-------------------------------------------------------------------
      1                           182                         4790
      2                           370                         3470
      3                           240                         4635
      4                          1475                         4850
      5                            70                         4775
      6                          2730                         4575
      7                          3180                         4565
      8                           265                         5650
      9                           270                         4690
     10                          1525                         4450
     11                          3210                         4735
     12                           120                         4690
     13                           185                         4625
     14                           305                         7020
     15                          2975                         4720
     16                           245                         4675
     17                           350                         4740
     18                            80                        17920
     19                           150                        17665
     20                           100                         4620

    Min                            70                         3470
    Max                          3210                        17920

   Mean                           270                         4720
    Avg                       923.421                     6161.579


Every test resulted in a 40MHz HT_XTAL_FSEL, but after seeing 70 usec
and 80 usec periods I wondered how many more tests it may take before
an 25MHz HT_XTAL_FSEL appears.

I was also surprised by the 17920 usec and 17665 usec periods listed
under the DISABLED LEDS BEFORE RESET column. Nothing unusual seemed
to be happening, at least as far as the kernel message output was
concerned.

What do you make of these results?


> One MT7531 pin used for an LED is also used to decide the crystal 
> frequency
> between 40MHz and 25Mhz. We should implement this there as well.
> 
> Arınç
Justin Swartz March 12, 2024, 3:25 p.m. UTC | #10
On 2024-03-12 16:06, Arınç ÜNAL wrote:
> On 12.03.2024 15:01, Justin Swartz wrote:
>> Arınç
>> 
>> On 2024-03-12 04:41, Arınç ÜNAL wrote:
>>> Wouldn't it be a better idea to increase the delay between
>>> reset_control_assert() and reset_control_deassert(), and
>>> gpiod_set_value_cansleep(priv->reset, 0) and
>>> gpiod_set_value_cansleep(priv->reset, 1) instead of disabling the LED
>>> controller and delaying before reset?
>> 
>> I've done some additional tests to see what the difference would be
>> between increasing the reset hold period vs. disabling the LEDs then
>> sleeping before reset.
>> 
>> 
>> I wanted to know:
>> 
>> When an active link is present on Port 3 at boot, what are the
>> minimum, maximum and average periods between ESW_P3_LED_0
>> going low and the signal inversion that seems to co-incide with
>> reset_control_deassert() for each approach?
>> 
>> 
>> I created two patches:
>> 
>> WITH INCREASED RESET DELAY
>> 
>> As I submitted a patch that added an intended 1000 - 1100 usec delay
>> before reset, I thought it would be fair to increase the reset hold
>> period by the same value.
>> 
>> ---%---
>> --- a/drivers/net/dsa/mt7530.c
>> +++ b/drivers/net/dsa/mt7530.c
>> @@ -2243,11 +2243,11 @@ mt7530_setup(struct dsa_switch *ds)
>>           */
>>          if (priv->mcm) {
>>                  reset_control_assert(priv->rstc);
>> -               usleep_range(1000, 1100);
>> +               usleep_range(2000, 2200);
>>                  reset_control_deassert(priv->rstc);
>>          } else {
>>                  gpiod_set_value_cansleep(priv->reset, 0);
>> -               usleep_range(1000, 1100);
>> +               usleep_range(2000, 2200);
>>                  gpiod_set_value_cansleep(priv->reset, 1);
>>          }
>> ---%---
>> 
>> 
>> DISABLE LEDS BEFORE RESET
>> 
>> Reset hold period unchanged from the intended 1000 - 1100 usec.
>> 
>> ---%---
>> --- a/drivers/net/dsa/mt7530.c
>> +++ b/drivers/net/dsa/mt7530.c
>> @@ -2238,6 +2238,12 @@ mt7530_setup(struct dsa_switch *ds)
>>                  }
>>          }
>> 
>> +       /* Disable LEDs before reset to prevent the MT7530 sampling a
>> +        * potentially incorrect HT_XTAL_FSEL value.
>> +        */
>> +       mt7530_write(priv, MT7530_LED_EN, 0);
>> +       usleep_range(1000, 1100);
>> +
>>          /* Reset whole chip through gpio pin or memory-mapped 
>> registers for
>>           * different type of hardware
>>           */
>> ---%---
>> 
>> 
>> I ran 20 tests per patch, applied exclusively. 40 tests in total.
>> 
>>       <-- ESW_P3_LED_0 Low Period before Reset Deassertion -->
>> 
>>    TEST    WITH INCREASED RESET DELAY    DISABLE LEDS BEFORE RESET
>>       #                        (usec)                       (usec)
>> -------------------------------------------------------------------
>>       1                           182                         4790
>>       2                           370                         3470
>>       3                           240                         4635
>>       4                          1475                         4850
>>       5                            70                         4775
>>       6                          2730                         4575
>>       7                          3180                         4565
>>       8                           265                         5650
>>       9                           270                         4690
>>      10                          1525                         4450
>>      11                          3210                         4735
>>      12                           120                         4690
>>      13                           185                         4625
>>      14                           305                         7020
>>      15                          2975                         4720
>>      16                           245                         4675
>>      17                           350                         4740
>>      18                            80                        17920
>>      19                           150                        17665
>>      20                           100                         4620
>> 
>>     Min                            70                         3470
>>     Max                          3210                        17920
>> 
>>    Mean                           270                         4720
-1s/  Mean/Median/

>>     Avg                       923.421                     6161.579
>> 
>> 
>> Every test resulted in a 40MHz HT_XTAL_FSEL, but after seeing 70 usec
>> and 80 usec periods I wondered how many more tests it may take before
>> an 25MHz HT_XTAL_FSEL appears.
>> 
>> I was also surprised by the 17920 usec and 17665 usec periods listed
>> under the DISABLED LEDS BEFORE RESET column. Nothing unusual seemed
>> to be happening, at least as far as the kernel message output was
>> concerned.
>> 
>> What do you make of these results?
> 
> What I see is setting ESW_P3_LED_0 low via reset assertion is much more
> efficient than doing so by setting the LED controller off. So I'd 
> prefer
> increasing the delay between assertion and reassertion. For example, 
> the
> Realtek DSA subdriver has a much more generous delay. 25ms after reset
> assertion [1].
> 
> Looking at your results, 2000 - 2200 usec delay still seems too close, 
> so
> let's agree on an amount that will ensure that boards in any 
> circumstances
> will have these pins back to the bootstrapping configuration before 
> reset
> deassertion. What about 5000 - 5100 usec?

    TEST    ESW_P3_LED_0 LOW PERIOD
       #                     (usec)
----------------------------------
       1                       5410
       2                       5440
       3                       4375
       4                       5490
       5                       5475
       6                       4335
       7                       4370
       8                       5435
       9                       4205
      10                       4335
      11                       3750
      12                       3170
      13                       4395
      14                       4375
      15                       3515
      16                       4335
      17                       4220
      18                       4175
      19                       4175
      20                       4350

     Min                       3170
     Max                       5490

  Median                   4342.500
     Avg                   4466.500

Looks reasonable to me.


> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/drivers/net/dsa/realtek/rtl83xx.c#n205
> 
> Arınç
Justin Swartz March 12, 2024, 4:35 p.m. UTC | #11
On 2024-03-12 17:25, Justin Swartz wrote:
> On 2024-03-12 16:06, Arınç ÜNAL wrote:
>> On 12.03.2024 15:01, Justin Swartz wrote:
>>> Arınç
>>> 
>>> On 2024-03-12 04:41, Arınç ÜNAL wrote:
>>>> Wouldn't it be a better idea to increase the delay between
>>>> reset_control_assert() and reset_control_deassert(), and
>>>> gpiod_set_value_cansleep(priv->reset, 0) and
>>>> gpiod_set_value_cansleep(priv->reset, 1) instead of disabling the 
>>>> LED
>>>> controller and delaying before reset?
>>> 
>>> I've done some additional tests to see what the difference would be
>>> between increasing the reset hold period vs. disabling the LEDs then
>>> sleeping before reset.
>>> 
>>> 
>>> I wanted to know:
>>> 
>>> When an active link is present on Port 3 at boot, what are the
>>> minimum, maximum and average periods between ESW_P3_LED_0
>>> going low and the signal inversion that seems to co-incide with
>>> reset_control_deassert() for each approach?
>>> 
>>> 
>>> I created two patches:
>>> 
>>> WITH INCREASED RESET DELAY
>>> 
>>> As I submitted a patch that added an intended 1000 - 1100 usec delay
>>> before reset, I thought it would be fair to increase the reset hold
>>> period by the same value.
>>> 
>>> ---%---
>>> --- a/drivers/net/dsa/mt7530.c
>>> +++ b/drivers/net/dsa/mt7530.c
>>> @@ -2243,11 +2243,11 @@ mt7530_setup(struct dsa_switch *ds)
>>>           */
>>>          if (priv->mcm) {
>>>                  reset_control_assert(priv->rstc);
>>> -               usleep_range(1000, 1100);
>>> +               usleep_range(2000, 2200);
>>>                  reset_control_deassert(priv->rstc);
>>>          } else {
>>>                  gpiod_set_value_cansleep(priv->reset, 0);
>>> -               usleep_range(1000, 1100);
>>> +               usleep_range(2000, 2200);
>>>                  gpiod_set_value_cansleep(priv->reset, 1);
>>>          }
>>> ---%---
>>> 
>>> 
>>> DISABLE LEDS BEFORE RESET
>>> 
>>> Reset hold period unchanged from the intended 1000 - 1100 usec.
>>> 
>>> ---%---
>>> --- a/drivers/net/dsa/mt7530.c
>>> +++ b/drivers/net/dsa/mt7530.c
>>> @@ -2238,6 +2238,12 @@ mt7530_setup(struct dsa_switch *ds)
>>>                  }
>>>          }
>>> 
>>> +       /* Disable LEDs before reset to prevent the MT7530 sampling a
>>> +        * potentially incorrect HT_XTAL_FSEL value.
>>> +        */
>>> +       mt7530_write(priv, MT7530_LED_EN, 0);
>>> +       usleep_range(1000, 1100);
>>> +
>>>          /* Reset whole chip through gpio pin or memory-mapped 
>>> registers for
>>>           * different type of hardware
>>>           */
>>> ---%---
>>> 
>>> 
>>> I ran 20 tests per patch, applied exclusively. 40 tests in total.
>>> 
>>>       <-- ESW_P3_LED_0 Low Period before Reset Deassertion -->
>>> 
>>>    TEST    WITH INCREASED RESET DELAY    DISABLE LEDS BEFORE RESET
>>>       #                        (usec)                       (usec)
>>> -------------------------------------------------------------------
>>>       1                           182                         4790
>>>       2                           370                         3470
>>>       3                           240                         4635
>>>       4                          1475                         4850
>>>       5                            70                         4775
>>>       6                          2730                         4575
>>>       7                          3180                         4565
>>>       8                           265                         5650
>>>       9                           270                         4690
>>>      10                          1525                         4450
>>>      11                          3210                         4735
>>>      12                           120                         4690
>>>      13                           185                         4625
>>>      14                           305                         7020
>>>      15                          2975                         4720
>>>      16                           245                         4675
>>>      17                           350                         4740
>>>      18                            80                        17920
>>>      19                           150                        17665
>>>      20                           100                         4620
>>> 
>>>     Min                            70                         3470
>>>     Max                          3210                        17920
>>> 
>>>    Mean                           270                         4720
> -1s/  Mean/Median/
> 
>>>     Avg                       923.421                     6161.579
>>> 
>>> 
>>> Every test resulted in a 40MHz HT_XTAL_FSEL, but after seeing 70 usec
>>> and 80 usec periods I wondered how many more tests it may take before
>>> an 25MHz HT_XTAL_FSEL appears.
>>> 
>>> I was also surprised by the 17920 usec and 17665 usec periods listed
>>> under the DISABLED LEDS BEFORE RESET column. Nothing unusual seemed
>>> to be happening, at least as far as the kernel message output was
>>> concerned.
>>> 
>>> What do you make of these results?
>> 
>> What I see is setting ESW_P3_LED_0 low via reset assertion is much 
>> more
>> efficient than doing so by setting the LED controller off. So I'd 
>> prefer
>> increasing the delay between assertion and reassertion. For example, 
>> the
>> Realtek DSA subdriver has a much more generous delay. 25ms after reset
>> assertion [1].
>> 
>> Looking at your results, 2000 - 2200 usec delay still seems too close, 
>> so
>> let's agree on an amount that will ensure that boards in any 
>> circumstances
>> will have these pins back to the bootstrapping configuration before 
>> reset
>> deassertion. What about 5000 - 5100 usec?
> 
>    TEST    ESW_P3_LED_0 LOW PERIOD
>       #                     (usec)
> ----------------------------------
>       1                       5410
>       2                       5440
>       3                       4375
>       4                       5490
>       5                       5475
>       6                       4335
>       7                       4370
>       8                       5435
>       9                       4205
>      10                       4335
>      11                       3750
>      12                       3170
>      13                       4395
>      14                       4375
>      15                       3515
>      16                       4335
>      17                       4220
>      18                       4175
>      19                       4175
>      20                       4350
> 
>     Min                       3170
>     Max                       5490
> 
>  Median                   4342.500
>     Avg                   4466.500
> 
> Looks reasonable to me.

I had messed up the Median/Average calculation with the data
I had pasted earlier after copying and pasting formulas without
double checking how they had been affected.

So here's the table again, now with the 5000 - 5100 usec test
run tacked on for easier comparison:

              2000 usec                      5000 usec
            - 2200 usec    DISABLE LEDS    - 5100 usec
    TEST     RESET HOLD    BEFORE RESET     RESET HOLD
       #         (usec)          (usec)         (usec)
--------------------------------------------------------
       1            182            4790           5410
       2            370            3470           5440
       3            240            4635           4375
       4           1475            4850           5490
       5             70            4775           5475
       6           2730            4575           4335
       7           3180            4565           4370
       8            265            5650           5435
       9            270            4690           4205
      10           1525            4450           4335
      11           3210            4735           3750
      12            120            4690           3170
      13            185            4625           4395
      14            305            7020           4375
      15           2975            4720           3515
      16            245            4675           4335
      17            350            4740           4220
      18             80           17920           4175
      19            150           17665           4175
      20            100            4620           4350

     Min             70            3470           3170
     Max           3210           17920           5490

  Median        267.500            4705       4342.500
     Avg        901.350            6093       4466.500


>> [1]
>> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/drivers/net/dsa/realtek/rtl83xx.c#n205
>> 
>> Arınç
diff mbox series

Patch

diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 3c1f65759..8fa113126 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2238,6 +2238,12 @@  mt7530_setup(struct dsa_switch *ds)
 		}
 	}
 
+	/* Disable LEDs before reset to prevent the MT7530 sampling a
+	 * potentially incorrect HT_XTAL_FSEL value.
+	 */
+	mt7530_write(priv, MT7530_LED_EN, 0);
+	usleep_range(1000, 1100);
+
 	/* Reset whole chip through gpio pin or memory-mapped registers for
 	 * different type of hardware
 	 */