net: dsa: qca8k: Improve SGMII interface handling
authorJonathan McDowell <noodles@earth.li>
Sat, 20 Jun 2020 10:31:05 +0000 (11:31 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 22 Jun 2020 22:54:34 +0000 (15:54 -0700)
This patch improves the handling of the SGMII interface on the QCA8K
devices. Previously the driver did no configuration of the port, even if
it was selected. We now configure it up in the appropriate
PHY/MAC/Base-X mode depending on what phylink tells us we are connected
to and ensure it is enabled.

Tested with a device where the CPU connection is RGMII (i.e. the common
current use case) + one where the CPU connection is SGMII. I don't have
any devices where the SGMII interface is brought out to something other
than the CPU.

Signed-off-by: Jonathan McDowell <noodles@earth.li>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/qca8k.c
drivers/net/dsa/qca8k.h

index 63b84789f16b18f2fe6bc265ba5428174c10e7db..11d1c290d90f6d140480c5d6745752aad11762ef 100644 (file)
@@ -673,6 +673,9 @@ qca8k_setup(struct dsa_switch *ds)
        /* Flush the FDB table */
        qca8k_fdb_flush(priv);
 
+       /* We don't have interrupts for link changes, so we need to poll */
+       ds->pcs_poll = true;
+
        return 0;
 }
 
@@ -681,7 +684,7 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
                         const struct phylink_link_state *state)
 {
        struct qca8k_priv *priv = ds->priv;
-       u32 reg;
+       u32 reg, val;
 
        switch (port) {
        case 0: /* 1st CPU port */
@@ -740,6 +743,34 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
        case PHY_INTERFACE_MODE_1000BASEX:
                /* Enable SGMII on the port */
                qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN);
+
+               /* Enable/disable SerDes auto-negotiation as necessary */
+               val = qca8k_read(priv, QCA8K_REG_PWS);
+               if (phylink_autoneg_inband(mode))
+                       val &= ~QCA8K_PWS_SERDES_AEN_DIS;
+               else
+                       val |= QCA8K_PWS_SERDES_AEN_DIS;
+               qca8k_write(priv, QCA8K_REG_PWS, val);
+
+               /* Configure the SGMII parameters */
+               val = qca8k_read(priv, QCA8K_REG_SGMII_CTRL);
+
+               val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
+                       QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD;
+
+               if (dsa_is_cpu_port(ds, port)) {
+                       /* CPU port, we're talking to the CPU MAC, be a PHY */
+                       val &= ~QCA8K_SGMII_MODE_CTRL_MASK;
+                       val |= QCA8K_SGMII_MODE_CTRL_PHY;
+               } else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
+                       val &= ~QCA8K_SGMII_MODE_CTRL_MASK;
+                       val |= QCA8K_SGMII_MODE_CTRL_MAC;
+               } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) {
+                       val &= ~QCA8K_SGMII_MODE_CTRL_MASK;
+                       val |= QCA8K_SGMII_MODE_CTRL_BASEX;
+               }
+
+               qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val);
                break;
        default:
                dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
index 42d6ea24eb14ecffbd9e199ce1b344abaa6cf108..10ef2bca2cde0f6cef9c2c11bf80f1be766bdf3b 100644 (file)
@@ -36,6 +36,8 @@
 #define   QCA8K_MAX_DELAY                              3
 #define   QCA8K_PORT_PAD_RGMII_RX_DELAY_EN             BIT(24)
 #define   QCA8K_PORT_PAD_SGMII_EN                      BIT(7)
+#define QCA8K_REG_PWS                                  0x010
+#define   QCA8K_PWS_SERDES_AEN_DIS                     BIT(7)
 #define QCA8K_REG_MODULE_EN                            0x030
 #define   QCA8K_MODULE_EN_MIB                          BIT(0)
 #define QCA8K_REG_MIB                                  0x034
@@ -69,6 +71,7 @@
 #define   QCA8K_PORT_STATUS_LINK_UP                    BIT(8)
 #define   QCA8K_PORT_STATUS_LINK_AUTO                  BIT(9)
 #define   QCA8K_PORT_STATUS_LINK_PAUSE                 BIT(10)
+#define   QCA8K_PORT_STATUS_FLOW_AUTO                  BIT(12)
 #define QCA8K_REG_PORT_HDR_CTRL(_i)                    (0x9c + (_i * 4))
 #define   QCA8K_PORT_HDR_CTRL_RX_MASK                  GENMASK(3, 2)
 #define   QCA8K_PORT_HDR_CTRL_RX_S                     2
 #define   QCA8K_PORT_HDR_CTRL_ALL                      2
 #define   QCA8K_PORT_HDR_CTRL_MGMT                     1
 #define   QCA8K_PORT_HDR_CTRL_NONE                     0
+#define QCA8K_REG_SGMII_CTRL                           0x0e0
+#define   QCA8K_SGMII_EN_PLL                           BIT(1)
+#define   QCA8K_SGMII_EN_RX                            BIT(2)
+#define   QCA8K_SGMII_EN_TX                            BIT(3)
+#define   QCA8K_SGMII_EN_SD                            BIT(4)
+#define   QCA8K_SGMII_CLK125M_DELAY                    BIT(7)
+#define   QCA8K_SGMII_MODE_CTRL_MASK                   (BIT(22) | BIT(23))
+#define   QCA8K_SGMII_MODE_CTRL_BASEX                  (0 << 22)
+#define   QCA8K_SGMII_MODE_CTRL_PHY                    (1 << 22)
+#define   QCA8K_SGMII_MODE_CTRL_MAC                    (2 << 22)
 
 /* EEE control registers */
 #define QCA8K_REG_EEE_CTRL                             0x100