blob: 9e64672f5cac30d84f66e51ae97980c2a3f58d89 [file] [log] [blame]
Marek Vasut1ac4e192023-03-19 18:08:10 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Marvell 10G 88x3310 PHY driver
4 *
5 * Based upon the ID registers, this PHY appears to be a mixture of IPs
6 * from two different companies.
7 *
8 * There appears to be several different data paths through the PHY which
9 * are automatically managed by the PHY. The following has been determined
10 * via observation and experimentation for a setup using single-lane Serdes:
11 *
12 * SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G)
13 * 10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G)
14 * 10GBASE-KR PHYXS -- BASE-R PCS -- Fiber
15 *
16 * With XAUI, observation shows:
17 *
18 * XAUI PHYXS -- <appropriate PCS as above>
19 *
20 * and no switching of the host interface mode occurs.
21 *
22 * If both the fiber and copper ports are connected, the first to gain
23 * link takes priority and the other port is completely locked out.
24 */
25#include <common.h>
26#include <console.h>
27#include <dm/device_compat.h>
28#include <dm/devres.h>
29#include <errno.h>
30#include <linux/bitfield.h>
31#include <linux/bitops.h>
32#include <linux/compat.h>
33#include <linux/delay.h>
34#include <linux/iopoll.h>
35#include <marvell_phy.h>
36#include <phy.h>
37
38#define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
39#define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa)
40
41#define MV_VERSION(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
42
43enum {
44 MV_PMA_FW_VER0 = 0xc011,
45 MV_PMA_FW_VER1 = 0xc012,
46 MV_PMA_21X0_PORT_CTRL = 0xc04a,
47 MV_PMA_21X0_PORT_CTRL_SWRST = BIT(15),
48 MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK = 0x7,
49 MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII = 0x0,
50 MV_PMA_2180_PORT_CTRL_MACTYPE_DXGMII = 0x1,
51 MV_PMA_2180_PORT_CTRL_MACTYPE_QXGMII = 0x2,
52 MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER = 0x4,
53 MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN = 0x5,
54 MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
55 MV_PMA_BOOT = 0xc050,
56 MV_PMA_BOOT_FATAL = BIT(0),
57
58 MV_PCS_BASE_T = 0x0000,
59 MV_PCS_BASE_R = 0x1000,
60 MV_PCS_1000BASEX = 0x2000,
61
62 MV_PCS_CSCR1 = 0x8000,
63 MV_PCS_CSCR1_ED_MASK = 0x0300,
64 MV_PCS_CSCR1_ED_OFF = 0x0000,
65 MV_PCS_CSCR1_ED_RX = 0x0200,
66 MV_PCS_CSCR1_ED_NLP = 0x0300,
67 MV_PCS_CSCR1_MDIX_MASK = 0x0060,
68 MV_PCS_CSCR1_MDIX_MDI = 0x0000,
69 MV_PCS_CSCR1_MDIX_MDIX = 0x0020,
70 MV_PCS_CSCR1_MDIX_AUTO = 0x0060,
71
72 MV_PCS_DSC1 = 0x8003,
73 MV_PCS_DSC1_ENABLE = BIT(9),
74 MV_PCS_DSC1_10GBT = 0x01c0,
75 MV_PCS_DSC1_1GBR = 0x0038,
76 MV_PCS_DSC1_100BTX = 0x0007,
77 MV_PCS_DSC2 = 0x8004,
78 MV_PCS_DSC2_2P5G = 0xf000,
79 MV_PCS_DSC2_5G = 0x0f00,
80
81 MV_PCS_CSSR1 = 0x8008,
82 MV_PCS_CSSR1_SPD1_MASK = 0xc000,
83 MV_PCS_CSSR1_SPD1_SPD2 = 0xc000,
84 MV_PCS_CSSR1_SPD1_1000 = 0x8000,
85 MV_PCS_CSSR1_SPD1_100 = 0x4000,
86 MV_PCS_CSSR1_SPD1_10 = 0x0000,
87 MV_PCS_CSSR1_DUPLEX_FULL = BIT(13),
88 MV_PCS_CSSR1_RESOLVED = BIT(11),
89 MV_PCS_CSSR1_MDIX = BIT(6),
90 MV_PCS_CSSR1_SPD2_MASK = 0x000c,
91 MV_PCS_CSSR1_SPD2_5000 = 0x0008,
92 MV_PCS_CSSR1_SPD2_2500 = 0x0004,
93 MV_PCS_CSSR1_SPD2_10000 = 0x0000,
94
95 /* Temperature read register (88E2110 only) */
96 MV_PCS_TEMP = 0x8042,
97
98 /* Number of ports on the device */
99 MV_PCS_PORT_INFO = 0xd00d,
100 MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380,
101 MV_PCS_PORT_INFO_NPORTS_SHIFT = 7,
102
103 /* SerDes reinitialization 88E21X0 */
104 MV_AN_21X0_SERDES_CTRL2 = 0x800f,
105 MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13),
106 MV_AN_21X0_SERDES_CTRL2_RUN_INIT = BIT(15),
107
108 /* These registers appear at 0x800X and 0xa00X - the 0xa00X control
109 * registers appear to set themselves to the 0x800X when AN is
110 * restarted, but status registers appear readable from either.
111 */
112 MV_AN_CTRL1000 = 0x8000, /* 1000base-T control register */
113 MV_AN_STAT1000 = 0x8001, /* 1000base-T status register */
114
115 /* Vendor2 MMD registers */
116 MV_V2_PORT_CTRL = 0xf001,
117 MV_V2_PORT_CTRL_PWRDOWN = BIT(11),
118 MV_V2_33X0_PORT_CTRL_SWRST = BIT(15),
119 MV_V2_33X0_PORT_CTRL_MACTYPE_MASK = 0x7,
120 MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI = 0x0,
121 MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH = 0x1,
122 MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN = 0x1,
123 MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH = 0x2,
124 MV_V2_3310_PORT_CTRL_MACTYPE_XAUI = 0x3,
125 MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER = 0x4,
126 MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5,
127 MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
128 MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7,
129 MV_V2_PORT_INTR_STS = 0xf040,
130 MV_V2_PORT_INTR_MASK = 0xf043,
131 MV_V2_PORT_INTR_STS_WOL_EN = BIT(8),
132 MV_V2_MAGIC_PKT_WORD0 = 0xf06b,
133 MV_V2_MAGIC_PKT_WORD1 = 0xf06c,
134 MV_V2_MAGIC_PKT_WORD2 = 0xf06d,
135 /* Wake on LAN registers */
136 MV_V2_WOL_CTRL = 0xf06e,
137 MV_V2_WOL_CTRL_CLEAR_STS = BIT(15),
138 MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0),
139 /* Temperature control/read registers (88X3310 only) */
140 MV_V2_TEMP_CTRL = 0xf08a,
141 MV_V2_TEMP_CTRL_MASK = 0xc000,
142 MV_V2_TEMP_CTRL_SAMPLE = 0x0000,
143 MV_V2_TEMP_CTRL_DISABLE = 0xc000,
144 MV_V2_TEMP = 0xf08c,
145 MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */
146};
147
148struct mv3310_chip {
149 bool (*has_downshift)(struct phy_device *phydev);
150 int (*test_supported_interfaces)(struct phy_device *phydev);
151 int (*get_mactype)(struct phy_device *phydev);
152 int (*set_mactype)(struct phy_device *phydev, int mactype);
153 int (*select_mactype)(struct phy_device *phydev);
154 int (*init_interface)(struct phy_device *phydev, int mactype);
155};
156
157struct mv3310_priv {
158 DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
159
160 u32 firmware_ver;
161 bool has_downshift;
162 bool rate_match;
163};
164
165static const struct mv3310_chip *to_mv3310_chip(struct phy_device *phydev)
166{
167 return (const struct mv3310_chip *)phydev->drv->data;
168}
169
170static int mv3310_power_down(struct phy_device *phydev)
171{
172 return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
173 MV_V2_PORT_CTRL_PWRDOWN);
174}
175
176static int mv3310_power_up(struct phy_device *phydev)
177{
178 struct mv3310_priv *priv = (struct mv3310_priv *)phydev->priv;
179 int ret;
180
181 ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
182 MV_V2_PORT_CTRL_PWRDOWN);
183
184 if (phydev->drv->uid != MARVELL_PHY_ID_88X3310 ||
185 priv->firmware_ver < 0x00030000)
186 return ret;
187
188 return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
189 MV_V2_33X0_PORT_CTRL_SWRST);
190}
191
192static int mv3310_reset(struct phy_device *phydev, u32 unit)
193{
194 int val, err;
195
196 err = phy_modify_mmd(phydev, MDIO_MMD_PCS, unit + MDIO_CTRL1,
197 MDIO_CTRL1_RESET, MDIO_CTRL1_RESET);
198 if (err < 0)
199 return err;
200
201 return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS,
202 unit + MDIO_CTRL1, val,
203 !(val & MDIO_CTRL1_RESET),
204 5000, 100000, true);
205}
206
207static int mv3310_set_downshift(struct phy_device *phydev)
208{
209 struct mv3310_priv *priv = (struct mv3310_priv *)phydev->priv;
210 const u8 ds = 1;
211 u16 val;
212 int err;
213
214 if (!priv->has_downshift)
215 return -EOPNOTSUPP;
216
217 val = FIELD_PREP(MV_PCS_DSC2_2P5G, ds);
218 val |= FIELD_PREP(MV_PCS_DSC2_5G, ds);
219 err = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC2,
220 MV_PCS_DSC2_2P5G | MV_PCS_DSC2_5G, val);
221 if (err < 0)
222 return err;
223
224 val = MV_PCS_DSC1_ENABLE;
225 val |= FIELD_PREP(MV_PCS_DSC1_10GBT, ds);
226 val |= FIELD_PREP(MV_PCS_DSC1_1GBR, ds);
227 val |= FIELD_PREP(MV_PCS_DSC1_100BTX, ds);
228
229 return phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
230 MV_PCS_DSC1_ENABLE | MV_PCS_DSC1_10GBT |
231 MV_PCS_DSC1_1GBR | MV_PCS_DSC1_100BTX, val);
232}
233
234static int mv3310_set_edpd(struct phy_device *phydev)
235{
236 int err;
237
238 err = phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, MV_PCS_CSCR1,
239 MV_PCS_CSCR1_ED_MASK,
240 MV_PCS_CSCR1_ED_NLP);
241 if (err > 0)
242 err = mv3310_reset(phydev, MV_PCS_BASE_T);
243
244 return err;
245}
246
247static int mv3310_probe(struct phy_device *phydev)
248{
249 const struct mv3310_chip *chip = to_mv3310_chip(phydev);
250 struct mv3310_priv *priv;
251 u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
252 int ret;
253
254 if (!phydev->is_c45 ||
255 (phydev->mmds & mmd_mask) != mmd_mask)
256 return -ENODEV;
257
258 ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT);
259 if (ret < 0)
260 return ret;
261
262 if (ret & MV_PMA_BOOT_FATAL) {
263 dev_warn(phydev->dev,
264 "PHY failed to boot firmware, status=%04x\n", ret);
265 return -ENODEV;
266 }
267
268 priv = devm_kzalloc(phydev->dev, sizeof(*priv), GFP_KERNEL);
269 if (!priv)
270 return -ENOMEM;
271
272 phydev->priv = priv;
273
274 ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_FW_VER0);
275 if (ret < 0)
276 return ret;
277
278 priv->firmware_ver = ret << 16;
279
280 ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_FW_VER1);
281 if (ret < 0)
282 return ret;
283
284 priv->firmware_ver |= ret;
285
286 dev_info(phydev->dev, "Firmware version %u.%u.%u.%u\n",
287 priv->firmware_ver >> 24, (priv->firmware_ver >> 16) & 255,
288 (priv->firmware_ver >> 8) & 255, priv->firmware_ver & 255);
289
290 if (chip->has_downshift)
291 priv->has_downshift = chip->has_downshift(phydev);
292
293 /* Powering down the port when not in use saves about 600mW */
294 ret = mv3310_power_down(phydev);
295 if (ret)
296 return ret;
297
298 return 0;
299}
300
301static int mv2110_get_mactype(struct phy_device *phydev)
302{
303 int mactype;
304
305 mactype = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL);
306 if (mactype < 0)
307 return mactype;
308
309 return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
310}
311
312static int mv2110_set_mactype(struct phy_device *phydev, int mactype)
313{
314 int err, val;
315
316 mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
317 err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL,
318 MV_PMA_21X0_PORT_CTRL_SWRST |
319 MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK,
320 MV_PMA_21X0_PORT_CTRL_SWRST | mactype);
321 if (err)
322 return err;
323
324 err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
325 MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS |
326 MV_AN_21X0_SERDES_CTRL2_RUN_INIT);
327 if (err)
328 return err;
329
330 err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN,
331 MV_AN_21X0_SERDES_CTRL2, val,
332 !(val &
333 MV_AN_21X0_SERDES_CTRL2_RUN_INIT),
334 5000, 100000, true);
335 if (err)
336 return err;
337
338 return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
339 MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS);
340}
341
342static int mv2110_select_mactype(struct phy_device *phydev)
343{
344 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII)
345 return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII;
346 else if (phydev->interface == PHY_INTERFACE_MODE_SGMII &&
347 !(phydev->interface == PHY_INTERFACE_MODE_10GBASER))
348 return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER;
349 else if (phydev->interface == PHY_INTERFACE_MODE_10GBASER)
350 return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
351 else
352 return -1;
353}
354
355static int mv3310_get_mactype(struct phy_device *phydev)
356{
357 int mactype;
358
359 mactype = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL);
360 if (mactype < 0)
361 return mactype;
362
363 return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
364}
365
366static int mv3310_set_mactype(struct phy_device *phydev, int mactype)
367{
368 int ret;
369
370 mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
371 ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
372 MV_V2_33X0_PORT_CTRL_MACTYPE_MASK,
373 mactype);
374 if (ret <= 0)
375 return ret;
376
377 return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
378 MV_V2_33X0_PORT_CTRL_SWRST);
379}
380
381static int mv3310_select_mactype(struct phy_device *phydev)
382{
383 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII)
384 return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
385 else if (phydev->interface == PHY_INTERFACE_MODE_SGMII &&
386 phydev->interface == PHY_INTERFACE_MODE_10GBASER)
387 return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
388 else if (phydev->interface == PHY_INTERFACE_MODE_SGMII &&
389 phydev->interface == PHY_INTERFACE_MODE_RXAUI)
390 return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
391 else if (phydev->interface == PHY_INTERFACE_MODE_SGMII &&
392 phydev->interface == PHY_INTERFACE_MODE_XAUI)
393 return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
394 else if (phydev->interface == PHY_INTERFACE_MODE_10GBASER)
395 return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
396 else if (phydev->interface == PHY_INTERFACE_MODE_RXAUI)
397 return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
398 else if (phydev->interface == PHY_INTERFACE_MODE_XAUI)
399 return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
400 else if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
401 return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
402 else
403 return -1;
404}
405
406static int mv2110_init_interface(struct phy_device *phydev, int mactype)
407{
408 struct mv3310_priv *priv = (struct mv3310_priv *)phydev->priv;
409
410 priv->rate_match = false;
411
412 if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH)
413 priv->rate_match = true;
414
415 return 0;
416}
417
418static int mv3310_init_interface(struct phy_device *phydev, int mactype)
419{
420 struct mv3310_priv *priv = (struct mv3310_priv *)phydev->priv;
421
422 priv->rate_match = false;
423
424 if (mactype != MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN)
425 return 0;
426
427 if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH ||
428 mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH ||
429 mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH)
430 priv->rate_match = true;
431
432 return 0;
433}
434
435static int mv3310_config_init(struct phy_device *phydev)
436{
437 const struct mv3310_chip *chip = to_mv3310_chip(phydev);
438 int err, mactype;
439
440 /* Check that the PHY interface type is compatible */
441 err = chip->test_supported_interfaces(phydev);
442 if (err)
443 return err;
444
445 /* Power up so reset works */
446 err = mv3310_power_up(phydev);
447 if (err)
448 return err;
449
450 /* If host provided host supported interface modes, try to select the
451 * best one
452 */
453 mactype = chip->select_mactype(phydev);
454 if (mactype >= 0) {
455 dev_info(phydev->dev, "Changing MACTYPE to %i\n",
456 mactype);
457 err = chip->set_mactype(phydev, mactype);
458 if (err)
459 return err;
460 }
461
462 mactype = chip->get_mactype(phydev);
463 if (mactype < 0)
464 return mactype;
465
466 err = chip->init_interface(phydev, mactype);
467 if (err) {
468 dev_err(phydev->dev, "MACTYPE configuration invalid\n");
469 return err;
470 }
471
472 /* Enable EDPD mode - saving 600mW */
473 err = mv3310_set_edpd(phydev);
474 if (err)
475 return err;
476
477 /* Allow downshift */
478 err = mv3310_set_downshift(phydev);
479 if (err && err != -EOPNOTSUPP)
480 return err;
481
482 return 0;
483}
484
485static int mv3310_config(struct phy_device *phydev)
486{
487 int err;
488
489 err = mv3310_probe(phydev);
490 if (!err)
491 err = mv3310_config_init(phydev);
492
493 return err;
494}
495
496static int mv3310_get_number_of_ports(struct phy_device *phydev)
497{
498 int ret;
499
500 ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PORT_INFO);
501 if (ret < 0)
502 return ret;
503
504 ret &= MV_PCS_PORT_INFO_NPORTS_MASK;
505 ret >>= MV_PCS_PORT_INFO_NPORTS_SHIFT;
506
507 return ret + 1;
508}
509
510static int mv3310_match_phy_device(struct phy_device *phydev)
511{
512 if ((phydev->phy_id & MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310)
513 return 0;
514
515 return mv3310_get_number_of_ports(phydev) == 1;
516}
517
518static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g)
519{
520 int val;
521
522 if ((phydev->phy_id & MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88E2110)
523 return 0;
524
525 val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_SPEED);
526 if (val < 0)
527 return val;
528
529 return !!(val & MDIO_PCS_SPEED_5G) == has_5g;
530}
531
532static int mv2110_match_phy_device(struct phy_device *phydev)
533{
534 return mv211x_match_phy_device(phydev, true);
535}
536
537static bool mv3310_has_downshift(struct phy_device *phydev)
538{
539 struct mv3310_priv *priv = (struct mv3310_priv *)phydev->priv;
540
541 /* Fails to downshift with firmware older than v0.3.5.0 */
542 return priv->firmware_ver >= MV_VERSION(0, 3, 5, 0);
543}
544
545#define mv_test_bit(iface, phydev) \
546 ({ if ((phydev)->interface & (iface)) return 0; })
547
548static int mv3310_mv3340_test_supported_interfaces(struct phy_device *phydev)
549{
550 mv_test_bit(PHY_INTERFACE_MODE_SGMII, phydev);
551 mv_test_bit(PHY_INTERFACE_MODE_2500BASEX, phydev);
552 mv_test_bit(PHY_INTERFACE_MODE_5GBASER, phydev);
553 if (mv3310_match_phy_device(phydev))
554 mv_test_bit(PHY_INTERFACE_MODE_XAUI, phydev);
555 mv_test_bit(PHY_INTERFACE_MODE_RXAUI, phydev);
556 mv_test_bit(PHY_INTERFACE_MODE_10GBASER, phydev);
557 mv_test_bit(PHY_INTERFACE_MODE_USXGMII, phydev);
558 return -ENODEV;
559}
560
561static int mv2110_mv2111_test_supported_interfaces(struct phy_device *phydev)
562{
563 mv_test_bit(PHY_INTERFACE_MODE_SGMII, phydev);
564 mv_test_bit(PHY_INTERFACE_MODE_2500BASEX, phydev);
565 if (mv2110_match_phy_device(phydev))
566 mv_test_bit(PHY_INTERFACE_MODE_5GBASER, phydev);
567 mv_test_bit(PHY_INTERFACE_MODE_10GBASER, phydev);
568 mv_test_bit(PHY_INTERFACE_MODE_USXGMII, phydev);
569 return -ENODEV;
570}
571
572static const struct mv3310_chip mv3310_mv3340_type = {
573 .has_downshift = mv3310_has_downshift,
574 .test_supported_interfaces = mv3310_mv3340_test_supported_interfaces,
575 .get_mactype = mv3310_get_mactype,
576 .set_mactype = mv3310_set_mactype,
577 .select_mactype = mv3310_select_mactype,
578 .init_interface = mv3310_init_interface,
579};
580
581static const struct mv3310_chip mv2110_mv2111_type = {
582 .test_supported_interfaces = mv2110_mv2111_test_supported_interfaces,
583 .get_mactype = mv2110_get_mactype,
584 .set_mactype = mv2110_set_mactype,
585 .select_mactype = mv2110_select_mactype,
586 .init_interface = mv2110_init_interface,
587};
588
589U_BOOT_PHY_DRIVER(mv88e3310_mv88e3340) = {
590 .name = "mv88x3310",
591 .uid = MARVELL_PHY_ID_88X3310,
592 .mask = MARVELL_PHY_ID_MASK,
593 .features = PHY_10G_FEATURES,
594 .data = (ulong)&mv3310_mv3340_type,
595 .config = mv3310_config,
596};
597
598U_BOOT_PHY_DRIVER(mv88e2110_mv88e2111) = {
599 .name = "mv88e2110",
600 .uid = MARVELL_PHY_ID_88E2110,
601 .mask = MARVELL_PHY_ID_MASK,
602 .features = PHY_10G_FEATURES,
603 .data = (ulong)&mv2110_mv2111_type,
604 .config = mv3310_config,
605};