1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
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>
@@ -438,6 +439,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;
@@ -3167,6 +3169,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);
@@ -3229,6 +3233,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)
@@ -3354,6 +3360,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 */
@@ -3374,8 +3381,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 */
@@ -3389,6 +3401,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,
@@ -3400,7 +3417,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
@@ -3515,12 +3534,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)
@@ -4433,7 +4460,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;
@@ -4450,6 +4477,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;
@@ -4475,6 +4503,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)) {
@@ -4491,6 +4527,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;
|