From: Ye Li <[email protected]>

Extend ENETC driver to support i.MX952 platform where 2 ENETC
controllers are located on different PCIe buses.

Key changes:
- Add enetc_dev_id_imx() to derive device ID from device tree "reg"
  property for i.MX952, mapping bus_devfn values 0x0 and 0x100 to device
  IDs 0 and 1 respectively
- Implement imx952_netcmix_init() to configure MII protocol and PCS
  settings based on PHY mode parsed from device tree
- Add i.MX952 to FSL_ENETC_NETC_BLK_CTRL Kconfig dependencies

Signed-off-by: Ye Li <[email protected]>
Signed-off-by: Alice Guo <[email protected]>
Reviewed-by: Peng Fan <[email protected]>
---
 drivers/net/Kconfig                   |  4 +-
 drivers/net/fsl_enetc.c               | 28 ++++++++++-
 drivers/net/fsl_enetc_netc_blk_ctrl.c | 72 +++++++++++++++++++++++++++
 3 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 666618681df..f2e838b84de 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1018,8 +1018,8 @@ config FSL_ENETC
 config FSL_ENETC_NETC_BLK_CTRL
        bool "NXP ENETC NETC blocks control driver"
        depends on FSL_ENETC
-       depends on IMX95 || IMX94
-       default y if IMX95 || IMX94
+       depends on IMX95 || IMX94 || IMX952
+       default y if IMX95 || IMX94 || IMX952
        help
          This driver configures Integrated Endpoint Register Block (IERB) and
          Privileged Register Block (PRB) of NETC. For i.MX platforms, it also
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index b07193e4e83..f393af40e27 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -75,10 +75,36 @@ static int enetc_is_ls1028a(struct udevice *dev)
               pplat->vendor == PCI_VENDOR_ID_FREESCALE;
 }
 
+static int enetc_dev_id_imx(struct udevice *dev)
+{
+       if (IS_ENABLED(CONFIG_IMX952)) {
+               int bus_devfn;
+               u32 reg[5];
+               int error;
+
+               error = dev_read_u32_array(dev, "reg", reg, ARRAY_SIZE(reg));
+               if (error)
+                       return error;
+
+               bus_devfn = (reg[0] >> 8) & 0xffff;
+
+               switch (bus_devfn) {
+               case 0:
+                       return 0;
+               case 0x100:
+                       return 1;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return PCI_DEV(pci_get_devfn(dev)) >> 3;
+}
+
 static int enetc_dev_id(struct udevice *dev)
 {
        if (enetc_is_imx95(dev))
-               return PCI_DEV(pci_get_devfn(dev)) >> 3;
+               return enetc_dev_id_imx(dev);
        if (enetc_is_ls1028a(dev))
                return PCI_FUNC(pci_get_devfn(dev));
 
diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c 
b/drivers/net/fsl_enetc_netc_blk_ctrl.c
index 8577bb75632..0c87d80ea5c 100644
--- a/drivers/net/fsl_enetc_netc_blk_ctrl.c
+++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c
@@ -35,6 +35,7 @@
 #define  MII_PROT_RGMII                        0x2
 #define  MII_PROT_SERIAL               0x3
 #define  MII_PROT(port, prot)          (((prot) & 0xf) << ((port) << 2))
+#define  MII_PROT_GET(reg, port)       (((reg) >> ((port) << 2)) & 0xf)
 
 #define IMX95_CFG_LINK_PCS_PROT(a)     (0x8 + (a) * 4)
 #define PCS_PROT_1G_SGMII              BIT(0)
@@ -97,6 +98,9 @@
 #define IMX94_TIMER1_ID                        1
 #define IMX94_TIMER2_ID                        2
 
+#define IMX952_ENETC0_BUS_DEVFN                0x0
+#define IMX952_ENETC1_BUS_DEVFN                0x100
+
 /* Flags for different platforms */
 #define NETC_HAS_NETCMIX               BIT(0)
 
@@ -567,6 +571,69 @@ static int netc_prb_check_error(struct netc_blk_ctrl *priv)
        return 0;
 }
 
+static int imx952_netcmix_init(struct udevice *dev)
+{
+       struct netc_blk_ctrl *priv = dev_get_priv(dev);
+       ofnode child, gchild;
+       phy_interface_t interface;
+       int bus_devfn, mii_proto;
+       u32 val;
+
+       /* Default setting */
+       val = MII_PROT(0, MII_PROT_RGMII) | MII_PROT(1, MII_PROT_RGMII);
+
+       /* Update the link MII protocol through parsing phy-mode */
+       dev_for_each_subnode(child, dev) {
+               if (!ofnode_is_enabled(child))
+                       continue;
+
+               ofnode_for_each_subnode(gchild, child) {
+                       if (!ofnode_is_enabled(gchild))
+                               continue;
+
+                       if (!ofnode_device_is_compatible(gchild, 
"pci1131,e101"))
+                               continue;
+
+                       bus_devfn = netc_of_pci_get_bus_devfn(gchild);
+                       if (bus_devfn < 0)
+                               return -EINVAL;
+
+                       interface = ofnode_read_phy_mode(gchild);
+                       if (interface == -1)
+                               continue;
+
+                       mii_proto = netc_get_link_mii_protocol(interface);
+                       if (mii_proto < 0)
+                               return -EINVAL;
+
+                       switch (bus_devfn) {
+                       case IMX952_ENETC0_BUS_DEVFN:
+                               val &= ~CFG_LINK_MII_PORT_0;
+                               val |= FIELD_PREP(CFG_LINK_MII_PORT_0, 
mii_proto);
+                               break;
+                       case IMX952_ENETC1_BUS_DEVFN:
+                               val &= ~CFG_LINK_MII_PORT_1;
+                               val |= FIELD_PREP(CFG_LINK_MII_PORT_1, 
mii_proto);
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       if (MII_PROT_GET(val, 1) == MII_PROT_SERIAL) {
+               /* Configure Link I/O variant */
+               netc_reg_write(priv->netcmix, IMX95_CFG_LINK_IO_VAR,
+                              IO_VAR(1, IO_VAR_16FF_16G_SERDES));
+               /* Configure Link 2 PCS protocol */
+               netc_reg_write(priv->netcmix, IMX95_CFG_LINK_PCS_PROT(1),
+                              PCS_PROT_2500M_SGMII);
+       }
+       netc_reg_write(priv->netcmix, IMX95_CFG_LINK_MII_PROT, val);
+
+       return 0;
+}
+
 static const struct netc_devinfo imx95_devinfo = {
        .netcmix_init = imx95_netcmix_init,
        .ierb_init = imx95_ierb_init,
@@ -578,9 +645,14 @@ static const struct netc_devinfo imx94_devinfo = {
        .xpcs_port_init = imx94_netc_xpcs_port_init,
 };
 
+static const struct netc_devinfo imx952_devinfo = {
+       .netcmix_init = imx952_netcmix_init,
+};
+
 static const struct udevice_id netc_blk_ctrl_match[] = {
        { .compatible = "nxp,imx95-netc-blk-ctrl", .data = 
(ulong)&imx95_devinfo },
        { .compatible = "nxp,imx94-netc-blk-ctrl", .data = 
(ulong)&imx94_devinfo },
+       { .compatible = "nxp,imx952-netc-blk-ctrl", .data = 
(ulong)&imx952_devinfo },
        {},
 };
 
-- 
2.34.1

Reply via email to