public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next] net: dsa: realtek: rtl8366rb: Configure ports properly
@ 2022-07-25 20:29 Linus Walleij
  2022-07-26 11:02 ` Vladimir Oltean
  0 siblings, 1 reply; 4+ messages in thread
From: Linus Walleij @ 2022-07-25 20:29 UTC (permalink / raw)
  To: Andrew Lunn, Vivien Didelot, Florian Fainelli, Vladimir Oltean,
	David S . Miller, Jakub Kicinski
  Cc: netdev, Linus Walleij, Alvin Šipraga

Instead of just hammering the CPU port up at 1GBit at
.phylink_mac_link_up calls for that specific port, support
configuring any port: this works like a charm.

Drop the code to enable/disable the port in the
.phylink_mac_link_up/.phylink_mac_link_down callbacks:
this is handled perfectly well by the callbacks to
.port_enable/.port_disable.

Tested on the D-Link DIR-685.

Cc: Alvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/net/dsa/realtek/rtl8366rb.c | 155 ++++++++++++++++++++--------
 1 file changed, 111 insertions(+), 44 deletions(-)

diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c
index 25f88022b9e4..6ef8449d3e7a 100644
--- a/drivers/net/dsa/realtek/rtl8366rb.c
+++ b/drivers/net/dsa/realtek/rtl8366rb.c
@@ -95,12 +95,6 @@
 #define RTL8366RB_PAACR_RX_PAUSE	BIT(6)
 #define RTL8366RB_PAACR_AN		BIT(7)
 
-#define RTL8366RB_PAACR_CPU_PORT	(RTL8366RB_PAACR_SPEED_1000M | \
-					 RTL8366RB_PAACR_FULL_DUPLEX | \
-					 RTL8366RB_PAACR_LINK_UP | \
-					 RTL8366RB_PAACR_TX_PAUSE | \
-					 RTL8366RB_PAACR_RX_PAUSE)
-
 /* bits 0..7 = port 0, bits 8..15 = port 1 */
 #define RTL8366RB_PSTAT0		0x0014
 /* bits 0..7 = port 2, bits 8..15 = port 3 */
@@ -1049,63 +1043,134 @@ static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds,
 	return DSA_TAG_PROTO_RTL4_A;
 }
 
-static void
-rtl8366rb_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)
+static void rtl8366rb_link_get_caps(struct dsa_switch *ds, int port,
+				    struct phylink_config *config)
 {
-	struct realtek_priv *priv = ds->priv;
-	int ret;
+	/* The SYM and ASYM pause is RX and TX pause */
+	config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
+				   MAC_10 | MAC_100 | MAC_1000;
 
-	if (port != priv->cpu_port)
-		return;
+	/* These are all internal, no external interfaces supported */
+	__set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces);
 
-	dev_dbg(priv->dev, "MAC link up on CPU port (%d)\n", port);
+	/* GMII is the default interface mode for phylib, so
+	 * we have to support it for ports with integrated PHY.
+	 */
+	__set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces);
+}
 
-	/* Force the fixed CPU port into 1Gbit mode, no autonegotiation */
-	ret = regmap_update_bits(priv->map, RTL8366RB_MAC_FORCE_CTRL_REG,
-				 BIT(port), BIT(port));
-	if (ret) {
-		dev_err(priv->dev, "failed to force 1Gbit on CPU port\n");
-		return;
+static int rtl8366rb_config_link(struct realtek_priv *priv, int port, bool link,
+				 int speed, int duplex, bool tx_pause, bool rx_pause)
+{
+	u32 paacr;
+	u32 portreg;
+	u32 portmask;
+	u32 portshift;
+	int ret;
+
+	switch (port) {
+	case 0:
+		portreg = RTL8366RB_PAACR0;
+		portshift = 0;
+		break;
+	case 1:
+		portreg = RTL8366RB_PAACR0;
+		portshift = 8;
+		break;
+	case 2:
+		portreg = RTL8366RB_PAACR1;
+		portshift = 0;
+		break;
+	case 3:
+		portreg = RTL8366RB_PAACR1;
+		portshift = 8;
+		break;
+	case 4:
+		portreg = RTL8366RB_PAACR2;
+		portshift = 0;
+		break;
+	case 5:
+		portreg = RTL8366RB_PAACR2;
+		portshift = 8;
+		break;
+	default:
+		dev_err(priv->dev, "illegal port %d\n", port);
+		return -EINVAL;
 	}
 
-	ret = regmap_update_bits(priv->map, RTL8366RB_PAACR2,
-				 0xFF00U,
-				 RTL8366RB_PAACR_CPU_PORT << 8);
-	if (ret) {
-		dev_err(priv->dev, "failed to set PAACR on CPU port\n");
-		return;
+	portmask = GENMASK(portshift + 7, portshift);
+
+	if (link) {
+		switch (speed) {
+		case SPEED_1000:
+			paacr = RTL8366RB_PAACR_SPEED_1000M;
+			dev_dbg(priv->dev, "set port %d to 1Gbit\n", port);
+			break;
+		case SPEED_100:
+			paacr = RTL8366RB_PAACR_SPEED_100M;
+			dev_dbg(priv->dev, "set port %d to 100Mbit\n", port);
+			break;
+		case SPEED_10:
+			paacr = RTL8366RB_PAACR_SPEED_10M;
+			dev_dbg(priv->dev, "set port %d to 10Mbit\n", port);
+			break;
+		default:
+			dev_err(priv->dev, "illegal speed request on port %d\n", port);
+			return -EINVAL;
+		}
+
+		if (duplex == DUPLEX_FULL)
+			paacr |= RTL8366RB_PAACR_FULL_DUPLEX;
+		dev_dbg(priv->dev, "set port %d to %s duplex\n", port,
+			(duplex == DUPLEX_FULL) ? "full" : "half");
+
+		if (tx_pause)
+			paacr |= RTL8366RB_PAACR_TX_PAUSE;
+
+		if (rx_pause)
+			paacr |= RTL8366RB_PAACR_RX_PAUSE;
+
+		/* We are in the link up function so force it up */
+		paacr |= RTL8366RB_PAACR_LINK_UP;
+	} else {
+		/* If link goes down just zero the register including link up */
+		paacr = 0;
 	}
 
-	/* Enable the CPU port */
-	ret = regmap_update_bits(priv->map, RTL8366RB_PECR, BIT(port),
-				 0);
+	ret = regmap_update_bits(priv->map, portreg, portmask, paacr << portshift);
 	if (ret) {
-		dev_err(priv->dev, "failed to enable the CPU port\n");
-		return;
+		dev_err(priv->dev, "failed to set PAACR on port %d\n", port);
+		return ret;
 	}
+	dev_dbg(priv->dev, "Updated port %d reg %08x, mask %08x, shift %d with value %08x\n",
+		port, portreg, portmask, portshift, paacr);
+
+	return 0;
 }
 
 static void
-rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
-			phy_interface_t interface)
+rtl8366rb_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 realtek_priv *priv = ds->priv;
 	int ret;
 
-	if (port != priv->cpu_port)
-		return;
+	ret = rtl8366rb_config_link(priv, port, true, speed, duplex, tx_pause, rx_pause);
+	if (ret)
+		dev_err(priv->dev, "error configuring link on port %d\n", port);
+}
 
-	dev_dbg(priv->dev, "MAC link down on CPU port (%d)\n", port);
+static void
+rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
+			phy_interface_t interface)
+{
+	struct realtek_priv *priv = ds->priv;
+	int ret;
 
-	/* Disable the CPU port */
-	ret = regmap_update_bits(priv->map, RTL8366RB_PECR, BIT(port),
-				 BIT(port));
-	if (ret) {
-		dev_err(priv->dev, "failed to disable the CPU port\n");
-		return;
-	}
+	ret = rtl8366rb_config_link(priv, port, false, 0, 0, false, false);
+	if (ret)
+		dev_err(priv->dev, "error configuring link on port %d\n", port);
 }
 
 static void rb8366rb_set_port_led(struct realtek_priv *priv,
@@ -1796,6 +1861,7 @@ static int rtl8366rb_detect(struct realtek_priv *priv)
 static const struct dsa_switch_ops rtl8366rb_switch_ops_smi = {
 	.get_tag_protocol = rtl8366_get_tag_protocol,
 	.setup = rtl8366rb_setup,
+	.phylink_get_caps = rtl8366rb_link_get_caps,
 	.phylink_mac_link_up = rtl8366rb_mac_link_up,
 	.phylink_mac_link_down = rtl8366rb_mac_link_down,
 	.get_strings = rtl8366_get_strings,
@@ -1821,6 +1887,7 @@ static const struct dsa_switch_ops rtl8366rb_switch_ops_mdio = {
 	.setup = rtl8366rb_setup,
 	.phy_read = rtl8366rb_dsa_phy_read,
 	.phy_write = rtl8366rb_dsa_phy_write,
+	.phylink_get_caps = rtl8366rb_link_get_caps,
 	.phylink_mac_link_up = rtl8366rb_mac_link_up,
 	.phylink_mac_link_down = rtl8366rb_mac_link_down,
 	.get_strings = rtl8366_get_strings,
-- 
2.36.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-07-27 14:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-07-25 20:29 [PATCH net-next] net: dsa: realtek: rtl8366rb: Configure ports properly Linus Walleij
2022-07-26 11:02 ` Vladimir Oltean
2022-07-26 14:20   ` Linus Walleij
2022-07-27 14:07     ` Vladimir Oltean

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox