xref: /openbmc/linux/drivers/net/phy/marvell10g.c (revision bbecb07f)
1 /*
2  * Marvell 10G 88x3310 PHY driver
3  *
4  * Based upon the ID registers, this PHY appears to be a mixture of IPs
5  * from two different companies.
6  *
7  * There appears to be several different data paths through the PHY which
8  * are automatically managed by the PHY.  The following has been determined
9  * via observation and experimentation:
10  *
11  *       SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G)
12  *  10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G)
13  *  10GBASE-KR PHYXS -- BASE-R PCS -- Fiber
14  *
15  * If both the fiber and copper ports are connected, the first to gain
16  * link takes priority and the other port is completely locked out.
17  */
18 #include <linux/phy.h>
19 #include <linux/marvell_phy.h>
20 
21 enum {
22 	MV_PCS_BASE_T		= 0x0000,
23 	MV_PCS_BASE_R		= 0x1000,
24 	MV_PCS_1000BASEX	= 0x2000,
25 
26 	/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
27 	 * registers appear to set themselves to the 0x800X when AN is
28 	 * restarted, but status registers appear readable from either.
29 	 */
30 	MV_AN_CTRL1000		= 0x8000, /* 1000base-T control register */
31 	MV_AN_STAT1000		= 0x8001, /* 1000base-T status register */
32 
33 	/* This register appears to reflect the copper status */
34 	MV_AN_RESULT		= 0xa016,
35 	MV_AN_RESULT_SPD_10	= BIT(12),
36 	MV_AN_RESULT_SPD_100	= BIT(13),
37 	MV_AN_RESULT_SPD_1000	= BIT(14),
38 	MV_AN_RESULT_SPD_10000	= BIT(15),
39 };
40 
41 static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
42 			 u16 mask, u16 bits)
43 {
44 	int old, val, ret;
45 
46 	old = phy_read_mmd(phydev, devad, reg);
47 	if (old < 0)
48 		return old;
49 
50 	val = (old & ~mask) | (bits & mask);
51 	if (val == old)
52 		return 0;
53 
54 	ret = phy_write_mmd(phydev, devad, reg, val);
55 
56 	return ret < 0 ? ret : 1;
57 }
58 
59 static int mv3310_probe(struct phy_device *phydev)
60 {
61 	u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
62 
63 	if (!phydev->is_c45 ||
64 	    (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
65 		return -ENODEV;
66 
67 	return 0;
68 }
69 
70 /*
71  * Resetting the MV88X3310 causes it to become non-responsive.  Avoid
72  * setting the reset bit(s).
73  */
74 static int mv3310_soft_reset(struct phy_device *phydev)
75 {
76 	return 0;
77 }
78 
79 static int mv3310_config_init(struct phy_device *phydev)
80 {
81 	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
82 	u32 mask;
83 	int val;
84 
85 	/* Check that the PHY interface type is compatible */
86 	if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
87 	    phydev->interface != PHY_INTERFACE_MODE_XGMII &&
88 	    phydev->interface != PHY_INTERFACE_MODE_XAUI &&
89 	    phydev->interface != PHY_INTERFACE_MODE_RXAUI &&
90 	    phydev->interface != PHY_INTERFACE_MODE_10GKR)
91 		return -ENODEV;
92 
93 	__set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
94 	__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
95 
96 	if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
97 		val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
98 		if (val < 0)
99 			return val;
100 
101 		if (val & MDIO_AN_STAT1_ABLE)
102 			__set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
103 	}
104 
105 	val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
106 	if (val < 0)
107 		return val;
108 
109 	/* Ethtool does not support the WAN mode bits */
110 	if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR |
111 		   MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 |
112 		   MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW |
113 		   MDIO_PMA_STAT2_10GBEW))
114 		__set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
115 	if (val & MDIO_PMA_STAT2_10GBSR)
116 		__set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
117 	if (val & MDIO_PMA_STAT2_10GBLR)
118 		__set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
119 	if (val & MDIO_PMA_STAT2_10GBER)
120 		__set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);
121 
122 	if (val & MDIO_PMA_STAT2_EXTABLE) {
123 		val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
124 		if (val < 0)
125 			return val;
126 
127 		if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT |
128 			   MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT))
129 			__set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
130 		if (val & MDIO_PMA_EXTABLE_10GBLRM)
131 			__set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
132 		if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR |
133 			   MDIO_PMA_EXTABLE_1000BKX))
134 			__set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported);
135 		if (val & MDIO_PMA_EXTABLE_10GBLRM)
136 			__set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
137 				  supported);
138 		if (val & MDIO_PMA_EXTABLE_10GBT)
139 			__set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
140 				  supported);
141 		if (val & MDIO_PMA_EXTABLE_10GBKX4)
142 			__set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
143 				  supported);
144 		if (val & MDIO_PMA_EXTABLE_10GBKR)
145 			__set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
146 				  supported);
147 		if (val & MDIO_PMA_EXTABLE_1000BT)
148 			__set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
149 				  supported);
150 		if (val & MDIO_PMA_EXTABLE_1000BKX)
151 			__set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
152 				  supported);
153 		if (val & MDIO_PMA_EXTABLE_100BTX)
154 			__set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
155 				  supported);
156 		if (val & MDIO_PMA_EXTABLE_10BT)
157 			__set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
158 				  supported);
159 	}
160 
161 	if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported))
162 		dev_warn(&phydev->mdio.dev,
163 			 "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n",
164 			 __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
165 
166 	phydev->supported &= mask;
167 	phydev->advertising &= phydev->supported;
168 
169 	return 0;
170 }
171 
172 static int mv3310_config_aneg(struct phy_device *phydev)
173 {
174 	bool changed = false;
175 	u32 advertising;
176 	int ret;
177 
178 	if (phydev->autoneg == AUTONEG_DISABLE) {
179 		ret = genphy_c45_pma_setup_forced(phydev);
180 		if (ret < 0)
181 			return ret;
182 
183 		return genphy_c45_an_disable_aneg(phydev);
184 	}
185 
186 	phydev->advertising &= phydev->supported;
187 	advertising = phydev->advertising;
188 
189 	ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
190 			    ADVERTISE_ALL | ADVERTISE_100BASE4 |
191 			    ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
192 			    ethtool_adv_to_mii_adv_t(advertising));
193 	if (ret < 0)
194 		return ret;
195 	if (ret > 0)
196 		changed = true;
197 
198 	ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000,
199 			    ADVERTISE_1000FULL | ADVERTISE_1000HALF,
200 			    ethtool_adv_to_mii_ctrl1000_t(advertising));
201 	if (ret < 0)
202 		return ret;
203 	if (ret > 0)
204 		changed = true;
205 
206 	/* 10G control register */
207 	ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
208 			    MDIO_AN_10GBT_CTRL_ADV10G,
209 			    advertising & ADVERTISED_10000baseT_Full ?
210 				MDIO_AN_10GBT_CTRL_ADV10G : 0);
211 	if (ret < 0)
212 		return ret;
213 	if (ret > 0)
214 		changed = true;
215 
216 	if (changed)
217 		ret = genphy_c45_restart_aneg(phydev);
218 
219 	return ret;
220 }
221 
222 static int mv3310_aneg_done(struct phy_device *phydev)
223 {
224 	int val;
225 
226 	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
227 	if (val < 0)
228 		return val;
229 
230 	if (val & MDIO_STAT1_LSTATUS)
231 		return 1;
232 
233 	return genphy_c45_aneg_done(phydev);
234 }
235 
236 /* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */
237 static int mv3310_read_10gbr_status(struct phy_device *phydev)
238 {
239 	phydev->link = 1;
240 	phydev->speed = SPEED_10000;
241 	phydev->duplex = DUPLEX_FULL;
242 
243 	if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
244 		phydev->interface = PHY_INTERFACE_MODE_10GKR;
245 
246 	return 0;
247 }
248 
249 static int mv3310_read_status(struct phy_device *phydev)
250 {
251 	u32 mmd_mask = phydev->c45_ids.devices_in_package;
252 	int val;
253 
254 	/* The vendor devads do not report link status.  Avoid the PHYXS
255 	 * instance as there are three, and its status depends on the MAC
256 	 * being appropriately configured for the negotiated speed.
257 	 */
258 	mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2) |
259 		      BIT(MDIO_MMD_PHYXS));
260 
261 	phydev->speed = SPEED_UNKNOWN;
262 	phydev->duplex = DUPLEX_UNKNOWN;
263 	phydev->lp_advertising = 0;
264 	phydev->link = 0;
265 	phydev->pause = 0;
266 	phydev->asym_pause = 0;
267 
268 	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
269 	if (val < 0)
270 		return val;
271 
272 	if (val & MDIO_STAT1_LSTATUS)
273 		return mv3310_read_10gbr_status(phydev);
274 
275 	val = genphy_c45_read_link(phydev, mmd_mask);
276 	if (val < 0)
277 		return val;
278 
279 	phydev->link = val > 0 ? 1 : 0;
280 
281 	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
282 	if (val < 0)
283 		return val;
284 
285 	if (val & MDIO_AN_STAT1_COMPLETE) {
286 		val = genphy_c45_read_lpa(phydev);
287 		if (val < 0)
288 			return val;
289 
290 		/* Read the link partner's 1G advertisment */
291 		val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_STAT1000);
292 		if (val < 0)
293 			return val;
294 
295 		phydev->lp_advertising |= mii_stat1000_to_ethtool_lpa_t(val);
296 
297 		if (phydev->autoneg == AUTONEG_ENABLE) {
298 			val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_RESULT);
299 			if (val < 0)
300 				return val;
301 
302 			if (val & MV_AN_RESULT_SPD_10000)
303 				phydev->speed = SPEED_10000;
304 			else if (val & MV_AN_RESULT_SPD_1000)
305 				phydev->speed = SPEED_1000;
306 			else if (val & MV_AN_RESULT_SPD_100)
307 				phydev->speed = SPEED_100;
308 			else if (val & MV_AN_RESULT_SPD_10)
309 				phydev->speed = SPEED_10;
310 
311 			phydev->duplex = DUPLEX_FULL;
312 		}
313 	}
314 
315 	if (phydev->autoneg != AUTONEG_ENABLE) {
316 		val = genphy_c45_read_pma(phydev);
317 		if (val < 0)
318 			return val;
319 	}
320 
321 	if ((phydev->interface == PHY_INTERFACE_MODE_SGMII ||
322 	     phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) {
323 		/* The PHY automatically switches its serdes interface (and
324 		 * active PHYXS instance) between Cisco SGMII and 10GBase-KR
325 		 * modes according to the speed.  Florian suggests setting
326 		 * phydev->interface to communicate this to the MAC. Only do
327 		 * this if we are already in either SGMII or 10GBase-KR mode.
328 		 */
329 		if (phydev->speed == SPEED_10000)
330 			phydev->interface = PHY_INTERFACE_MODE_10GKR;
331 		else if (phydev->speed >= SPEED_10 &&
332 			 phydev->speed < SPEED_10000)
333 			phydev->interface = PHY_INTERFACE_MODE_SGMII;
334 	}
335 
336 	return 0;
337 }
338 
339 static struct phy_driver mv3310_drivers[] = {
340 	{
341 		.phy_id		= 0x002b09aa,
342 		.phy_id_mask	= MARVELL_PHY_ID_MASK,
343 		.name		= "mv88x3310",
344 		.features	= SUPPORTED_10baseT_Full |
345 				  SUPPORTED_100baseT_Full |
346 				  SUPPORTED_1000baseT_Full |
347 				  SUPPORTED_Autoneg |
348 				  SUPPORTED_TP |
349 				  SUPPORTED_FIBRE |
350 				  SUPPORTED_10000baseT_Full |
351 				  SUPPORTED_Backplane,
352 		.probe		= mv3310_probe,
353 		.soft_reset	= mv3310_soft_reset,
354 		.config_init	= mv3310_config_init,
355 		.config_aneg	= mv3310_config_aneg,
356 		.aneg_done	= mv3310_aneg_done,
357 		.read_status	= mv3310_read_status,
358 	},
359 };
360 
361 module_phy_driver(mv3310_drivers);
362 
363 static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
364 	{ 0x002b09aa, MARVELL_PHY_ID_MASK },
365 	{ },
366 };
367 MODULE_DEVICE_TABLE(mdio, mv3310_tbl);
368 MODULE_DESCRIPTION("Marvell Alaska X 10Gigabit Ethernet PHY driver (MV88X3310)");
369 MODULE_LICENSE("GPL");
370