Commit 5b89aeae authored by Daniel Golle's avatar Daniel Golle Committed by Jakub Kicinski
Browse files

net: dsa: mt7530: use external PCS driver



Implement regmap access wrappers, for now only to be used by the
pcs-mtk-lynxi driver.
Make use of this external PCS driver and drop the now reduntant
implementation in mt7530.c.
As a nice side effect the SGMII registers can now also more easily be
inspected for debugging via /sys/kernel/debug/regmap.

Tested-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDaniel Golle <daniel@makrotopia.org>
Tested-by: default avatarFrank Wunderlich <frank-w@public-files.de>
Reviewed-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2a3ec7ae
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ config NET_DSA_MT7530
	tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
	select NET_DSA_TAG_MTK
	select MEDIATEK_GE_PHY
	select PCS_MTK_LYNXI
	help
	  This enables support for the MediaTek MT7530 and MT7531 Ethernet
	  switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
+66 −211
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <linux/pcs/pcs-mtk-lynxi.h>
#include <linux/phylink.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -2572,128 +2573,11 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
	return 0;
}

static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
			       phy_interface_t interface, int speed, int duplex)
{
	struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
	int port = pcs_to_mt753x_pcs(pcs)->port;
	unsigned int val;

	/* For adjusting speed and duplex of SGMII force mode. */
	if (interface != PHY_INTERFACE_MODE_SGMII ||
	    phylink_autoneg_inband(mode))
		return;

	/* SGMII force mode setting */
	val = mt7530_read(priv, MT7531_SGMII_MODE(port));
	val &= ~MT7531_SGMII_IF_MODE_MASK;

	switch (speed) {
	case SPEED_10:
		val |= MT7531_SGMII_FORCE_SPEED_10;
		break;
	case SPEED_100:
		val |= MT7531_SGMII_FORCE_SPEED_100;
		break;
	case SPEED_1000:
		val |= MT7531_SGMII_FORCE_SPEED_1000;
		break;
	}

	/* MT7531 SGMII 1G force mode can only work in full duplex mode,
	 * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
	 *
	 * The speed check is unnecessary as the MAC capabilities apply
	 * this restriction. --rmk
	 */
	if ((speed == SPEED_10 || speed == SPEED_100) &&
	    duplex != DUPLEX_FULL)
		val |= MT7531_SGMII_FORCE_HALF_DUPLEX;

	mt7530_write(priv, MT7531_SGMII_MODE(port), val);
}

static bool mt753x_is_mac_port(u32 port)
{
	return (port == 5 || port == 6);
}

static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port,
					 phy_interface_t interface)
{
	u32 val;

	if (!mt753x_is_mac_port(port))
		return -EINVAL;

	mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
		   MT7531_SGMII_PHYA_PWD);

	val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port));
	val &= ~MT7531_RG_TPHY_SPEED_MASK;
	/* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B
	 * encoding.
	 */
	val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ?
		MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G;
	mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val);

	mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);

	/* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex
	 * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
	 */
	mt7530_rmw(priv, MT7531_SGMII_MODE(port),
		   MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS,
		   MT7531_SGMII_FORCE_SPEED_1000);

	mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);

	return 0;
}

static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port,
				      phy_interface_t interface)
{
	if (!mt753x_is_mac_port(port))
		return -EINVAL;

	mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
		   MT7531_SGMII_PHYA_PWD);

	mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
		   MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G);

	mt7530_set(priv, MT7531_SGMII_MODE(port),
		   MT7531_SGMII_REMOTE_FAULT_DIS |
		   MT7531_SGMII_SPEED_DUPLEX_AN);

	mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port),
		   MT7531_SGMII_TX_CONFIG_MASK, 1);

	mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);

	mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART);

	mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);

	return 0;
}

static void mt7531_pcs_an_restart(struct phylink_pcs *pcs)
{
	struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
	int port = pcs_to_mt753x_pcs(pcs)->port;
	u32 val;

	/* Only restart AN when AN is enabled */
	val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
	if (val & MT7531_SGMII_AN_ENABLE) {
		val |= MT7531_SGMII_AN_RESTART;
		mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val);
	}
}

static int
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
		  phy_interface_t interface)
@@ -2716,11 +2600,11 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
		phydev = dp->slave->phydev;
		return mt7531_rgmii_setup(priv, port, interface, phydev);
	case PHY_INTERFACE_MODE_SGMII:
		return mt7531_sgmii_setup_mode_an(priv, port, interface);
	case PHY_INTERFACE_MODE_NA:
	case PHY_INTERFACE_MODE_1000BASEX:
	case PHY_INTERFACE_MODE_2500BASEX:
		return mt7531_sgmii_setup_mode_force(priv, port, interface);
		/* handled in SGMII PCS driver */
		return 0;
	default:
		return -EINVAL;
	}
@@ -2745,11 +2629,11 @@ mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,

	switch (interface) {
	case PHY_INTERFACE_MODE_TRGMII:
		return &priv->pcs[port].pcs;
	case PHY_INTERFACE_MODE_SGMII:
	case PHY_INTERFACE_MODE_1000BASEX:
	case PHY_INTERFACE_MODE_2500BASEX:
		return &priv->pcs[port].pcs;

		return priv->ports[port].sgmii_pcs;
	default:
		return NULL;
	}
@@ -2987,86 +2871,6 @@ static void mt7530_pcs_get_state(struct phylink_pcs *pcs,
		state->pause |= MLO_PAUSE_TX;
}

static int
mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port,
			      struct phylink_link_state *state)
{
	u32 status, val;
	u16 config_reg;

	status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
	state->link = !!(status & MT7531_SGMII_LINK_STATUS);
	state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE);
	if (state->interface == PHY_INTERFACE_MODE_SGMII &&
	    (status & MT7531_SGMII_AN_ENABLE)) {
		val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
		config_reg = val >> 16;

		switch (config_reg & LPA_SGMII_SPD_MASK) {
		case LPA_SGMII_1000:
			state->speed = SPEED_1000;
			break;
		case LPA_SGMII_100:
			state->speed = SPEED_100;
			break;
		case LPA_SGMII_10:
			state->speed = SPEED_10;
			break;
		default:
			dev_err(priv->dev, "invalid sgmii PHY speed\n");
			state->link = false;
			return -EINVAL;
		}

		if (config_reg & LPA_SGMII_FULL_DUPLEX)
			state->duplex = DUPLEX_FULL;
		else
			state->duplex = DUPLEX_HALF;
	}

	return 0;
}

static void
mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port,
				  struct phylink_link_state *state)
{
	unsigned int val;

	val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
	state->link = !!(val & MT7531_SGMII_LINK_STATUS);
	if (!state->link)
		return;

	state->an_complete = state->link;

	if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
		state->speed = SPEED_2500;
	else
		state->speed = SPEED_1000;

	state->duplex = DUPLEX_FULL;
	state->pause = MLO_PAUSE_NONE;
}

static void mt7531_pcs_get_state(struct phylink_pcs *pcs,
				 struct phylink_link_state *state)
{
	struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
	int port = pcs_to_mt753x_pcs(pcs)->port;

	if (state->interface == PHY_INTERFACE_MODE_SGMII) {
		mt7531_sgmii_pcs_get_state_an(priv, port, state);
		return;
	} else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) ||
		   (state->interface == PHY_INTERFACE_MODE_2500BASEX)) {
		mt7531_sgmii_pcs_get_state_inband(priv, port, state);
		return;
	}

	state->link = false;
}

static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
			     phy_interface_t interface,
			     const unsigned long *advertising,
@@ -3086,18 +2890,57 @@ static const struct phylink_pcs_ops mt7530_pcs_ops = {
	.pcs_an_restart = mt7530_pcs_an_restart,
};

static const struct phylink_pcs_ops mt7531_pcs_ops = {
	.pcs_validate = mt753x_pcs_validate,
	.pcs_get_state = mt7531_pcs_get_state,
	.pcs_config = mt753x_pcs_config,
	.pcs_an_restart = mt7531_pcs_an_restart,
	.pcs_link_up = mt7531_pcs_link_up,
static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
{
	struct mt7530_priv *priv = context;

	*val = mt7530_read(priv, reg);
	return 0;
};

static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
{
	struct mt7530_priv *priv = context;

	mt7530_write(priv, reg, val);
	return 0;
};

static int mt7530_regmap_update_bits(void *context, unsigned int reg,
				     unsigned int mask, unsigned int val)
{
	struct mt7530_priv *priv = context;

	mt7530_rmw(priv, reg, mask, val);
	return 0;
};

static const struct regmap_bus mt7531_regmap_bus = {
	.reg_write = mt7530_regmap_write,
	.reg_read = mt7530_regmap_read,
	.reg_update_bits = mt7530_regmap_update_bits,
};

#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \
	{				\
		.name = _name,		\
		.reg_bits = 16,		\
		.val_bits = 32,		\
		.reg_stride = 4,	\
		.reg_base = _reg_base,	\
		.max_register = 0x17c,	\
	}

static const struct regmap_config mt7531_pcs_config[] = {
	MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)),
	MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)),
};

static int
mt753x_setup(struct dsa_switch *ds)
{
	struct mt7530_priv *priv = ds->priv;
	struct regmap *regmap;
	int i, ret;

	/* Initialise the PCS devices */
@@ -3105,8 +2948,6 @@ mt753x_setup(struct dsa_switch *ds)
		priv->pcs[i].pcs.ops = priv->info->pcs_ops;
		priv->pcs[i].priv = priv;
		priv->pcs[i].port = i;
		if (mt753x_is_mac_port(i))
			priv->pcs[i].pcs.poll = 1;
	}

	ret = priv->info->sw_setup(ds);
@@ -3121,6 +2962,16 @@ mt753x_setup(struct dsa_switch *ds)
	if (ret && priv->irq)
		mt7530_free_irq_common(priv);

	if (priv->id == ID_MT7531)
		for (i = 0; i < 2; i++) {
			regmap = devm_regmap_init(ds->dev,
						  &mt7531_regmap_bus, priv,
						  &mt7531_pcs_config[i]);
			priv->ports[5 + i].sgmii_pcs =
				mtk_pcs_lynxi_create(ds->dev, regmap,
						     MT7531_PHYA_CTRL_SIGNAL3, 0);
		}

	return ret;
}

@@ -3216,7 +3067,7 @@ static const struct mt753x_info mt753x_table[] = {
	},
	[ID_MT7531] = {
		.id = ID_MT7531,
		.pcs_ops = &mt7531_pcs_ops,
		.pcs_ops = &mt7530_pcs_ops,
		.sw_setup = mt7531_setup,
		.phy_read_c22 = mt7531_ind_c22_phy_read,
		.phy_write_c22 = mt7531_ind_c22_phy_write,
@@ -3326,7 +3177,7 @@ static void
mt7530_remove(struct mdio_device *mdiodev)
{
	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
	int ret = 0;
	int ret = 0, i;

	if (!priv)
		return;
@@ -3345,6 +3196,10 @@ mt7530_remove(struct mdio_device *mdiodev)
		mt7530_free_irq(priv);

	dsa_unregister_switch(priv->ds);

	for (i = 0; i < 2; ++i)
		mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);

	mutex_destroy(&priv->reg_mutex);
}

+4 −43
Original line number Diff line number Diff line
@@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm {
					 CCR_TX_OCT_CNT_BAD)

/* MT7531 SGMII register group */
#define MT7531_SGMII_REG_BASE		0x5000
#define MT7531_SGMII_REG(p, r)		(MT7531_SGMII_REG_BASE + \
					((p) - 5) * 0x1000 + (r))

/* Register forSGMII PCS_CONTROL_1 */
#define MT7531_PCS_CONTROL_1(p)		MT7531_SGMII_REG(p, 0x00)
#define  MT7531_SGMII_LINK_STATUS	BIT(18)
#define  MT7531_SGMII_AN_ENABLE		BIT(12)
#define  MT7531_SGMII_AN_RESTART	BIT(9)
#define  MT7531_SGMII_AN_COMPLETE	BIT(21)

/* Register for SGMII PCS_SPPED_ABILITY */
#define MT7531_PCS_SPEED_ABILITY(p)	MT7531_SGMII_REG(p, 0x08)
#define  MT7531_SGMII_TX_CONFIG_MASK	GENMASK(15, 0)
#define  MT7531_SGMII_TX_CONFIG		BIT(0)

/* Register for SGMII_MODE */
#define MT7531_SGMII_MODE(p)		MT7531_SGMII_REG(p, 0x20)
#define  MT7531_SGMII_REMOTE_FAULT_DIS	BIT(8)
#define  MT7531_SGMII_IF_MODE_MASK	GENMASK(5, 1)
#define  MT7531_SGMII_FORCE_DUPLEX	BIT(4)
#define  MT7531_SGMII_FORCE_SPEED_MASK	GENMASK(3, 2)
#define  MT7531_SGMII_FORCE_SPEED_1000	BIT(3)
#define  MT7531_SGMII_FORCE_SPEED_100	BIT(2)
#define  MT7531_SGMII_FORCE_SPEED_10	0
#define  MT7531_SGMII_SPEED_DUPLEX_AN	BIT(1)

enum mt7531_sgmii_force_duplex {
	MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
	MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
};

/* Fields of QPHY_PWR_STATE_CTRL */
#define MT7531_QPHY_PWR_STATE_CTRL(p)	MT7531_SGMII_REG(p, 0xe8)
#define  MT7531_SGMII_PHYA_PWD		BIT(4)

/* Values of SGMII SPEED */
#define MT7531_PHYA_CTRL_SIGNAL3(p)	MT7531_SGMII_REG(p, 0x128)
#define  MT7531_RG_TPHY_SPEED_MASK	(BIT(2) | BIT(3))
#define  MT7531_RG_TPHY_SPEED_1_25G	0x0
#define  MT7531_RG_TPHY_SPEED_3_125G	BIT(2)
#define MT7531_SGMII_REG_BASE(p)	(0x5000 + ((p) - 5) * 0x1000)
#define MT7531_PHYA_CTRL_SIGNAL3	0x128

/* Register for system reset */
#define MT7530_SYS_CTRL			0x7000
@@ -703,13 +664,13 @@ struct mt7530_fdb {
 * @pm:		The matrix used to show all connections with the port.
 * @pvid:	The VLAN specified is to be considered a PVID at ingress.  Any
 *		untagged frames will be assigned to the related VLAN.
 * @vlan_filtering: The flags indicating whether the port that can recognize
 *		    VLAN-tagged frames.
 * @sgmii_pcs:	Pointer to PCS instance for SerDes ports
 */
struct mt7530_port {
	bool enable;
	u32 pm;
	u16 pvid;
	struct phylink_pcs *sgmii_pcs;
};

/* Port 5 interface select definitions */