summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2018-03-09 03:23:29 -0300
committerLuiz Souza <luiz@netgate.com>2018-03-08 21:52:00 -0600
commit303bd062b084943267b4499e4122a360cbb0a48b (patch)
treebc05630f066ca6bbf53571e64321550771dc5717 /sys
parent0e9eabe9801fa38e44b9e421f643f4b4431b93f3 (diff)
downloadFreeBSD-src-303bd062b084943267b4499e4122a360cbb0a48b.zip
FreeBSD-src-303bd062b084943267b4499e4122a360cbb0a48b.tar.gz
Enable the SERDES interfaces on MV88E6190 during the switch initialization.
(cherry picked from commit 465e5577e8a32d4f98def4ec75a00c09feb140a1)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/etherswitch/e6000sw/e6000sw.c111
-rw-r--r--sys/dev/etherswitch/e6000sw/e6000swreg.h16
2 files changed, 127 insertions, 0 deletions
diff --git a/sys/dev/etherswitch/e6000sw/e6000sw.c b/sys/dev/etherswitch/e6000sw/e6000sw.c
index 4d711b6..3ec9abd 100644
--- a/sys/dev/etherswitch/e6000sw/e6000sw.c
+++ b/sys/dev/etherswitch/e6000sw/e6000sw.c
@@ -118,6 +118,8 @@ static void e6000sw_identify(driver_t *, device_t);
static int e6000sw_probe(device_t);
static int e6000sw_attach(device_t);
static int e6000sw_detach(device_t);
+static int e6000sw_read_xmdio(device_t, int, int, int);
+static int e6000sw_write_xmdio(device_t, int, int, int, int);
static int e6000sw_readphy(device_t, int, int);
static int e6000sw_writephy(device_t, int, int, int);
static etherswitch_info_t* e6000sw_getinfo(device_t);
@@ -602,9 +604,36 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port)
return (0);
}
+static void
+e6000sw_serdes_power(device_t dev, int port, bool sgmii)
+{
+ uint32_t reg;
+
+ /* SGMII */
+ reg = e6000sw_read_xmdio(dev, port, E6000SW_SERDES_DEV,
+ E6000SW_SERDES_SGMII_CTL);
+ if (sgmii)
+ reg &= ~E6000SW_SERDES_PDOWN;
+ else
+ reg |= E6000SW_SERDES_PDOWN;
+ e6000sw_write_xmdio(dev, port, E6000SW_SERDES_DEV,
+ E6000SW_SERDES_SGMII_CTL, reg);
+
+ /* 10GBASE-R/10GBASE-X4/X2 */
+ reg = e6000sw_read_xmdio(dev, port, E6000SW_SERDES_DEV,
+ E6000SW_SERDES_PCS_CTL1);
+ if (sgmii)
+ reg |= E6000SW_SERDES_PDOWN;
+ else
+ reg &= ~E6000SW_SERDES_PDOWN;
+ e6000sw_write_xmdio(dev, port, E6000SW_SERDES_DEV,
+ E6000SW_SERDES_PCS_CTL1, reg);
+}
+
static int
e6000sw_attach(device_t dev)
{
+ bool sgmii;
e6000sw_softc_t *sc;
#ifdef FDT
phandle_t child;
@@ -685,6 +714,15 @@ e6000sw_attach(device_t dev)
reg |= PSC_CONTROL_FORCED_EEE;
e6000sw_writereg(sc, REG_PORT(sc, port), PSC_CONTROL,
reg);
+ /* Power on the SERDES interfaces. */
+ if (MVSWITCH(sc, MV88E6190) &&
+ (port == 9 || port == 10)) {
+ if (e6000sw_is_fixed25port(sc, port))
+ sgmii = false;
+ else
+ sgmii = true;
+ e6000sw_serdes_power(sc->dev, port, sgmii);
+ }
}
/* Don't attach miibus at CPU/fixed ports */
@@ -723,6 +761,79 @@ out_fail:
return (err);
}
+/* XMDIO/Clause 45 access. */
+static int
+e6000sw_read_xmdio(device_t dev, int phy, int devaddr, int devreg)
+{
+ e6000sw_softc_t *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
+ if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
+ device_printf(dev, "Timeout while waiting for switch\n");
+ return (ETIMEDOUT);
+ }
+
+ reg = devaddr & SMI_CMD_REG_ADDR_MASK;
+ reg |= (phy << SMI_CMD_DEV_ADDR) & SMI_CMD_DEV_ADDR_MASK;
+
+ /* Load C45 register address. */
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, devreg);
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
+ reg | SMI_CMD_OP_C45_ADDR);
+ if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
+ device_printf(dev, "Timeout while waiting for switch\n");
+ return (ETIMEDOUT);
+ }
+
+ /* Start C45 read operation. */
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
+ reg | SMI_CMD_OP_C45_READ);
+ if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
+ device_printf(dev, "Timeout while waiting for switch\n");
+ return (ETIMEDOUT);
+ }
+
+ /* Read C45 data. */
+ reg = e6000sw_readreg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG);
+
+ return (reg & PHY_DATA_MASK);
+}
+
+static int
+e6000sw_write_xmdio(device_t dev, int phy, int devaddr, int devreg, int val)
+{
+ e6000sw_softc_t *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
+ if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
+ device_printf(dev, "Timeout while waiting for switch\n");
+ return (ETIMEDOUT);
+ }
+
+ reg = devaddr & SMI_CMD_REG_ADDR_MASK;
+ reg |= (phy << SMI_CMD_DEV_ADDR) & SMI_CMD_DEV_ADDR_MASK;
+
+ /* Load C45 register address. */
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, devreg);
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
+ reg | SMI_CMD_OP_C45_ADDR);
+ if (E6000SW_WAITREADY2(sc, SMI_PHY_CMD_REG, SMI_CMD_BUSY)) {
+ device_printf(dev, "Timeout while waiting for switch\n");
+ return (ETIMEDOUT);
+ }
+
+ /* Load data and start the C45 write operation. */
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_DATA_REG, devreg);
+ e6000sw_writereg(sc, REG_GLOBAL2, SMI_PHY_CMD_REG,
+ reg | SMI_CMD_OP_C45_WRITE);
+
+ return (0);
+}
+
/*
* PHY registers are paged. Put page index in reg 22 (accessible from every
* page), then access specific register.
diff --git a/sys/dev/etherswitch/e6000sw/e6000swreg.h b/sys/dev/etherswitch/e6000sw/e6000swreg.h
index 72c6da2..74b73c1 100644
--- a/sys/dev/etherswitch/e6000sw/e6000swreg.h
+++ b/sys/dev/etherswitch/e6000sw/e6000swreg.h
@@ -247,6 +247,16 @@ struct atu_opt {
(SMI_CMD_C22_WRITE | SMI_CMD_BUSY | SMI_CMD_MODE_C22)
#define SMI_CMD_OP_C22_READ \
(SMI_CMD_C22_READ | SMI_CMD_BUSY | SMI_CMD_MODE_C22)
+#define SMI_CMD_C45 (0 << 12)
+#define SMI_CMD_C45_ADDR (0 << 10)
+#define SMI_CMD_C45_WRITE (1 << 10)
+#define SMI_CMD_C45_READ (3 << 10)
+#define SMI_CMD_OP_C45_ADDR \
+ (SMI_CMD_C45_ADDR | SMI_CMD_BUSY | SMI_CMD_C45)
+#define SMI_CMD_OP_C45_WRITE \
+ (SMI_CMD_C45_WRITE | SMI_CMD_BUSY | SMI_CMD_C45)
+#define SMI_CMD_OP_C45_READ \
+ (SMI_CMD_C45_READ | SMI_CMD_BUSY | SMI_CMD_C45)
#define SMI_CMD_DEV_ADDR 5
#define SMI_CMD_DEV_ADDR_MASK 0x3e0
#define SMI_CMD_REG_ADDR_MASK 0x1f
@@ -264,6 +274,12 @@ struct atu_opt {
#define SCR_AND_MISC_PTR_CFG 0x7000
#define SCR_AND_MISC_DATA_CFG_MASK 0xf0
+/* SERDES registers. */
+#define E6000SW_SERDES_DEV 4
+#define E6000SW_SERDES_PCS_CTL1 0x1000
+#define E6000SW_SERDES_SGMII_CTL 0x2000
+#define E6000SW_SERDES_PDOWN (1 << 11)
+
#define E6000SW_NUM_VLANS 128
#define E6000SW_NUM_LAGS 16
#define E6000SW_NUM_PHY_REGS 29
OpenPOWER on IntegriCloud