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
next prev parent reply other threads:[~2020-03-17 14:53 UTC|newest]
Thread overview: 30+ 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:21 ` Russell King - ARM Linux admin
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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).