cancel
Showing results for 
Search instead for 
Did you mean: 

Bringing up Ethernet on STM32MP153 with KSZ8081RNB in RMII mode and 25 MHz clock on ETH_CLK (no PHY Crystal)

velaros
Associate III

Hello!

I have an issue on a custom board with STM32MP153CAB and KSZ8081RNB.

TF-A, FIP and kernel were built in Developer package. Linux distribution was built as startard configuration st-image-core in Distribution package.

Clocks and device trees are configured like specified in https://wiki.st.com/stm32mpu/wiki/Ethernet_device_tree_configuration#RMII_with_25MHz_on_ETH_CLK_-28no_PHY_Crystal-29-2C_REF_CLK_from_PHY_-28Reference_clock_-28standard_RMII_clock_name-29_is_provided_by_a_RCC_SoC_internal_clock-29

Here are fragments of device tree for U-Boot and kernel (generated by STM32CubeIDE and manually edited):

eth1_pins_mx: eth1_mx-0 {
		pins1 {
			pinmux = <STM32_PINMUX('A', 1, AF11)>, /* ETH1_REF_CLK */
					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
					 <STM32_PINMUX('G', 8, AF2)>, /* ETH1_CLK */
					 <STM32_PINMUX('G', 13, AF11)>, /* ETH1_TXD0 */
					 <STM32_PINMUX('G', 14, AF11)>; /* ETH1_TXD1 */
			bias-disable;
			drive-push-pull;
			slew-rate = <1>;
		};
		pins2 {
			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
			bias-disable;
			drive-push-pull;
			slew-rate = <0>;
		};
		pins3 {
			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
					 <STM32_PINMUX('C', 5, AF11)>; /* ETH1_RXD1 */
			bias-disable;
		};
		pins4 {
			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
		};
	};
 
	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
		pins {
			pinmux = <STM32_PINMUX('A', 1, ANALOG)>, /* ETH1_REF_CLK */
					 <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
					 <STM32_PINMUX('G', 8, ANALOG)>, /* ETH1_CLK */
					 <STM32_PINMUX('G', 13, ANALOG)>, /* ETH1_TXD0 */
					 <STM32_PINMUX('G', 14, ANALOG)>; /* ETH1_TXD1 */
		};
	};
 
&ethernet0{
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&eth1_pins_mx>;
	pinctrl-1 = <&eth1_sleep_pins_mx>;
	status = "okay";
 
	/* USER CODE BEGIN ethernet0 */
 
	phy-mode = "rmii";
	max-speed = <100>;
	phy-handle = <&phy0>;
	local-mac-address = [XX XX XX XX XX XX];
	mdio0 {
			#address-cells = <1>;
			#size-cells = <0>;
			compatible = "snps,dwmac-mdio";
			phy0: ethernet-phy@1 {
					reg = <1>;
					clocks = <&rcc ETHCK_K>;
					clock-names = "rmii-ref";
       		};
	};
 
	/* USER CODE END ethernet0 */
};

At first, I tested it in U-Boot.

After power on and reset it seems like MPU does not see PHY (and leds on RJ-45 are off). "mdio list" command shows only this: 

ethernet@5800a000:

After I set ipaddr and make ping, leds on RJ-45 become on and the answer to ping is received. The same thing after dhcp or bootp command.

"mdio list" now shows: 

ethernet@5800a000:
1 - Micrel KSZ8081 <--> ethernet@5800a000

When kernel loads, the following log appears: 

...
[    2.828774] stm32-dwmac 5800a000.ethernet: IRQ eth_lpi not found
[    2.833564] stm32-dwmac 5800a000.ethernet: PTP uses main clock
[    2.839294] stm32-dwmac 5800a000.ethernet: no reset control found
[    2.845980] stm32-dwmac 5800a000.ethernet: User ID: 0x40, Synopsys ID: 0x42
[    2.852185] stm32-dwmac 5800a000.ethernet:   DWMAC4/5
[    2.857216] stm32-dwmac 5800a000.ethernet: DMA HW capability register supported
[    2.864426] stm32-dwmac 5800a000.ethernet: RX Checksum Offload Engine supported
[    2.871772] stm32-dwmac 5800a000.ethernet: TX Checksum insertion supported
[    2.878618] stm32-dwmac 5800a000.ethernet: Wake-Up On Lan supported
[    2.884974] stm32-dwmac 5800a000.ethernet: TSO supported
[    2.890173] stm32-dwmac 5800a000.ethernet: Enable RX Mitigation via HW Watchdog Timer
[    2.897994] stm32-dwmac 5800a000.ethernet: Enabled Flow TC (entries=2)
[    2.904475] stm32-dwmac 5800a000.ethernet: TSO feature enabled
[    2.910324] stm32-dwmac 5800a000.ethernet: Using 32 bits DMA width
[    2.917336] libphy: stmmac: probed
...
[   14.178529] stm32-dwmac 5800a000.ethernet eth0: PHY [stmmac-0:01] driver [Micrel KSZ8081 or KSZ8091] (irq=POLL)
[   14.264265] stm32-dwmac 5800a000.ethernet eth0: IEEE 1588-2008 Advanced Timestamp supported
[   14.333679] stm32-dwmac 5800a000.ethernet eth0: registered PTP clock
[   14.369464] stm32-dwmac 5800a000.ethernet eth0: configuring for phy/rmii link mode
...

And I can not make ethernet work in kernel though it must start work automatically with DHCP.

ifconfig says that link is up, but ethtool shows that link is not detected. Autonegotiation does not start on "ethtool -r eth0".

I launched the same linux image (with my builds of TF-A, FIP and device trees) on STM32MP157C-DK2 board. Ethernet starts work immediately after kernel booting or cable plugging in RJ-45. In U-Boot it works the same way as on my board.

What can be the isuue?

1 ACCEPTED SOLUTION

Accepted Solutions

I checked this and it seems that SYSCFG ETH_REF_CLK_SEL bit is set, so MAC is really clocked wrongly.

I digged in the linux driver (https://github.com/STMicroelectronics/linux/blob/v5.10-stm32mp/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c) and discovered that in stm32mp1_set_mode() function it always sets this bit with enabling clock.

So using 25 MHz mode without crystal is impossible at all:

...
case PHY_INTERFACE_MODE_RMII:
	val = SYSCFG_PMCR_ETH_SEL_RMII;
	if ((clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_50M) &&
		(dwmac->eth_ref_clk_sel_reg || dwmac->ext_phyclk)) {
		dwmac->enable_eth_ck = true;
		val |= SYSCFG_PMCR_ETH_REF_CLK_SEL;
	}
	pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
	break;
...

I changed this to the following:

...
case PHY_INTERFACE_MODE_RMII:
	val = SYSCFG_PMCR_ETH_SEL_RMII;
	if (clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_50M) {
		dwmac->enable_eth_ck = true;
		if (clk_rate == ETH_CK_F_50M && 
			(dwmac->eth_ref_clk_sel_reg || dwmac->ext_phyclk)) {
			val |= SYSCFG_PMCR_ETH_REF_CLK_SEL;
		}
	}
	pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
	break;
...

And now it finally works fine in 25 MHz mode, and I can see clock on PCB.

I don't really get the meaning of "st,ext-phyclk" so my patch may be wrong. But the current driver definitely seems buggy. I didn't checked U-Boot but there also may be similar bugs.

As I understand, in the master of the ST Linux repository this driver is reworked, so it may be not the issue in future releases.

View solution in original post

21 REPLIES 21
OlivierK
ST Employee

Hi velaros (Community Member)

Some remarks/hints

  • To me it is strange to see clocks and clock-names in the phy node, these should be added in the stm32mp151.dtsi in U-boot/Kernel DT source files.

clocks = <&rcc ETHCK_K>;

clock-names = "rmii-ref";

  • I guess you've updated TFA devicetree to generate 25Mhz clock (from PLL4P or PLL3Q)
  • Are you sure you are using the Micrel PHY?

>make menuconfig

Symbol: PHY_MICREL_KSZ8XXX [=n] │

│ Type : bool │

│ Prompt: Micrel KSZ8xxx family support │

│ Location: │

│ -> Device Drivers │

│ -> Ethernet PHY (physical media interface) support (PHYLIB [=y]) │

│ (2) -> Micrel Ethernet PHYs support (PHY_MICREL [=n])

  • Digging the subject, we had a similar case (autonegociation fails) with the same PHY because the u-boot driver was not up to date.

PHY patch:

diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c

index 60d42fe984..7f96d1e393 100644

--- a/drivers/net/phy/micrel_ksz8xxx.c

+++ b/drivers/net/phy/micrel_ksz8xxx.c

@@ -28,6 +28,11 @@ static struct phy_driver KSZ804_driver = {

#define KSZPHY_OMSO_FACTORY_TEST BIT(15)

#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)

+#define MII_KSZPHY_CTRL_1 0x1e

+#define MII_KSZPHY_CTRL_2 0x1f

+#define MII_KSZPHY_CTRL MII_KSZPHY_CTRL_2

+#define KSZPHY_RMII_REF_CLK_SEL BIT(7)

+

static int ksz_genconfig_bcastoff(struct phy_device *phydev)

{

int ret;

@@ -102,13 +107,24 @@ static int ksz8081_config(struct phy_device *phydev)

int ret;

ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);

+

if (ret < 0)

return ret;

ret &= ~KSZPHY_OMSO_FACTORY_TEST;

+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO, ret);

+

+ if (ret < 0)

+ return ret;

+

+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_CTRL);

+

+ if (ret < 0)

+ return ret;

+

+ ret |= KSZPHY_RMII_REF_CLK_SEL;

+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_CTRL, ret);

- ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,

- ret | KSZPHY_OMSO_B_CAST_OFF);

if (ret < 0)

return ret;

Hope it helps.

Regards,

Olivier

velaros
Associate III

Hi, Olivier!

Сlocks and clock-names in phy node is specifically requested for micrel PHYs to specify the frequency (https://www.kernel.org/doc/Documentation/devicetree/bindings/net/micrel.txt). Of course, this clock is declared in the dts header stm32mp151.dtsi. 

TFA devicetree is configured for using 25 MHz from PLL3Q.

The Micrel PHY is selected in menuconfig (as you can see, U-Boot shows the correct name of the PHY).

As far as I understand, your U-Boot patch force PHY to 50 MHz clk mode. I tried it and PHY not worked at all (negotiation failed), while before patching it worked after "dhcp" command.

I checked the settings written to PHY by kernel, and seems like kernel writes correct '0' value to clock select bit.

velaros
Associate III

I have found that actually I don't need to use 25 MHz clock at ETH_CLK.

I changed settings to 50 MHz and patched device trees as specified at https://wiki.st.com/stm32mpu/wiki/Ethernet_device_tree_configuration#RMII_with_50MHz_on_ETH_CLK_-28no_PHY_Crystal-29-2C_internal_REF_CLK_from_RCC_-28Reference_clock_-28standard_RMII_clock_name-29_is_provided_by_a_RCC_SoC_internal_clock-29

With these setting eth0 is working right after kernel booting.

My problem is solved because it is not critical for me to use 25 MHz clock but there still may be some issue if someone really need this mode.

Hi,

Could you share your HW Setup around KSZ8081RNB ?

Do you have 25MHz crystal on XI/XO pins or XI connected to ETH_CLK ?

Is the KSZ8081RNB REF_CLK pin connected to STM32MP15x REF_CLK pin ?

What is the config of KSZ8081RNB SW setting between 25MHz and 50MHz mode ?

I suggest to carefully map the right Device Tree from wiki with your HW. See also AN5031.

Regards.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hi, Patrick.

The fragment of schematic is attached.

There is no crystal, XI is connected to ETH_CLK, REF_CLK is connected to STM32MP153.

I wrote my device tree as said in wiki, the ethernet fragment is shown in the first message. As I can see, my settings satisfy requirements from AN5031.

To use 50MHz the config was changed as follows:

- ETH_CLK was set to 50MHz (TFA and U-Boot device trees generated from STM32CubeIDE);

- pinctrl changed, and added "st,eth-ref-clk-sel" to ethernet node:

	eth1_pins_mx: eth1_mx-0 {
		pins1 {
			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
			bias-disable;
			drive-push-pull;
			slew-rate = <0>;
		};
		pins2 {
			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
					 <STM32_PINMUX('C', 5, AF11)>, /* ETH1_RXD1 */
					 <STM32_PINMUX('G', 12, AF11)>; /* ETH1_PHY_INTN */
			bias-disable;
		};
		pins3 {
			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
		};
		pins4 {
			pinmux = <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
					 <STM32_PINMUX('G', 8, AF2)>, /* ETH1_CLK */
					 <STM32_PINMUX('G', 13, AF11)>, /* ETH1_TXD0 */
					 <STM32_PINMUX('G', 14, AF11)>; /* ETH1_TXD1 */
			bias-disable;
			drive-push-pull;
			slew-rate = <1>;
		};
	};
 
	eth1_sleep_pins_mx: eth1_sleep_mx-0 {
		pins {
			pinmux = <STM32_PINMUX('A', 2, ANALOG)>, /* ETH1_MDIO */
					 <STM32_PINMUX('A', 7, ANALOG)>, /* ETH1_CRS_DV */
					 <STM32_PINMUX('B', 11, ANALOG)>, /* ETH1_TX_EN */
					 <STM32_PINMUX('C', 1, ANALOG)>, /* ETH1_MDC */
					 <STM32_PINMUX('C', 4, ANALOG)>, /* ETH1_RXD0 */
					 <STM32_PINMUX('C', 5, ANALOG)>, /* ETH1_RXD1 */
					 <STM32_PINMUX('G', 8, ANALOG)>, /* ETH1_CLK */
					 <STM32_PINMUX('G', 12, ANALOG)>, /* ETH1_PHY_INTN */
					 <STM32_PINMUX('G', 13, ANALOG)>, /* ETH1_TXD0 */
					 <STM32_PINMUX('G', 14, ANALOG)>; /* ETH1_TXD1 */
		};
	};
 
&ethernet0{
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&eth1_pins_mx>;
	pinctrl-1 = <&eth1_sleep_pins_mx>;
	status = "okay";
 
	/* USER CODE BEGIN ethernet0 */
	
	phy-mode = "rmii";
	max-speed = <100>;
	phy-handle = <&phy0>;
	st,eth-ref-clk-sel;
	local-mac-address = [XX XX XX XX XX XX];
	mdio0 {
			#address-cells = <1>;
			#size-cells = <0>;
			compatible = "snps,dwmac-mdio";
			phy0: ethernet-phy@1 {
					reg = <1>;
					clocks = <&rcc ETHCK_K>;
					clock-names = "rmii-ref";
       		};
	};
	
	/* USER CODE END ethernet0 */
};

0693W00000DmHrUQAV.png

OlivierK
ST Employee

Hi,

The issue might be linked to the 50MHz Eth ref clk coming from the PHY not seen by the MAC in the initial 25MHz configuration. Did you checked at the oscilloscope you truly had the Eth_ref_clk=50MHz on PA1 ?

Rgds,

Olivier

PatrickF
ST Employee

Hi,

if you feed 50MHz to PHY (and btw 50MHz internally from RCC to GMAC), you don't need to connect the REF_CLK, but this should not hurt (you could gain one pin).

Note that st,eth-ref-clk-sel (or st,eth_ref_clk_sel for uBoot) is for ecosystem v2.1 using kernel 5.4

For ecosystem v3 and kernel 5.10, it is st,ext-phyclk (for both kernel and uBoot).

Did you check that your PHY is correctly setup to use 50MHz on XI ?

I understand from KSZ8081RNB datasheet that driver need to set internal KSZ8081RNB registers 0x1F bit 7 to enable that.

Did you check that the 50MHz output is present on pin PG8 ?

Did you check you correctly enabled the 50MHz clock tree with right frequency in TF-A ?

e.g. with PLL4P (VCO @ 600MHz)

st,pkcs = <
....
 CLK_ETH_PLL4P
....
   pll4: st,pll@3 {
     compatible = "st,stm32mp1-pll";
     reg = <3>;
    cfg = < 1 49 11 9 9 PQR(1,1,1) >;
  };

You could use cat /sys/kernel/debug/clk/clk_summary to check PLL4P or PLL3Q frequency and usage

Regards.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

When I use ETH_CLK at 50 MHz all works perfectly, so I think the PHY is set up correctly.

I checked PHY setup when ETH_CLK was at 25 MHz and it seems that it also get correct setup (I added printf to kernel code and this register was set it should be).

Unfortunately I cannot test signals directly on STM32 pins because of BGA package. So I tested ETH_CLK on the R3 resistor and KSZ8081 input pin. At 50 MHz the signal is correct, but at 25 MHz there is no clock.

I checked clk_summary and got the following:

At 50 MHz:

enable  prepare  protect                                duty
   clock                          count    count    count        rate   accuracy phase  cycle
---------------------------------------------------------------------------------------------
...
       pll3_q                         1        1        0    50000000          0     0  50000
          ethptp_k                    0        0        0    50000000          0     0  50000
          ethck_k                     1        1        0    50000000          0     0  50000

At 25 MHz:

enable  prepare  protect                                duty
   clock                          count    count    count        rate   accuracy phase  cycle
---------------------------------------------------------------------------------------------
...
       pll3_q                         0        0        0    25000000          0     0  47619
          ethptp_k                    0        0        0    25000000          0     0  50000
          ethck_k                     0        0        0    25000000          0     0  50000

I see that "enable count" for pll3_q and ethck_k is 0 at 25 MHz, so it explains the absence of clock but I don't know why it is not enabled.

I also tried to use pll4_p as source for ETH_CLK, but result was the same.

I tested ETH_REF_CLK when 25 MHz was absent and got a signal of about 28 MHz. As I cannot test in on STM32 BGA package I tested in using PCB via in the middle of the signal.

At the same time Ethernet worked in U-Boot but I don't know how.

My clock setting in device trees:

 At 50 MHz (PLL3Q), not using ETH_REF_CLK:

st,pkcs = <
		CLK_CKPER_DISABLED
		CLK_FMC_ACLK
		CLK_ETH_PLL3Q
		CLK_SDMMC12_PLL3R
		CLK_STGEN_HSI
		CLK_USBPHY_PLL4R
...
	pll3:st,pll@2 {
		compatible = "st,stm32mp1-pll";
		reg = <2>;
		cfg = < 1 49 2 11 2 PQR(1,1,1) >;
	};
	pll4:st,pll@3 {
		compatible = "st,stm32mp1-pll";
		reg = <3>;
		cfg = < 2 59 1 1 19 PQR(0,0,1) >;
	};

At 25 MHz (PLL3Q):

st,pkcs = <
		CLK_CKPER_DISABLED
		CLK_FMC_ACLK
		CLK_ETH_PLL3Q
		CLK_SDMMC12_PLL3R
		CLK_STGEN_HSI
		CLK_USBPHY_PLL4R
...
	pll3:st,pll@2 {
		compatible = "st,stm32mp1-pll";
		reg = <2>;
		cfg = < 1 42 2 20 2 PQR(1,1,1) >;
		frac = < 0x1800 >;
	};
	pll4:st,pll@3 {
		compatible = "st,stm32mp1-pll";
		reg = <3>;
		cfg = < 2 59 1 1 19 PQR(0,0,1) >;
	};

At 25 MHz (PLL4P):

st,pkcs = <
		CLK_CKPER_DISABLED
		CLK_FMC_ACLK
		CLK_ETH_PLL4P
		CLK_SDMMC12_PLL3R
		CLK_STGEN_HSI
		CLK_USBPHY_HSE
...
	pll3:st,pll@2 {
		compatible = "st,stm32mp1-pll";
		reg = <2>;
		cfg = < 1 42 2 20 2 PQR(1,0,1) >;
		frac = < 0x1800 >;
	};
	pll4:st,pll@3 {
		compatible = "st,stm32mp1-pll";
		reg = <3>;
		cfg = < 1 49 23 1 11 PQR(1,0,1) >;
	};

Pins at 25 MHz:

eth1_pins_mx: eth1_mx-0 {
		pins1 {
			pinmux = <STM32_PINMUX('A', 1, AF11)>, /* ETH1_REF_CLK */
					 <STM32_PINMUX('C', 1, AF11)>, /* ETH1_MDC */
					 <STM32_PINMUX('G', 8, AF2)>, /* ETH1_CLK */
					 <STM32_PINMUX('G', 13, AF11)>, /* ETH1_TXD0 */
					 <STM32_PINMUX('G', 14, AF11)>; /* ETH1_TXD1 */
			bias-disable;
			drive-push-pull;
			slew-rate = <1>;
		};
		pins2 {
			pinmux = <STM32_PINMUX('A', 2, AF11)>; /* ETH1_MDIO */
			bias-disable;
			drive-push-pull;
			slew-rate = <0>;
		};
		pins3 {
			pinmux = <STM32_PINMUX('A', 7, AF11)>, /* ETH1_CRS_DV */
					 <STM32_PINMUX('C', 4, AF11)>, /* ETH1_RXD0 */
					 <STM32_PINMUX('C', 5, AF11)>, /* ETH1_RXD1 */
					 <STM32_PINMUX('G', 12, AF11)>; /* ETH1_PHY_INTN */
			bias-disable;
		};
		pins4 {
			pinmux = <STM32_PINMUX('B', 11, AF11)>; /* ETH1_TX_EN */
		};
	};

Replied your answer below, in answer to Patrick's message.