Commit 147c50ac authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'lan9303-phylink'



Jerry Ray says:

====================
dsa: lan9303: Move to PHYLINK

This patch series moves the lan9303 driver to use the phylink
api away from phylib.

Migrating to phylink means removing the .adjust_link api. The
functionality from the adjust_link is moved to the phylink_mac_link_up
api.  The code being removed only affected the cpu port.  The other
ports on the LAN9303 do not need anything from the phylink_mac_link_up
api.

Patches:
 0001 - Whitespace only change aligning the dsa_switch_ops members.
	No code changes.
 0002 - Moves the Turbo bit initialization out of the adjust_link api and
	places it in a driver initialization execution path. It only needs
	to be initialized once, it is never changed, and it is not a
	per-port flag.
 0003 - Adds exception handling logic in the extremely unlikely event that
	the read of the device fails.
 0004 - Performance optimization that skips a slow register write if there
	is no need to perform it.
 0005 - Change the way we identify the xMII port as phydev will be NULL
	when this logic is moved into phylink_mac_link_up.
 0006 - Removes adjust_link and begins using the phylink dsa_switch_ops
	apis.
 0007 - Adds XMII port flow control settings in the phylink_mac_link_up()
	api while cleaning up the ANEG / speed / duplex implementation.
---
v6->v7:
  - Moved the initialization of the Turbo bit into lan9303_setup().
  - Added a macro for determining is a port is an XMII port.
  - Added setting the XMII flow control in the phylink_mac_link_up() API.
  - removed unnecessary error handling and cleaned up the code flow in
    phylink_mac_link_up().
v5->v6:
  - Moved to using port number to identify xMII port for the LAN9303.
v4->v5:
  - Created prep patches to better show how things migrate.
  - cleaned up comments.
v3->v4:
  - Addressed whitespace issues as a separate patch.
  - Removed port_max_mtu api patch as it is unrelated to phylink migration.
  - Reworked the implementation to preserve the adjust_link functionality
    by including it in the phylink_mac_link_up api.
v2->v3:
  Added back in disabling Turbo Mode on the CPU MII interface.
  Removed the unnecessary clearing of the phy supported interfaces.
v1->v2:
  corrected the reported mtu size, removing ETH_HLEN and ETH_FCS_LEN
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cff9b79e 87523986
Loading
Loading
Loading
Loading
+114 −55
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@

#include "lan9303.h"

/* For the LAN9303 and LAN9354, only port 0 is an XMII port. */
#define IS_PORT_XMII(port)	((port) == 0)

#define LAN9303_NUM_PORTS 3

/* 13.2 System Control and Status Registers
@@ -50,6 +53,9 @@
#define LAN9303_MANUAL_FC_1 0x68
#define LAN9303_MANUAL_FC_2 0x69
#define LAN9303_MANUAL_FC_0 0x6a
# define LAN9303_BP_EN BIT(6)
# define LAN9303_RX_FC_EN BIT(2)
# define LAN9303_TX_FC_EN BIT(1)
#define LAN9303_SWITCH_CSR_DATA 0x6b
#define LAN9303_SWITCH_CSR_CMD 0x6c
#define LAN9303_SWITCH_CSR_CMD_BUSY BIT(31)
@@ -225,6 +231,13 @@ const struct regmap_access_table lan9303_register_set = {
};
EXPORT_SYMBOL(lan9303_register_set);

/* Flow Control registers indexed by port number */
static unsigned int flow_ctl_reg[] = {
	LAN9303_MANUAL_FC_0,
	LAN9303_MANUAL_FC_1,
	LAN9303_MANUAL_FC_2
};

static int lan9303_read(struct regmap *regmap, unsigned int offset, u32 *reg)
{
	int ret, i;
@@ -902,6 +915,7 @@ static int lan9303_setup(struct dsa_switch *ds)
{
	struct lan9303 *chip = ds->priv;
	int ret;
	u32 reg;

	/* Make sure that port 0 is the cpu port */
	if (!dsa_is_cpu_port(ds, 0)) {
@@ -909,6 +923,17 @@ static int lan9303_setup(struct dsa_switch *ds)
		return -EINVAL;
	}

	/* Virtual Phy: Remove Turbo 200Mbit mode */
	ret = lan9303_read(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, &reg);
	if (ret)
		return (ret);

	/* Clear the TURBO Mode bit if it was set. */
	if (reg & LAN9303_VIRT_SPECIAL_TURBO) {
		reg &= ~LAN9303_VIRT_SPECIAL_TURBO;
		regmap_write(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, reg);
	}

	ret = lan9303_setup_tagging(chip);
	if (ret)
		dev_err(chip->dev, "failed to setup port tagging %d\n", ret);
@@ -1049,42 +1074,6 @@ static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum,
	return chip->ops->phy_write(chip, phy, regnum, val);
}

static void lan9303_adjust_link(struct dsa_switch *ds, int port,
				struct phy_device *phydev)
{
	struct lan9303 *chip = ds->priv;
	int ctl;

	if (!phy_is_pseudo_fixed_link(phydev))
		return;

	ctl = lan9303_phy_read(ds, port, MII_BMCR);

	ctl &= ~BMCR_ANENABLE;

	if (phydev->speed == SPEED_100)
		ctl |= BMCR_SPEED100;
	else if (phydev->speed == SPEED_10)
		ctl &= ~BMCR_SPEED100;
	else
		dev_err(ds->dev, "unsupported speed: %d\n", phydev->speed);

	if (phydev->duplex == DUPLEX_FULL)
		ctl |= BMCR_FULLDPLX;
	else
		ctl &= ~BMCR_FULLDPLX;

	lan9303_phy_write(ds, port, MII_BMCR, ctl);

	if (port == chip->phy_addr_base) {
		/* Virtual Phy: Remove Turbo 200Mbit mode */
		lan9303_read(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, &ctl);

		ctl &= ~LAN9303_VIRT_SPECIAL_TURBO;
		regmap_write(chip->regmap, LAN9303_VIRT_SPECIAL_CTRL, ctl);
	}
}

static int lan9303_port_enable(struct dsa_switch *ds, int port,
			       struct phy_device *phy)
{
@@ -1281,13 +1270,83 @@ static int lan9303_port_mdb_del(struct dsa_switch *ds, int port,
	return 0;
}

static void lan9303_phylink_get_caps(struct dsa_switch *ds, int port,
				     struct phylink_config *config)
{
	struct lan9303 *chip = ds->priv;

	dev_dbg(chip->dev, "%s(%d) entered.", __func__, port);

	config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE |
				   MAC_SYM_PAUSE;

	if (port == 0) {
		__set_bit(PHY_INTERFACE_MODE_RMII,
			  config->supported_interfaces);
		__set_bit(PHY_INTERFACE_MODE_MII,
			  config->supported_interfaces);
	} else {
		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
			  config->supported_interfaces);
		/* Compatibility for phylib's default interface type when the
		 * phy-mode property is absent
		 */
		__set_bit(PHY_INTERFACE_MODE_GMII,
			  config->supported_interfaces);
	}

	/* This driver does not make use of the speed, duplex, pause or the
	 * advertisement in its mac_config, so it is safe to mark this driver
	 * as non-legacy.
	 */
	config->legacy_pre_march2020 = false;
}

static void lan9303_phylink_mac_link_up(struct dsa_switch *ds, int port,
					unsigned int mode,
					phy_interface_t interface,
					struct phy_device *phydev, int speed,
					int duplex, bool tx_pause,
					bool rx_pause)
{
	struct lan9303 *chip = ds->priv;
	u32 ctl;
	u32 reg;

	/* On this device, we are only interested in doing something here if
	 * this is the xMII port. All other ports are 10/100 phys using MDIO
	 * to control there link settings.
	 */
	if (!IS_PORT_XMII(port))
		return;

	/* Disable auto-negotiation and force the speed/duplex settings. */
	ctl = lan9303_phy_read(ds, port, MII_BMCR);
	ctl &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
	if (speed == SPEED_100)
		ctl |= BMCR_SPEED100;
	if (duplex == DUPLEX_FULL)
		ctl |= BMCR_FULLDPLX;
	lan9303_phy_write(ds, port, MII_BMCR, ctl);

	/* Force the flow control settings. */
	lan9303_read(chip->regmap, flow_ctl_reg[port], &reg);
	reg &= ~(LAN9303_BP_EN | LAN9303_RX_FC_EN | LAN9303_TX_FC_EN);
	if (rx_pause)
		reg |= (LAN9303_RX_FC_EN | LAN9303_BP_EN);
	if (tx_pause)
		reg |= LAN9303_TX_FC_EN;
	regmap_write(chip->regmap, flow_ctl_reg[port], reg);
}

static const struct dsa_switch_ops lan9303_switch_ops = {
	.get_tag_protocol	= lan9303_get_tag_protocol,
	.setup			= lan9303_setup,
	.get_strings		= lan9303_get_strings,
	.phy_read		= lan9303_phy_read,
	.phy_write		= lan9303_phy_write,
	.adjust_link = lan9303_adjust_link,
	.phylink_get_caps	= lan9303_phylink_get_caps,
	.phylink_mac_link_up	= lan9303_phylink_mac_link_up,
	.get_ethtool_stats	= lan9303_get_ethtool_stats,
	.get_sset_count		= lan9303_get_sset_count,
	.port_enable		= lan9303_port_enable,