mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Quentin Schulz <quentin.schulz@bootlin.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									51f6b410fc
								
							
						
					
					
						commit
						71e32a20cf
					
				
					 5 changed files with 63 additions and 12 deletions
				
			
		| 
						 | 
					@ -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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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)
 | 
				
			||||||
			 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 @@
 | 
				
			||||||
#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 {
 | 
				
			||||||
	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 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#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)
 | 
				
			||||||
	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)
 | 
				
			||||||
			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 @@
 | 
				
			||||||
 * 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),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue