18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#include "common.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* VSC8211 PHY specific registers. */ 358c2ecf20Sopenharmony_cienum { 368c2ecf20Sopenharmony_ci VSC8211_SIGDET_CTRL = 19, 378c2ecf20Sopenharmony_ci VSC8211_EXT_CTRL = 23, 388c2ecf20Sopenharmony_ci VSC8211_INTR_ENABLE = 25, 398c2ecf20Sopenharmony_ci VSC8211_INTR_STATUS = 26, 408c2ecf20Sopenharmony_ci VSC8211_LED_CTRL = 27, 418c2ecf20Sopenharmony_ci VSC8211_AUX_CTRL_STAT = 28, 428c2ecf20Sopenharmony_ci VSC8211_EXT_PAGE_AXS = 31, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cienum { 468c2ecf20Sopenharmony_ci VSC_INTR_RX_ERR = 1 << 0, 478c2ecf20Sopenharmony_ci VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ 488c2ecf20Sopenharmony_ci VSC_INTR_CABLE = 1 << 2, /* cable impairment */ 498c2ecf20Sopenharmony_ci VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ 508c2ecf20Sopenharmony_ci VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ 518c2ecf20Sopenharmony_ci VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ 528c2ecf20Sopenharmony_ci VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ 538c2ecf20Sopenharmony_ci VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ 548c2ecf20Sopenharmony_ci VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ 558c2ecf20Sopenharmony_ci VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ 568c2ecf20Sopenharmony_ci VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ 578c2ecf20Sopenharmony_ci VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ 588c2ecf20Sopenharmony_ci VSC_INTR_LINK_CHG = 1 << 13, /* link change */ 598c2ecf20Sopenharmony_ci VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ 608c2ecf20Sopenharmony_ci VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cienum { 648c2ecf20Sopenharmony_ci VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ 658c2ecf20Sopenharmony_ci VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ 698c2ecf20Sopenharmony_ci VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ 708c2ecf20Sopenharmony_ci VSC_INTR_NEG_DONE) 718c2ecf20Sopenharmony_ci#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ 728c2ecf20Sopenharmony_ci VSC_INTR_ENABLE) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* PHY specific auxiliary control & status register fields */ 758c2ecf20Sopenharmony_ci#define S_ACSR_ACTIPHY_TMR 0 768c2ecf20Sopenharmony_ci#define M_ACSR_ACTIPHY_TMR 0x3 778c2ecf20Sopenharmony_ci#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define S_ACSR_SPEED 3 808c2ecf20Sopenharmony_ci#define M_ACSR_SPEED 0x3 818c2ecf20Sopenharmony_ci#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define S_ACSR_DUPLEX 5 848c2ecf20Sopenharmony_ci#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define S_ACSR_ACTIPHY 6 878c2ecf20Sopenharmony_ci#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Reset the PHY. This PHY completes reset immediately so we never wait. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic int vsc8211_reset(struct cphy *cphy, int wait) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int vsc8211_intr_enable(struct cphy *cphy) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 1008c2ecf20Sopenharmony_ci INTR_MASK); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int vsc8211_intr_disable(struct cphy *cphy) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int vsc8211_intr_clear(struct cphy *cphy) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u32 val; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Clear PHY interrupts by reading the register. */ 1138c2ecf20Sopenharmony_ci return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int vsc8211_autoneg_enable(struct cphy *cphy) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, 1198c2ecf20Sopenharmony_ci BMCR_PDOWN | BMCR_ISOLATE, 1208c2ecf20Sopenharmony_ci BMCR_ANENABLE | BMCR_ANRESTART); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int vsc8211_autoneg_restart(struct cphy *cphy) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, 1268c2ecf20Sopenharmony_ci BMCR_PDOWN | BMCR_ISOLATE, 1278c2ecf20Sopenharmony_ci BMCR_ANRESTART); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, 1318c2ecf20Sopenharmony_ci int *speed, int *duplex, int *fc) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci unsigned int bmcr, status, lpa, adv; 1348c2ecf20Sopenharmony_ci int err, sp = -1, dplx = -1, pause = 0; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); 1378c2ecf20Sopenharmony_ci if (!err) 1388c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); 1398c2ecf20Sopenharmony_ci if (err) 1408c2ecf20Sopenharmony_ci return err; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (link_ok) { 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 1458c2ecf20Sopenharmony_ci * once more to get the current link state. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (!(status & BMSR_LSTATUS)) 1488c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, 1498c2ecf20Sopenharmony_ci &status); 1508c2ecf20Sopenharmony_ci if (err) 1518c2ecf20Sopenharmony_ci return err; 1528c2ecf20Sopenharmony_ci *link_ok = (status & BMSR_LSTATUS) != 0; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci if (!(bmcr & BMCR_ANENABLE)) { 1558c2ecf20Sopenharmony_ci dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 1568c2ecf20Sopenharmony_ci if (bmcr & BMCR_SPEED1000) 1578c2ecf20Sopenharmony_ci sp = SPEED_1000; 1588c2ecf20Sopenharmony_ci else if (bmcr & BMCR_SPEED100) 1598c2ecf20Sopenharmony_ci sp = SPEED_100; 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci sp = SPEED_10; 1628c2ecf20Sopenharmony_ci } else if (status & BMSR_ANEGCOMPLETE) { 1638c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT, 1648c2ecf20Sopenharmony_ci &status); 1658c2ecf20Sopenharmony_ci if (err) 1668c2ecf20Sopenharmony_ci return err; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; 1698c2ecf20Sopenharmony_ci sp = G_ACSR_SPEED(status); 1708c2ecf20Sopenharmony_ci if (sp == 0) 1718c2ecf20Sopenharmony_ci sp = SPEED_10; 1728c2ecf20Sopenharmony_ci else if (sp == 1) 1738c2ecf20Sopenharmony_ci sp = SPEED_100; 1748c2ecf20Sopenharmony_ci else 1758c2ecf20Sopenharmony_ci sp = SPEED_1000; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (fc && dplx == DUPLEX_FULL) { 1788c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, 1798c2ecf20Sopenharmony_ci &lpa); 1808c2ecf20Sopenharmony_ci if (!err) 1818c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, 1828c2ecf20Sopenharmony_ci MII_ADVERTISE, &adv); 1838c2ecf20Sopenharmony_ci if (err) 1848c2ecf20Sopenharmony_ci return err; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (lpa & adv & ADVERTISE_PAUSE_CAP) 1878c2ecf20Sopenharmony_ci pause = PAUSE_RX | PAUSE_TX; 1888c2ecf20Sopenharmony_ci else if ((lpa & ADVERTISE_PAUSE_CAP) && 1898c2ecf20Sopenharmony_ci (lpa & ADVERTISE_PAUSE_ASYM) && 1908c2ecf20Sopenharmony_ci (adv & ADVERTISE_PAUSE_ASYM)) 1918c2ecf20Sopenharmony_ci pause = PAUSE_TX; 1928c2ecf20Sopenharmony_ci else if ((lpa & ADVERTISE_PAUSE_ASYM) && 1938c2ecf20Sopenharmony_ci (adv & ADVERTISE_PAUSE_CAP)) 1948c2ecf20Sopenharmony_ci pause = PAUSE_RX; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci if (speed) 1988c2ecf20Sopenharmony_ci *speed = sp; 1998c2ecf20Sopenharmony_ci if (duplex) 2008c2ecf20Sopenharmony_ci *duplex = dplx; 2018c2ecf20Sopenharmony_ci if (fc) 2028c2ecf20Sopenharmony_ci *fc = pause; 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, 2078c2ecf20Sopenharmony_ci int *speed, int *duplex, int *fc) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci unsigned int bmcr, status, lpa, adv; 2108c2ecf20Sopenharmony_ci int err, sp = -1, dplx = -1, pause = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); 2138c2ecf20Sopenharmony_ci if (!err) 2148c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); 2158c2ecf20Sopenharmony_ci if (err) 2168c2ecf20Sopenharmony_ci return err; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (link_ok) { 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 2218c2ecf20Sopenharmony_ci * once more to get the current link state. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci if (!(status & BMSR_LSTATUS)) 2248c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, 2258c2ecf20Sopenharmony_ci &status); 2268c2ecf20Sopenharmony_ci if (err) 2278c2ecf20Sopenharmony_ci return err; 2288c2ecf20Sopenharmony_ci *link_ok = (status & BMSR_LSTATUS) != 0; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci if (!(bmcr & BMCR_ANENABLE)) { 2318c2ecf20Sopenharmony_ci dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 2328c2ecf20Sopenharmony_ci if (bmcr & BMCR_SPEED1000) 2338c2ecf20Sopenharmony_ci sp = SPEED_1000; 2348c2ecf20Sopenharmony_ci else if (bmcr & BMCR_SPEED100) 2358c2ecf20Sopenharmony_ci sp = SPEED_100; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci sp = SPEED_10; 2388c2ecf20Sopenharmony_ci } else if (status & BMSR_ANEGCOMPLETE) { 2398c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa); 2408c2ecf20Sopenharmony_ci if (!err) 2418c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE, 2428c2ecf20Sopenharmony_ci &adv); 2438c2ecf20Sopenharmony_ci if (err) 2448c2ecf20Sopenharmony_ci return err; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (adv & lpa & ADVERTISE_1000XFULL) { 2478c2ecf20Sopenharmony_ci dplx = DUPLEX_FULL; 2488c2ecf20Sopenharmony_ci sp = SPEED_1000; 2498c2ecf20Sopenharmony_ci } else if (adv & lpa & ADVERTISE_1000XHALF) { 2508c2ecf20Sopenharmony_ci dplx = DUPLEX_HALF; 2518c2ecf20Sopenharmony_ci sp = SPEED_1000; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (fc && dplx == DUPLEX_FULL) { 2558c2ecf20Sopenharmony_ci if (lpa & adv & ADVERTISE_1000XPAUSE) 2568c2ecf20Sopenharmony_ci pause = PAUSE_RX | PAUSE_TX; 2578c2ecf20Sopenharmony_ci else if ((lpa & ADVERTISE_1000XPAUSE) && 2588c2ecf20Sopenharmony_ci (adv & lpa & ADVERTISE_1000XPSE_ASYM)) 2598c2ecf20Sopenharmony_ci pause = PAUSE_TX; 2608c2ecf20Sopenharmony_ci else if ((lpa & ADVERTISE_1000XPSE_ASYM) && 2618c2ecf20Sopenharmony_ci (adv & ADVERTISE_1000XPAUSE)) 2628c2ecf20Sopenharmony_ci pause = PAUSE_RX; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci if (speed) 2668c2ecf20Sopenharmony_ci *speed = sp; 2678c2ecf20Sopenharmony_ci if (duplex) 2688c2ecf20Sopenharmony_ci *duplex = dplx; 2698c2ecf20Sopenharmony_ci if (fc) 2708c2ecf20Sopenharmony_ci *fc = pause; 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#ifdef UNUSED 2758c2ecf20Sopenharmony_ci/* 2768c2ecf20Sopenharmony_ci * Enable/disable auto MDI/MDI-X in forced link speed mode. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic int vsc8211_set_automdi(struct cphy *phy, int enable) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci int err; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5); 2838c2ecf20Sopenharmony_ci if (err) 2848c2ecf20Sopenharmony_ci return err; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12); 2878c2ecf20Sopenharmony_ci if (err) 2888c2ecf20Sopenharmony_ci return err; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003); 2918c2ecf20Sopenharmony_ci if (err) 2928c2ecf20Sopenharmony_ci return err; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa); 2958c2ecf20Sopenharmony_ci if (err) 2968c2ecf20Sopenharmony_ci return err; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); 2998c2ecf20Sopenharmony_ci if (err) 3008c2ecf20Sopenharmony_ci return err; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ciint vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int err; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci err = t3_set_phy_speed_duplex(phy, speed, duplex); 3108c2ecf20Sopenharmony_ci if (!err) 3118c2ecf20Sopenharmony_ci err = vsc8211_set_automdi(phy, 1); 3128c2ecf20Sopenharmony_ci return err; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci#endif /* UNUSED */ 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int vsc8211_power_down(struct cphy *cphy, int enable) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, 3198c2ecf20Sopenharmony_ci enable ? BMCR_PDOWN : 0); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int vsc8211_intr_handler(struct cphy *cphy) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci unsigned int cause; 3258c2ecf20Sopenharmony_ci int err, cphy_cause = 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause); 3288c2ecf20Sopenharmony_ci if (err) 3298c2ecf20Sopenharmony_ci return err; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci cause &= INTR_MASK; 3328c2ecf20Sopenharmony_ci if (cause & CFG_CHG_INTR_MASK) 3338c2ecf20Sopenharmony_ci cphy_cause |= cphy_cause_link_change; 3348c2ecf20Sopenharmony_ci if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) 3358c2ecf20Sopenharmony_ci cphy_cause |= cphy_cause_fifo_error; 3368c2ecf20Sopenharmony_ci return cphy_cause; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic const struct cphy_ops vsc8211_ops = { 3408c2ecf20Sopenharmony_ci .reset = vsc8211_reset, 3418c2ecf20Sopenharmony_ci .intr_enable = vsc8211_intr_enable, 3428c2ecf20Sopenharmony_ci .intr_disable = vsc8211_intr_disable, 3438c2ecf20Sopenharmony_ci .intr_clear = vsc8211_intr_clear, 3448c2ecf20Sopenharmony_ci .intr_handler = vsc8211_intr_handler, 3458c2ecf20Sopenharmony_ci .autoneg_enable = vsc8211_autoneg_enable, 3468c2ecf20Sopenharmony_ci .autoneg_restart = vsc8211_autoneg_restart, 3478c2ecf20Sopenharmony_ci .advertise = t3_phy_advertise, 3488c2ecf20Sopenharmony_ci .set_speed_duplex = t3_set_phy_speed_duplex, 3498c2ecf20Sopenharmony_ci .get_link_status = vsc8211_get_link_status, 3508c2ecf20Sopenharmony_ci .power_down = vsc8211_power_down, 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic const struct cphy_ops vsc8211_fiber_ops = { 3548c2ecf20Sopenharmony_ci .reset = vsc8211_reset, 3558c2ecf20Sopenharmony_ci .intr_enable = vsc8211_intr_enable, 3568c2ecf20Sopenharmony_ci .intr_disable = vsc8211_intr_disable, 3578c2ecf20Sopenharmony_ci .intr_clear = vsc8211_intr_clear, 3588c2ecf20Sopenharmony_ci .intr_handler = vsc8211_intr_handler, 3598c2ecf20Sopenharmony_ci .autoneg_enable = vsc8211_autoneg_enable, 3608c2ecf20Sopenharmony_ci .autoneg_restart = vsc8211_autoneg_restart, 3618c2ecf20Sopenharmony_ci .advertise = t3_phy_advertise_fiber, 3628c2ecf20Sopenharmony_ci .set_speed_duplex = t3_set_phy_speed_duplex, 3638c2ecf20Sopenharmony_ci .get_link_status = vsc8211_get_link_status_fiber, 3648c2ecf20Sopenharmony_ci .power_down = vsc8211_power_down, 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciint t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, 3688c2ecf20Sopenharmony_ci int phy_addr, const struct mdio_ops *mdio_ops) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci int err; 3718c2ecf20Sopenharmony_ci unsigned int val; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, 3748c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | 3758c2ecf20Sopenharmony_ci SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | 3768c2ecf20Sopenharmony_ci SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); 3778c2ecf20Sopenharmony_ci msleep(20); /* PHY needs ~10ms to start responding to MDIO */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci err = t3_mdio_read(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, &val); 3808c2ecf20Sopenharmony_ci if (err) 3818c2ecf20Sopenharmony_ci return err; 3828c2ecf20Sopenharmony_ci if (val & VSC_CTRL_MEDIA_MODE_HI) { 3838c2ecf20Sopenharmony_ci /* copper interface, just need to configure the LEDs */ 3848c2ecf20Sopenharmony_ci return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL, 3858c2ecf20Sopenharmony_ci 0x100); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 3898c2ecf20Sopenharmony_ci SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; 3908c2ecf20Sopenharmony_ci phy->desc = "1000BASE-X"; 3918c2ecf20Sopenharmony_ci phy->ops = &vsc8211_fiber_ops; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1); 3948c2ecf20Sopenharmony_ci if (err) 3958c2ecf20Sopenharmony_ci return err; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1); 3988c2ecf20Sopenharmony_ci if (err) 3998c2ecf20Sopenharmony_ci return err; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); 4028c2ecf20Sopenharmony_ci if (err) 4038c2ecf20Sopenharmony_ci return err; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, 4068c2ecf20Sopenharmony_ci val | VSC_CTRL_CLAUSE37_VIEW); 4078c2ecf20Sopenharmony_ci if (err) 4088c2ecf20Sopenharmony_ci return err; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci err = vsc8211_reset(phy, 0); 4118c2ecf20Sopenharmony_ci if (err) 4128c2ecf20Sopenharmony_ci return err; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci udelay(5); /* delay after reset before next SMI */ 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 417