xref: /openbmc/u-boot/drivers/net/phy/teranetics.c (revision 2f3f477b)
1 /*
2  * Teranetics PHY drivers
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  *
6  * Copyright 2010-2011 Freescale Semiconductor, Inc.
7  * author Andy Fleming
8  */
9 #include <config.h>
10 #include <common.h>
11 #include <phy.h>
12 
13 #ifndef CONFIG_PHYLIB_10G
14 #error The Teranetics PHY needs 10G support
15 #endif
16 
17 int tn2020_config(struct phy_device *phydev)
18 {
19 	if (phydev->port == PORT_FIBRE) {
20 		unsigned short restart_an = (MDIO_AN_CTRL1_RESTART |
21 						MDIO_AN_CTRL1_ENABLE |
22 						MDIO_AN_CTRL1_XNP);
23 		u8 phy_hwversion;
24 
25 		/*
26 		 * bit 15:12 of register 30.32 indicates PHY hardware
27 		 * version. It can be used to distinguish TN80xx from
28 		 * TN2020. TN2020 needs write 0x2 to 30.93, but TN80xx
29 		 * needs 0x1.
30 		 */
31 		phy_hwversion = (phy_read(phydev, 30, 32) >> 12) & 0xf;
32 		if (phy_hwversion <= 3) {
33 			phy_write(phydev, 30, 93, 2);
34 			phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an);
35 		} else {
36 			phy_write(phydev, 30, 93, 1);
37 		}
38 	}
39 
40 	return 0;
41 }
42 
43 int tn2020_startup(struct phy_device *phydev)
44 {
45 	unsigned int timeout = 5 * 1000; /* 5 second timeout */
46 
47 #define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \
48 			       MDIO_PHYXS_LNSTAT_SYNC1 | \
49 			       MDIO_PHYXS_LNSTAT_SYNC2 | \
50 			       MDIO_PHYXS_LNSTAT_SYNC3 | \
51 			       MDIO_PHYXS_LNSTAT_ALIGN)
52 
53 	/*
54 	 * Wait for the XAUI-SERDES lanes to align first.  Under normal
55 	 * circumstances, this can take up to three seconds.
56 	 */
57 	while (--timeout) {
58 		int reg = phy_read(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT);
59 		if (reg < 0) {
60 			printf("TN2020: Error reading from PHY at "
61 			       "address %u\n", phydev->addr);
62 			break;
63 		}
64 		if ((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)
65 			break;
66 		udelay(1000);
67 	}
68 	if (!timeout) {
69 		/*
70 		 * A timeout is bad, but it may not be fatal, so don't
71 		 * return an error.  Display a warning instead.
72 		 */
73 		printf("TN2020: Timeout waiting for PHY at address %u to "
74 		       "align.\n", phydev->addr);
75 	}
76 
77 	if (phydev->port != PORT_FIBRE)
78 		return gen10g_startup(phydev);
79 
80 	/*
81 	 * The TN2020 only pretends to support fiber.
82 	 * It works, but it doesn't look like it works,
83 	 * so the link status reports no link.
84 	 */
85 	phydev->link = 1;
86 
87 	/* For now just lie and say it's 10G all the time */
88 	phydev->speed = SPEED_10000;
89 	phydev->duplex = DUPLEX_FULL;
90 
91 	return 0;
92 }
93 
94 struct phy_driver tn2020_driver = {
95 	.name = "Teranetics TN2020",
96 	.uid = PHY_UID_TN2020,
97 	.mask = 0xfffffff0,
98 	.features = PHY_10G_FEATURES,
99 	.mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
100 			MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
101 			MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
102 	.config = &tn2020_config,
103 	.startup = &tn2020_startup,
104 	.shutdown = &gen10g_shutdown,
105 };
106 
107 int phy_teranetics_init(void)
108 {
109 	phy_register(&tn2020_driver);
110 
111 	return 0;
112 }
113