Commit 71e32a20 authored by Quentin Schulz's avatar Quentin Schulz Committed by David S. Miller

net: mscc: ocelot: make use of SerDes PHYs for handling their configuration

Previously, the SerDes muxing was hardcoded to a given mode in the MAC
controller driver. Now, the SerDes muxing is configured within the
Device Tree and is enforced in the MAC controller driver so we can have
a lot of different SerDes configurations.

Make use of the SerDes PHYs in the MAC controller to set up the SerDes
according to the SerDes<->switch port mapping and the communication mode
with the Ethernet PHY.
Signed-off-by: default avatarQuentin Schulz <quentin.schulz@bootlin.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 51f6b410
...@@ -23,6 +23,8 @@ config MSCC_OCELOT_SWITCH ...@@ -23,6 +23,8 @@ config MSCC_OCELOT_SWITCH
config MSCC_OCELOT_SWITCH_OCELOT config MSCC_OCELOT_SWITCH_OCELOT
tristate "Ocelot switch driver on Ocelot" tristate "Ocelot switch driver on Ocelot"
depends on MSCC_OCELOT_SWITCH depends on MSCC_OCELOT_SWITCH
depends on GENERIC_PHY
depends on OF_NET
help help
This driver supports the Ocelot network switch device as present on This driver supports the Ocelot network switch device as present on
the Ocelot SoCs. the Ocelot SoCs.
......
...@@ -472,6 +472,7 @@ static int ocelot_port_open(struct net_device *dev) ...@@ -472,6 +472,7 @@ static int ocelot_port_open(struct net_device *dev)
{ {
struct ocelot_port *port = netdev_priv(dev); struct ocelot_port *port = netdev_priv(dev);
struct ocelot *ocelot = port->ocelot; struct ocelot *ocelot = port->ocelot;
enum phy_mode phy_mode;
int err; int err;
/* Enable receiving frames on the port, and activate auto-learning of /* Enable receiving frames on the port, and activate auto-learning of
...@@ -482,8 +483,21 @@ static int ocelot_port_open(struct net_device *dev) ...@@ -482,8 +483,21 @@ static int ocelot_port_open(struct net_device *dev)
ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port), ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port),
ANA_PORT_PORT_CFG, port->chip_port); ANA_PORT_PORT_CFG, port->chip_port);
if (port->serdes) {
if (port->phy_mode == PHY_INTERFACE_MODE_SGMII)
phy_mode = PHY_MODE_SGMII;
else
phy_mode = PHY_MODE_QSGMII;
err = phy_set_mode(port->serdes, phy_mode);
if (err) {
netdev_err(dev, "Could not set mode of SerDes\n");
return err;
}
}
err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link, err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link,
PHY_INTERFACE_MODE_NA); port->phy_mode);
if (err) { if (err) {
netdev_err(dev, "Could not attach to PHY\n"); netdev_err(dev, "Could not attach to PHY\n");
return err; return err;
......
...@@ -11,9 +11,10 @@ ...@@ -11,9 +11,10 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/phy.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <soc/mscc/ocelot_hsio.h>
#include "ocelot_ana.h" #include "ocelot_ana.h"
#include "ocelot_dev.h" #include "ocelot_dev.h"
...@@ -454,6 +455,9 @@ struct ocelot_port { ...@@ -454,6 +455,9 @@ struct ocelot_port {
u8 vlan_aware; u8 vlan_aware;
u64 *stats; u64 *stats;
phy_interface_t phy_mode;
struct phy *serdes;
}; };
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset); u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_net.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
...@@ -253,18 +254,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -253,18 +254,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ocelot->multicast); INIT_LIST_HEAD(&ocelot->multicast);
ocelot_init(ocelot); ocelot_init(ocelot);
ocelot_rmw(ocelot, HSIO_HW_CFG_DEV1G_4_MODE |
HSIO_HW_CFG_DEV1G_6_MODE |
HSIO_HW_CFG_DEV1G_9_MODE,
HSIO_HW_CFG_DEV1G_4_MODE |
HSIO_HW_CFG_DEV1G_6_MODE |
HSIO_HW_CFG_DEV1G_9_MODE,
HSIO_HW_CFG);
for_each_available_child_of_node(ports, portnp) { for_each_available_child_of_node(ports, portnp) {
struct device_node *phy_node; struct device_node *phy_node;
struct phy_device *phy; struct phy_device *phy;
struct resource *res; struct resource *res;
struct phy *serdes;
enum phy_mode phy_mode;
void __iomem *regs; void __iomem *regs;
char res_name[8]; char res_name[8];
u32 port; u32 port;
...@@ -289,10 +284,45 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ...@@ -289,10 +284,45 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
continue; continue;
err = ocelot_probe_port(ocelot, port, regs, phy); err = ocelot_probe_port(ocelot, port, regs, phy);
if (err) { if (err)
dev_err(&pdev->dev, "failed to probe ports\n"); return err;
err = of_get_phy_mode(portnp);
if (err < 0)
ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA;
else
ocelot->ports[port]->phy_mode = err;
switch (ocelot->ports[port]->phy_mode) {
case PHY_INTERFACE_MODE_NA:
continue;
case PHY_INTERFACE_MODE_SGMII:
phy_mode = PHY_MODE_SGMII;
break;
case PHY_INTERFACE_MODE_QSGMII:
phy_mode = PHY_MODE_QSGMII;
break;
default:
dev_err(ocelot->dev,
"invalid phy mode for port%d, (Q)SGMII only\n",
port);
return -EINVAL;
}
serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
if (IS_ERR(serdes)) {
err = PTR_ERR(serdes);
if (err == -EPROBE_DEFER)
dev_dbg(ocelot->dev, "deferring probe\n");
else
dev_err(ocelot->dev,
"missing SerDes phys for port%d\n",
port);
goto err_probe_ports; goto err_probe_ports;
} }
ocelot->ports[port]->serdes = serdes;
} }
register_netdevice_notifier(&ocelot_netdevice_nb); register_netdevice_notifier(&ocelot_netdevice_nb);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Copyright (c) 2017 Microsemi Corporation * Copyright (c) 2017 Microsemi Corporation
*/ */
#include "ocelot.h" #include "ocelot.h"
#include <soc/mscc/ocelot_hsio.h>
static const u32 ocelot_ana_regmap[] = { static const u32 ocelot_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x009000), REG(ANA_ADVLEARN, 0x009000),
......
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