1167514Skmacy/************************************************************************** 2167514Skmacy 3167514SkmacyCopyright (c) 2007, Chelsio Inc. 4167514SkmacyAll rights reserved. 5167514Skmacy 6167514SkmacyRedistribution and use in source and binary forms, with or without 7167514Skmacymodification, are permitted provided that the following conditions are met: 8167514Skmacy 9167514Skmacy 1. Redistributions of source code must retain the above copyright notice, 10167514Skmacy this list of conditions and the following disclaimer. 11167514Skmacy 12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 13167514Skmacy contributors may be used to endorse or promote products derived from 14167514Skmacy this software without specific prior written permission. 15167514Skmacy 16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26167514SkmacyPOSSIBILITY OF SUCH DAMAGE. 27167514Skmacy 28167514Skmacy***************************************************************************/ 29167514Skmacy 30167514Skmacy#include <sys/cdefs.h> 31167514Skmacy__FBSDID("$FreeBSD$"); 32167514Skmacy 33170076Skmacy#include <cxgb_include.h> 34167514Skmacy 35176472Skmacy#undef msleep 36176472Skmacy#define msleep t3_os_sleep 37176472Skmacy 38167514Skmacy/* VSC8211 PHY specific registers. */ 39167514Skmacyenum { 40176472Skmacy VSC8211_SIGDET_CTRL = 19, 41176472Skmacy VSC8211_EXT_CTRL = 23, 42197791Snp VSC8211_PHY_CTRL = 24, 43167514Skmacy VSC8211_INTR_ENABLE = 25, 44167514Skmacy VSC8211_INTR_STATUS = 26, 45180583Skmacy VSC8211_LED_CTRL = 27, 46167514Skmacy VSC8211_AUX_CTRL_STAT = 28, 47176472Skmacy VSC8211_EXT_PAGE_AXS = 31, 48167514Skmacy}; 49167514Skmacy 50167514Skmacyenum { 51167514Skmacy VSC_INTR_RX_ERR = 1 << 0, 52167514Skmacy VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ 53167514Skmacy VSC_INTR_CABLE = 1 << 2, /* cable impairment */ 54167514Skmacy VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ 55167514Skmacy VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ 56167514Skmacy VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ 57167514Skmacy VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ 58167514Skmacy VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ 59167514Skmacy VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ 60167514Skmacy VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ 61167514Skmacy VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ 62176472Skmacy VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ 63167514Skmacy VSC_INTR_LINK_CHG = 1 << 13, /* link change */ 64176472Skmacy VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ 65167514Skmacy VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ 66167514Skmacy}; 67167514Skmacy 68176472Skmacyenum { 69176472Skmacy VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ 70176472Skmacy VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ 71176472Skmacy}; 72176472Skmacy 73167514Skmacy#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ 74176472Skmacy VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ 75167514Skmacy VSC_INTR_NEG_DONE) 76167514Skmacy#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ 77167514Skmacy VSC_INTR_ENABLE) 78167514Skmacy 79167514Skmacy/* PHY specific auxiliary control & status register fields */ 80167514Skmacy#define S_ACSR_ACTIPHY_TMR 0 81167514Skmacy#define M_ACSR_ACTIPHY_TMR 0x3 82167514Skmacy#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) 83167514Skmacy 84167514Skmacy#define S_ACSR_SPEED 3 85167514Skmacy#define M_ACSR_SPEED 0x3 86167514Skmacy#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) 87167514Skmacy 88167514Skmacy#define S_ACSR_DUPLEX 5 89167514Skmacy#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) 90167514Skmacy 91167514Skmacy#define S_ACSR_ACTIPHY 6 92167514Skmacy#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) 93167514Skmacy 94167514Skmacy/* 95167514Skmacy * Reset the PHY. This PHY completes reset immediately so we never wait. 96167514Skmacy */ 97167514Skmacystatic int vsc8211_reset(struct cphy *cphy, int wait) 98167514Skmacy{ 99167514Skmacy return t3_phy_reset(cphy, 0, 0); 100167514Skmacy} 101167514Skmacy 102167514Skmacystatic int vsc8211_intr_enable(struct cphy *cphy) 103167514Skmacy{ 104167514Skmacy return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK); 105167514Skmacy} 106167514Skmacy 107167514Skmacystatic int vsc8211_intr_disable(struct cphy *cphy) 108167514Skmacy{ 109167514Skmacy return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0); 110167514Skmacy} 111167514Skmacy 112167514Skmacystatic int vsc8211_intr_clear(struct cphy *cphy) 113167514Skmacy{ 114167514Skmacy u32 val; 115167514Skmacy 116167514Skmacy /* Clear PHY interrupts by reading the register. */ 117167514Skmacy return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val); 118167514Skmacy} 119167514Skmacy 120167514Skmacystatic int vsc8211_autoneg_enable(struct cphy *cphy) 121167514Skmacy{ 122167514Skmacy return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 123167514Skmacy BMCR_ANENABLE | BMCR_ANRESTART); 124167514Skmacy} 125167514Skmacy 126167514Skmacystatic int vsc8211_autoneg_restart(struct cphy *cphy) 127167514Skmacy{ 128167514Skmacy return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 129167514Skmacy BMCR_ANRESTART); 130167514Skmacy} 131167514Skmacy 132167514Skmacystatic int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, 133167514Skmacy int *speed, int *duplex, int *fc) 134167514Skmacy{ 135167514Skmacy unsigned int bmcr, status, lpa, adv; 136167514Skmacy int err, sp = -1, dplx = -1, pause = 0; 137167514Skmacy 138167514Skmacy err = mdio_read(cphy, 0, MII_BMCR, &bmcr); 139167514Skmacy if (!err) 140167514Skmacy err = mdio_read(cphy, 0, MII_BMSR, &status); 141167514Skmacy if (err) 142167514Skmacy return err; 143167514Skmacy 144167514Skmacy if (link_ok) { 145167514Skmacy /* 146167514Skmacy * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 147167514Skmacy * once more to get the current link state. 148167514Skmacy */ 149167514Skmacy if (!(status & BMSR_LSTATUS)) 150167514Skmacy err = mdio_read(cphy, 0, MII_BMSR, &status); 151167514Skmacy if (err) 152167514Skmacy return err; 153167514Skmacy *link_ok = (status & BMSR_LSTATUS) != 0; 154167514Skmacy } 155167514Skmacy if (!(bmcr & BMCR_ANENABLE)) { 156167514Skmacy dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 157167514Skmacy if (bmcr & BMCR_SPEED1000) 158167514Skmacy sp = SPEED_1000; 159167514Skmacy else if (bmcr & BMCR_SPEED100) 160167514Skmacy sp = SPEED_100; 161167514Skmacy else 162167514Skmacy sp = SPEED_10; 163167514Skmacy } else if (status & BMSR_ANEGCOMPLETE) { 164167514Skmacy err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status); 165167514Skmacy if (err) 166167514Skmacy return err; 167167514Skmacy 168167514Skmacy dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; 169167514Skmacy sp = G_ACSR_SPEED(status); 170167514Skmacy if (sp == 0) 171167514Skmacy sp = SPEED_10; 172167514Skmacy else if (sp == 1) 173167514Skmacy sp = SPEED_100; 174167514Skmacy else 175167514Skmacy sp = SPEED_1000; 176167514Skmacy 177167514Skmacy if (fc && dplx == DUPLEX_FULL) { 178167514Skmacy err = mdio_read(cphy, 0, MII_LPA, &lpa); 179167514Skmacy if (!err) 180167514Skmacy err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); 181167514Skmacy if (err) 182167514Skmacy return err; 183167514Skmacy 184167514Skmacy if (lpa & adv & ADVERTISE_PAUSE_CAP) 185167514Skmacy pause = PAUSE_RX | PAUSE_TX; 186167514Skmacy else if ((lpa & ADVERTISE_PAUSE_CAP) && 187167514Skmacy (lpa & ADVERTISE_PAUSE_ASYM) && 188167514Skmacy (adv & ADVERTISE_PAUSE_ASYM)) 189167514Skmacy pause = PAUSE_TX; 190167514Skmacy else if ((lpa & ADVERTISE_PAUSE_ASYM) && 191167514Skmacy (adv & ADVERTISE_PAUSE_CAP)) 192167514Skmacy pause = PAUSE_RX; 193167514Skmacy } 194167514Skmacy } 195167514Skmacy if (speed) 196167514Skmacy *speed = sp; 197167514Skmacy if (duplex) 198167514Skmacy *duplex = dplx; 199167514Skmacy if (fc) 200167514Skmacy *fc = pause; 201167514Skmacy return 0; 202167514Skmacy} 203167514Skmacy 204176472Skmacystatic int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, 205176472Skmacy int *speed, int *duplex, int *fc) 206176472Skmacy{ 207176472Skmacy unsigned int bmcr, status, lpa, adv; 208176472Skmacy int err, sp = -1, dplx = -1, pause = 0; 209176472Skmacy 210176472Skmacy err = mdio_read(cphy, 0, MII_BMCR, &bmcr); 211176472Skmacy if (!err) 212176472Skmacy err = mdio_read(cphy, 0, MII_BMSR, &status); 213176472Skmacy if (err) 214176472Skmacy return err; 215176472Skmacy 216176472Skmacy if (link_ok) { 217176472Skmacy /* 218176472Skmacy * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 219176472Skmacy * once more to get the current link state. 220176472Skmacy */ 221176472Skmacy if (!(status & BMSR_LSTATUS)) 222176472Skmacy err = mdio_read(cphy, 0, MII_BMSR, &status); 223176472Skmacy if (err) 224176472Skmacy return err; 225176472Skmacy *link_ok = (status & BMSR_LSTATUS) != 0; 226176472Skmacy } 227176472Skmacy if (!(bmcr & BMCR_ANENABLE)) { 228176472Skmacy dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 229176472Skmacy if (bmcr & BMCR_SPEED1000) 230176472Skmacy sp = SPEED_1000; 231176472Skmacy else if (bmcr & BMCR_SPEED100) 232176472Skmacy sp = SPEED_100; 233176472Skmacy else 234176472Skmacy sp = SPEED_10; 235176472Skmacy } else if (status & BMSR_ANEGCOMPLETE) { 236176472Skmacy err = mdio_read(cphy, 0, MII_LPA, &lpa); 237176472Skmacy if (!err) 238176472Skmacy err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); 239176472Skmacy if (err) 240176472Skmacy return err; 241176472Skmacy 242176472Skmacy if (adv & lpa & ADVERTISE_1000XFULL) { 243176472Skmacy dplx = DUPLEX_FULL; 244176472Skmacy sp = SPEED_1000; 245176472Skmacy } else if (adv & lpa & ADVERTISE_1000XHALF) { 246176472Skmacy dplx = DUPLEX_HALF; 247176472Skmacy sp = SPEED_1000; 248176472Skmacy } 249176472Skmacy 250176472Skmacy if (fc && dplx == DUPLEX_FULL) { 251176472Skmacy if (lpa & adv & ADVERTISE_1000XPAUSE) 252176472Skmacy pause = PAUSE_RX | PAUSE_TX; 253176472Skmacy else if ((lpa & ADVERTISE_1000XPAUSE) && 254176472Skmacy (adv & lpa & ADVERTISE_1000XPSE_ASYM)) 255176472Skmacy pause = PAUSE_TX; 256176472Skmacy else if ((lpa & ADVERTISE_1000XPSE_ASYM) && 257176472Skmacy (adv & ADVERTISE_1000XPAUSE)) 258176472Skmacy pause = PAUSE_RX; 259176472Skmacy } 260176472Skmacy } 261176472Skmacy if (speed) 262176472Skmacy *speed = sp; 263176472Skmacy if (duplex) 264176472Skmacy *duplex = dplx; 265176472Skmacy if (fc) 266176472Skmacy *fc = pause; 267176472Skmacy return 0; 268176472Skmacy} 269176472Skmacy 270176472Skmacy/* 271176472Skmacy * Enable/disable auto MDI/MDI-X in forced link speed mode. 272176472Skmacy */ 273176472Skmacystatic int vsc8211_set_automdi(struct cphy *phy, int enable) 274176472Skmacy{ 275176472Skmacy int err; 276176472Skmacy 277176472Skmacy if ((err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5)) != 0 || 278176472Skmacy (err = mdio_write(phy, 0, 18, 0x12)) != 0 || 279176472Skmacy (err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003)) != 0 || 280176472Skmacy (err = mdio_write(phy, 0, 16, 0x87fa)) != 0 || 281176472Skmacy (err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0)) != 0) 282176472Skmacy return err; 283176472Skmacy return 0; 284176472Skmacy} 285176472Skmacy 286176472Skmacystatic int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) 287176472Skmacy{ 288176472Skmacy int err; 289176472Skmacy 290176472Skmacy err = t3_set_phy_speed_duplex(phy, speed, duplex); 291176472Skmacy if (!err) 292176472Skmacy err = vsc8211_set_automdi(phy, 1); 293176472Skmacy return err; 294176472Skmacy} 295176472Skmacy 296167514Skmacystatic int vsc8211_power_down(struct cphy *cphy, int enable) 297167514Skmacy{ 298167514Skmacy return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, 299167514Skmacy enable ? BMCR_PDOWN : 0); 300167514Skmacy} 301167514Skmacy 302167514Skmacystatic int vsc8211_intr_handler(struct cphy *cphy) 303167514Skmacy{ 304167514Skmacy unsigned int cause; 305167514Skmacy int err, cphy_cause = 0; 306167514Skmacy 307167514Skmacy err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause); 308167514Skmacy if (err) 309167514Skmacy return err; 310167514Skmacy 311167514Skmacy cause &= INTR_MASK; 312167514Skmacy if (cause & CFG_CHG_INTR_MASK) 313167514Skmacy cphy_cause |= cphy_cause_link_change; 314167514Skmacy if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) 315167514Skmacy cphy_cause |= cphy_cause_fifo_error; 316167514Skmacy return cphy_cause; 317167514Skmacy} 318167514Skmacy 319167514Skmacy#ifdef C99_NOT_SUPPORTED 320167514Skmacystatic struct cphy_ops vsc8211_ops = { 321167514Skmacy vsc8211_reset, 322167514Skmacy vsc8211_intr_enable, 323167514Skmacy vsc8211_intr_disable, 324167514Skmacy vsc8211_intr_clear, 325167514Skmacy vsc8211_intr_handler, 326167514Skmacy vsc8211_autoneg_enable, 327167514Skmacy vsc8211_autoneg_restart, 328167514Skmacy t3_phy_advertise, 329167514Skmacy NULL, 330176472Skmacy vsc8211_set_speed_duplex, 331167514Skmacy vsc8211_get_link_status, 332167514Skmacy vsc8211_power_down, 333167514Skmacy}; 334176472Skmacy 335176472Skmacystatic struct cphy_ops vsc8211_fiber_ops = { 336176472Skmacy vsc8211_reset, 337176472Skmacy vsc8211_intr_enable, 338176472Skmacy vsc8211_intr_disable, 339176472Skmacy vsc8211_intr_clear, 340176472Skmacy vsc8211_intr_handler, 341176472Skmacy vsc8211_autoneg_enable, 342176472Skmacy vsc8211_autoneg_restart, 343176472Skmacy t3_phy_advertise_fiber, 344176472Skmacy NULL, 345176472Skmacy t3_set_phy_speed_duplex, 346176472Skmacy vsc8211_get_link_status_fiber, 347176472Skmacy vsc8211_power_down, 348176472Skmacy}; 349167514Skmacy#else 350167514Skmacystatic struct cphy_ops vsc8211_ops = { 351167514Skmacy .reset = vsc8211_reset, 352167514Skmacy .intr_enable = vsc8211_intr_enable, 353167514Skmacy .intr_disable = vsc8211_intr_disable, 354167514Skmacy .intr_clear = vsc8211_intr_clear, 355167514Skmacy .intr_handler = vsc8211_intr_handler, 356167514Skmacy .autoneg_enable = vsc8211_autoneg_enable, 357167514Skmacy .autoneg_restart = vsc8211_autoneg_restart, 358167514Skmacy .advertise = t3_phy_advertise, 359176472Skmacy .set_speed_duplex = vsc8211_set_speed_duplex, 360167514Skmacy .get_link_status = vsc8211_get_link_status, 361167514Skmacy .power_down = vsc8211_power_down, 362167514Skmacy}; 363176472Skmacy 364176472Skmacystatic struct cphy_ops vsc8211_fiber_ops = { 365176472Skmacy .reset = vsc8211_reset, 366176472Skmacy .intr_enable = vsc8211_intr_enable, 367176472Skmacy .intr_disable = vsc8211_intr_disable, 368176472Skmacy .intr_clear = vsc8211_intr_clear, 369176472Skmacy .intr_handler = vsc8211_intr_handler, 370176472Skmacy .autoneg_enable = vsc8211_autoneg_enable, 371176472Skmacy .autoneg_restart = vsc8211_autoneg_restart, 372176472Skmacy .advertise = t3_phy_advertise_fiber, 373176472Skmacy .set_speed_duplex = t3_set_phy_speed_duplex, 374176472Skmacy .get_link_status = vsc8211_get_link_status_fiber, 375176472Skmacy .power_down = vsc8211_power_down, 376176472Skmacy}; 377167514Skmacy#endif 378167514Skmacy 379197791Snp#define VSC8211_PHY_CTRL 24 380197791Snp 381197791Snp#define S_VSC8211_TXFIFODEPTH 7 382197791Snp#define M_VSC8211_TXFIFODEPTH 0x7 383197791Snp#define V_VSC8211_TXFIFODEPTH(x) ((x) << S_VSC8211_TXFIFODEPTH) 384197791Snp#define G_VSC8211_TXFIFODEPTH(x) (((x) >> S_VSC8211_TXFIFODEPTH) & M_VSC8211_TXFIFODEPTH) 385197791Snp 386197791Snp#define S_VSC8211_RXFIFODEPTH 4 387197791Snp#define M_VSC8211_RXFIFODEPTH 0x7 388197791Snp#define V_VSC8211_RXFIFODEPTH(x) ((x) << S_VSC8211_RXFIFODEPTH) 389197791Snp#define G_VSC8211_RXFIFODEPTH(x) (((x) >> S_VSC8211_RXFIFODEPTH) & M_VSC8211_RXFIFODEPTH) 390197791Snp 391197791Snpint t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port) 392197791Snp{ 393197791Snp /* TX FIFO Depth set bits 9:7 to 100 (IEEE mode) */ 394197791Snp unsigned int val = 4; 395197791Snp unsigned int currentregval; 396197791Snp unsigned int regval; 397197791Snp int err; 398197791Snp 399197791Snp /* Retrieve the port info structure from adater_t */ 400197791Snp struct port_info *portinfo = adap2pinfo(adap, port); 401197791Snp 402197791Snp /* What phy is this */ 403197791Snp struct cphy *phy = &portinfo->phy; 404197791Snp 405197791Snp /* Read the current value of the PHY control Register */ 406197791Snp err = mdio_read(phy, 0, VSC8211_PHY_CTRL, ¤tregval); 407197791Snp 408197791Snp if (err) 409197791Snp return err; 410197791Snp 411197791Snp /* IEEE mode supports up to 1518 bytes */ 412197791Snp /* mtu does not contain the header + FCS (18 bytes) */ 413197791Snp if (mtu > 1500) 414197791Snp /* 415197791Snp * If using a packet size > 1500 set TX FIFO Depth bits 416197791Snp * 9:7 to 011 (Jumbo packet mode) 417197791Snp */ 418197791Snp val = 3; 419197791Snp 420197791Snp regval = V_VSC8211_TXFIFODEPTH(val) | V_VSC8211_RXFIFODEPTH(val) | 421197791Snp (currentregval & ~V_VSC8211_TXFIFODEPTH(M_VSC8211_TXFIFODEPTH) & 422197791Snp ~V_VSC8211_RXFIFODEPTH(M_VSC8211_RXFIFODEPTH)); 423197791Snp 424197791Snp return mdio_write(phy, 0, VSC8211_PHY_CTRL, regval); 425197791Snp} 426197791Snp 427197791Snpint t3_vsc8211_phy_prep(pinfo_t *pinfo, int phy_addr, 428176472Skmacy const struct mdio_ops *mdio_ops) 429167514Skmacy{ 430197791Snp struct cphy *phy = &pinfo->phy; 431176472Skmacy int err; 432176472Skmacy unsigned int val; 433176472Skmacy 434197791Snp cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &vsc8211_ops, mdio_ops, 435176472Skmacy SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | 436176472Skmacy SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | 437176472Skmacy SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); 438176472Skmacy msleep(20); /* PHY needs ~10ms to start responding to MDIO */ 439176472Skmacy 440176472Skmacy err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val); 441176472Skmacy if (err) 442176472Skmacy return err; 443180583Skmacy if (val & VSC_CTRL_MEDIA_MODE_HI) { 444180583Skmacy /* copper interface, just need to configure the LEDs */ 445180583Skmacy return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100); 446180583Skmacy } 447176472Skmacy 448176472Skmacy phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 449176472Skmacy SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; 450176472Skmacy phy->desc = "1000BASE-X"; 451176472Skmacy phy->ops = &vsc8211_fiber_ops; 452176472Skmacy 453176472Skmacy if ((err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1)) != 0 || 454176472Skmacy (err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1)) != 0 || 455176472Skmacy (err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0)) != 0 || 456176472Skmacy (err = mdio_write(phy, 0, VSC8211_EXT_CTRL, 457176472Skmacy val | VSC_CTRL_CLAUSE37_VIEW)) != 0 || 458176472Skmacy (err = vsc8211_reset(phy, 0)) != 0) 459176472Skmacy return err; 460176472Skmacy 461176472Skmacy udelay(5); /* delay after reset before next SMI */ 462176472Skmacy return 0; 463167514Skmacy} 464