I.mx7d fec2 internal reference clocking

I’m trying to bring up a board with a second Ethernet interface on a Colibri i.mx7D. We’re using RMII to connect a KSZ8041 PHY. In our design, the 50MHz reference clock is to be generated internal to the i.mx SoC and driven out the CCM_ENET2_REF_CLK path. Things are mostly working, but there’s no data going through the MAC. Some sleuthing suggests that the MAC is missing its reference clock, although that clock is enabled (see clk summary below) and is driving the PHY correctly.

Here’s how we have the fec configured:

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2>;
	clocks = <&clks IMX7D_ENET2_IPG_ROOT_CLK>,
			 <&clks IMX7D_ENET_AXI_ROOT_CLK>,
			 <&clks IMX7D_ENET2_TIME_ROOT_CLK>,
			 <&clks IMX7D_PLL_ENET_MAIN_50M_CLK>,
			 <&clks IMX7D_ENET2_REF_ROOT_DIV>;
	clock-names = "ipg", "ahb", "ptp", "enet_clk_ref", "enet_out";
	assigned-clocks = 	<&clks IMX7D_ENET2_TIME_ROOT_SRC>,
	       				<&clks IMX7D_ENET2_TIME_ROOT_CLK>,
	       				<&clks IMX7D_ENET_PHY_REF_ROOT_DIV>;
	assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
	assigned-clock-rates = <0>, <100000000>, <50000000>;

	phy-mode = "rmii";
	fsl,mii-exclusive;

	status = "okay";
};

The pin group is defined as follows:

	pinctrl_enet2: enet2grp {
		fsl,pins = <
			MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL	0x73
			MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0	0x73
			MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1	    0x73
			MX7D_PAD_EPDC_SDCE1__ENET2_RX_ER		0x73

			MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL	0x73
			MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0	0x73
			MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1	0x73
			MX7D_PAD_EPDC_BDR0__CCM_ENET_REF_CLK2	0x73 
			MX7D_PAD_GPIO1_IO14__ENET2_MDIO			0x3
			MX7D_PAD_GPIO1_IO15__ENET2_MDC			0x3
		>;
	};

As already mentioned, the 50 MHz clock is appearing on the EPDC_BDR0 ball and the PHY is properly negotiating the link. Data is received by the PHY, and there is clearly data queued for transmission in the kernel. An ethtool dump of the MAC registers shows that the receiver is enabled, and the TDAR bit is set. Yet, nothing is received through the MAC and nothing is ever transmitted. There’s no action on the TX_EN or the TD RMII signals. The TDAR bit never clears, and eventually the driver times out and dumps the ring buffer to the console. So it looks to me like the MAC isn’t getting the reference clock.

We’re using the latest supported Linux kernel (4.9.84). Here’s a dump of the Ethernet clock tree (edited to remove what I think are the irrelevant parts):

    pll_enet_main                         1           
       pll_enet_main_bypass               1 
          pll_enet_main_clk               3 
             pll_enet_25m                 0 
                pll_enet_25m_clk           0 
                   enet_phy_ref_src           0 
                      enet_phy_ref_cg           0 
                         enet_phy_ref_pre_div           0 
                            enet_phy_ref_post_div           0 
             pll_enet_50m                 1  
                pll_enet_50m_clk           3  
                   enet2_ref_src           1   
                      enet2_ref_cg           1 
                         enet2_ref_pre_div           1
                            enet2_ref_post_div           1 
             pll_enet_100m                1  
                pll_enet_100m_clk           2  
                   pcie_phy_src           0  
                      pcie_phy_cg           0 
                         pcie_phy_pre_div           0  
                            pcie_phy_post_div           0 
                               pcie_phy_root_clk           0  
                   enet2_time_src           1  
                      enet2_time_cg           1
                         enet2_time_pre_div           1  
                            enet2_time_post_div           1  
                               enet2_time_root_clk           1
                   enet1_time_src           1
                      enet1_time_cg           1 
                         enet1_time_pre_div           1 
                            enet1_time_post_div           1 
                               enet1_time_root_clk           1  
             pll_enet_250m                1  
                pll_enet_250m_clk           1   
                   enet_axi_src           1  
                      enet_axi_cg           1  
                         enet_axi_pre_div           1  
                            enet_axi_post_div           3   
                               enet2_ipg_root_clk           1  
                               enet1_ipg_root_clk           1  
                               enet_axi_root_clk           2  

Where does the MAC get its reference clock from when the ENET2_TX_CLK_SEL bit is set to use an internal reference clock? (I.e., which CCM output) The documentation from NXP seems a big vague on this subject.

What is the meaning of ALT1 vis a vis the ENET2_CLK_DIR bit in GPR1? The ball that outputs the ENET_REF_CLK2 has no ALT1 function defined. Is that a documentation error, or am I missing something?

Hi

Where does the MAC get its reference clock from when the ENET2_TX_CLK_SEL bit is set to use an internal reference clock?

The MAC gets its clock from the ENET_REF_CLK2 pin independent if the clock is generated outside or inside the i.MX7.
If generated inside, both the output and the input driver must be active, i.e. the SION bit must be set.

Could you try to set the SION bit on the ENET_REF_CLK2? (0x73 → 0x40000073)?

What is the meaning of ALT1 vis a vis the ENET2_CLK_DIR bit in GPR1?

I’m confused as well. But I guess that is a question better posted in the NXP community.

Max

Hi,

To clarify my question: I don’t know what are these clock used to (ipg, ahb, etc) and how you have chosen to assign a clock output to one of the fec clock input.
Where can I found some documentation on the fec clocks and on the way to select the proper clock source?

Regards

Hi @systemix

In a similar way, I would like to connect the second ethernet of iMX7d to KSZ8041 via RMII. The only difference is that I’m using a I2C2_SCL ball to output the ENET2_REF_CLK_ROOT.

I have reuse your settings with SION bit set and it is working properly.

My question is related to clocks. It seems you are not using the same clock setting than the one provided by Toradex in imx7d.dtsi:

	clocks = <&clks IMX7D_ENET2_IPG_ROOT_CLK>,
		<&clks IMX7D_ENET_AXI_ROOT_CLK>,
		<&clks IMX7D_ENET2_TIME_ROOT_CLK>,
		<&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,
		<&clks IMX7D_ENET_PHY_REF_ROOT_DIV>;
	clock-names = "ipg", "ahb", "ptp",
		"enet_clk_ref", "enet_out";

Could you clarify why you need to change them?

Regards

Hi Max,

That did the trick. And, of course, it makes sense. Inputting the clock from the pin works whether its internally or externally generated.

Thank you!

hi @ykrons

You can find the description of the different clocks here. I hope it helps.

Best regards, Jaski

Thanks for the doc.
However I’m knowing nearly nothing to internal clocks and Ethernet controller world so it is a bit hard to guess why some values are selected. I don’t want to get the full understanding but at least why these settings have been selected and are properly working.

I think now I better understand how clock a configured (iMX7d reference manual) and how to get there current setting from /sys/kernel/debug/clk, but it is still unclear why some values have been selected.

Here are some (probably dumb) questions:

  • In that case fec1 and fec2 are using rmii for two fast ethernet PHY that have the same reference. Why in that case, can’t we just use the same clocks for fec1 and fec2?
  • I can see that ipg and ahb clocks run at around 196MHz. Where can I get that this frequency is required? I can’t find it in the iMX7d reference manual
  • How did the PHY for fec1 gets its reference clock in the iMX7d colibri SoC? I would have guess it is generated by the iMX7d, but in that case, why isn’t enet_out not assigned and SION bit not required for fec1?

Kind regards

Hi @ykrons

In that case fec1 and fec2 are using rmii for two fast ethernet PHY that have the same reference. Why in that case, can’t we just use the same clocks for fec1 and fec2?

Actually the clock for fec1 is generated by the SOC and this PHY is on the module. Fec2 will be placed on the carrier board. So for using the same clock for both, you need to route this clock out of the module, which is dangerous, since then this clock can be affected by the customers configuration. Thats why we use there two different reference clocks.

I can see that ipg and ahb clocks run at around 196MHz. Where can I get that this frequency is required? I can’t find it in the iMX7d reference manual * How did the PHY for fec1 gets its reference clock in the iMX7d colibri SoC? I would have guess it is generated by the iMX7d, but in that case, why isn’t enet_out not assigned and SION bit not required for fec1?

You are right, these clocks are generated by the SOC. The frequency of the clock is given by the requirement for the ASICS on our module. This is not the part of the reference manual of SOC.

Best regards, Jaski

I am using Colibri Evaluation V3.3b Carrier board (Colibri IMX7D 1GB V1.1A module) with torizoncore upstream version 5.1.0+build.1 image (Linux kernel 5.4.77-5.1.0)

Similarly i want to set the second ethernet port using KSZ8041NL transreceiver.
I made the same device tree changes as mentioned above and applying it through torizon core builder. But I am unable to get the clock from SODIMM 106 (MX7D_PAD_EPDC_BDR0__CCM_ENET_REF_CLK2 ) pin. Is there any additional changes need to be done in order to get the clock signal from that pin?

I also tried by giving external clock to both IMX7d and KSZ8041 as mentioned

still no transmission and receiving is not happening (ping not working), dynamic ip is not assigned.

Is there any kernel changes need to be done?

Hi @Roshini_d

Welcome to Toradex community.
I would request you to create a new thread with proper details like software and hardware versions,dmsg logs, etc.