Commit dfca93ed authored by Colin Foster's avatar Colin Foster Committed by David S. Miller
Browse files

net: mscc: ocelot: expose serdes configuration function



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: default avatarColin Foster <colin.foster@in-advantage.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 69f7f89c
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -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)
+3 −26
Original line number Diff line number Diff line
@@ -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));
	err = ocelot_port_configure_serdes(ocelot, port, portnp);
	if (err)
		return err;
		}
	}

	priv = container_of(ocelot_port, struct ocelot_port_private, port);

+4 −0
Original line number Diff line number Diff line
@@ -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);