Skip to content

Commit 6c0c620

Browse files
committed
Merge branch 'altera-tse-sgmii-pcs'
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>
2 parents b3b9fa0 + 3b80456 commit 6c0c620

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

drivers/net/ethernet/altera/altera_tse.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@
120120
#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27)
121121
#define MAC_CMDCFG_CNT_RESET_GET(v) GET_BIT_VALUE(v, 31)
122122

123+
/* SGMII PCS register addresses
124+
*/
125+
#define SGMII_PCS_SCRATCH 0x10
126+
#define SGMII_PCS_REV 0x11
127+
#define SGMII_PCS_LINK_TIMER_0 0x12
128+
#define SGMII_PCS_LINK_TIMER_1 0x13
129+
#define SGMII_PCS_IF_MODE 0x14
130+
#define SGMII_PCS_DIS_READ_TO 0x15
131+
#define SGMII_PCS_READ_TO 0x16
132+
#define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */
133+
123134
/* MDIO registers within MAC register Space
124135
*/
125136
struct altera_tse_mdio {

drivers/net/ethernet/altera/altera_tse_main.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/io.h>
3838
#include <linux/kernel.h>
3939
#include <linux/module.h>
40+
#include <linux/mii.h>
4041
#include <linux/netdevice.h>
4142
#include <linux/of_device.h>
4243
#include <linux/of_mdio.h>
@@ -96,6 +97,27 @@ static inline u32 tse_tx_avail(struct altera_tse_private *priv)
9697
return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1;
9798
}
9899

100+
/* PCS Register read/write functions
101+
*/
102+
static u16 sgmii_pcs_read(struct altera_tse_private *priv, int regnum)
103+
{
104+
return csrrd32(priv->mac_dev,
105+
tse_csroffs(mdio_phy0) + regnum * 4) & 0xffff;
106+
}
107+
108+
static void sgmii_pcs_write(struct altera_tse_private *priv, int regnum,
109+
u16 value)
110+
{
111+
csrwr32(value, priv->mac_dev, tse_csroffs(mdio_phy0) + regnum * 4);
112+
}
113+
114+
/* Check PCS scratch memory */
115+
static int sgmii_pcs_scratch_test(struct altera_tse_private *priv, u16 value)
116+
{
117+
sgmii_pcs_write(priv, SGMII_PCS_SCRATCH, value);
118+
return (sgmii_pcs_read(priv, SGMII_PCS_SCRATCH) == value);
119+
}
120+
99121
/* MDIO specific functions
100122
*/
101123
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)
10831105
spin_unlock(&priv->mac_cfg_lock);
10841106
}
10851107

1108+
/* Initialise (if necessary) the SGMII PCS component
1109+
*/
1110+
static int init_sgmii_pcs(struct net_device *dev)
1111+
{
1112+
struct altera_tse_private *priv = netdev_priv(dev);
1113+
int n;
1114+
unsigned int tmp_reg = 0;
1115+
1116+
if (priv->phy_iface != PHY_INTERFACE_MODE_SGMII)
1117+
return 0; /* Nothing to do, not in SGMII mode */
1118+
1119+
/* The TSE SGMII PCS block looks a little like a PHY, it is
1120+
* mapped into the zeroth MDIO space of the MAC and it has
1121+
* ID registers like a PHY would. Sadly this is often
1122+
* configured to zeroes, so don't be surprised if it does
1123+
* show 0x00000000.
1124+
*/
1125+
1126+
if (sgmii_pcs_scratch_test(priv, 0x0000) &&
1127+
sgmii_pcs_scratch_test(priv, 0xffff) &&
1128+
sgmii_pcs_scratch_test(priv, 0xa5a5) &&
1129+
sgmii_pcs_scratch_test(priv, 0x5a5a)) {
1130+
netdev_info(dev, "PCS PHY ID: 0x%04x%04x\n",
1131+
sgmii_pcs_read(priv, MII_PHYSID1),
1132+
sgmii_pcs_read(priv, MII_PHYSID2));
1133+
} else {
1134+
netdev_err(dev, "SGMII PCS Scratch memory test failed.\n");
1135+
return -ENOMEM;
1136+
}
1137+
1138+
/* Starting on page 5-29 of the MegaCore Function User Guide
1139+
* Set SGMII Link timer to 1.6ms
1140+
*/
1141+
sgmii_pcs_write(priv, SGMII_PCS_LINK_TIMER_0, 0x0D40);
1142+
sgmii_pcs_write(priv, SGMII_PCS_LINK_TIMER_1, 0x03);
1143+
1144+
/* Enable SGMII Interface and Enable SGMII Auto Negotiation */
1145+
sgmii_pcs_write(priv, SGMII_PCS_IF_MODE, 0x3);
1146+
1147+
/* Enable Autonegotiation */
1148+
tmp_reg = sgmii_pcs_read(priv, MII_BMCR);
1149+
tmp_reg |= (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE);
1150+
sgmii_pcs_write(priv, MII_BMCR, tmp_reg);
1151+
1152+
/* Reset PCS block */
1153+
tmp_reg |= BMCR_RESET;
1154+
sgmii_pcs_write(priv, MII_BMCR, tmp_reg);
1155+
for (n = 0; n < SGMII_PCS_SW_RESET_TIMEOUT; n++) {
1156+
if (!(sgmii_pcs_read(priv, MII_BMCR) & BMCR_RESET)) {
1157+
netdev_info(dev, "SGMII PCS block initialised OK\n");
1158+
return 0;
1159+
}
1160+
udelay(1);
1161+
}
1162+
1163+
/* We failed to reset the block, return a timeout */
1164+
netdev_err(dev, "SGMII PCS block reset failed.\n");
1165+
return -ETIMEDOUT;
1166+
}
1167+
10861168
/* Open and initialize the interface
10871169
*/
10881170
static int tse_open(struct net_device *dev)
@@ -1107,6 +1189,15 @@ static int tse_open(struct net_device *dev)
11071189
netdev_warn(dev, "TSE revision %x\n", priv->revision);
11081190

11091191
spin_lock(&priv->mac_cfg_lock);
1192+
/* no-op if MAC not operating in SGMII mode*/
1193+
ret = init_sgmii_pcs(dev);
1194+
if (ret) {
1195+
netdev_err(dev,
1196+
"Cannot init the SGMII PCS (error: %d)\n", ret);
1197+
spin_unlock(&priv->mac_cfg_lock);
1198+
goto phy_error;
1199+
}
1200+
11101201
ret = reset_mac(priv);
11111202
/* Note that reset_mac will fail if the clocks are gated by the PHY
11121203
* due to the PHY being put into isolation or power down mode.

drivers/net/phy/vitesse.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#define PHY_ID_VSC8234 0x000fc620
7070
#define PHY_ID_VSC8244 0x000fc6c0
7171
#define PHY_ID_VSC8514 0x00070670
72+
#define PHY_ID_VSC8572 0x000704d0
7273
#define PHY_ID_VSC8574 0x000704a0
7374
#define PHY_ID_VSC8601 0x00070420
7475
#define PHY_ID_VSC8662 0x00070660
@@ -166,6 +167,7 @@ static int vsc82xx_config_intr(struct phy_device *phydev)
166167
(phydev->drv->phy_id == PHY_ID_VSC8234 ||
167168
phydev->drv->phy_id == PHY_ID_VSC8244 ||
168169
phydev->drv->phy_id == PHY_ID_VSC8514 ||
170+
phydev->drv->phy_id == PHY_ID_VSC8572 ||
169171
phydev->drv->phy_id == PHY_ID_VSC8574 ||
170172
phydev->drv->phy_id == PHY_ID_VSC8601) ?
171173
MII_VSC8244_IMASK_MASK :
@@ -290,6 +292,17 @@ static struct phy_driver vsc82xx_driver[] = {
290292
.read_status = &genphy_read_status,
291293
.ack_interrupt = &vsc824x_ack_interrupt,
292294
.config_intr = &vsc82xx_config_intr,
295+
}, {
296+
.phy_id = PHY_ID_VSC8572,
297+
.name = "Vitesse VSC8572",
298+
.phy_id_mask = 0x000ffff0,
299+
.features = PHY_GBIT_FEATURES,
300+
.flags = PHY_HAS_INTERRUPT,
301+
.config_init = &vsc824x_config_init,
302+
.config_aneg = &vsc82x4_config_aneg,
303+
.read_status = &genphy_read_status,
304+
.ack_interrupt = &vsc824x_ack_interrupt,
305+
.config_intr = &vsc82xx_config_intr,
293306
}, {
294307
.phy_id = PHY_ID_VSC8574,
295308
.name = "Vitesse VSC8574",
@@ -355,6 +368,7 @@ static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
355368
{ PHY_ID_VSC8234, 0x000ffff0 },
356369
{ PHY_ID_VSC8244, 0x000fffc0 },
357370
{ PHY_ID_VSC8514, 0x000ffff0 },
371+
{ PHY_ID_VSC8572, 0x000ffff0 },
358372
{ PHY_ID_VSC8574, 0x000ffff0 },
359373
{ PHY_ID_VSC8662, 0x000ffff0 },
360374
{ PHY_ID_VSC8221, 0x000ffff0 },

0 commit comments

Comments
 (0)