We have imx6ull and lan8720A. Many board works fine but there is couple of chips where ethernet do not always start up correctly. The main reason of bug is that phy's clock need to be always on for LAN8720A , but from some reason the clock goes down at kernel start-up. It is known bug and there is lot of patches for it like:
https://lore.kernel.org/patchwork/patch/861449/
,but error still occurs sometimes with kernel imx_5.4.24_2.1.0
When the device starts in error mode, we can see:
There is only two way to get ethernet works correctly
In the fec_main.c is function phy_reset_after_clk_enable() which should fix problem, but it do not change physical pin status to phy's RST pin (from SNVS_TAMPER9). I have measured pins with oscilloscope and RST pin change status at startup and seguence, but clock will disable after it. After that driver do not reset phy via RST-pin never.
Clock and RST sequence at kernel start-up looks like
RST 111110000111111111111111111111111111111111
CLK 000011111111000000000000000000000000011111
There is fec_reset_phy() function in main.c which should active RST-pin. I tried to use it in fec_main.c but I can see error in kernel:
fec 20b4000.ethernet: failed to get phy-reset-gpios: -16
Is there any way to get RST-pin works from driver?
I have also tried to keep clock always on by comment line "fec_enet_clk_enable(ndev, false);" from end of function fec_probe() in fec_main.c, but the kernel stuck after that.
Clock is connected from imx6ull ENET2_TX_CLK__ENET2_REF_CLK2 to LAN8720 XTAL1/CLKIN. Is that correct way to use clock? I haven't change any iomuxc pad settings to clock.
Devicetree:
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2
&pinctrl_enet2_mdio
&pinctrl_enet1_int_and_reset>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
phy-reset-duration = <5>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
smsc,disable-energy-detect;
interrupt-parent = <&gpio5>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
status = "okay";
};
};
};
&iomuxc_snvs {
pinctrl_enet1_int_and_reset: enet1intandresetgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05 0x1b0b0 /* ENET1_nINT */
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79 /* ENET1_nRESET */
>;
};
};
&iomuxc {
pinctrl-names = "default";
pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
>;
};
pinctrl_enet2_mdio: mdioenet2grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
>;
};
};
Now I found some kind of solution.
I changed to kernel version lf-5.10.y.
Reset pin is used in mdio region.
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
//phy-reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
//phy-reset-duration = <5>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
smsc,disable-energy-detect;
interrupt-parent = <&gpio5>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
reset-names = "phy";
reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
reset-assert-us = <1000>;
reset-deassert-us = <1000>;
status = "okay";
};
};
};
And then add the reset flag back, which has removed from this chip.
Now we have reset after and before clock enabled and ethernet works in all chips, but I'm not happy about the comment in the linked patch. It sounds like don't do that.
-Janne
I fixed u-boot's device tree and added reset function to u-boot. Now ping 8.8.8.8 works perfect in u-boot, so I think that network is ok in u-boot.
It didn't help in kernel side. I think that reason for this is that clock is disabled at the kernel startup, but RST pin doesn't active after clock is enabled again.
Best regards
Janne
Hi,
The following configuration is correct:
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2
&pinctrl_enet2_mdio
&pinctrl_enet1_int_and_reset>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
phy-reset-duration = <5>;
status = "okay";
......
But firstly you should confirm if the SNVS_TAMPER9 can be configured GPIO, we can know that by read fuse value.
you can operate fuse like below:
------------------------------------------------
To view or modify eFuse in the uboot phase, the syntax is as follows.
=> fuse read <bank> <word> [<cnt>]
//Read the value of eFuse from the shadow register
=> fuse sense <bank> <word> [<cnt>]
Reads the eFuse value directly from the fusebox.
=> fuse prog [-y] <bank> <word> <hexval>
//Write eFuse value to fusebox, this operation is irreversible, wrong operation may damage the chip
=> fuse override <bank> <word> <hexval> [<hexval>…]
//Only overwrite the value of the shadow register, this operation does not affect the physical fusebox. If the system is reset, this value will be cleared.
//This command is especially useful in testing.
So what are bank and word in the command line and how to calculate it?
In i.mx6ul and 6ull, a word is 32 bits, and 8 words form a bank. The bit number of word is from 0 to 31, and the word number of bank is from 0 to 7. So taking MAC as an example, you can calculate:
The base address of eFuse is: 21B_C000h base + 400h offset = 21B_C400h
The MAC address is: 21B_C000h base + 620h offset = 21B_C620h
(620h-400h) / 0x10 = 22h = 34d, here is the total number of words calculated, the address of the word is in steps of 0x10 (0x400, 0x410, 0x420...), so it must be divided by 0x10.
22h / 08h = 04h = 4d, because 8 words are a bank, so divide by 8 here, and finally get bank=4.
22h% 08h = 02h = 2d, after calculating the remainder, the second word of the fourth bank is obtained.
Read shadow register example
=> fuse read 4 2
Reading bank 4:
Word 0x00000002: 00000000
//00000000 is a hexadecimal number
---------------------------------------------------------------
If TAMPER_PIN_DISABLE[1:0]=01 or 11, it means SNVS_TAMPER9 pin can be used GPIO.
Try it, please!
Have a nice day!
B.R,
weidong
Thanks for the answer.
I calculated
(430h-400h)/10h = 3h = 3d
3h / 08h = 0h
3h% 08h = 03h
So,
=> fuse read 0 3
Reading bank 0:Word 0x00000003: 713100d4
Calculator shows that bits 20:21 are 1
best regards
Janne
Hi,
try the following device tree:
pinctrl_enet2: enet2grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO07__ENET2_MDC 0x1b0b0
MX6UL_PAD_GPIO1_IO06__ENET2_MDIO 0x1b0b0
MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN 0x1b0b0
MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00 0x1b0b0
MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00 0x1b0b0
MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01 0x1b0b0
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b031
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x79 /* LAN8720 PHY Reset */
MX6ULL_PAD_SNVS_TAMPER5__GPIO5_IO05 0x1b0b0 /* ENET1_nINT */
>;
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
phy-reset-duration = <5>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy1: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>; /* Phy address*/
smsc,disable-energy-detect;
interrupt-parent = <&gpio5>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
};
};
};
Have a nice day!
B.R,
weidong
Hi,
It didn't help.
Just for remaining, that we have 20 prototypes and other boards works fine. Only 2 boards starts with fault if we do not cool PHY-chip down in the kernel start-up.
Should processor atcive RST-pin after clk enabled?
>>Should processor atcive RST-pin after clk enabled?
Yes, this order is correct.
Now it active RST-pin before disable clk, but not after enable clk.
If I use reset-gpios inside ethphy0 (not in fec2) in device tree, processor active RST-pin every time when try to reset phy. I can't use reset-gpios in the fec2 and ethphy0 at same time.
Is this new feature to reset inside ethphy0, or is it only for other chips?
The reset of the PHY is done by the MAC driver, fec_main.c on the CPU side, . the reset gpio shouldn't be placed in the PHY driver.
Okay. Good to know.
Should mdio_device_reset() reset RST-pin? In this case it return from first if condition
if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl)
this function is called from phy_reset_after_clk_enable()
Hi,
LAN8720 is supported by a device tree of i.MX6SX board.
so you can read relevent code in it.
reset-gpio is only used to reset PHY after Phy's power , clock etc get ready, and the reset operation is controlled by MAC driver on cpu side. in other words, it is only Low to High operation of a GPIO, which is not related to mdio (used to manage phy).
Have a nice day!
B.R
weidong
Hi,
It's not enough to reset LAN8720 after it get power. It need to reset every time after clock has been disabled.
I found patch which uses gpio-reset in PHY in later kernel version:
I know that mdio should be to the communication with PHY registers, but if I use reset-gpio inside PHY like link above, it looks like mdio_device_reset() resets phy after every clock enabled via gpio-reset.
If it's not right place. Please show me where is correct function to reset phy after clock enabled.
Best regards
Janne Terho
Hi,
I am considering whether we are in the wrong direction, we return to this phenomenon:
>> we have 20 prototypes and other boards works fine. Only 2 boards starts with fault if we do not cool PHY-chip down in the kernel start-up.
18 boards work well, only 2 boards have ethernet errors. This shows that there are no issues with hardware and software.
Therefore, do issues come from production and manufacturing?
Can you consider looking for issues in this direction?
Have a nice day!
B.R,
weidong
Hi,
We started to find solution from producting and manufacturing first. We have changed lot of components and tried to find solutions in many many ways. After all tests and informations it looks like it is known issue and it should work when code is correct.
Like in my first messages link and many other patches says
https://lore.kernel.org/patchwork/patch/861449/
In our specific case (PCB) this problem does occur at about every 10th to 50th POR of an LAN8710 connected to an i.MX6SOLO SoC.
We have noticed that it should works when reset PHY after clock enable and now I want to try it via kernel driver, but I haven't find to way to test it. If it will not work, it could be good idea to change chip.
Best regards,
Janne
Hi Janne,
Maybe replacing the PHY chip is a way, but this should be the choice when there is no other way.
You mentioned earlier that you manually reset the LAN8720, and it will work normally.
If you operate reset in this way, can you make it work normally?
--multiplex SNVS_TAMPER9 as GPIO
--remove reset-gpio from fec2 node
--After the linux boot is complete, operate this GPIO on the command line to reset the PHY.
Can PHY work normally? Can you test it?
Have a great day!
B.R,
weidong
Hi Janne,
I checked source code just now.
Did you add lan8720a to linux-imx/arch/arm/mach-imx/mach-imx6ul.c ?
ksz8081 on evk board is handled in the file.
Have a nice day!
B.R,
weidong