diff --git a/drivers/net/ethernet/altera/altera_tse.h b/drivers/net/ethernet/altera/altera_tse.h index 9b640c8fbc28b96a97d2bf1da58d7e6b851b102b..e2feee87180a84a91708b2d43e12a3f2d7b5b650 100644 --- a/drivers/net/ethernet/altera/altera_tse.h +++ b/drivers/net/ethernet/altera/altera_tse.h @@ -120,6 +120,17 @@ #define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27) #define MAC_CMDCFG_CNT_RESET_GET(v) GET_BIT_VALUE(v, 31) +/* SGMII PCS register addresses + */ +#define SGMII_PCS_SCRATCH 0x10 +#define SGMII_PCS_REV 0x11 +#define SGMII_PCS_LINK_TIMER_0 0x12 +#define SGMII_PCS_LINK_TIMER_1 0x13 +#define SGMII_PCS_IF_MODE 0x14 +#define SGMII_PCS_DIS_READ_TO 0x15 +#define SGMII_PCS_READ_TO 0x16 +#define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */ + /* MDIO registers within MAC register Space */ struct altera_tse_mdio { diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 8e92084342622732ecdcd4d8e4b164551906c74e..d8bca949d810d790d1cdc58e70de481fb7ed960a 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,27 @@ static inline u32 tse_tx_avail(struct altera_tse_private *priv) return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1; } +/* PCS Register read/write functions + */ +static u16 sgmii_pcs_read(struct altera_tse_private *priv, int regnum) +{ + return csrrd32(priv->mac_dev, + tse_csroffs(mdio_phy0) + regnum * 4) & 0xffff; +} + +static void sgmii_pcs_write(struct altera_tse_private *priv, int regnum, + u16 value) +{ + csrwr32(value, priv->mac_dev, tse_csroffs(mdio_phy0) + regnum * 4); +} + +/* Check PCS scratch memory */ +static int sgmii_pcs_scratch_test(struct altera_tse_private *priv, u16 value) +{ + sgmii_pcs_write(priv, SGMII_PCS_SCRATCH, value); + return (sgmii_pcs_read(priv, SGMII_PCS_SCRATCH) == value); +} + /* MDIO specific functions */ static int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum) @@ -1083,6 +1105,66 @@ static void tse_set_rx_mode(struct net_device *dev) spin_unlock(&priv->mac_cfg_lock); } +/* Initialise (if necessary) the SGMII PCS component + */ +static int init_sgmii_pcs(struct net_device *dev) +{ + struct altera_tse_private *priv = netdev_priv(dev); + int n; + unsigned int tmp_reg = 0; + + if (priv->phy_iface != PHY_INTERFACE_MODE_SGMII) + return 0; /* Nothing to do, not in SGMII mode */ + + /* The TSE SGMII PCS block looks a little like a PHY, it is + * mapped into the zeroth MDIO space of the MAC and it has + * ID registers like a PHY would. Sadly this is often + * configured to zeroes, so don't be surprised if it does + * show 0x00000000. + */ + + if (sgmii_pcs_scratch_test(priv, 0x0000) && + sgmii_pcs_scratch_test(priv, 0xffff) && + sgmii_pcs_scratch_test(priv, 0xa5a5) && + sgmii_pcs_scratch_test(priv, 0x5a5a)) { + netdev_info(dev, "PCS PHY ID: 0x%04x%04x\n", + sgmii_pcs_read(priv, MII_PHYSID1), + sgmii_pcs_read(priv, MII_PHYSID2)); + } else { + netdev_err(dev, "SGMII PCS Scratch memory test failed.\n"); + return -ENOMEM; + } + + /* Starting on page 5-29 of the MegaCore Function User Guide + * Set SGMII Link timer to 1.6ms + */ + sgmii_pcs_write(priv, SGMII_PCS_LINK_TIMER_0, 0x0D40); + sgmii_pcs_write(priv, SGMII_PCS_LINK_TIMER_1, 0x03); + + /* Enable SGMII Interface and Enable SGMII Auto Negotiation */ + sgmii_pcs_write(priv, SGMII_PCS_IF_MODE, 0x3); + + /* Enable Autonegotiation */ + tmp_reg = sgmii_pcs_read(priv, MII_BMCR); + tmp_reg |= (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE); + sgmii_pcs_write(priv, MII_BMCR, tmp_reg); + + /* Reset PCS block */ + tmp_reg |= BMCR_RESET; + sgmii_pcs_write(priv, MII_BMCR, tmp_reg); + for (n = 0; n < SGMII_PCS_SW_RESET_TIMEOUT; n++) { + if (!(sgmii_pcs_read(priv, MII_BMCR) & BMCR_RESET)) { + netdev_info(dev, "SGMII PCS block initialised OK\n"); + return 0; + } + udelay(1); + } + + /* We failed to reset the block, return a timeout */ + netdev_err(dev, "SGMII PCS block reset failed.\n"); + return -ETIMEDOUT; +} + /* Open and initialize the interface */ static int tse_open(struct net_device *dev) @@ -1107,6 +1189,15 @@ static int tse_open(struct net_device *dev) netdev_warn(dev, "TSE revision %x\n", priv->revision); spin_lock(&priv->mac_cfg_lock); + /* no-op if MAC not operating in SGMII mode*/ + ret = init_sgmii_pcs(dev); + if (ret) { + netdev_err(dev, + "Cannot init the SGMII PCS (error: %d)\n", ret); + spin_unlock(&priv->mac_cfg_lock); + goto phy_error; + } + ret = reset_mac(priv); /* Note that reset_mac will fail if the clocks are gated by the PHY * due to the PHY being put into isolation or power down mode. diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 24b4a09468dd0f5784d6bfd32814a73f6302a1e2..f78ff0279648fddbf6f7085e2a145c79850a61d8 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -69,6 +69,7 @@ #define PHY_ID_VSC8234 0x000fc620 #define PHY_ID_VSC8244 0x000fc6c0 #define PHY_ID_VSC8514 0x00070670 +#define PHY_ID_VSC8572 0x000704d0 #define PHY_ID_VSC8574 0x000704a0 #define PHY_ID_VSC8601 0x00070420 #define PHY_ID_VSC8662 0x00070660 @@ -166,6 +167,7 @@ static int vsc82xx_config_intr(struct phy_device *phydev) (phydev->drv->phy_id == PHY_ID_VSC8234 || phydev->drv->phy_id == PHY_ID_VSC8244 || phydev->drv->phy_id == PHY_ID_VSC8514 || + phydev->drv->phy_id == PHY_ID_VSC8572 || phydev->drv->phy_id == PHY_ID_VSC8574 || phydev->drv->phy_id == PHY_ID_VSC8601) ? MII_VSC8244_IMASK_MASK : @@ -290,6 +292,17 @@ static struct phy_driver vsc82xx_driver[] = { .read_status = &genphy_read_status, .ack_interrupt = &vsc824x_ack_interrupt, .config_intr = &vsc82xx_config_intr, +}, { + .phy_id = PHY_ID_VSC8572, + .name = "Vitesse VSC8572", + .phy_id_mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &vsc824x_config_init, + .config_aneg = &vsc82x4_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &vsc824x_ack_interrupt, + .config_intr = &vsc82xx_config_intr, }, { .phy_id = PHY_ID_VSC8574, .name = "Vitesse VSC8574", @@ -355,6 +368,7 @@ static struct mdio_device_id __maybe_unused vitesse_tbl[] = { { PHY_ID_VSC8234, 0x000ffff0 }, { PHY_ID_VSC8244, 0x000fffc0 }, { PHY_ID_VSC8514, 0x000ffff0 }, + { PHY_ID_VSC8572, 0x000ffff0 }, { PHY_ID_VSC8574, 0x000ffff0 }, { PHY_ID_VSC8662, 0x000ffff0 }, { PHY_ID_VSC8221, 0x000ffff0 },