aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/phy/adin.c117
1 files changed, 113 insertions, 4 deletions
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 4ca685780622..51c0d17577de 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -19,6 +19,10 @@
19#define ADIN1300_MII_EXT_REG_PTR 0x0010 19#define ADIN1300_MII_EXT_REG_PTR 0x0010
20#define ADIN1300_MII_EXT_REG_DATA 0x0011 20#define ADIN1300_MII_EXT_REG_DATA 0x0011
21 21
22#define ADIN1300_PHY_CTRL1 0x0012
23#define ADIN1300_AUTO_MDI_EN BIT(10)
24#define ADIN1300_MAN_MDIX_EN BIT(9)
25
22#define ADIN1300_INT_MASK_REG 0x0018 26#define ADIN1300_INT_MASK_REG 0x0018
23#define ADIN1300_INT_MDIO_SYNC_EN BIT(9) 27#define ADIN1300_INT_MDIO_SYNC_EN BIT(9)
24#define ADIN1300_INT_ANEG_STAT_CHNG_EN BIT(8) 28#define ADIN1300_INT_ANEG_STAT_CHNG_EN BIT(8)
@@ -33,6 +37,9 @@
33 (ADIN1300_INT_LINK_STAT_CHNG_EN | ADIN1300_INT_HW_IRQ_EN) 37 (ADIN1300_INT_LINK_STAT_CHNG_EN | ADIN1300_INT_HW_IRQ_EN)
34#define ADIN1300_INT_STATUS_REG 0x0019 38#define ADIN1300_INT_STATUS_REG 0x0019
35 39
40#define ADIN1300_PHY_STATUS1 0x001a
41#define ADIN1300_PAIR_01_SWAP BIT(11)
42
36#define ADIN1300_GE_RGMII_CFG_REG 0xff23 43#define ADIN1300_GE_RGMII_CFG_REG 0xff23
37#define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6) 44#define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6)
38#define ADIN1300_GE_RGMII_RX_SEL(x) \ 45#define ADIN1300_GE_RGMII_RX_SEL(x) \
@@ -206,6 +213,8 @@ static int adin_config_init(struct phy_device *phydev)
206{ 213{
207 int rc; 214 int rc;
208 215
216 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
217
209 rc = genphy_config_init(phydev); 218 rc = genphy_config_init(phydev);
210 if (rc < 0) 219 if (rc < 0)
211 return rc; 220 return rc;
@@ -269,13 +278,113 @@ static int adin_write_mmd(struct phy_device *phydev, int devad, u16 regnum,
269 return __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_DATA, val); 278 return __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_DATA, val);
270} 279}
271 280
281static int adin_config_mdix(struct phy_device *phydev)
282{
283 bool auto_en, mdix_en;
284 int reg;
285
286 mdix_en = false;
287 auto_en = false;
288 switch (phydev->mdix_ctrl) {
289 case ETH_TP_MDI:
290 break;
291 case ETH_TP_MDI_X:
292 mdix_en = true;
293 break;
294 case ETH_TP_MDI_AUTO:
295 auto_en = true;
296 break;
297 default:
298 return -EINVAL;
299 }
300
301 reg = phy_read(phydev, ADIN1300_PHY_CTRL1);
302 if (reg < 0)
303 return reg;
304
305 if (mdix_en)
306 reg |= ADIN1300_MAN_MDIX_EN;
307 else
308 reg &= ~ADIN1300_MAN_MDIX_EN;
309
310 if (auto_en)
311 reg |= ADIN1300_AUTO_MDI_EN;
312 else
313 reg &= ~ADIN1300_AUTO_MDI_EN;
314
315 return phy_write(phydev, ADIN1300_PHY_CTRL1, reg);
316}
317
318static int adin_config_aneg(struct phy_device *phydev)
319{
320 int ret;
321
322 ret = adin_config_mdix(phydev);
323 if (ret)
324 return ret;
325
326 return genphy_config_aneg(phydev);
327}
328
329static int adin_mdix_update(struct phy_device *phydev)
330{
331 bool auto_en, mdix_en;
332 bool swapped;
333 int reg;
334
335 reg = phy_read(phydev, ADIN1300_PHY_CTRL1);
336 if (reg < 0)
337 return reg;
338
339 auto_en = !!(reg & ADIN1300_AUTO_MDI_EN);
340 mdix_en = !!(reg & ADIN1300_MAN_MDIX_EN);
341
342 /* If MDI/MDIX is forced, just read it from the control reg */
343 if (!auto_en) {
344 if (mdix_en)
345 phydev->mdix = ETH_TP_MDI_X;
346 else
347 phydev->mdix = ETH_TP_MDI;
348 return 0;
349 }
350
351 /**
352 * Otherwise, we need to deduce it from the PHY status2 reg.
353 * When Auto-MDI is enabled, the ADIN1300_MAN_MDIX_EN bit implies
354 * a preference for MDIX when it is set.
355 */
356 reg = phy_read(phydev, ADIN1300_PHY_STATUS1);
357 if (reg < 0)
358 return reg;
359
360 swapped = !!(reg & ADIN1300_PAIR_01_SWAP);
361
362 if (mdix_en != swapped)
363 phydev->mdix = ETH_TP_MDI_X;
364 else
365 phydev->mdix = ETH_TP_MDI;
366
367 return 0;
368}
369
370static int adin_read_status(struct phy_device *phydev)
371{
372 int ret;
373
374 ret = adin_mdix_update(phydev);
375 if (ret < 0)
376 return ret;
377
378 return genphy_read_status(phydev);
379}
380
272static struct phy_driver adin_driver[] = { 381static struct phy_driver adin_driver[] = {
273 { 382 {
274 PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200), 383 PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200),
275 .name = "ADIN1200", 384 .name = "ADIN1200",
276 .config_init = adin_config_init, 385 .config_init = adin_config_init,
277 .config_aneg = genphy_config_aneg, 386 .config_aneg = adin_config_aneg,
278 .read_status = genphy_read_status, 387 .read_status = adin_read_status,
279 .ack_interrupt = adin_phy_ack_intr, 388 .ack_interrupt = adin_phy_ack_intr,
280 .config_intr = adin_phy_config_intr, 389 .config_intr = adin_phy_config_intr,
281 .resume = genphy_resume, 390 .resume = genphy_resume,
@@ -287,8 +396,8 @@ static struct phy_driver adin_driver[] = {
287 PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300), 396 PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300),
288 .name = "ADIN1300", 397 .name = "ADIN1300",
289 .config_init = adin_config_init, 398 .config_init = adin_config_init,
290 .config_aneg = genphy_config_aneg, 399 .config_aneg = adin_config_aneg,
291 .read_status = genphy_read_status, 400 .read_status = adin_read_status,
292 .ack_interrupt = adin_phy_ack_intr, 401 .ack_interrupt = adin_phy_ack_intr,
293 .config_intr = adin_phy_config_intr, 402 .config_intr = adin_phy_config_intr,
294 .resume = genphy_resume, 403 .resume = genphy_resume,