162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include "common.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* VSC8211 PHY specific registers. */ 3562306a36Sopenharmony_cienum { 3662306a36Sopenharmony_ci VSC8211_SIGDET_CTRL = 19, 3762306a36Sopenharmony_ci VSC8211_EXT_CTRL = 23, 3862306a36Sopenharmony_ci VSC8211_INTR_ENABLE = 25, 3962306a36Sopenharmony_ci VSC8211_INTR_STATUS = 26, 4062306a36Sopenharmony_ci VSC8211_LED_CTRL = 27, 4162306a36Sopenharmony_ci VSC8211_AUX_CTRL_STAT = 28, 4262306a36Sopenharmony_ci VSC8211_EXT_PAGE_AXS = 31, 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cienum { 4662306a36Sopenharmony_ci VSC_INTR_RX_ERR = 1 << 0, 4762306a36Sopenharmony_ci VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ 4862306a36Sopenharmony_ci VSC_INTR_CABLE = 1 << 2, /* cable impairment */ 4962306a36Sopenharmony_ci VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ 5062306a36Sopenharmony_ci VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ 5162306a36Sopenharmony_ci VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ 5262306a36Sopenharmony_ci VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ 5362306a36Sopenharmony_ci VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ 5462306a36Sopenharmony_ci VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ 5562306a36Sopenharmony_ci VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ 5662306a36Sopenharmony_ci VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ 5762306a36Sopenharmony_ci VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ 5862306a36Sopenharmony_ci VSC_INTR_LINK_CHG = 1 << 13, /* link change */ 5962306a36Sopenharmony_ci VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ 6062306a36Sopenharmony_ci VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cienum { 6462306a36Sopenharmony_ci VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ 6562306a36Sopenharmony_ci VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ 6962306a36Sopenharmony_ci VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ 7062306a36Sopenharmony_ci VSC_INTR_NEG_DONE) 7162306a36Sopenharmony_ci#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ 7262306a36Sopenharmony_ci VSC_INTR_ENABLE) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* PHY specific auxiliary control & status register fields */ 7562306a36Sopenharmony_ci#define S_ACSR_ACTIPHY_TMR 0 7662306a36Sopenharmony_ci#define M_ACSR_ACTIPHY_TMR 0x3 7762306a36Sopenharmony_ci#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define S_ACSR_SPEED 3 8062306a36Sopenharmony_ci#define M_ACSR_SPEED 0x3 8162306a36Sopenharmony_ci#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define S_ACSR_DUPLEX 5 8462306a36Sopenharmony_ci#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define S_ACSR_ACTIPHY 6 8762306a36Sopenharmony_ci#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Reset the PHY. This PHY completes reset immediately so we never wait. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic int vsc8211_reset(struct cphy *cphy, int wait) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int vsc8211_intr_enable(struct cphy *cphy) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 10062306a36Sopenharmony_ci INTR_MASK); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int vsc8211_intr_disable(struct cphy *cphy) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int vsc8211_intr_clear(struct cphy *cphy) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci u32 val; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Clear PHY interrupts by reading the register. */ 11362306a36Sopenharmony_ci return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int vsc8211_autoneg_enable(struct cphy *cphy) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, 11962306a36Sopenharmony_ci BMCR_PDOWN | BMCR_ISOLATE, 12062306a36Sopenharmony_ci BMCR_ANENABLE | BMCR_ANRESTART); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int vsc8211_autoneg_restart(struct cphy *cphy) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, 12662306a36Sopenharmony_ci BMCR_PDOWN | BMCR_ISOLATE, 12762306a36Sopenharmony_ci BMCR_ANRESTART); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, 13162306a36Sopenharmony_ci int *speed, int *duplex, int *fc) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci unsigned int bmcr, status, lpa, adv; 13462306a36Sopenharmony_ci int err, sp = -1, dplx = -1, pause = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); 13762306a36Sopenharmony_ci if (!err) 13862306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); 13962306a36Sopenharmony_ci if (err) 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (link_ok) { 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 14562306a36Sopenharmony_ci * once more to get the current link state. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci if (!(status & BMSR_LSTATUS)) 14862306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, 14962306a36Sopenharmony_ci &status); 15062306a36Sopenharmony_ci if (err) 15162306a36Sopenharmony_ci return err; 15262306a36Sopenharmony_ci *link_ok = (status & BMSR_LSTATUS) != 0; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci if (!(bmcr & BMCR_ANENABLE)) { 15562306a36Sopenharmony_ci dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 15662306a36Sopenharmony_ci if (bmcr & BMCR_SPEED1000) 15762306a36Sopenharmony_ci sp = SPEED_1000; 15862306a36Sopenharmony_ci else if (bmcr & BMCR_SPEED100) 15962306a36Sopenharmony_ci sp = SPEED_100; 16062306a36Sopenharmony_ci else 16162306a36Sopenharmony_ci sp = SPEED_10; 16262306a36Sopenharmony_ci } else if (status & BMSR_ANEGCOMPLETE) { 16362306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT, 16462306a36Sopenharmony_ci &status); 16562306a36Sopenharmony_ci if (err) 16662306a36Sopenharmony_ci return err; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; 16962306a36Sopenharmony_ci sp = G_ACSR_SPEED(status); 17062306a36Sopenharmony_ci if (sp == 0) 17162306a36Sopenharmony_ci sp = SPEED_10; 17262306a36Sopenharmony_ci else if (sp == 1) 17362306a36Sopenharmony_ci sp = SPEED_100; 17462306a36Sopenharmony_ci else 17562306a36Sopenharmony_ci sp = SPEED_1000; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (fc && dplx == DUPLEX_FULL) { 17862306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, 17962306a36Sopenharmony_ci &lpa); 18062306a36Sopenharmony_ci if (!err) 18162306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, 18262306a36Sopenharmony_ci MII_ADVERTISE, &adv); 18362306a36Sopenharmony_ci if (err) 18462306a36Sopenharmony_ci return err; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (lpa & adv & ADVERTISE_PAUSE_CAP) 18762306a36Sopenharmony_ci pause = PAUSE_RX | PAUSE_TX; 18862306a36Sopenharmony_ci else if ((lpa & ADVERTISE_PAUSE_CAP) && 18962306a36Sopenharmony_ci (lpa & ADVERTISE_PAUSE_ASYM) && 19062306a36Sopenharmony_ci (adv & ADVERTISE_PAUSE_ASYM)) 19162306a36Sopenharmony_ci pause = PAUSE_TX; 19262306a36Sopenharmony_ci else if ((lpa & ADVERTISE_PAUSE_ASYM) && 19362306a36Sopenharmony_ci (adv & ADVERTISE_PAUSE_CAP)) 19462306a36Sopenharmony_ci pause = PAUSE_RX; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci if (speed) 19862306a36Sopenharmony_ci *speed = sp; 19962306a36Sopenharmony_ci if (duplex) 20062306a36Sopenharmony_ci *duplex = dplx; 20162306a36Sopenharmony_ci if (fc) 20262306a36Sopenharmony_ci *fc = pause; 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, 20762306a36Sopenharmony_ci int *speed, int *duplex, int *fc) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci unsigned int bmcr, status, lpa, adv; 21062306a36Sopenharmony_ci int err, sp = -1, dplx = -1, pause = 0; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); 21362306a36Sopenharmony_ci if (!err) 21462306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); 21562306a36Sopenharmony_ci if (err) 21662306a36Sopenharmony_ci return err; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (link_ok) { 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 22162306a36Sopenharmony_ci * once more to get the current link state. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci if (!(status & BMSR_LSTATUS)) 22462306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, 22562306a36Sopenharmony_ci &status); 22662306a36Sopenharmony_ci if (err) 22762306a36Sopenharmony_ci return err; 22862306a36Sopenharmony_ci *link_ok = (status & BMSR_LSTATUS) != 0; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci if (!(bmcr & BMCR_ANENABLE)) { 23162306a36Sopenharmony_ci dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 23262306a36Sopenharmony_ci if (bmcr & BMCR_SPEED1000) 23362306a36Sopenharmony_ci sp = SPEED_1000; 23462306a36Sopenharmony_ci else if (bmcr & BMCR_SPEED100) 23562306a36Sopenharmony_ci sp = SPEED_100; 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci sp = SPEED_10; 23862306a36Sopenharmony_ci } else if (status & BMSR_ANEGCOMPLETE) { 23962306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa); 24062306a36Sopenharmony_ci if (!err) 24162306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE, 24262306a36Sopenharmony_ci &adv); 24362306a36Sopenharmony_ci if (err) 24462306a36Sopenharmony_ci return err; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (adv & lpa & ADVERTISE_1000XFULL) { 24762306a36Sopenharmony_ci dplx = DUPLEX_FULL; 24862306a36Sopenharmony_ci sp = SPEED_1000; 24962306a36Sopenharmony_ci } else if (adv & lpa & ADVERTISE_1000XHALF) { 25062306a36Sopenharmony_ci dplx = DUPLEX_HALF; 25162306a36Sopenharmony_ci sp = SPEED_1000; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (fc && dplx == DUPLEX_FULL) { 25562306a36Sopenharmony_ci if (lpa & adv & ADVERTISE_1000XPAUSE) 25662306a36Sopenharmony_ci pause = PAUSE_RX | PAUSE_TX; 25762306a36Sopenharmony_ci else if ((lpa & ADVERTISE_1000XPAUSE) && 25862306a36Sopenharmony_ci (adv & lpa & ADVERTISE_1000XPSE_ASYM)) 25962306a36Sopenharmony_ci pause = PAUSE_TX; 26062306a36Sopenharmony_ci else if ((lpa & ADVERTISE_1000XPSE_ASYM) && 26162306a36Sopenharmony_ci (adv & ADVERTISE_1000XPAUSE)) 26262306a36Sopenharmony_ci pause = PAUSE_RX; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci if (speed) 26662306a36Sopenharmony_ci *speed = sp; 26762306a36Sopenharmony_ci if (duplex) 26862306a36Sopenharmony_ci *duplex = dplx; 26962306a36Sopenharmony_ci if (fc) 27062306a36Sopenharmony_ci *fc = pause; 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci#ifdef UNUSED 27562306a36Sopenharmony_ci/* 27662306a36Sopenharmony_ci * Enable/disable auto MDI/MDI-X in forced link speed mode. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_cistatic int vsc8211_set_automdi(struct cphy *phy, int enable) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5); 28362306a36Sopenharmony_ci if (err) 28462306a36Sopenharmony_ci return err; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12); 28762306a36Sopenharmony_ci if (err) 28862306a36Sopenharmony_ci return err; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003); 29162306a36Sopenharmony_ci if (err) 29262306a36Sopenharmony_ci return err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa); 29562306a36Sopenharmony_ci if (err) 29662306a36Sopenharmony_ci return err; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); 29962306a36Sopenharmony_ci if (err) 30062306a36Sopenharmony_ci return err; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciint vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci int err; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci err = t3_set_phy_speed_duplex(phy, speed, duplex); 31062306a36Sopenharmony_ci if (!err) 31162306a36Sopenharmony_ci err = vsc8211_set_automdi(phy, 1); 31262306a36Sopenharmony_ci return err; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci#endif /* UNUSED */ 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int vsc8211_power_down(struct cphy *cphy, int enable) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, 31962306a36Sopenharmony_ci enable ? BMCR_PDOWN : 0); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int vsc8211_intr_handler(struct cphy *cphy) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci unsigned int cause; 32562306a36Sopenharmony_ci int err, cphy_cause = 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause); 32862306a36Sopenharmony_ci if (err) 32962306a36Sopenharmony_ci return err; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci cause &= INTR_MASK; 33262306a36Sopenharmony_ci if (cause & CFG_CHG_INTR_MASK) 33362306a36Sopenharmony_ci cphy_cause |= cphy_cause_link_change; 33462306a36Sopenharmony_ci if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) 33562306a36Sopenharmony_ci cphy_cause |= cphy_cause_fifo_error; 33662306a36Sopenharmony_ci return cphy_cause; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic const struct cphy_ops vsc8211_ops = { 34062306a36Sopenharmony_ci .reset = vsc8211_reset, 34162306a36Sopenharmony_ci .intr_enable = vsc8211_intr_enable, 34262306a36Sopenharmony_ci .intr_disable = vsc8211_intr_disable, 34362306a36Sopenharmony_ci .intr_clear = vsc8211_intr_clear, 34462306a36Sopenharmony_ci .intr_handler = vsc8211_intr_handler, 34562306a36Sopenharmony_ci .autoneg_enable = vsc8211_autoneg_enable, 34662306a36Sopenharmony_ci .autoneg_restart = vsc8211_autoneg_restart, 34762306a36Sopenharmony_ci .advertise = t3_phy_advertise, 34862306a36Sopenharmony_ci .set_speed_duplex = t3_set_phy_speed_duplex, 34962306a36Sopenharmony_ci .get_link_status = vsc8211_get_link_status, 35062306a36Sopenharmony_ci .power_down = vsc8211_power_down, 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic const struct cphy_ops vsc8211_fiber_ops = { 35462306a36Sopenharmony_ci .reset = vsc8211_reset, 35562306a36Sopenharmony_ci .intr_enable = vsc8211_intr_enable, 35662306a36Sopenharmony_ci .intr_disable = vsc8211_intr_disable, 35762306a36Sopenharmony_ci .intr_clear = vsc8211_intr_clear, 35862306a36Sopenharmony_ci .intr_handler = vsc8211_intr_handler, 35962306a36Sopenharmony_ci .autoneg_enable = vsc8211_autoneg_enable, 36062306a36Sopenharmony_ci .autoneg_restart = vsc8211_autoneg_restart, 36162306a36Sopenharmony_ci .advertise = t3_phy_advertise_fiber, 36262306a36Sopenharmony_ci .set_speed_duplex = t3_set_phy_speed_duplex, 36362306a36Sopenharmony_ci .get_link_status = vsc8211_get_link_status_fiber, 36462306a36Sopenharmony_ci .power_down = vsc8211_power_down, 36562306a36Sopenharmony_ci}; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciint t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, 36862306a36Sopenharmony_ci int phy_addr, const struct mdio_ops *mdio_ops) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci int err; 37162306a36Sopenharmony_ci unsigned int val; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, 37462306a36Sopenharmony_ci SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | 37562306a36Sopenharmony_ci SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | 37662306a36Sopenharmony_ci SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); 37762306a36Sopenharmony_ci msleep(20); /* PHY needs ~10ms to start responding to MDIO */ 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = t3_mdio_read(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, &val); 38062306a36Sopenharmony_ci if (err) 38162306a36Sopenharmony_ci return err; 38262306a36Sopenharmony_ci if (val & VSC_CTRL_MEDIA_MODE_HI) { 38362306a36Sopenharmony_ci /* copper interface, just need to configure the LEDs */ 38462306a36Sopenharmony_ci return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL, 38562306a36Sopenharmony_ci 0x100); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 38962306a36Sopenharmony_ci SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; 39062306a36Sopenharmony_ci phy->desc = "1000BASE-X"; 39162306a36Sopenharmony_ci phy->ops = &vsc8211_fiber_ops; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1); 39462306a36Sopenharmony_ci if (err) 39562306a36Sopenharmony_ci return err; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1); 39862306a36Sopenharmony_ci if (err) 39962306a36Sopenharmony_ci return err; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); 40262306a36Sopenharmony_ci if (err) 40362306a36Sopenharmony_ci return err; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, 40662306a36Sopenharmony_ci val | VSC_CTRL_CLAUSE37_VIEW); 40762306a36Sopenharmony_ci if (err) 40862306a36Sopenharmony_ci return err; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci err = vsc8211_reset(phy, 0); 41162306a36Sopenharmony_ci if (err) 41262306a36Sopenharmony_ci return err; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci udelay(5); /* delay after reset before next SMI */ 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 417