/* * Xilinx PCS/PMA Core phy driver * * Copyright (C) 2015 - 2016 Xilinx, Inc. * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include DECLARE_GLOBAL_DATA_PTR; #define MII_PHY_STATUS_SPD_MASK 0x0C00 #define MII_PHY_STATUS_FULLDUPLEX 0x1000 #define MII_PHY_STATUS_1000 0x0800 #define MII_PHY_STATUS_100 0x0400 #define XPCSPMA_PHY_CTRL_ISOLATE_DISABLE 0xFBFF /* Mask used for ID comparisons */ #define XILINX_PHY_ID_MASK 0xfffffff0 /* Known PHY IDs */ #define XILINX_PHY_ID 0x01740c00 /* struct phy_device dev_flags definitions */ #define XAE_PHY_TYPE_MII 0 #define XAE_PHY_TYPE_GMII 1 #define XAE_PHY_TYPE_RGMII_1_3 2 #define XAE_PHY_TYPE_RGMII_2_0 3 #define XAE_PHY_TYPE_SGMII 4 #define XAE_PHY_TYPE_1000BASE_X 5 static int xilinxphy_startup(struct phy_device *phydev) { int err; int status = 0; debug("%s\n", __func__); /* Update the link, but return if there * was an error */ err = genphy_update_link(phydev); if (err) return err; if (AUTONEG_ENABLE == phydev->autoneg) { status = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA); status = status & MII_PHY_STATUS_SPD_MASK; if (status & MII_PHY_STATUS_FULLDUPLEX) phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; switch (status) { case MII_PHY_STATUS_1000: phydev->speed = SPEED_1000; break; case MII_PHY_STATUS_100: phydev->speed = SPEED_100; break; default: phydev->speed = SPEED_10; break; } } else { int bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); if (bmcr < 0) return bmcr; if (bmcr & BMCR_FULLDPLX) phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; if (bmcr & BMCR_SPEED1000) phydev->speed = SPEED_1000; else if (bmcr & BMCR_SPEED100) phydev->speed = SPEED_100; else phydev->speed = SPEED_10; } /* * For 1000BASE-X Phy Mode the speed/duplex will always be * 1000Mbps/fullduplex */ if (phydev->flags == XAE_PHY_TYPE_1000BASE_X) { phydev->duplex = DUPLEX_FULL; phydev->speed = SPEED_1000; } return 0; } static int xilinxphy_of_init(struct phy_device *phydev) { struct udevice *dev = (struct udevice *)&phydev->dev; u32 phytype; debug("%s\n", __func__); phytype = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "phy-type", -1); if (phytype == XAE_PHY_TYPE_1000BASE_X) phydev->flags |= XAE_PHY_TYPE_1000BASE_X; return 0; } static int xilinxphy_config(struct phy_device *phydev) { int temp; debug("%s\n", __func__); xilinxphy_of_init(phydev); temp = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE; phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, temp); return 0; } static struct phy_driver xilinxphy_driver = { .uid = XILINX_PHY_ID, .mask = XILINX_PHY_ID_MASK, .name = "Xilinx PCS/PMA PHY", .features = PHY_GBIT_FEATURES, .config = &xilinxphy_config, .startup = &xilinxphy_startup, .shutdown = &genphy_shutdown, }; int phy_xilinx_init(void) { debug("%s\n", __func__); phy_register(&xilinxphy_driver); return 0; }