
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 alexm.osslist@gmail.com --- 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