xref: /rk3399_rockchip-uboot/drivers/net/phy/teranetics.c (revision 326ea986ac150acdc7656d57fca647db80b50158)
19082eeacSAndy Fleming /*
29082eeacSAndy Fleming  * Teranetics PHY drivers
39082eeacSAndy Fleming  *
4*1a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
59082eeacSAndy Fleming  *
69082eeacSAndy Fleming  * Copyright 2010-2011 Freescale Semiconductor, Inc.
79082eeacSAndy Fleming  * author Andy Fleming
89082eeacSAndy Fleming  */
99082eeacSAndy Fleming #include <config.h>
102339e497STimur Tabi #include <common.h>
119082eeacSAndy Fleming #include <phy.h>
129082eeacSAndy Fleming 
139082eeacSAndy Fleming #ifndef CONFIG_PHYLIB_10G
149082eeacSAndy Fleming #error The Teranetics PHY needs 10G support
159082eeacSAndy Fleming #endif
169082eeacSAndy Fleming 
tn2020_config(struct phy_device * phydev)179082eeacSAndy Fleming int tn2020_config(struct phy_device *phydev)
189082eeacSAndy Fleming {
199082eeacSAndy Fleming 	if (phydev->port == PORT_FIBRE) {
209082eeacSAndy Fleming 		unsigned short restart_an = (MDIO_AN_CTRL1_RESTART |
219082eeacSAndy Fleming 						MDIO_AN_CTRL1_ENABLE |
229082eeacSAndy Fleming 						MDIO_AN_CTRL1_XNP);
23d54097b6SShaohui Xie 		u8 phy_hwversion;
249082eeacSAndy Fleming 
25d54097b6SShaohui Xie 		/*
26d54097b6SShaohui Xie 		 * bit 15:12 of register 30.32 indicates PHY hardware
27d54097b6SShaohui Xie 		 * version. It can be used to distinguish TN80xx from
28d54097b6SShaohui Xie 		 * TN2020. TN2020 needs write 0x2 to 30.93, but TN80xx
29d54097b6SShaohui Xie 		 * needs 0x1.
30d54097b6SShaohui Xie 		 */
31d54097b6SShaohui Xie 		phy_hwversion = (phy_read(phydev, 30, 32) >> 12) & 0xf;
32d54097b6SShaohui Xie 		if (phy_hwversion <= 3) {
339082eeacSAndy Fleming 			phy_write(phydev, 30, 93, 2);
349082eeacSAndy Fleming 			phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an);
35d54097b6SShaohui Xie 		} else {
36d54097b6SShaohui Xie 			phy_write(phydev, 30, 93, 1);
37d54097b6SShaohui Xie 		}
389082eeacSAndy Fleming 	}
399082eeacSAndy Fleming 
409082eeacSAndy Fleming 	return 0;
419082eeacSAndy Fleming }
429082eeacSAndy Fleming 
tn2020_startup(struct phy_device * phydev)43ebfdacb4SAndy Fleming int tn2020_startup(struct phy_device *phydev)
44ebfdacb4SAndy Fleming {
452339e497STimur Tabi 	unsigned int timeout = 5 * 1000; /* 5 second timeout */
462339e497STimur Tabi 
472339e497STimur Tabi #define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \
482339e497STimur Tabi 			       MDIO_PHYXS_LNSTAT_SYNC1 | \
492339e497STimur Tabi 			       MDIO_PHYXS_LNSTAT_SYNC2 | \
502339e497STimur Tabi 			       MDIO_PHYXS_LNSTAT_SYNC3 | \
512339e497STimur Tabi 			       MDIO_PHYXS_LNSTAT_ALIGN)
522339e497STimur Tabi 
532339e497STimur Tabi 	/*
542339e497STimur Tabi 	 * Wait for the XAUI-SERDES lanes to align first.  Under normal
552339e497STimur Tabi 	 * circumstances, this can take up to three seconds.
562339e497STimur Tabi 	 */
572339e497STimur Tabi 	while (--timeout) {
582339e497STimur Tabi 		int reg = phy_read(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT);
592339e497STimur Tabi 		if (reg < 0) {
602339e497STimur Tabi 			printf("TN2020: Error reading from PHY at "
612339e497STimur Tabi 			       "address %u\n", phydev->addr);
622339e497STimur Tabi 			break;
632339e497STimur Tabi 		}
642339e497STimur Tabi 		if ((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)
652339e497STimur Tabi 			break;
662339e497STimur Tabi 		udelay(1000);
672339e497STimur Tabi 	}
682339e497STimur Tabi 	if (!timeout) {
692339e497STimur Tabi 		/*
702339e497STimur Tabi 		 * A timeout is bad, but it may not be fatal, so don't
712339e497STimur Tabi 		 * return an error.  Display a warning instead.
722339e497STimur Tabi 		 */
732339e497STimur Tabi 		printf("TN2020: Timeout waiting for PHY at address %u to "
742339e497STimur Tabi 		       "align.\n", phydev->addr);
752339e497STimur Tabi 	}
762339e497STimur Tabi 
77ebfdacb4SAndy Fleming 	if (phydev->port != PORT_FIBRE)
78ebfdacb4SAndy Fleming 		return gen10g_startup(phydev);
79ebfdacb4SAndy Fleming 
80ebfdacb4SAndy Fleming 	/*
81ebfdacb4SAndy Fleming 	 * The TN2020 only pretends to support fiber.
82ebfdacb4SAndy Fleming 	 * It works, but it doesn't look like it works,
83ebfdacb4SAndy Fleming 	 * so the link status reports no link.
84ebfdacb4SAndy Fleming 	 */
85ebfdacb4SAndy Fleming 	phydev->link = 1;
86ebfdacb4SAndy Fleming 
87ebfdacb4SAndy Fleming 	/* For now just lie and say it's 10G all the time */
88ebfdacb4SAndy Fleming 	phydev->speed = SPEED_10000;
89ebfdacb4SAndy Fleming 	phydev->duplex = DUPLEX_FULL;
90ebfdacb4SAndy Fleming 
91ebfdacb4SAndy Fleming 	return 0;
92ebfdacb4SAndy Fleming }
93ebfdacb4SAndy Fleming 
949082eeacSAndy Fleming struct phy_driver tn2020_driver = {
959082eeacSAndy Fleming 	.name = "Teranetics TN2020",
96a836626cSTimur Tabi 	.uid = PHY_UID_TN2020,
979082eeacSAndy Fleming 	.mask = 0xfffffff0,
989082eeacSAndy Fleming 	.features = PHY_10G_FEATURES,
999082eeacSAndy Fleming 	.mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
1009082eeacSAndy Fleming 			MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
1019082eeacSAndy Fleming 			MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
1029082eeacSAndy Fleming 	.config = &tn2020_config,
103ebfdacb4SAndy Fleming 	.startup = &tn2020_startup,
1049082eeacSAndy Fleming 	.shutdown = &gen10g_shutdown,
1059082eeacSAndy Fleming };
1069082eeacSAndy Fleming 
phy_teranetics_init(void)1079082eeacSAndy Fleming int phy_teranetics_init(void)
1089082eeacSAndy Fleming {
1099082eeacSAndy Fleming 	phy_register(&tn2020_driver);
1109082eeacSAndy Fleming 
1119082eeacSAndy Fleming 	return 0;
1129082eeacSAndy Fleming }
113