All of lore.kernel.org
 help / color / mirror / Atom feed
From: Russell King <rmk+kernel@armlinux.org.uk>
To: Andrew Lunn <andrew@lunn.ch>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Heiner Kallweit <hkallweit1@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>,
	netdev@vger.kernel.org,
	Ioana Radulescu <ruxandra.radulescu@nxp.com>
Subject: [RFC net-next 4/5] dpaa2-mac: add 1000BASE-X/SGMII PCS support
Date: Tue, 17 Mar 2020 14:53:01 +0000	[thread overview]
Message-ID: <E1jEDaX-0008JW-Sl@rmk-PC.armlinux.org.uk> (raw)
In-Reply-To: <20200317144944.GP25745@shell.armlinux.org.uk>

*NOT FOR MERGING*

Add support for the PCS block, so we can dynamically configure it for
1000base-X or SGMII depending on the SFP module inserted. This gives
us more flexibility than using the MC firmware with a "fixed" link
type, which can only be setup to support a single interface mode.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
 .../net/ethernet/freescale/dpaa2/dpaa2-mac.c  | 206 +++++++++++++++++-
 .../net/ethernet/freescale/dpaa2/dpaa2-mac.h  |   1 +
 2 files changed, 204 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
index 3ee236c5fc37..e7b2dc366338 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
@@ -7,6 +7,117 @@
 #define phylink_to_dpaa2_mac(config) \
 	container_of((config), struct dpaa2_mac, phylink_config)
 
+#define MII_IFMODE		0x14
+#define IF_MODE_SGMII_ENA	BIT(0)
+#define IF_MODE_USE_SGMII_AN	BIT(1)
+#define IF_MODE_SGMII_SPEED_10	(0 << 2)
+#define IF_MODE_SGMII_SPEED_100	(1 << 2)
+#define IF_MODE_SGMII_SPEED_1G	(2 << 2)
+#define IF_MODE_SGMII_SPEED_MSK	(3 << 2)
+#define IF_MODE_SGMII_DUPLEX	BIT(4)		// set = half duplex
+
+static void dpaa2_mac_pcs_get_state(struct phylink_config *config,
+				    struct phylink_link_state *state)
+{
+	struct mdio_device *pcs = phylink_to_dpaa2_mac(config)->pcs;
+
+	switch (state->interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
+		phylink_mii_c22_pcs_get_state(pcs, state);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void dpaa2_mac_pcs_an_restart(struct phylink_config *config)
+{
+	struct mdio_device *pcs = phylink_to_dpaa2_mac(config)->pcs;
+
+	phylink_mii_c22_pcs_an_restart(pcs);
+}
+
+static int dpaa2_mac_pcs_config(struct phylink_config *config,
+				unsigned int mode,
+				const struct phylink_link_state *state)
+{
+	struct mdio_device *pcs = phylink_to_dpaa2_mac(config)->pcs;
+	u16 if_mode;
+	int bmcr, ret;
+
+	if (mode == MLO_AN_INBAND)
+		bmcr = BMCR_ANENABLE;
+	else
+		bmcr = 0;
+
+	switch (state->interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+		if_mode = IF_MODE_SGMII_ENA;
+		if (mode == MLO_AN_INBAND)
+			if_mode |= IF_MODE_USE_SGMII_AN;
+		mdiobus_modify(pcs->bus, 0, MII_IFMODE,
+			       IF_MODE_SGMII_ENA | IF_MODE_USE_SGMII_AN,
+			       if_mode);
+		mdiobus_modify(pcs->bus, 0, MII_BMCR, BMCR_ANENABLE, bmcr);
+		ret = phylink_mii_c22_pcs_set_advertisement(pcs, state);
+		break;
+
+	case PHY_INTERFACE_MODE_1000BASEX:
+		mdiobus_write(pcs->bus, 0, MII_IFMODE, 0);
+		mdiobus_modify(pcs->bus, 0, MII_BMCR, BMCR_ANENABLE, bmcr);
+		ret = phylink_mii_c22_pcs_set_advertisement(pcs, state);
+		break;
+
+	default:
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static void dpaa2_mac_pcs_link_up(struct phylink_config *config,
+				  unsigned int mode, phy_interface_t interface,
+				  int speed, int duplex)
+{
+	struct mdio_device *pcs = phylink_to_dpaa2_mac(config)->pcs;
+	u16 if_mode;
+
+	/* The PCS PHY needs to be configured manually for the speed and
+	 * duplex when operating in SGMII mode without in-band negotiation.
+	 */
+	if (mode == MLO_AN_INBAND || interface != PHY_INTERFACE_MODE_SGMII)
+		return;
+
+	switch (speed) {
+	case SPEED_10:
+		if_mode = IF_MODE_SGMII_SPEED_10;
+		break;
+
+	case SPEED_100:
+		if_mode = IF_MODE_SGMII_SPEED_100;
+		break;
+
+	default:
+		if_mode = IF_MODE_SGMII_SPEED_1G;
+		break;
+	}
+	if (duplex == DUPLEX_HALF)
+		if_mode |= IF_MODE_SGMII_DUPLEX;
+
+	mdiobus_modify(pcs->bus, pcs->addr, MII_IFMODE,
+		       IF_MODE_SGMII_DUPLEX | IF_MODE_SGMII_SPEED_MSK, if_mode);
+}
+
+static const struct phylink_pcs_ops dpaa2_pcs_phylink_ops = {
+	.pcs_get_state = dpaa2_mac_pcs_get_state,
+	.pcs_config = dpaa2_mac_pcs_config,
+	.pcs_an_restart = dpaa2_mac_pcs_an_restart,
+	.pcs_link_up = dpaa2_mac_pcs_link_up,
+};
+
 static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
 {
 	*if_mode = PHY_INTERFACE_MODE_NA;
@@ -15,6 +126,11 @@ static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
 	case DPMAC_ETH_IF_RGMII:
 		*if_mode = PHY_INTERFACE_MODE_RGMII;
 		break;
+
+	case DPMAC_ETH_IF_SGMII:
+		*if_mode = PHY_INTERFACE_MODE_SGMII;
+		break;
+
 	default:
 		return -EINVAL;
 	}
@@ -67,6 +183,10 @@ static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac,
 					phy_interface_t interface)
 {
 	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
+		return interface != mac->if_mode && !mac->pcs;
+
 	case PHY_INTERFACE_MODE_RGMII:
 	case PHY_INTERFACE_MODE_RGMII_ID:
 	case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -95,13 +215,19 @@ static void dpaa2_mac_validate(struct phylink_config *config,
 	phylink_set(mask, Asym_Pause);
 
 	switch (state->interface) {
+	case PHY_INTERFACE_MODE_NA:
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_SGMII:
 	case PHY_INTERFACE_MODE_RGMII:
 	case PHY_INTERFACE_MODE_RGMII_ID:
 	case PHY_INTERFACE_MODE_RGMII_RXID:
 	case PHY_INTERFACE_MODE_RGMII_TXID:
-		phylink_set(mask, 10baseT_Full);
-		phylink_set(mask, 100baseT_Full);
+		phylink_set(mask, 1000baseX_Full);
 		phylink_set(mask, 1000baseT_Full);
+		if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
+			break;
+		phylink_set(mask, 100baseT_Full);
+		phylink_set(mask, 10baseT_Full);
 		break;
 	default:
 		goto empty_set;
@@ -227,6 +353,65 @@ bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
 	return fixed;
 }
 
+static int dpaa2_pcs_create(struct dpaa2_mac *mac,
+			    struct device_node *dpmac_node, int id)
+{
+	struct mdio_device *mdiodev;
+	struct device_node *node;
+	struct mii_bus *bus;
+	int err;
+
+	node = of_parse_phandle(dpmac_node, "pcs-mdio", 0);
+	if (!node) {
+		/* allow old DT files to work */
+		netdev_warn(mac->netdev, "pcs-mdio node not found\n");
+		return 0;
+	}
+
+	if (!of_device_is_available(node)) {
+		netdev_err(mac->net_dev, "pcs-mdio node not available\n");
+		return -ENODEV;
+	}
+
+	bus = of_mdio_find_bus(node);
+	of_node_put(node);
+	if (!bus)
+		return -EPROBE_DEFER;
+
+	mdiodev = mdio_device_create(bus, 0);
+	if (IS_ERR(mdiodev)) {
+		err = PTR_ERR(mdiodev);
+		netdev_err(mac->net_dev, "failed to create mdio device: %d\n",
+			   err);
+		goto err;
+	}
+
+	err = mdio_device_register(mdiodev);
+	if (err) {
+		netdev_err(mac->net_dev, "failed to register mdio device: %d\n",
+			   err);
+		goto dev_free;
+	}
+
+	mac->pcs = mdiodev;
+	mac->phylink_config.pcs_poll = true;
+
+	return 0;
+
+dev_free:
+	mdio_device_free(mdiodev);
+err:
+	return err;
+}
+
+static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
+{
+	if (mac->pcs) {
+		mdio_device_remove(mac->pcs);
+		mdio_device_free(mac->pcs);
+	}
+}
+
 int dpaa2_mac_connect(struct dpaa2_mac *mac)
 {
 	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
@@ -236,6 +421,8 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
 	struct dpmac_attr attr;
 	int err;
 
+	memset(&mac->phylink_config, 0, sizeof(mac->phylink_config));
+
 	err = dpmac_open(mac->mc_io, 0, dpmac_dev->obj_desc.id,
 			 &dpmac_dev->mc_handle);
 	if (err || !dpmac_dev->mc_handle) {
@@ -278,6 +465,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
 		goto err_put_node;
 	}
 
+	if (attr.link_type == DPMAC_LINK_TYPE_PHY &&
+	    attr.eth_if != DPMAC_ETH_IF_RGMII) {
+		err = dpaa2_pcs_create(mac, dpmac_node, attr.id);
+		if (err)
+			goto err_put_node;
+	}
+
 	mac->phylink_config.dev = &net_dev->dev;
 	mac->phylink_config.type = PHYLINK_NETDEV;
 
@@ -286,10 +480,13 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
 				 &dpaa2_mac_phylink_ops);
 	if (IS_ERR(phylink)) {
 		err = PTR_ERR(phylink);
-		goto err_put_node;
+		goto err_pcs_destroy;
 	}
 	mac->phylink = phylink;
 
+	if (mac->pcs)
+		phylink_add_pcs(mac->phylink, &dpaa2_pcs_phylink_ops);
+
 	err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
 	if (err) {
 		netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err);
@@ -302,6 +499,8 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
 
 err_phylink_destroy:
 	phylink_destroy(mac->phylink);
+err_pcs_destroy:
+	dpaa2_pcs_destroy(mac);
 err_put_node:
 	of_node_put(dpmac_node);
 err_close_dpmac:
@@ -316,6 +515,7 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac)
 
 	phylink_disconnect_phy(mac->phylink);
 	phylink_destroy(mac->phylink);
+	dpaa2_pcs_destroy(mac);
 	dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle);
 }
 
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
index 2130d9c7d40e..5cfae5f8f55e 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
@@ -19,6 +19,7 @@ struct dpaa2_mac {
 
 	struct phylink_config phylink_config;
 	struct phylink *phylink;
+	struct mdio_device *pcs;
 	phy_interface_t if_mode;
 	enum dpmac_link_type if_link_type;
 };
-- 
2.20.1


  parent reply	other threads:[~2020-03-17 14:53 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-17 14:49 [RFC net-next 0/2] split phylink PCS operations and add PCS support for dpaa2 Russell King - ARM Linux admin
2020-03-17 14:52 ` [RFC net-next 1/5] net: phylink: rename 'ops' to 'mac_ops' Russell King
2020-03-17 16:20   ` Andrew Lunn
2020-03-17 14:52 ` [RFC net-next 2/5] net: phylink: add separate pcs operations structure Russell King
2020-03-17 15:48   ` Jose Abreu
2020-03-17 15:56     ` Russell King - ARM Linux admin
2020-03-17 16:04       ` Jose Abreu
2020-03-17 16:52         ` Russell King - ARM Linux admin
2020-03-18  7:45           ` Jose Abreu
2020-03-19 11:14             ` Russell King - ARM Linux admin
2020-03-20  9:55               ` Jose Abreu
2020-03-17 16:38   ` Andrew Lunn
2020-03-17 16:54     ` Russell King - ARM Linux admin
2020-03-19 12:14       ` Russell King - ARM Linux admin
2020-03-19 15:06         ` Andrew Lunn
2020-03-19 17:20           ` Russell King - ARM Linux admin
2020-03-19 20:59           ` Russell King - ARM Linux admin
2020-03-24 19:46           ` Russell King - ARM Linux admin
2020-03-17 14:52 ` [RFC net-next 3/5] arm64: dts: lx2160a: add PCS MDIO nodes Russell King
2020-03-26 21:14   ` Ioana Ciornei
2020-03-26 21:14     ` Ioana Ciornei
2020-03-26 21:21     ` Russell King - ARM Linux admin
2020-03-26 21:21       ` Russell King - ARM Linux admin
2020-03-26 21:26       ` Ioana Ciornei
2020-03-26 21:26         ` Ioana Ciornei
2020-03-17 14:53 ` Russell King [this message]
2020-03-26 22:09   ` [RFC net-next 4/5] dpaa2-mac: add 1000BASE-X/SGMII PCS support Ioana Ciornei
2020-03-17 14:53 ` [RFC net-next 5/5] dpaa2-mac: add 10GBASE-R " Russell King
2020-03-26 14:57 ` [RFC net-next 0/2] split phylink PCS operations and add PCS support for dpaa2 Russell King - ARM Linux admin
2020-03-26 14:57   ` Russell King - ARM Linux admin
2020-03-26 15:04   ` Andrew Lunn
2020-03-26 15:04     ` Andrew Lunn
2020-03-26 15:14 ` [PATCH " Russell King - ARM Linux admin
2020-03-30  4:57   ` David Miller
2020-03-30  8:44     ` Russell King - ARM Linux admin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=E1jEDaX-0008JW-Sl@rmk-PC.armlinux.org.uk \
    --to=rmk+kernel@armlinux.org.uk \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=f.fainelli@gmail.com \
    --cc=hkallweit1@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=ruxandra.radulescu@nxp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.