imx6: enet: clock selection (ref/ptp)

Stephan Bauroth der_steffi at gmx.de
Wed Feb 8 06:09:29 PST 2017


Dear linux-arm,

I recently stumbled upon a few minor things that took a lot of time. The 
meta-situation was, that I wanted to have a PHY attached via RMII to an 
IMX6D (very similar to Q). While the management of the PHY over MDIO 
worked fine and U-boot was able to transfer my kernel image via NFS, the 
kernel itself couldn't even ping my development PC.

A lot of research later, I was able to isolate the problem down to the 
reference clock of the RMII interface. U-Boot initialized it falsely 
with 125 MHz (for RMII, only 25 or 50 are OK) but then did not use it 
but relied on the external oscillator which was present. Sadly, Linux 
didn't. After first correcting U-Boot to set the clock to 50 MHz, which 
did not help (due to phase-async, I think), I tried to figure out why 
Linux switches to the internal PLL instead of keeping the external one. 
I finally found this one:

arch/arm/mach-imx/mach-imx6q.c:191::
     np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec");
     if (!np) {
         ...
     }

     ptp_clk = of_clk_get(np, 2);
     if (IS_ERR(ptp_clk)) {
         ...
     }

     enet_ref = clk_get_sys(NULL, "enet_ref");
     if (IS_ERR(enet_ref)) {
         ...
     }

     /*
      * If enet_ref from ANATOP/CCM is the PTP clock source, we need to
      * set bit IOMUXC_GPR1[21].  Or the PTP clock must be from pad
      * (external OSC), and we need to clear the bit.
      */
     clksel = clk_is_match(ptp_clk, enet_ref) ?
                 IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
                 IMX6Q_GPR1_ENET_CLK_SEL_PAD;
     gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
     if (!IS_ERR(gpr))
         regmap_update_bits(gpr, IOMUXC_GPR1,
                 IMX6Q_GPR1_ENET_CLK_SEL_MASK,
                 clksel);

I think there are multiple small issues here:
In my case, I want enet_ref to be the external clock. This is controlled 
by IOMUXC_GPR1[21]. The code assumes enet_ref to be internal (does not 
look into the DT).
ptp_clk is not found by name, but by index. While this works for all DTs 
I saw, it's clearly not a good style?
Finally, IOMUXCGPR1[21] is only set to ..._PAD when the two clocks from 
above differ.

My current workaround is this:
     ptp_clk = of_clk_get_by_name(np, "ptp");
     if (IS_ERR(ptp_clk)) {
         ...
     }

     enet_ref = of_clk_get_by_name(np, "enet_ref");
     if (IS_ERR(enet_ref)) {
         ...
     }

Of course, I then have to supply both clocks in the DT. I am clear 
that's not a feasible solution :)
I would like to clean that a little bit but do not have a good solution 
in mind right now. Ideas/corrections/thoughts welcome.

thanks for all work so far and regards,
Stephan



More information about the linux-arm-kernel mailing list