Commit e3d8178c authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'part-2-of-sja1105-dsa-driver-preparation-for-new-switch-introduction-sja1110'

Vladimir Oltean says:

====================
Part 2 of SJA1105 DSA driver preparation for new switch introduction (SJA1110)

This series is a continuation of:
https://patchwork.kernel.org/project/netdevbpf/cover/20210524131421.1030789-1-olteanv@gmail.com/

even though it isn't the first time these patches are submitted (they
were part of the group previously called "Add NXP SJA1110 support to the
sja1105 DSA driver"):
https://patchwork.kernel.org/project/netdevbpf/cover/20210526135535.2515123-1-vladimir.oltean@nxp.com/

but I broke that up again since these patches are already reviewed, for
the most part. There are no changes compared to v2 and v1.

This series of patches contains:

- an adaptation of the driver to the new "ethernet-ports" OF node name
- an adaptation of the driver to support more than 1 SGMII port
- a generalization of the supported phy_interface_t values per port
- an adaptation to encode SPEED_10, SPEED_100, SPEED_1000 into the
  hardware registers differently depending on switch revision
- a consolidation of the PHY interface type used for RGMII and another
  one for the API exposed for sja1105_dynamic_config_read()
====================

Link: https://lore.kernel.org/r/20210530225939.772553-1-olteanv@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 44fdd2ed 96c85f51
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ struct sja1105_regs {
	u64 rgu;
	u64 vl_status;
	u64 config;
	u64 sgmii;
	u64 rmii_pll1;
	u64 ptppinst;
	u64 ptppindur;
@@ -73,6 +72,15 @@ struct sja1105_regs {
	u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
};

enum {
	SJA1105_SPEED_AUTO,
	SJA1105_SPEED_10MBPS,
	SJA1105_SPEED_100MBPS,
	SJA1105_SPEED_1000MBPS,
	SJA1105_SPEED_2500MBPS,
	SJA1105_SPEED_MAX,
};

struct sja1105_info {
	u64 device_id;
	/* Needed for distinction between P and R, and between Q and S
@@ -112,6 +120,12 @@ struct sja1105_info {
				enum packing_op op);
	int (*clocking_setup)(struct sja1105_private *priv);
	const char *name;
	bool supports_mii[SJA1105_MAX_NUM_PORTS];
	bool supports_rmii[SJA1105_MAX_NUM_PORTS];
	bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
	bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
	bool supports_2500basex[SJA1105_MAX_NUM_PORTS];
	const u64 port_speed[SJA1105_SPEED_MAX];
};

enum sja1105_key_type {
@@ -211,6 +225,7 @@ struct sja1105_private {
	struct sja1105_static_config static_config;
	bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
	bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
	phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
	bool best_effort_vlan_filtering;
	unsigned long learn_ena;
	unsigned long ucast_egress_floods;
@@ -309,13 +324,6 @@ typedef enum {
	XMII_MODE_SGMII		= 3,
} sja1105_phy_interface_t;

typedef enum {
	SJA1105_SPEED_10MBPS	= 3,
	SJA1105_SPEED_100MBPS	= 2,
	SJA1105_SPEED_1000MBPS	= 1,
	SJA1105_SPEED_AUTO	= 0,
} sja1105_speed_t;

int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);
+10 −19
Original line number Diff line number Diff line
@@ -328,7 +328,7 @@ sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
}

static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
					   int port, sja1105_speed_t speed)
					   int port, u64 speed)
{
	const struct sja1105_regs *regs = priv->info->regs;
	struct sja1105_cgu_mii_ctrl txc;
@@ -338,7 +338,7 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
	if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR)
		return 0;

	if (speed == SJA1105_SPEED_1000MBPS) {
	if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
		clksrc = CLKSRC_PLL0;
	} else {
		int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
@@ -524,35 +524,31 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
{
	struct device *dev = priv->ds->dev;
	struct sja1105_mac_config_entry *mac;
	sja1105_speed_t speed;
	u64 speed;
	int rc;

	mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
	speed = mac[port].speed;

	dev_dbg(dev, "Configuring port %d RGMII at speed %dMbps\n",
	dev_dbg(dev, "Configuring port %d RGMII at speed %lldMbps\n",
		port, speed);

	switch (speed) {
	case SJA1105_SPEED_1000MBPS:
	if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
		/* 1000Mbps, IDIV disabled (125 MHz) */
		rc = sja1105_cgu_idiv_config(priv, port, false, 1);
		break;
	case SJA1105_SPEED_100MBPS:
	} else if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) {
		/* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
		rc = sja1105_cgu_idiv_config(priv, port, true, 1);
		break;
	case SJA1105_SPEED_10MBPS:
	} else if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) {
		/* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
		rc = sja1105_cgu_idiv_config(priv, port, true, 10);
		break;
	case SJA1105_SPEED_AUTO:
	} else if (speed == priv->info->port_speed[SJA1105_SPEED_AUTO]) {
		/* Skip CGU configuration if there is no speed available
		 * (e.g. link is not established yet)
		 */
		dev_dbg(dev, "Speed not available, skipping CGU config\n");
		return 0;
	default:
	} else {
		rc = -EINVAL;
	}

@@ -570,14 +566,9 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
		dev_err(dev, "Failed to configure Tx pad registers\n");
		return rc;
	}

	if (!priv->info->setup_rgmii_delay)
		return 0;
	/* The role has no hardware effect for RGMII. However we use it as
	 * a proxy for this interface being a MAC-to-MAC connection, with
	 * the RGMII internal delays needing to be applied by us.
	 */
	if (role == XMII_MAC)
		return 0;

	return priv->info->setup_rgmii_delay(priv, port);
}
+8 −7
Original line number Diff line number Diff line
@@ -78,6 +78,9 @@
 *		   on its ENTRY portion, as a result of a SPI write command.
 *		   Only the TCAM-based FDB table on SJA1105 P/Q/R/S supports
 *		   this.
 *	OP_VALID_ANYWAY: Reading some tables through the dynamic config
 *			 interface is possible even if the VALIDENT bit is not
 *			 set in the writeback. So don't error out in that case.
 * - .max_entry_count: The number of entries, counting from zero, that can be
 *		       reconfigured through the dynamic interface. If a static
 *		       table can be reconfigured at all dynamically, this
@@ -651,6 +654,7 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
#define OP_WRITE	BIT(1)
#define OP_DEL		BIT(2)
#define OP_SEARCH	BIT(3)
#define OP_VALID_ANYWAY	BIT(4)

/* SJA1105E/T: First generation */
const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
@@ -673,7 +677,7 @@ const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_MGMT_ROUTE] = {
		.entry_packing = sja1105et_mgmt_route_entry_packing,
		.cmd_packing = sja1105et_mgmt_route_cmd_packing,
		.access = (OP_READ | OP_WRITE),
		.access = (OP_READ | OP_WRITE | OP_VALID_ANYWAY),
		.max_entry_count = SJA1105_NUM_PORTS,
		.packed_size = SJA1105ET_SIZE_L2_LOOKUP_DYN_CMD,
		.addr = 0x20,
@@ -757,7 +761,7 @@ const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_MGMT_ROUTE] = {
		.entry_packing = sja1105pqrs_mgmt_route_entry_packing,
		.cmd_packing = sja1105pqrs_mgmt_route_cmd_packing,
		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH),
		.access = (OP_READ | OP_WRITE | OP_DEL | OP_SEARCH | OP_VALID_ANYWAY),
		.max_entry_count = SJA1105_NUM_PORTS,
		.packed_size = SJA1105PQRS_SIZE_L2_LOOKUP_DYN_CMD,
		.addr = 0x24,
@@ -911,11 +915,8 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv,

		cmd = (struct sja1105_dyn_cmd) {0};
		ops->cmd_packing(packed_buf, &cmd, UNPACK);
		/* UM10944: [valident] will always be found cleared
		 * during a read access with MGMTROUTE set.
		 * So don't error out in that case.
		 */
		if (!cmd.valident && blk_idx != BLK_IDX_MGMT_ROUTE)

		if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY))
			return -ENOENT;
		cpu_relax();
	} while (cmd.valid && --retries);
+110 −97
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
		/* Always put the MAC speed in automatic mode, where it can be
		 * adjusted at runtime by PHYLINK.
		 */
		.speed = SJA1105_SPEED_AUTO,
		.speed = priv->info->port_speed[SJA1105_SPEED_AUTO],
		/* No static correction for 1-step 1588 events */
		.tp_delin = 0,
		.tp_delout = 0,
@@ -143,21 +143,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
	return 0;
}

static bool sja1105_supports_sgmii(struct sja1105_private *priv, int port)
{
	if (priv->info->part_no != SJA1105R_PART_NO &&
	    priv->info->part_no != SJA1105S_PART_NO)
		return false;

	if (port != SJA1105_SGMII_PORT)
		return false;

	if (dsa_is_unused_port(priv->ds, port))
		return false;

	return true;
}

static int sja1105_init_mii_settings(struct sja1105_private *priv,
				     struct sja1105_dt_port *ports)
{
@@ -191,33 +176,56 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,

		switch (ports[i].phy_mode) {
		case PHY_INTERFACE_MODE_MII:
			if (!priv->info->supports_mii[i])
				goto unsupported;

			mii->xmii_mode[i] = XMII_MODE_MII;
			break;
		case PHY_INTERFACE_MODE_RMII:
			if (!priv->info->supports_rmii[i])
				goto unsupported;

			mii->xmii_mode[i] = XMII_MODE_RMII;
			break;
		case PHY_INTERFACE_MODE_RGMII:
		case PHY_INTERFACE_MODE_RGMII_ID:
		case PHY_INTERFACE_MODE_RGMII_RXID:
		case PHY_INTERFACE_MODE_RGMII_TXID:
			if (!priv->info->supports_rgmii[i])
				goto unsupported;

			mii->xmii_mode[i] = XMII_MODE_RGMII;
			break;
		case PHY_INTERFACE_MODE_SGMII:
			if (!sja1105_supports_sgmii(priv, i))
				return -EINVAL;
			if (!priv->info->supports_sgmii[i])
				goto unsupported;

			mii->xmii_mode[i] = XMII_MODE_SGMII;
			break;
		case PHY_INTERFACE_MODE_2500BASEX:
			if (!priv->info->supports_2500basex[i])
				goto unsupported;

			mii->xmii_mode[i] = XMII_MODE_SGMII;
			break;
unsupported:
		default:
			dev_err(dev, "Unsupported PHY mode %s!\n",
				phy_modes(ports[i].phy_mode));
			dev_err(dev, "Unsupported PHY mode %s on port %d!\n",
				phy_modes(ports[i].phy_mode), i);
			return -EINVAL;
		}

		/* Even though the SerDes port is able to drive SGMII autoneg
		 * like a PHY would, from the perspective of the XMII tables,
		 * the SGMII port should always be put in MAC mode.
		 */
		if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII)
		 * Similarly, RGMII is a symmetric protocol electrically
		 * speaking, and the 'RGMII PHY' role does not mean anything to
		 * hardware. Just keep the 'PHY role' notation relevant to the
		 * driver to mean 'the switch port should apply RGMII delays',
		 * but unconditionally put the port in the MAC role.
		 */
		if (ports[i].phy_mode == PHY_INTERFACE_MODE_SGMII ||
		    phy_interface_mode_is_rgmii(ports[i].phy_mode))
			mii->phy_mac[i] = XMII_MAC;
		else
			mii->phy_mac[i] = ports[i].role;
@@ -871,6 +879,8 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
			ports[index].role = XMII_MAC;
		else if (of_property_read_bool(child, "sja1105,role-phy"))
			ports[index].role = XMII_PHY;

		priv->phy_mode[index] = phy_mode;
	}

	return 0;
@@ -885,6 +895,8 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
	int rc;

	ports_node = of_get_child_by_name(switch_node, "ports");
	if (!ports_node)
		ports_node = of_get_child_by_name(switch_node, "ethernet-ports");
	if (!ports_node) {
		dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
		return -ENODEV;
@@ -896,36 +908,41 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
	return rc;
}

static int sja1105_sgmii_read(struct sja1105_private *priv, int pcs_reg)
static int sja1105_sgmii_read(struct sja1105_private *priv, int port, int mmd,
			      int pcs_reg)
{
	const struct sja1105_regs *regs = priv->info->regs;
	u64 addr = (mmd << 16) | pcs_reg;
	u32 val;
	int rc;

	rc = sja1105_xfer_u32(priv, SPI_READ, regs->sgmii + pcs_reg, &val,
			      NULL);
	if (port != SJA1105_SGMII_PORT)
		return -ENODEV;

	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &val, NULL);
	if (rc < 0)
		return rc;

	return val;
}

static int sja1105_sgmii_write(struct sja1105_private *priv, int pcs_reg,
			       u16 pcs_val)
static int sja1105_sgmii_write(struct sja1105_private *priv, int port, int mmd,
			       int pcs_reg, u16 pcs_val)
{
	const struct sja1105_regs *regs = priv->info->regs;
	u64 addr = (mmd << 16) | pcs_reg;
	u32 val = pcs_val;
	int rc;

	rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->sgmii + pcs_reg, &val,
			      NULL);
	if (port != SJA1105_SGMII_PORT)
		return -ENODEV;

	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &val, NULL);
	if (rc < 0)
		return rc;

	return val;
}

static void sja1105_sgmii_pcs_config(struct sja1105_private *priv,
static void sja1105_sgmii_pcs_config(struct sja1105_private *priv, int port,
				     bool an_enabled, bool an_master)
{
	u16 ac = SJA1105_AC_AUTONEG_MODE_SGMII;
@@ -934,27 +951,29 @@ static void sja1105_sgmii_pcs_config(struct sja1105_private *priv,
	 * stop the clock during LPI mode, make the MAC reconfigure
	 * autonomously after PCS autoneg is done, flush the internal FIFOs.
	 */
	sja1105_sgmii_write(priv, SJA1105_DC1, SJA1105_DC1_EN_VSMMD1 |
	sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_DC1,
			    SJA1105_DC1_EN_VSMMD1 |
			    SJA1105_DC1_CLOCK_STOP_EN |
			    SJA1105_DC1_MAC_AUTO_SW |
			    SJA1105_DC1_INIT);
	/* DIGITAL_CONTROL_2: No polarity inversion for TX and RX lanes */
	sja1105_sgmii_write(priv, SJA1105_DC2, SJA1105_DC2_TX_POL_INV_DISABLE);
	sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_DC2,
			    SJA1105_DC2_TX_POL_INV_DISABLE);
	/* AUTONEG_CONTROL: Use SGMII autoneg */
	if (an_master)
		ac |= SJA1105_AC_PHY_MODE | SJA1105_AC_SGMII_LINK;
	sja1105_sgmii_write(priv, SJA1105_AC, ac);
	sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, SJA1105_AC, ac);
	/* BASIC_CONTROL: enable in-band AN now, if requested. Otherwise,
	 * sja1105_sgmii_pcs_force_speed must be called later for the link
	 * to become operational.
	 */
	if (an_enabled)
		sja1105_sgmii_write(priv, MII_BMCR,
		sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
				    BMCR_ANENABLE | BMCR_ANRESTART);
}

static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv,
					  int speed)
					  int port, int speed)
{
	int pcs_speed;

@@ -972,26 +991,32 @@ static void sja1105_sgmii_pcs_force_speed(struct sja1105_private *priv,
		dev_err(priv->ds->dev, "Invalid speed %d\n", speed);
		return;
	}
	sja1105_sgmii_write(priv, MII_BMCR, pcs_speed | BMCR_FULLDPLX);
	sja1105_sgmii_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
			    pcs_speed | BMCR_FULLDPLX);
}

/* Convert link speed from SJA1105 to ethtool encoding */
static int sja1105_speed[] = {
	[SJA1105_SPEED_AUTO]		= SPEED_UNKNOWN,
	[SJA1105_SPEED_10MBPS]		= SPEED_10,
	[SJA1105_SPEED_100MBPS]		= SPEED_100,
	[SJA1105_SPEED_1000MBPS]	= SPEED_1000,
};
static int sja1105_port_speed_to_ethtool(struct sja1105_private *priv,
					 u64 speed)
{
	if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS])
		return SPEED_10;
	if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS])
		return SPEED_100;
	if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS])
		return SPEED_1000;
	if (speed == priv->info->port_speed[SJA1105_SPEED_2500MBPS])
		return SPEED_2500;
	return SPEED_UNKNOWN;
}

/* Set link speed in the MAC configuration for a specific port. */
static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
				      int speed_mbps)
{
	struct sja1105_xmii_params_entry *mii;
	struct sja1105_mac_config_entry *mac;
	struct device *dev = priv->ds->dev;
	sja1105_phy_interface_t phy_mode;
	sja1105_speed_t speed;
	u64 speed;
	int rc;

	/* On P/Q/R/S, one can read from the device via the MAC reconfiguration
@@ -1001,7 +1026,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
	 * reasonable approximation for both E/T and P/Q/R/S.
	 */
	mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
	mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;

	switch (speed_mbps) {
	case SPEED_UNKNOWN:
@@ -1012,16 +1036,16 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
		 * ok for power consumption in case AN will never complete -
		 * otherwise PHYLINK should come back with a new update.
		 */
		speed = SJA1105_SPEED_AUTO;
		speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
		break;
	case SPEED_10:
		speed = SJA1105_SPEED_10MBPS;
		speed = priv->info->port_speed[SJA1105_SPEED_10MBPS];
		break;
	case SPEED_100:
		speed = SJA1105_SPEED_100MBPS;
		speed = priv->info->port_speed[SJA1105_SPEED_100MBPS];
		break;
	case SPEED_1000:
		speed = SJA1105_SPEED_1000MBPS;
		speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
		break;
	default:
		dev_err(dev, "Invalid speed %iMbps\n", speed_mbps);
@@ -1035,8 +1059,8 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
	 * Actually for the SGMII port, the MAC is fixed at 1 Gbps and
	 * we need to configure the PCS only (if even that).
	 */
	if (sja1105_supports_sgmii(priv, port))
		mac[port].speed = SJA1105_SPEED_1000MBPS;
	if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII)
		mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
	else
		mac[port].speed = speed;

@@ -1054,8 +1078,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
	 * the clock setup does interrupt the clock signal for a certain time
	 * which causes trouble for all PHYs relying on this signal.
	 */
	phy_mode = mii->xmii_mode[port];
	if (phy_mode != XMII_MODE_RGMII)
	if (!phy_interface_mode_is_rgmii(priv->phy_mode[port]))
		return 0;

	return sja1105_clocking_setup_port(priv, port);
@@ -1071,27 +1094,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
static bool sja1105_phy_mode_mismatch(struct sja1105_private *priv, int port,
				      phy_interface_t interface)
{
	struct sja1105_xmii_params_entry *mii;
	sja1105_phy_interface_t phy_mode;

	mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
	phy_mode = mii->xmii_mode[port];

	switch (interface) {
	case PHY_INTERFACE_MODE_MII:
		return (phy_mode != XMII_MODE_MII);
	case PHY_INTERFACE_MODE_RMII:
		return (phy_mode != XMII_MODE_RMII);
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
	case PHY_INTERFACE_MODE_RGMII_TXID:
		return (phy_mode != XMII_MODE_RGMII);
	case PHY_INTERFACE_MODE_SGMII:
		return (phy_mode != XMII_MODE_SGMII);
	default:
		return true;
	}
	return priv->phy_mode[port] != interface;
}

static void sja1105_mac_config(struct dsa_switch *ds, int port,
@@ -1099,7 +1102,9 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
			       const struct phylink_link_state *state)
{
	struct sja1105_private *priv = ds->priv;
	bool is_sgmii = sja1105_supports_sgmii(priv, port);
	bool is_sgmii;

	is_sgmii = (state->interface == PHY_INTERFACE_MODE_SGMII);

	if (sja1105_phy_mode_mismatch(priv, port, state->interface)) {
		dev_err(ds->dev, "Changing PHY mode to %s not supported!\n",
@@ -1113,7 +1118,8 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
	}

	if (is_sgmii)
		sja1105_sgmii_pcs_config(priv, phylink_autoneg_inband(mode),
		sja1105_sgmii_pcs_config(priv, port,
					 phylink_autoneg_inband(mode),
					 false);
}

@@ -1135,8 +1141,9 @@ static void sja1105_mac_link_up(struct dsa_switch *ds, int port,

	sja1105_adjust_port_config(priv, port, speed);

	if (sja1105_supports_sgmii(priv, port) && !phylink_autoneg_inband(mode))
		sja1105_sgmii_pcs_force_speed(priv, speed);
	if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII &&
	    !phylink_autoneg_inband(mode))
		sja1105_sgmii_pcs_force_speed(priv, port, speed);

	sja1105_inhibit_tx(priv, BIT(port), false);
}
@@ -1189,7 +1196,7 @@ static int sja1105_mac_pcs_get_state(struct dsa_switch *ds, int port,
	int ais;

	/* Read the vendor-specific AUTONEG_INTR_STATUS register */
	ais = sja1105_sgmii_read(priv, SJA1105_AIS);
	ais = sja1105_sgmii_read(priv, port, MDIO_MMD_VEND2, SJA1105_AIS);
	if (ais < 0)
		return ais;

@@ -1871,11 +1878,11 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
	struct ptp_system_timestamp ptp_sts_before;
	struct ptp_system_timestamp ptp_sts_after;
	int speed_mbps[SJA1105_MAX_NUM_PORTS];
	u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0};
	struct sja1105_mac_config_entry *mac;
	struct dsa_switch *ds = priv->ds;
	s64 t1, t2, t3, t4;
	s64 t12, t34;
	u16 bmcr = 0;
	int rc, i;
	s64 now;

@@ -1889,12 +1896,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
	 * change it through the dynamic interface later.
	 */
	for (i = 0; i < ds->num_ports; i++) {
		speed_mbps[i] = sja1105_speed[mac[i].speed];
		mac[i].speed = SJA1105_SPEED_AUTO;
	}
		speed_mbps[i] = sja1105_port_speed_to_ethtool(priv,
							      mac[i].speed);
		mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];

	if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT))
		bmcr = sja1105_sgmii_read(priv, MII_BMCR);
		if (priv->phy_mode[i] == PHY_INTERFACE_MODE_SGMII)
			bmcr[i] = sja1105_sgmii_read(priv, i,
						     MDIO_MMD_VEND2,
						     MDIO_CTRL1);
	}

	/* No PTP operations can run right now */
	mutex_lock(&priv->ptp_data.lock);
@@ -1941,27 +1951,30 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
		goto out;

	for (i = 0; i < ds->num_ports; i++) {
		bool an_enabled;

		rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
		if (rc < 0)
			goto out;
	}

	if (sja1105_supports_sgmii(priv, SJA1105_SGMII_PORT)) {
		bool an_enabled = !!(bmcr & BMCR_ANENABLE);
		if (priv->phy_mode[i] != PHY_INTERFACE_MODE_SGMII)
			continue;

		an_enabled = !!(bmcr[i] & BMCR_ANENABLE);

		sja1105_sgmii_pcs_config(priv, an_enabled, false);
		sja1105_sgmii_pcs_config(priv, i, an_enabled, false);

		if (!an_enabled) {
			int speed = SPEED_UNKNOWN;

			if (bmcr & BMCR_SPEED1000)
			if (bmcr[i] & BMCR_SPEED1000)
				speed = SPEED_1000;
			else if (bmcr & BMCR_SPEED100)
			else if (bmcr[i] & BMCR_SPEED100)
				speed = SPEED_100;
			else
				speed = SPEED_10;

			sja1105_sgmii_pcs_force_speed(priv, speed);
			sja1105_sgmii_pcs_force_speed(priv, i, speed);
		}
	}

+62 −1
Original line number Diff line number Diff line
@@ -440,7 +440,6 @@ static struct sja1105_regs sja1105pqrs_regs = {
	.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
	.pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
	.pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
	.sgmii = 0x1F0000,
	.rmii_pll1 = 0x10000A,
	.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
	.stats[MAC] = {0x200, 0x202, 0x204, 0x206, 0x208},
@@ -483,6 +482,16 @@ const struct sja1105_info sja1105e_info = {
	.ptp_cmd_packing	= sja1105et_ptp_cmd_packing,
	.clocking_setup		= sja1105_clocking_setup,
	.regs			= &sja1105et_regs,
	.port_speed		= {
		[SJA1105_SPEED_AUTO] = 0,
		[SJA1105_SPEED_10MBPS] = 3,
		[SJA1105_SPEED_100MBPS] = 2,
		[SJA1105_SPEED_1000MBPS] = 1,
		[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
	},
	.supports_mii		= {true, true, true, true, true},
	.supports_rmii		= {true, true, true, true, true},
	.supports_rgmii		= {true, true, true, true, true},
	.name			= "SJA1105E",
};

@@ -503,6 +512,16 @@ const struct sja1105_info sja1105t_info = {
	.ptp_cmd_packing	= sja1105et_ptp_cmd_packing,
	.clocking_setup		= sja1105_clocking_setup,
	.regs			= &sja1105et_regs,
	.port_speed		= {
		[SJA1105_SPEED_AUTO] = 0,
		[SJA1105_SPEED_10MBPS] = 3,
		[SJA1105_SPEED_100MBPS] = 2,
		[SJA1105_SPEED_1000MBPS] = 1,
		[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
	},
	.supports_mii		= {true, true, true, true, true},
	.supports_rmii		= {true, true, true, true, true},
	.supports_rgmii		= {true, true, true, true, true},
	.name			= "SJA1105T",
};

@@ -524,6 +543,16 @@ const struct sja1105_info sja1105p_info = {
	.ptp_cmd_packing	= sja1105pqrs_ptp_cmd_packing,
	.clocking_setup		= sja1105_clocking_setup,
	.regs			= &sja1105pqrs_regs,
	.port_speed		= {
		[SJA1105_SPEED_AUTO] = 0,
		[SJA1105_SPEED_10MBPS] = 3,
		[SJA1105_SPEED_100MBPS] = 2,
		[SJA1105_SPEED_1000MBPS] = 1,
		[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
	},
	.supports_mii		= {true, true, true, true, true},
	.supports_rmii		= {true, true, true, true, true},
	.supports_rgmii		= {true, true, true, true, true},
	.name			= "SJA1105P",
};

@@ -545,6 +574,16 @@ const struct sja1105_info sja1105q_info = {
	.ptp_cmd_packing	= sja1105pqrs_ptp_cmd_packing,
	.clocking_setup		= sja1105_clocking_setup,
	.regs			= &sja1105pqrs_regs,
	.port_speed		= {
		[SJA1105_SPEED_AUTO] = 0,
		[SJA1105_SPEED_10MBPS] = 3,
		[SJA1105_SPEED_100MBPS] = 2,
		[SJA1105_SPEED_1000MBPS] = 1,
		[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
	},
	.supports_mii		= {true, true, true, true, true},
	.supports_rmii		= {true, true, true, true, true},
	.supports_rgmii		= {true, true, true, true, true},
	.name			= "SJA1105Q",
};

@@ -566,6 +605,17 @@ const struct sja1105_info sja1105r_info = {
	.ptp_cmd_packing	= sja1105pqrs_ptp_cmd_packing,
	.clocking_setup		= sja1105_clocking_setup,
	.regs			= &sja1105pqrs_regs,
	.port_speed		= {
		[SJA1105_SPEED_AUTO] = 0,
		[SJA1105_SPEED_10MBPS] = 3,
		[SJA1105_SPEED_100MBPS] = 2,
		[SJA1105_SPEED_1000MBPS] = 1,
		[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
	},
	.supports_mii		= {true, true, true, true, true},
	.supports_rmii		= {true, true, true, true, true},
	.supports_rgmii		= {true, true, true, true, true},
	.supports_sgmii		= {false, false, false, false, true},
	.name			= "SJA1105R",
};

@@ -587,5 +637,16 @@ const struct sja1105_info sja1105s_info = {
	.fdb_del_cmd		= sja1105pqrs_fdb_del,
	.ptp_cmd_packing	= sja1105pqrs_ptp_cmd_packing,
	.clocking_setup		= sja1105_clocking_setup,
	.port_speed		= {
		[SJA1105_SPEED_AUTO] = 0,
		[SJA1105_SPEED_10MBPS] = 3,
		[SJA1105_SPEED_100MBPS] = 2,
		[SJA1105_SPEED_1000MBPS] = 1,
		[SJA1105_SPEED_2500MBPS] = 0, /* Not supported */
	},
	.supports_mii		= {true, true, true, true, true},
	.supports_rmii		= {true, true, true, true, true},
	.supports_rgmii		= {true, true, true, true, true},
	.supports_sgmii		= {false, false, false, false, true},
	.name			= "SJA1105S",
};