]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: enetc: add ptp timer binding support for i.MX94
authorClark Wang <xiaoning.wang@nxp.com>
Wed, 29 Oct 2025 01:38:58 +0000 (09:38 +0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Oct 2025 01:44:19 +0000 (18:44 -0700)
The i.MX94 has three PTP timers, and all standalone ENETCs can select
one of them to bind to as their PHC. The 'ptp-timer' property is used
to represent the PTP device of the Ethernet controller. So users can
add 'ptp-timer' to the ENETC node to specify the PTP timer. The driver
parses this property to bind the two hardware devices.

If the "ptp-timer" property is not present, the first timer of the PCIe
bus where the ENETC is located is used as the default bound PTP timer.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Wei Fang <wei.fang@nxp.com>
Link: https://patch.msgid.link/20251029013900.407583-5-wei.fang@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c

index 5978ea096e80f2faa2d136b7e0c2968310f3a2cc..d7aee3c934d3a1fec3e9f3a934cf6094db98b7ee 100644 (file)
@@ -66,6 +66,7 @@
 /* NETC integrated endpoint register block register */
 #define IERB_EMDIOFAUXR                        0x344
 #define IERB_T0FAUXR                   0x444
+#define IERB_ETBCR(a)                  (0x300c + 0x100 * (a))
 #define IERB_EFAUXR(a)                 (0x3044 + 0x100 * (a))
 #define IERB_VFAUXR(a)                 (0x4004 + 0x40 * (a))
 #define FAUXR_LDID                     GENMASK(3, 0)
 #define IMX94_ENETC0_BUS_DEVFN         0x100
 #define IMX94_ENETC1_BUS_DEVFN         0x140
 #define IMX94_ENETC2_BUS_DEVFN         0x180
+#define IMX94_TIMER0_BUS_DEVFN         0x1
+#define IMX94_TIMER1_BUS_DEVFN         0x101
+#define IMX94_TIMER2_BUS_DEVFN         0x181
 #define IMX94_ENETC0_LINK              3
 #define IMX94_ENETC1_LINK              4
 #define IMX94_ENETC2_LINK              5
 
+#define NETC_ENETC_ID(a)               (a)
+#define NETC_TIMER_ID(a)               (a)
+
 /* Flags for different platforms */
 #define NETC_HAS_NETCMIX               BIT(0)
 
@@ -345,6 +352,98 @@ static int imx95_ierb_init(struct platform_device *pdev)
        return 0;
 }
 
+static int imx94_get_enetc_id(struct device_node *np)
+{
+       int bus_devfn = netc_of_pci_get_bus_devfn(np);
+
+       /* Parse ENETC offset */
+       switch (bus_devfn) {
+       case IMX94_ENETC0_BUS_DEVFN:
+               return NETC_ENETC_ID(0);
+       case IMX94_ENETC1_BUS_DEVFN:
+               return NETC_ENETC_ID(1);
+       case IMX94_ENETC2_BUS_DEVFN:
+               return NETC_ENETC_ID(2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int imx94_get_timer_id(struct device_node *np)
+{
+       int bus_devfn = netc_of_pci_get_bus_devfn(np);
+
+       /* Parse NETC PTP timer ID, the timer0 is on bus 0,
+        * the timer 1 and timer2 is on bus 1.
+        */
+       switch (bus_devfn) {
+       case IMX94_TIMER0_BUS_DEVFN:
+               return NETC_TIMER_ID(0);
+       case IMX94_TIMER1_BUS_DEVFN:
+               return NETC_TIMER_ID(1);
+       case IMX94_TIMER2_BUS_DEVFN:
+               return NETC_TIMER_ID(2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int imx94_enetc_update_tid(struct netc_blk_ctrl *priv,
+                                 struct device_node *np)
+{
+       struct device *dev = &priv->pdev->dev;
+       struct device_node *timer_np;
+       int eid, tid;
+
+       eid = imx94_get_enetc_id(np);
+       if (eid < 0) {
+               dev_err(dev, "Failed to get ENETC ID\n");
+               return eid;
+       }
+
+       timer_np = of_parse_phandle(np, "ptp-timer", 0);
+       if (!timer_np) {
+               /* If 'ptp-timer' is not present, the timer1 is the default
+                * timer of all standalone ENETCs, which is on the same PCIe
+                * bus as these ENETCs.
+                */
+               tid = NETC_TIMER_ID(1);
+               goto end;
+       }
+
+       tid = imx94_get_timer_id(timer_np);
+       of_node_put(timer_np);
+       if (tid < 0) {
+               dev_err(dev, "Failed to get NETC Timer ID\n");
+               return tid;
+       }
+
+end:
+       netc_reg_write(priv->ierb, IERB_ETBCR(eid), tid);
+
+       return 0;
+}
+
+static int imx94_ierb_init(struct platform_device *pdev)
+{
+       struct netc_blk_ctrl *priv = platform_get_drvdata(pdev);
+       struct device_node *np = pdev->dev.of_node;
+       int err;
+
+       for_each_child_of_node_scoped(np, child) {
+               for_each_child_of_node_scoped(child, gchild) {
+                       if (!of_device_is_compatible(gchild, "pci1131,e101"))
+                               continue;
+
+                       err = imx94_enetc_update_tid(priv, gchild);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
 static int netc_ierb_init(struct platform_device *pdev)
 {
        struct netc_blk_ctrl *priv = platform_get_drvdata(pdev);
@@ -441,6 +540,7 @@ static const struct netc_devinfo imx95_devinfo = {
 static const struct netc_devinfo imx94_devinfo = {
        .flags = NETC_HAS_NETCMIX,
        .netcmix_init = imx94_netcmix_init,
+       .ierb_init = imx94_ierb_init,
 };
 
 static const struct of_device_id netc_blk_ctrl_match[] = {