Adds a driver for the MDIO interface currently integrated in LS1028a SoC.
This MDIO interface is shared by multiple ethernet interfaces and is
presented as a stand-alone PCI function on the SoC ECAM.

Signed-off-by: Alex Marginean <[email protected]>
---
 configs/ls1028aqds_tfa_defconfig |   1 +
 configs/ls1028ardb_tfa_defconfig |   1 +
 drivers/net/fsl_enetc.c          | 169 +++++++++++++++++++++++++++++++
 drivers/net/fsl_enetc.h          |  13 +++
 include/pci_ids.h                |   1 +
 5 files changed, 185 insertions(+)

diff --git a/configs/ls1028aqds_tfa_defconfig b/configs/ls1028aqds_tfa_defconfig
index 11fe344b04..84a1bf90bf 100644
--- a/configs/ls1028aqds_tfa_defconfig
+++ b/configs/ls1028aqds_tfa_defconfig
@@ -43,6 +43,7 @@ CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_PHYLIB=y
 CONFIG_PHY_ATHEROS=y
 CONFIG_DM_ETH=y
+CONFIG_DM_MDIO=y
 CONFIG_PHY_GIGE=y
 CONFIG_E1000=y
 CONFIG_FSL_ENETC=y
diff --git a/configs/ls1028ardb_tfa_defconfig b/configs/ls1028ardb_tfa_defconfig
index ab6f2a850c..3f5bc2e139 100644
--- a/configs/ls1028ardb_tfa_defconfig
+++ b/configs/ls1028ardb_tfa_defconfig
@@ -43,6 +43,7 @@ CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_PHYLIB=y
 CONFIG_PHY_ATHEROS=y
 CONFIG_DM_ETH=y
+CONFIG_DM_MDIO=y
 CONFIG_PHY_GIGE=y
 CONFIG_E1000=y
 CONFIG_FSL_ENETC=y
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index b253292bc0..6be01e7d7f 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -11,6 +11,7 @@
 #include <memalign.h>
 #include <asm/io.h>
 #include <pci.h>
+#include <miiphy.h>
 
 static int enetc_bind(struct udevice *dev)
 {
@@ -28,6 +29,61 @@ static int enetc_bind(struct udevice *dev)
        return 0;
 }
 
+static void enetc_start_phy(struct udevice *dev)
+{
+#ifdef CONFIG_DM_MDIO
+       int supported, if_type = PHY_INTERFACE_MODE_NONE;
+       struct udevice *miidev;
+       struct phy_device *phy;
+       u32 phandle, phy_id;
+       const char *if_str;
+       ofnode phy_node;
+
+       if (!ofnode_valid(dev->node)) {
+               ENETC_DBG(dev, "no enetc ofnode found, skipping PHY set-up\n");
+               return;
+       }
+
+       if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) {
+               ENETC_DBG(dev, "phy-handle not found, skipping PHY set-up\n");
+               return;
+       }
+
+       phy_node = ofnode_get_by_phandle(phandle);
+       if (!ofnode_valid(phy_node)) {
+               ENETC_DBG(dev, "invalid phy node, skipping PHY set-up\n");
+               return;
+       }
+       ENETC_DBG(dev, "phy node: %s\n", ofnode_get_name(phy_node));
+
+       if (ofnode_read_u32(phy_node, "reg", &phy_id)) {
+               ENETC_DBG(dev,
+                         "missing reg in PHY node, skipping PHY set-up\n");
+               return;
+       }
+
+       if_str = ofnode_read_string(phy_node, "phy-mode");
+       if (if_str)
+               if_type = phy_get_interface_by_name(if_str);
+       if (if_type < 0)
+               if_type = PHY_INTERFACE_MODE_NONE;
+
+       if (uclass_get_device_by_ofnode(UCLASS_MDIO,
+                                       ofnode_get_parent(phy_node),
+                                       &miidev))
+               return;
+
+       phy = dm_mdio_phy_connect(miidev, phy_id, dev, if_type);
+       if (!phy)
+               return;
+
+       supported = GENMASK(6, 0); /* speeds up to 1G & AN */
+       phy->advertising = phy->supported & supported;
+       phy_config(phy);
+       phy_startup(phy);
+#endif
+}
+
 /*
  * Probe ENETC driver:
  * - initialize port and station interface BARs
@@ -223,6 +279,8 @@ static int enetc_start(struct udevice *dev)
        enetc_setup_tx_bdr(hw);
        enetc_setup_rx_bdr(dev, hw);
 
+       enetc_start_phy(dev);
+
        return 0;
 }
 
@@ -343,3 +401,114 @@ static struct pci_device_id enetc_ids[] = {
 };
 
 U_BOOT_PCI_DEVICE(eth_enetc, enetc_ids);
+
+#ifdef CONFIG_DM_MDIO
+
+static int enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+       struct enetc_devfn *hw = dev_get_priv(dev);
+
+       if (devad == MDIO_DEVAD_NONE)
+               enetc_write(hw, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
+       else
+               enetc_write(hw, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
+
+       while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+               ;
+       if (devad == MDIO_DEVAD_NONE) {
+               enetc_write(hw, ENETC_MDIO_CTL, (addr << 5) + reg + 0x8000);
+       } else {
+               enetc_write(hw, ENETC_MDIO_CTL, (addr << 5) + devad);
+               while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+                       ;
+               enetc_write(hw, ENETC_MDIO_STAT, reg);
+               while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+                       ;
+               enetc_write(hw, ENETC_MDIO_CTL, (addr << 5) + devad + 0x8000);
+       }
+
+       while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+               ;
+       if (enetc_read(hw, ENETC_MDIO_CFG) & 2)
+               return ENETC_MDIO_READ_ERR;
+
+       return enetc_read(hw, ENETC_MDIO_DATA);
+}
+
+static int enetc_mdio_write(struct udevice *dev, int addr, int devad, int reg,
+                           u16 val)
+{
+       struct enetc_devfn *hw = dev_get_priv(dev);
+
+       if (devad == MDIO_DEVAD_NONE)
+               enetc_write(hw, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
+       else
+               enetc_write(hw, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
+
+       while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+               ;
+       if (devad != MDIO_DEVAD_NONE) {
+               enetc_write(hw, ENETC_MDIO_CTL, (addr << 5) + devad);
+               enetc_write(hw, ENETC_MDIO_STAT, reg);
+       } else {
+               enetc_write(hw, ENETC_MDIO_CTL, (addr << 5) + reg);
+       }
+       while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+               ;
+       enetc_write(hw, ENETC_MDIO_DATA, val);
+       while (enetc_read(hw, ENETC_MDIO_CFG) & 1)
+               ;
+       return 0;
+}
+
+static const struct mdio_ops enetc_mdio_ops = {
+       .read = enetc_mdio_read,
+       .write = enetc_mdio_write,
+};
+
+static int enetc_mdio_bind(struct udevice *dev)
+{
+       static int mdio_num_devices;
+       char name[16];
+
+       if (ofnode_valid(dev->node))
+               sprintf(name, "emdio%u", PCI_FUNC(pci_get_devfn(dev)));
+       else
+               sprintf(name, "emdio#%u", mdio_num_devices++);
+
+       device_set_name(dev, name);
+
+       return 0;
+}
+
+static int enetc_mdio_probe(struct udevice *dev)
+{
+       struct enetc_devfn *hw = dev_get_priv(dev);
+
+       hw->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+       if (!hw->regs_base) {
+               ENETC_DBG(dev, "failed to map BAR0\n");
+               return -EINVAL;
+       }
+
+       dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+
+       return 0;
+}
+
+U_BOOT_DRIVER(enetc_mdio) = {
+       .name   = "enetc_mdio",
+       .id     = UCLASS_MDIO,
+       .bind   = enetc_mdio_bind,
+       .probe  = enetc_mdio_probe,
+       .ops    = &enetc_mdio_ops,
+       .priv_auto_alloc_size = sizeof(struct enetc_mdio_devfn),
+};
+
+static struct pci_device_id enetc_mdio_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_MDIO_V1) },
+};
+
+U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);
+
+#endif /* CONFIG_DM_MDIO */
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
index 4ebf03a61a..3636ce1d93 100644
--- a/drivers/net/fsl_enetc.h
+++ b/drivers/net/fsl_enetc.h
@@ -173,4 +173,17 @@ struct enetc_devfn {
 #define enetc_bdr_write(hw, t, n, off, val) \
                                enetc_write(hw, ENETC_BDR(t, n, off), val)
 
+#define ENETC_MDIO_CFG         0x1c00
+#define ENETC_EMDIO_CFG_C22    0x00009508
+#define ENETC_EMDIO_CFG_C45    0x00009548
+#define ENETC_MDIO_CTL         0x1c04
+#define ENETC_MDIO_DATA                0x1c08
+#define ENETC_MDIO_STAT                0x1c0c
+
+#define ENETC_MDIO_READ_ERR    0xffff
+
+struct enetc_mdio_devfn {
+       void *regs_base;
+};
+
 #endif /* _ENETC_H */
diff --git a/include/pci_ids.h b/include/pci_ids.h
index 06e1319366..c4b424c6a9 100644
--- a/include/pci_ids.h
+++ b/include/pci_ids.h
@@ -2484,6 +2484,7 @@
 #define PCI_DEVICE_ID_MPC8641D         0x7011
 #define PCI_DEVICE_ID_MPC8610          0x7018
 #define PCI_DEVICE_ID_ENETC_PF_V1      0xE100
+#define PCI_DEVICE_ID_MDIO_V1          0xEE01
 
 #define PCI_VENDOR_ID_PASEMI           0x1959
 
-- 
2.17.1

_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to