diff mbox series

[net-next,10/10] net: mscc: ocelot: make use of SerDes PHYs for handling their configuration

Message ID 0ce1b3e8466064741dc6e484f87bbe48542cb978.1532954208.git-series.quentin.schulz@bootlin.com
State Changes Requested, archived
Delegated to: David Miller
Headers show
Series mscc: ocelot: add support for SerDes muxing configuration | expand

Commit Message

Quentin Schulz July 30, 2018, 12:43 p.m. UTC
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: Quentin Schulz <quentin.schulz@bootlin.com>
---
 drivers/net/ethernet/mscc/Kconfig        |  2 +-
 drivers/net/ethernet/mscc/ocelot.c       | 16 ++++++++-
 drivers/net/ethernet/mscc/ocelot.h       |  5 +++-
 drivers/net/ethernet/mscc/ocelot_board.c | 43 +++++++++++++++++++------
 4 files changed, 55 insertions(+), 11 deletions(-)

Comments

Andrew Lunn July 30, 2018, 1:50 p.m. UTC | #1
On Mon, Jul 30, 2018 at 02:43:55PM +0200, Quentin Schulz wrote:

> +		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;
> +
> +		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_NA)
> +			continue;
> +
> +		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_SGMII)
> +			phy_mode = PHY_MODE_SGMII;
> +		else
> +			phy_mode = PHY_MODE_QSGMII;

Hi Quentin

Say somebody puts RGMII as the phy-mode? It would be better to verify
it is only SGMII or QSGMII and return -EINVAL otherwise.

> +
> +		serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
> +		if (IS_ERR(serdes)) {
> +			if (PTR_ERR(serdes) == -EPROBE_DEFER) {
> +				dev_err(ocelot->dev, "deferring probe\n");

dev_dbg() ? It is not really an error.

> +				err = -EPROBE_DEFER;
> +				goto err_probe_ports;
> +			}
> +
> +			dev_err(ocelot->dev, "missing SerDes phys for port%d\n",
> +				port);
> +			err = -ENODEV;

err = PTR_ERR(serdes) so we get the actual error?

>  			goto err_probe_ports;
>  		}
> +
> +		ocelot->ports[port]->serdes = serdes;
>  	}
>  
>  	register_netdevice_notifier(&ocelot_netdevice_nb);


	Andrew
Quentin Schulz Aug. 1, 2018, 7:51 a.m. UTC | #2
Hi Andrew,

On Mon, Jul 30, 2018 at 03:50:18PM +0200, Andrew Lunn wrote:
>  On Mon, Jul 30, 2018 at 02:43:55PM +0200, Quentin Schulz wrote:
> 
> > +		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;
> > +
> > +		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_NA)
> > +			continue;
> > +
> > +		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_SGMII)
> > +			phy_mode = PHY_MODE_SGMII;
> > +		else
> > +			phy_mode = PHY_MODE_QSGMII;
> 
> Hi Quentin
> 
> Say somebody puts RGMII as the phy-mode? It would be better to verify
> it is only SGMII or QSGMII and return -EINVAL otherwise.
> 

I'll replace this with a switch case to handle other cases.

> > +
> > +		serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
> > +		if (IS_ERR(serdes)) {
> > +			if (PTR_ERR(serdes) == -EPROBE_DEFER) {
> > +				dev_err(ocelot->dev, "deferring probe\n");
> 
> dev_dbg() ? It is not really an error.
> 

Ack.

> > +				err = -EPROBE_DEFER;
> > +				goto err_probe_ports;
> > +			}
> > +
> > +			dev_err(ocelot->dev, "missing SerDes phys for port%d\n",
> > +				port);
> > +			err = -ENODEV;
> 
> err = PTR_ERR(serdes) so we get the actual error?
> 

Ack.

Thanks,
Quentin
diff mbox series

Patch

diff --git a/drivers/net/ethernet/mscc/Kconfig b/drivers/net/ethernet/mscc/Kconfig
index 36c8462..bcec058 100644
--- a/drivers/net/ethernet/mscc/Kconfig
+++ b/drivers/net/ethernet/mscc/Kconfig
@@ -23,6 +23,8 @@  config MSCC_OCELOT_SWITCH
 config MSCC_OCELOT_SWITCH_OCELOT
 	tristate "Ocelot switch driver on Ocelot"
 	depends on MSCC_OCELOT_SWITCH
+	depends on GENERIC_PHY
+	depends on OF_NET
 	help
 	  This driver supports the Ocelot network switch device as present on
 	  the Ocelot SoCs.
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 1a4f2bb..8f11fdb 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -472,6 +472,7 @@  static int ocelot_port_open(struct net_device *dev)
 {
 	struct ocelot_port *port = netdev_priv(dev);
 	struct ocelot *ocelot = port->ocelot;
+	enum phy_mode phy_mode;
 	int err;
 
 	/* Enable receiving frames on the port, and activate auto-learning of
@@ -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, 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,
-				 PHY_INTERFACE_MODE_NA);
+				 port->phy_mode);
 	if (err) {
 		netdev_err(dev, "Could not attach to PHY\n");
 		return err;
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index 3720e51..62c7c8e 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -11,6 +11,8 @@ 
 #include <linux/bitops.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
@@ -453,6 +455,9 @@  struct ocelot_port {
 	u8 vlan_aware;
 
 	u64 *stats;
+
+	phy_interface_t phy_mode;
+	struct phy *serdes;
 };
 
 u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index b7d755b..3bb71b7 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -6,6 +6,7 @@ 
  */
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/of_net.h>
 #include <linux/netdevice.h>
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
@@ -247,18 +248,12 @@  static int mscc_ocelot_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&ocelot->multicast);
 	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) {
 		struct device_node *phy_node;
 		struct phy_device *phy;
 		struct resource *res;
+		struct phy *serdes;
+		enum phy_mode phy_mode;
 		void __iomem *regs;
 		char res_name[8];
 		u32 port;
@@ -283,10 +278,38 @@  static int mscc_ocelot_probe(struct platform_device *pdev)
 			continue;
 
 		err = ocelot_probe_port(ocelot, port, regs, phy);
-		if (err) {
-			dev_err(&pdev->dev, "failed to probe ports\n");
+		if (err)
+			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;
+
+		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_NA)
+			continue;
+
+		if (ocelot->ports[port]->phy_mode == PHY_INTERFACE_MODE_SGMII)
+			phy_mode = PHY_MODE_SGMII;
+		else
+			phy_mode = PHY_MODE_QSGMII;
+
+		serdes = devm_of_phy_get(ocelot->dev, portnp, NULL);
+		if (IS_ERR(serdes)) {
+			if (PTR_ERR(serdes) == -EPROBE_DEFER) {
+				dev_err(ocelot->dev, "deferring probe\n");
+				err = -EPROBE_DEFER;
+				goto err_probe_ports;
+			}
+
+			dev_err(ocelot->dev, "missing SerDes phys for port%d\n",
+				port);
+			err = -ENODEV;
 			goto err_probe_ports;
 		}
+
+		ocelot->ports[port]->serdes = serdes;
 	}
 
 	register_netdevice_notifier(&ocelot_netdevice_nb);