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

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
......@@ -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)
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment