[PATCH 13/20] net: dsa: xilinx: wire up phylink for the switch ports

Nagadheeraj Rottela <[email protected]>
Newsgroups org.kernel.vger.linux-devicetree,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.netdev
Message-ID <[email protected]>
Wire up the MAC-side phylink ops for all three switch ports.

For the two external user ports, phylink_get_caps fills
supported_interfaces with RGMII variants, SGMII, and GMII, and sets
mac_capabilities to MAC_100FD and MAC_1000FD. The speed-config field
only encodes those two speeds, so 10 Mbps and half-duplex are not
reachable in hardware. The CPU port has no external PHY. Its link is
internal and fixed at MAC_1000FD, so phylink_get_caps sets
PHY_INTERFACE_MODE_INTERNAL and returns early for it.

mac_link_up programs the resolved speed into the speed-config field
and sets TX_EN and RX_EN to allow frames to flow. mac_link_down clears
them. mac_config is intentionally empty. The interface mode is fixed
at IP synthesis time and there is no runtime register to program.

Co-developed-by: Srinivas Neeli <[email protected]>
Signed-off-by: Srinivas Neeli <[email protected]>
Signed-off-by: Nagadheeraj Rottela <[email protected]>
---
 drivers/net/dsa/xilinx/xilinx_tsn.c | 102 ++++++++++++++++++++++++++++
 drivers/net/dsa/xilinx/xilinx_tsn.h |  12 ++++
 2 files changed, 114 insertions(+)

diff --git a/drivers/net/dsa/xilinx/xilinx_tsn.c b/drivers/net/dsa/xilinx/xilinx_tsn.c
index 542b74514ed3..86aba2e8b6e9 100644
--- a/drivers/net/dsa/xilinx/xilinx_tsn.c
+++ b/drivers/net/dsa/xilinx/xilinx_tsn.c
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/of_mdio.h>
 #include <linux/phy.h>
+#include <linux/phylink.h>
 #include <linux/platform_device.h>
 #include <net/dsa.h>
 
@@ -324,6 +325,105 @@ static void xlnx_tsn_port_stp_state_set(struct dsa_switch *ds, int port,
 	xlnx_tsn_set_port_state(sw, port, hw_state);
 }
 
+static void xlnx_tsn_phylink_get_caps(struct dsa_switch *ds, int port,
+				      struct phylink_config *config)
+{
+	if (port == XLNX_TSN_CPU_PORT) {
+		config->mac_capabilities = MAC_1000FD;
+		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
+			  config->supported_interfaces);
+		return;
+	}
+
+	/* The MAC's speed-config field only encodes 100 / 1000.
+	 * Half-duplex and 10 Mbps are not supported.
+	 */
+	config->mac_capabilities = MAC_100FD | MAC_1000FD;
+	phy_interface_set_rgmii(config->supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces);
+}
+
+static void xlnx_tsn_mac_config(struct phylink_config *config,
+				unsigned int mode,
+				const struct phylink_link_state *state)
+{
+	/* Interface mode (RGMII / SGMII / GMII) is fixed at IP synthesis
+	 * time. There is no runtime register to program it here.
+	 */
+}
+
+static void xlnx_tsn_mac_link_down(struct phylink_config *config,
+				   unsigned int mode,
+				   phy_interface_t interface)
+{
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+	struct xlnx_tsn *sw = dp->ds->priv;
+	struct xlnx_tsn_mac *m;
+	u32 rcw1, tc;
+
+	m = &sw->mac[dp->index];
+
+	/* The CPU port has no switch-side MAC registers. Nothing to
+	 * tear down here (see xlnx_tsn_mac_link_up).
+	 */
+	if (dp->index == XLNX_TSN_CPU_PORT)
+		return;
+
+	tc = mac_ior(m, TSN_TC_OFFSET) & ~TSN_TC_TX_EN;
+	mac_iow(m, TSN_TC_OFFSET, tc);
+
+	rcw1 = mac_ior(m, TSN_RCW1_OFFSET) & ~TSN_RCW1_RX_EN;
+	mac_iow(m, TSN_RCW1_OFFSET, rcw1);
+}
+
+static void xlnx_tsn_mac_link_up(struct phylink_config *config,
+				 struct phy_device *phy, unsigned int mode,
+				 phy_interface_t interface, int speed,
+				 int duplex, bool tx_pause, bool rx_pause)
+{
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+	struct xlnx_tsn *sw = dp->ds->priv;
+	u32 speed_cfg, rcw1, tc;
+	struct xlnx_tsn_mac *m;
+
+	m = &sw->mac[dp->index];
+
+	/* The CPU port is the internal endpoint MAC. It has no switch-side
+	 * MAC registers and is managed by the endpoint driver, not here.
+	 */
+	if (dp->index == XLNX_TSN_CPU_PORT)
+		return;
+
+	speed_cfg = mac_ior(m, TSN_SPEED_CFG_OFFSET) & ~TSN_SPEED_CFG_MASK;
+	switch (speed) {
+	case SPEED_1000:
+		speed_cfg |= TSN_SPEED_CFG_1000;
+		break;
+	case SPEED_100:
+		speed_cfg |= TSN_SPEED_CFG_100;
+		break;
+	default:
+		dev_warn(sw->dev,
+			 "port %d: unsupported link speed %d Mbps\n",
+			 dp->index, speed);
+		return;
+	}
+	mac_iow(m, TSN_SPEED_CFG_OFFSET, speed_cfg);
+
+	rcw1 = mac_ior(m, TSN_RCW1_OFFSET) | TSN_RCW1_RX_EN;
+	mac_iow(m, TSN_RCW1_OFFSET, rcw1);
+
+	tc = mac_ior(m, TSN_TC_OFFSET) | TSN_TC_TX_EN;
+	mac_iow(m, TSN_TC_OFFSET, tc);
+}
+
+static const struct phylink_mac_ops xlnx_tsn_phylink_mac_ops = {
+	.mac_config	= xlnx_tsn_mac_config,
+	.mac_link_up	= xlnx_tsn_mac_link_up,
+	.mac_link_down	= xlnx_tsn_mac_link_down,
+};
+
 static int xlnx_tsn_setup(struct dsa_switch *ds)
 {
 	struct xlnx_tsn *sw = ds->priv;
@@ -372,6 +472,7 @@ static const struct dsa_switch_ops xlnx_tsn_switch_ops = {
 	.setup			= xlnx_tsn_setup,
 	.teardown		= xlnx_tsn_teardown,
 	.port_stp_state_set	= xlnx_tsn_port_stp_state_set,
+	.phylink_get_caps	= xlnx_tsn_phylink_get_caps,
 };
 
 static int xlnx_tsn_map_reg(struct platform_device *pdev, const char *name,
@@ -421,6 +522,7 @@ static int xlnx_tsn_probe(struct platform_device *pdev)
 	ds->dev = dev;
 	ds->num_ports = XLNX_TSN_NUM_PORTS;
 	ds->ops = &xlnx_tsn_switch_ops;
+	ds->phylink_mac_ops = &xlnx_tsn_phylink_mac_ops;
 	ds->priv = sw;
 
 	platform_set_drvdata(pdev, sw);
diff --git a/drivers/net/dsa/xilinx/xilinx_tsn.h b/drivers/net/dsa/xilinx/xilinx_tsn.h
index 025645a83992..6286caff7a1c 100644
--- a/drivers/net/dsa/xilinx/xilinx_tsn.h
+++ b/drivers/net/dsa/xilinx/xilinx_tsn.h
@@ -66,6 +66,18 @@ enum tsn_port_state {
 
 #define TSN_MDIO_MRD_MASK		GENMASK(15, 0)
 
+/* Per-MAC receive / transmit / speed configuration registers. */
+#define TSN_RCW1_OFFSET			0x00000404
+#define TSN_RCW1_RX_EN			BIT(28)
+
+#define TSN_TC_OFFSET			0x00000408
+#define TSN_TC_TX_EN			BIT(28)
+
+#define TSN_SPEED_CFG_OFFSET		0x00000410
+#define TSN_SPEED_CFG_MASK		GENMASK(31, 30)
+#define TSN_SPEED_CFG_100		BIT(30)
+#define TSN_SPEED_CFG_1000		BIT(31)
+
 struct mii_bus;
 struct xlnx_tsn;
 
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.