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