Hi,
I have a custom board based upon the Beagle Bone Black revC3. The board occasionally has the problem that one of my two LAN8720 PHY(s) will not come up. The boot loader and kernel cannot find the PHY. The BBB C3 board includes GPIO controlled PHY reset circuit. The GPIO pin, uart0_ctsn.gpio1_8, is used to reset the LAN8710 ethernet PHY. My custom board uses that pin as uart4.rxd for my UART4. Instead, I choose gpmc_ben1.gpio1_28 as my PHY reset pin.
Here is snippet from my device tree.
davinci_mdio_default: davinci_mdio_default {
pinctrl-single,pins = <
/* MDIO */
AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* (M17) mdio_data.mdio_data */
AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0) /* (M18) mdio_clk.mdio_clk */
/* Added to support GPIO controlled PHY reset */
AM33XX_IOPAD(0x878, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (N14) gpmc_ben1.gpio1_28 */
>;
};
davinci_mdio_sleep: davinci_mdio_sleep {
pinctrl-single,pins = <
/* MDIO reset value */
AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M17) mdio_data.gpio0_0 */
AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7) /* (M18) mdio_clk.gpio0_1 */
/* Added to support GPIO controlled PHY reset */
AM33XX_IOPAD(0x878, PIN_INPUT_PULLDOWN | MUX_MODE7) /* (N14) gpmc_ben1.gpio1_28 */
>;
};
&davinci_mdio {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
status = "okay";
/* Support GPIO reset */
reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
reset-delay-us = <300>;
reset-deassert-us = <6500>;
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
ethphy1: ethernet-phy@1 {
reg = <1>;
};
};
&aes {
status = "okay";
};
While viewing gpio1_28 with an o-scope, I am expecting that gpio1_28 should pulse low for 300ms, during kernel boot just before MDIO probes for the PHYs. My problem is the signal stays high and I never see low pulse.
I temporarily removed the GPIO support lines from the DT so that I could try to control the line with sysfs. I used these commands in attempt to control the pin.
cd /sys/class/gpio
# I used 60 because (32x1) + 28 = 60
echo 60 > export
echo out > gpio60/direction
echo 1 > gpio60/value
echo 0 > gpio60/value
The gpio1_28 never changes state. I can control other GPIO pins with sysfs, so I know that sysfs works. I cannot control gpio1_28.
Is that something special about the gpmc_ben1 pin that won’t allow it to be used as a gpio1_28?
Thank you,
Your reset node is one level too far down..
RCN,
Thank you for your guidance. Here is snippet of my change.
&davinci_mdio {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
status = "okay";
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
/* Support GPIO reset */
reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
reset-delay-us = <300>;
reset-deassert-us = <6500>;
};
ethphy1: ethernet-phy@1 {
reg = <1>;
};
};
My board has two PHYs. Both of the Phy’s nRST pins are connected to the reset circuit. When the reset is asserted then both PHYs will be reset. I added the support for reset only to PHY0. My thought is that only one of he PHYs needs support for reset and will reset the other.
Since the reset signal is common to both PHYS, does only one PHY need the ‘support for reset’ properties or do they both need the properties?
Thank you,
as long as it’s defined in one, it’ll reset both..
RCN,
I have put the ‘support for reset’ properties in the ethphy0 node. Success! Using a o-scope shows a single reset pulse. Viewing the kernel code, mdio_bus.c mdiobus_register_device() gets called for each device in the DT (ethphy0, ethphy1…). However I cannot find how the kernel decides the order which the PHYs are registered. I think the order is important because the reset should be done before any PHY is probed for.
Will ethphy0 always be the first phy registered (probed)?
Thank you,
This depends on the specific kernel version, but most modern Major releases, do this in parallel for most of the supported peripherals.
RCN,
My kernel version is 6.1.134.
My previous snippets of the &davinci_mdio {} node have an error. the ‘reset-delay-us’ property is not correct. Instead, it should be ‘reset-assert-us’. Here is my corrected snippet.
&davinci_mdio {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
status = "okay";
ethphy0: ethernet-phy@0 {
reg = <0>;
/* Support GPIO reset */
reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
reset-assert-us = <300>;
reset-deassert-us = <50000>;
};
ethphy1: ethernet-phy@1 {
reg = <1>;
};
};
O-scope screen shot of reset signal during kernel boot. Scope probe is connected to BBB ETH_RESETn, pin-4 of the SN74AHC1G09DCKR. I noticed that the 300us value measured appox 0.640us pulse width.
Here are some other values I tried.
assert value = pulse width
10000us = 17.8ms
5000 = 7.8ms
1000 = 2.1ms
500 = 1.0ms
300 = 0.64ms
Thank you,
Here’s the values we eventually settled on with 6.1.x with an smsc phy… Making sure you're not a bot!
&davinci_mdio_sw {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
ethphy0: ethernet-phy@0 {
reg = <0>;
/* Support GPIO reset on revision C3 boards */
reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
reset-assert-us = <300>;
reset-deassert-us = <50000>;
};
};
RCN,
I understand the reset-assert-us value controls how long the reset pulse is held low. My guess is the reset-deassert-us value controls how to wait, after the pulse goes high, before attempting to probe for the PHY(s). It allows time for the PHYs to boot (if boot is the correct word here).
Do I understand correctly?
Thank you,