mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 18:47:06 +00:00
d2a1075973
These patches backport support for the ARMADA 3700 COMPHY driver. Also backported is the mvneta driver. This will allow switching the SGMII speed using SMC calls. To support this you must update the firmware using Marvells 18.12 version (this has now been upstreamed). The mvneta driver allows 2500basex and 2500baset. Signed-off-by: Scott Roberts <ttocsr@gmail.com>
160 lines
5.2 KiB
Diff
160 lines
5.2 KiB
Diff
From a10c1c8191e04c21769656c2ca8e1c69a6218954 Mon Sep 17 00:00:00 2001
|
|
From: Russell King <rmk+kernel@armlinux.org.uk>
|
|
Date: Thu, 7 Feb 2019 16:19:26 +0000
|
|
Subject: [PATCH] net: marvell: neta: add comphy support
|
|
|
|
Add support for the common phy binding, so that we can reconfigure the
|
|
comphy according to the desired ethernet speed. This will allow us to
|
|
support 1000base-X and 2500base-X SFPs dynamically on SolidRun Clearfog.
|
|
|
|
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
drivers/net/ethernet/marvell/mvneta.c | 45 +++++++++++++++++++++++++++++++----
|
|
1 file changed, 41 insertions(+), 4 deletions(-)
|
|
|
|
--- a/drivers/net/ethernet/marvell/mvneta.c
|
|
+++ b/drivers/net/ethernet/marvell/mvneta.c
|
|
@@ -27,6 +27,7 @@
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_mdio.h>
|
|
#include <linux/of_net.h>
|
|
+#include <linux/phy/phy.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/phylink.h>
|
|
#include <linux/platform_device.h>
|
|
@@ -436,6 +437,7 @@ struct mvneta_port {
|
|
struct device_node *dn;
|
|
unsigned int tx_csum_limit;
|
|
struct phylink *phylink;
|
|
+ struct phy *comphy;
|
|
|
|
struct mvneta_bm *bm_priv;
|
|
struct mvneta_bm_pool *pool_long;
|
|
@@ -3153,6 +3155,8 @@ static void mvneta_start_dev(struct mvne
|
|
{
|
|
int cpu;
|
|
|
|
+ WARN_ON(phy_power_on(pp->comphy));
|
|
+
|
|
mvneta_max_rx_size_set(pp, pp->pkt_size);
|
|
mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
|
|
|
|
@@ -3215,6 +3219,8 @@ static void mvneta_stop_dev(struct mvnet
|
|
|
|
mvneta_tx_reset(pp);
|
|
mvneta_rx_reset(pp);
|
|
+
|
|
+ WARN_ON(phy_power_off(pp->comphy));
|
|
}
|
|
|
|
static void mvneta_percpu_enable(void *arg)
|
|
@@ -3340,6 +3346,7 @@ static int mvneta_set_mac_addr(struct ne
|
|
static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
|
|
struct phylink_link_state *state)
|
|
{
|
|
+ struct mvneta_port *pp = netdev_priv(ndev);
|
|
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
|
|
|
/* We only support QSGMII, SGMII, 802.3z and RGMII modes */
|
|
@@ -3360,8 +3367,13 @@ static void mvneta_validate(struct net_d
|
|
phylink_set(mask, Pause);
|
|
|
|
/* Half-duplex at speeds higher than 100Mbit is unsupported */
|
|
- phylink_set(mask, 1000baseT_Full);
|
|
- phylink_set(mask, 1000baseX_Full);
|
|
+ if (pp->comphy || state->interface != PHY_INTERFACE_MODE_2500BASEX) {
|
|
+ phylink_set(mask, 1000baseT_Full);
|
|
+ phylink_set(mask, 1000baseX_Full);
|
|
+ }
|
|
+ if (pp->comphy || state->interface == PHY_INTERFACE_MODE_2500BASEX) {
|
|
+ phylink_set(mask, 2500baseX_Full);
|
|
+ }
|
|
|
|
if (!phy_interface_mode_is_8023z(state->interface)) {
|
|
/* 10M and 100M are only supported in non-802.3z mode */
|
|
@@ -3375,6 +3387,11 @@ static void mvneta_validate(struct net_d
|
|
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
|
bitmap_and(state->advertising, state->advertising, mask,
|
|
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
|
+
|
|
+ /* We can only operate at 2500BaseX or 1000BaseX. If requested
|
|
+ * to advertise both, only report advertising at 2500BaseX.
|
|
+ */
|
|
+ phylink_helper_basex_speed(state);
|
|
}
|
|
|
|
static int mvneta_mac_link_state(struct net_device *ndev,
|
|
@@ -3386,7 +3403,9 @@ static int mvneta_mac_link_state(struct
|
|
gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
|
|
|
|
if (gmac_stat & MVNETA_GMAC_SPEED_1000)
|
|
- state->speed = SPEED_1000;
|
|
+ state->speed =
|
|
+ state->interface == PHY_INTERFACE_MODE_2500BASEX ?
|
|
+ SPEED_2500 : SPEED_1000;
|
|
else if (gmac_stat & MVNETA_GMAC_SPEED_100)
|
|
state->speed = SPEED_100;
|
|
else
|
|
@@ -3501,12 +3520,20 @@ static void mvneta_mac_config(struct net
|
|
MVNETA_GMAC_FORCE_LINK_DOWN);
|
|
}
|
|
|
|
+
|
|
/* When at 2.5G, the link partner can send frames with shortened
|
|
* preambles.
|
|
*/
|
|
if (state->speed == SPEED_2500)
|
|
new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
|
|
|
|
+ if (pp->comphy &&
|
|
+ (state->interface == PHY_INTERFACE_MODE_SGMII ||
|
|
+ state->interface == PHY_INTERFACE_MODE_1000BASEX ||
|
|
+ state->interface == PHY_INTERFACE_MODE_2500BASEX))
|
|
+ WARN_ON(phy_set_mode_ext(pp->comphy, PHY_MODE_ETHERNET,
|
|
+ state->interface));
|
|
+
|
|
if (new_ctrl0 != gmac_ctrl0)
|
|
mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0);
|
|
if (new_ctrl2 != gmac_ctrl2)
|
|
@@ -4419,7 +4446,7 @@ static int mvneta_port_power_up(struct m
|
|
if (phy_mode == PHY_INTERFACE_MODE_QSGMII)
|
|
mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_QSGMII_SERDES_PROTO);
|
|
else if (phy_mode == PHY_INTERFACE_MODE_SGMII ||
|
|
- phy_mode == PHY_INTERFACE_MODE_1000BASEX)
|
|
+ phy_interface_mode_is_8023z(phy_mode))
|
|
mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
|
|
else if (!phy_interface_mode_is_rgmii(phy_mode))
|
|
return -EINVAL;
|
|
@@ -4436,6 +4463,7 @@ static int mvneta_probe(struct platform_
|
|
struct mvneta_port *pp;
|
|
struct net_device *dev;
|
|
struct phylink *phylink;
|
|
+ struct phy *comphy;
|
|
const char *dt_mac_addr;
|
|
char hw_mac_addr[ETH_ALEN];
|
|
const char *mac_from;
|
|
@@ -4461,6 +4489,14 @@ static int mvneta_probe(struct platform_
|
|
goto err_free_irq;
|
|
}
|
|
|
|
+ comphy = devm_of_phy_get(&pdev->dev, dn, NULL);
|
|
+ if (comphy == ERR_PTR(-EPROBE_DEFER)) {
|
|
+ err = -EPROBE_DEFER;
|
|
+ goto err_free_irq;
|
|
+ } else if (IS_ERR(comphy)) {
|
|
+ comphy = NULL;
|
|
+ }
|
|
+
|
|
phylink = phylink_create(dev, pdev->dev.fwnode, phy_mode,
|
|
&mvneta_phylink_ops);
|
|
if (IS_ERR(phylink)) {
|
|
@@ -4477,6 +4513,7 @@ static int mvneta_probe(struct platform_
|
|
pp = netdev_priv(dev);
|
|
spin_lock_init(&pp->lock);
|
|
pp->phylink = phylink;
|
|
+ pp->comphy = comphy;
|
|
pp->phy_interface = phy_mode;
|
|
pp->dn = dn;
|
|
|