net: mscc: ocelot: expose serdes configuration function
authorColin Foster <colin.foster@in-advantage.com>
Fri, 17 Mar 2023 18:54:11 +0000 (11:54 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 20 Mar 2023 09:08:48 +0000 (09:08 +0000)
During chip initialization, ports that use SGMII / QSGMII to interface to
external phys need to be configured on the VSC7513 and VSC7514. Expose this
configuration routine, so it can be used by DSA drivers.

Signed-off-by: Colin Foster <colin.foster@in-advantage.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_net.c
include/soc/mscc/ocelot.h

index 8292e93a3782d7601d4a5d73eca56e9fef504d14..1502bb2c8ea752c0646af69920944a696d71cb30 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/dsa/ocelot.h>
 #include <linux/if_bridge.h>
 #include <linux/iopoll.h>
+#include <linux/phy/phy.h>
 #include <soc/mscc/ocelot_hsio.h>
 #include <soc/mscc/ocelot_vcap.h>
 #include "ocelot.h"
@@ -809,6 +810,45 @@ static int ocelot_port_flush(struct ocelot *ocelot, int port)
        return err;
 }
 
+int ocelot_port_configure_serdes(struct ocelot *ocelot, int port,
+                                struct device_node *portnp)
+{
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       struct device *dev = ocelot->dev;
+       int err;
+
+       /* Ensure clock signals and speed are set on all QSGMII links */
+       if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_QSGMII)
+               ocelot_port_rmwl(ocelot_port, 0,
+                                DEV_CLOCK_CFG_MAC_TX_RST |
+                                DEV_CLOCK_CFG_MAC_RX_RST,
+                                DEV_CLOCK_CFG);
+
+       if (ocelot_port->phy_mode != PHY_INTERFACE_MODE_INTERNAL) {
+               struct phy *serdes = of_phy_get(portnp, NULL);
+
+               if (IS_ERR(serdes)) {
+                       err = PTR_ERR(serdes);
+                       dev_err_probe(dev, err,
+                                     "missing SerDes phys for port %d\n",
+                                     port);
+                       return err;
+               }
+
+               err = phy_set_mode_ext(serdes, PHY_MODE_ETHERNET,
+                                      ocelot_port->phy_mode);
+               of_phy_put(serdes);
+               if (err) {
+                       dev_err(dev, "Could not SerDes mode on port %d: %pe\n",
+                               port, ERR_PTR(err));
+                       return err;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ocelot_port_configure_serdes);
+
 void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
                               unsigned int link_an_mode,
                               const struct phylink_link_state *state)
index 590a2b2816ade38cec2e08b5550947bfe07e89ed..21a87a3fc5562d39cc1539a1c3ab84fb2d8c78dc 100644 (file)
@@ -1742,34 +1742,11 @@ static int ocelot_port_phylink_create(struct ocelot *ocelot, int port,
                return -EINVAL;
        }
 
-       /* Ensure clock signals and speed are set on all QSGMII links */
-       if (phy_mode == PHY_INTERFACE_MODE_QSGMII)
-               ocelot_port_rmwl(ocelot_port, 0,
-                                DEV_CLOCK_CFG_MAC_TX_RST |
-                                DEV_CLOCK_CFG_MAC_RX_RST,
-                                DEV_CLOCK_CFG);
-
        ocelot_port->phy_mode = phy_mode;
 
-       if (phy_mode != PHY_INTERFACE_MODE_INTERNAL) {
-               struct phy *serdes = of_phy_get(portnp, NULL);
-
-               if (IS_ERR(serdes)) {
-                       err = PTR_ERR(serdes);
-                       dev_err_probe(dev, err,
-                                     "missing SerDes phys for port %d\n",
-                                     port);
-                       return err;
-               }
-
-               err = phy_set_mode_ext(serdes, PHY_MODE_ETHERNET, phy_mode);
-               of_phy_put(serdes);
-               if (err) {
-                       dev_err(dev, "Could not SerDes mode on port %d: %pe\n",
-                               port, ERR_PTR(err));
-                       return err;
-               }
-       }
+       err = ocelot_port_configure_serdes(ocelot, port, portnp);
+       if (err)
+               return err;
 
        priv = container_of(ocelot_port, struct ocelot_port_private, port);
 
index 87ade87d35407b1b5d37e026aca237e355d06883..d757b5e26d26c0c59d6d8726e5e4cb2036daed96 100644 (file)
@@ -644,6 +644,7 @@ enum ocelot_tag_prefix {
 };
 
 struct ocelot;
+struct device_node;
 
 struct ocelot_ops {
        struct net_device *(*port_to_netdev)(struct ocelot *ocelot, int port);
@@ -1111,6 +1112,9 @@ int ocelot_sb_occ_tc_port_bind_get(struct ocelot *ocelot, int port,
                                   enum devlink_sb_pool_type pool_type,
                                   u32 *p_cur, u32 *p_max);
 
+int ocelot_port_configure_serdes(struct ocelot *ocelot, int port,
+                                struct device_node *portnp);
+
 void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
                               unsigned int link_an_mode,
                               const struct phylink_link_state *state);