mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
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: Colin Foster <colin.foster@in-advantage.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
69f7f89c0d
commit
dfca93ed51
@@ -7,6 +7,7 @@
|
|||||||
#include <linux/dsa/ocelot.h>
|
#include <linux/dsa/ocelot.h>
|
||||||
#include <linux/if_bridge.h>
|
#include <linux/if_bridge.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
#include <soc/mscc/ocelot_hsio.h>
|
#include <soc/mscc/ocelot_hsio.h>
|
||||||
#include <soc/mscc/ocelot_vcap.h>
|
#include <soc/mscc/ocelot_vcap.h>
|
||||||
#include "ocelot.h"
|
#include "ocelot.h"
|
||||||
@@ -809,6 +810,45 @@ static int ocelot_port_flush(struct ocelot *ocelot, int port)
|
|||||||
return err;
|
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,
|
void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
|
||||||
unsigned int link_an_mode,
|
unsigned int link_an_mode,
|
||||||
const struct phylink_link_state *state)
|
const struct phylink_link_state *state)
|
||||||
|
@@ -1742,34 +1742,11 @@ static int ocelot_port_phylink_create(struct ocelot *ocelot, int port,
|
|||||||
return -EINVAL;
|
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;
|
ocelot_port->phy_mode = phy_mode;
|
||||||
|
|
||||||
if (phy_mode != PHY_INTERFACE_MODE_INTERNAL) {
|
err = ocelot_port_configure_serdes(ocelot, port, portnp);
|
||||||
struct phy *serdes = of_phy_get(portnp, NULL);
|
if (err)
|
||||||
|
return err;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priv = container_of(ocelot_port, struct ocelot_port_private, port);
|
priv = container_of(ocelot_port, struct ocelot_port_private, port);
|
||||||
|
|
||||||
|
@@ -644,6 +644,7 @@ enum ocelot_tag_prefix {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ocelot;
|
struct ocelot;
|
||||||
|
struct device_node;
|
||||||
|
|
||||||
struct ocelot_ops {
|
struct ocelot_ops {
|
||||||
struct net_device *(*port_to_netdev)(struct ocelot *ocelot, int port);
|
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,
|
enum devlink_sb_pool_type pool_type,
|
||||||
u32 *p_cur, u32 *p_max);
|
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,
|
void ocelot_phylink_mac_config(struct ocelot *ocelot, int port,
|
||||||
unsigned int link_an_mode,
|
unsigned int link_an_mode,
|
||||||
const struct phylink_link_state *state);
|
const struct phylink_link_state *state);
|
||||||
|
Reference in New Issue
Block a user