Introduction
Time Synchronization stands for the alignment of time within distributed nodes, pretty critical for real-time applications, control and measurement systems as voice and video networks; all of them being embedded applications.
It needs the synchronization of frequency, phase and time between all the nodes and offers action coordination, high precision triggers and event reference or timestamping. [1]
A Time Synchronization resource it's the ethernet standard for time PTP or IEEE 1588 standard, its study begin with the physical representation of time information: PPS; Pulse Per Second.
An squared wave timed by the capable MACs, in i.MX families we have two MACs of which.
Background
Customers are interested in this signal, we have an i.MX 8M Plus kernel 5 resource but there is a new processor family using the next major kernel version; 6. [2]
We will go through demonstrating PPS on i.MX 93 EVK in both MACs; FEC and EQOS.
HW setup
Hands-on for FEC or eth0 MAC
uSDHC2 pin group conflicts with the pps output pin and you are ought to remove the uSDHC2 nodes and assign the event0 out pin to the FEC pin group as shown below.
--- imx93-11x11-evk.dts 2024-08-23 18:19:56.344798901 +0200
+++ imx93-11x11-evk-pps.dts 2024-09-02 21:31:46.569477421 +0200
@@ -100,18 +100,6 @@
regulator-max-microvolt = <1800000>;
};
- reg_usdhc2_vmmc: regulator-usdhc2 {
- compatible = "regulator-fixed";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
- regulator-name = "VSD_3V3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
- off-on-delay-us = <12000>;
- enable-active-high;
- };
-
reg_vdd_12v: regulator-vdd-12v {
compatible = "regulator-fixed";
regulator-name = "reg_vdd_12v";
@@ -770,21 +766,6 @@
status = "okay";
};
-&usdhc2 {
- pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
- pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
- pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
- pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
- pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
- cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
- fsl,cd-gpio-wakeup-disable;
- vmmc-supply = <®_usdhc2_vmmc>;
- bus-width = <4>;
- status = "okay";
- no-sdio;
- no-mmc;
-};
-
&usdhc3 {
pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
@@ -860,14 +842,15 @@
MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x57e
MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2 0x57e
MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3 0x57e
MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC 0x58e
MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL 0x57e
MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0 0x57e
MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1 0x57e
MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2 0x57e
MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3 0x57e
MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC 0x58e
MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL 0x57e
+ MX93_PAD_SD2_DATA0__ENET1_1588_EVENT0_OUT 0x31e
>;
};
@@ -887,6 +870,7 @@
MX93_PAD_ENET2_TD3__GPIO4_IO16 0x51e
MX93_PAD_ENET2_TXC__GPIO4_IO21 0x51e
MX93_PAD_ENET2_TX_CTL__GPIO4_IO20 0x51e
+ MX93_PAD_SD2_DATA0__GPIO3_IO03 0x31e
>;
};
@@ -998,75 +982,6 @@
>;
};
- pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
- fsl,pins = <
- MX93_PAD_SD2_RESET_B__GPIO3_IO07 0x31e
- >;
- };
-
- pinctrl_usdhc2_gpio: usdhc2gpiogrp {
- fsl,pins = <
- MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e
- >;
- };
-
- pinctrl_usdhc2_gpio_sleep: usdhc2gpiogrpsleep {
- fsl,pins = <
- MX93_PAD_SD2_CD_B__GPIO3_IO00 0x51e
- >;
- };
-
- /* need to config the SION for data and cmd pad, refer to ERR052021 */
- pinctrl_usdhc2: usdhc2grp {
- fsl,pins = <
- MX93_PAD_SD2_CLK__USDHC2_CLK 0x1582
- MX93_PAD_SD2_CMD__USDHC2_CMD 0x40001382
- MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x40001382
- MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x40001382
- MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x40001382
- MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x40001382
- MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
- >;
- };
-
- /* need to config the SION for data and cmd pad, refer to ERR052021 */
- pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
- fsl,pins = <
- MX93_PAD_SD2_CLK__USDHC2_CLK 0x158e
- MX93_PAD_SD2_CMD__USDHC2_CMD 0x4000138e
- MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x4000138e
- MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x4000138e
- MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x4000138e
- MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x4000138e
- MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
- >;
- };
-
- /* need to config the SION for data and cmd pad, refer to ERR052021 */
- pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
- fsl,pins = <
- MX93_PAD_SD2_CLK__USDHC2_CLK 0x15fe
- MX93_PAD_SD2_CMD__USDHC2_CMD 0x400013fe
- MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x400013fe
- MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x400013fe
- MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x400013fe
- MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x400013fe
- MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
- >;
- };
-
- pinctrl_usdhc2_sleep: usdhc2grpsleep {
- fsl,pins = <
- MX93_PAD_SD2_CLK__GPIO3_IO01 0x51e
- MX93_PAD_SD2_CMD__GPIO3_IO02 0x51e
- MX93_PAD_SD2_DATA0__GPIO3_IO03 0x51e
- MX93_PAD_SD2_DATA1__GPIO3_IO04 0x51e
- MX93_PAD_SD2_DATA2__GPIO3_IO05 0x51e
- MX93_PAD_SD2_DATA3__GPIO3_IO06 0x51e
- MX93_PAD_SD2_VSELECT__GPIO3_IO19 0x51e
- >;
- };
-
/* need to config the SION for data and cmd pad, refer to ERR052021 */
pinctrl_usdhc3: usdhc3grp {
fsl,pins = <
The driver also needs the following rework.
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -184,7 +184,8 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
val |= (1 << FEC_T_TF_OFFSET | 1 << FEC_T_TIE_OFFSET);
val &= ~(1 << FEC_T_TDRE_OFFSET);
val &= ~(FEC_T_TMODE_MASK);
- val |= (FEC_HIGH_PULSE << FEC_T_TMODE_OFFSET);
+ // val |= (FEC_HIGH_PULSE << FEC_T_TMODE_OFFSET);
+ val |= (FEC_TMODE_TOGGLE << FEC_T_TMODE_OFFSET);
writel(val, fep->hwp + FEC_TCSR(fep->pps_channel));
/* Write the second compare event timestamp and calculate
After booting the board, run these commands:
$ ptp4l -A -4 -H -m -i eth0 &
$ echo 1 > /sys/class/ptp/ptp0/pps_enable
These will get the SD2_DATA0 or TP1009 running a square wave at 0.5 Hz through setting the ptp0 port with:
-A Select the delay mechanism automatically. Start with E2E and switch to P2P when a peer delay request is received.
-4 Select the UDP IPv4 network transport. This is the default transport.
-H Select the hardware time stamping.
-m Print messages to the standard output.
Run the next command to set the pps (1 Hz signal):
$ echo "0 $(date +%s) 100000000 1 0" > /sys/class/ptp/ptp0/period
The last because the current driver needs the actual date and a future start; in this case the signal will start within 100 ms, in order to work. You can try with different start times until the optimal value is found. [3]
Hands-on for EQOS or eth1 MAC
This is reduced to the proper devicetree changes, and it does not have driver rework nor pps_enable control file.
It uses SD2_CLK or TP1008, so DTS need this adjustment:
--- imx93-11x11-evk.dts 2024-08-23 18:19:56.344798901 +0200
+++ imx93-11x11-evk-pps.dts 2024-09-02 21:31:46.569477421 +0200
@@ -100,18 +100,6 @@
regulator-max-microvolt = <1800000>;
};
- reg_usdhc2_vmmc: regulator-usdhc2 {
- compatible = "regulator-fixed";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
- regulator-name = "VSD_3V3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
- off-on-delay-us = <12000>;
- enable-active-high;
- };
-
reg_vdd_12v: regulator-vdd-12v {
compatible = "regulator-fixed";
regulator-name = "reg_vdd_12v";
@@ -770,21 +766,6 @@
status = "okay";
};
-&usdhc2 {
- pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
- pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
- pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
- pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
- pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>;
- cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
- fsl,cd-gpio-wakeup-disable;
- vmmc-supply = <®_usdhc2_vmmc>;
- bus-width = <4>;
- status = "okay";
- no-sdio;
- no-mmc;
-};
-
&usdhc3 {
pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep";
pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_wlan>;
@@ -822,14 +802,15 @@
MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1 0x57e
MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2 0x57e
MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3 0x57e
MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x58e
MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x57e
MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0 0x57e
MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1 0x57e
MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2 0x57e
MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3 0x57e
MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x58e
MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x57e
+ MX93_PAD_SD2_CLK__ENET_QOS_1588_EVENT0_OUT 0x31e
>;
};
@@ -849,6 +830,7 @@
MX93_PAD_ENET1_TD3__GPIO4_IO02 0x31e
MX93_PAD_ENET1_TXC__GPIO4_IO07 0x31e
MX93_PAD_ENET1_TX_CTL__GPIO4_IO06 0x31e
+ MX93_PAD_SD2_CLK__GPIO3_IO01 0x31e
>;
};
@@ -998,75 +982,6 @@
>;
};
- pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
- fsl,pins = <
- MX93_PAD_SD2_RESET_B__GPIO3_IO07 0x31e
- >;
- };
-
- pinctrl_usdhc2_gpio: usdhc2gpiogrp {
- fsl,pins = <
- MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e
- >;
- };
-
- pinctrl_usdhc2_gpio_sleep: usdhc2gpiogrpsleep {
- fsl,pins = <
- MX93_PAD_SD2_CD_B__GPIO3_IO00 0x51e
- >;
- };
-
- /* need to config the SION for data and cmd pad, refer to ERR052021 */
- pinctrl_usdhc2: usdhc2grp {
- fsl,pins = <
- MX93_PAD_SD2_CLK__USDHC2_CLK 0x1582
- MX93_PAD_SD2_CMD__USDHC2_CMD 0x40001382
- MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x40001382
- MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x40001382
- MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x40001382
- MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x40001382
- MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
- >;
- };
-
- /* need to config the SION for data and cmd pad, refer to ERR052021 */
- pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
- fsl,pins = <
- MX93_PAD_SD2_CLK__USDHC2_CLK 0x158e
- MX93_PAD_SD2_CMD__USDHC2_CMD 0x4000138e
- MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x4000138e
- MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x4000138e
- MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x4000138e
- MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x4000138e
- MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
- >;
- };
-
- /* need to config the SION for data and cmd pad, refer to ERR052021 */
- pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
- fsl,pins = <
- MX93_PAD_SD2_CLK__USDHC2_CLK 0x15fe
- MX93_PAD_SD2_CMD__USDHC2_CMD 0x400013fe
- MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x400013fe
- MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x400013fe
- MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x400013fe
- MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x400013fe
- MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
- >;
- };
-
- pinctrl_usdhc2_sleep: usdhc2grpsleep {
- fsl,pins = <
- MX93_PAD_SD2_CLK__GPIO3_IO01 0x51e
- MX93_PAD_SD2_CMD__GPIO3_IO02 0x51e
- MX93_PAD_SD2_DATA0__GPIO3_IO03 0x51e
- MX93_PAD_SD2_DATA1__GPIO3_IO04 0x51e
- MX93_PAD_SD2_DATA2__GPIO3_IO05 0x51e
- MX93_PAD_SD2_DATA3__GPIO3_IO06 0x51e
- MX93_PAD_SD2_VSELECT__GPIO3_IO19 0x51e
- >;
- };
-
/* need to config the SION for data and cmd pad, refer to ERR052021 */
pinctrl_usdhc3: usdhc3grp {
fsl,pins = <
After boot, issue these commands:
$ ptp4l -A -4 -H -m -i eth1 &
$ echo "0 $(date +%s) 1000000000 1 0" > /sys/class/ptp/ptp1/period
You will have an squared wave of 1 Hz running within 1 s with the same settings as the FEC setup.
Conclusion
Both PPS can run in the same image changes and DTS changes, proven in imx-linux-nanbield branch, with the manifest imx-6.6.3-1.0.0.xml.
And it's the start of testing IEEE 1588 and syncing capabilities of this i.MX 9 series processors.
Sources
[1] http://events17.linuxfoundation.org/sites/events/files/slides/elc_insop_2015.pdf