Skip to content

Commit

Permalink
Merge branch 'altera-tse-sgmii-pcs'
Browse files Browse the repository at this point in the history
Neill Whillans says:

====================
net: Add support for SGMII PCS on Altera TSE MAC

These patches were created as part of work to add support for SGMII
PCS functionality to the Altera TSE MAC. Patches are based on 4.9-rc6
git tree.

The first patch in the series adds support for the VSC8572 dual-port
Gigabit Ethernet transceiver, used in integration testing.

The second patch adds support for the SGMII PCS functionality to the
Altera TSE driver.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 2, 2016
2 parents b3b9fa0 + 3b80456 commit 6c0c620
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
11 changes: 11 additions & 0 deletions drivers/net/ethernet/altera/altera_tse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
91 changes: 91 additions & 0 deletions drivers/net/ethernet/altera/altera_tse_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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.
Expand Down
14 changes: 14 additions & 0 deletions drivers/net/phy/vitesse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 :
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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 },
Expand Down

0 comments on commit 6c0c620

Please sign in to comment.