1180586Skmacy/************************************************************************** 2180586Skmacy 3180586SkmacyCopyright (c) 2008, Chelsio Inc. 4180586SkmacyAll rights reserved. 5180586Skmacy 6180586SkmacyRedistribution and use in source and binary forms, with or without 7180586Skmacymodification, are permitted provided that the following conditions are met: 8180586Skmacy 9180586Skmacy 1. Redistributions of source code must retain the above copyright notice, 10180586Skmacy this list of conditions and the following disclaimer. 11180586Skmacy 12180586Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 13180586Skmacy contributors may be used to endorse or promote products derived from 14180586Skmacy this software without specific prior written permission. 15180586Skmacy 16180586SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17180586SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18180586SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19180586SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20180586SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21180586SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22180586SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23180586SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24180586SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25180586SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26180586SkmacyPOSSIBILITY OF SUCH DAMAGE. 27180586Skmacy 28180586Skmacy***************************************************************************/ 29180586Skmacy 30180586Skmacy#include <sys/cdefs.h> 31180586Skmacy__FBSDID("$FreeBSD$"); 32180586Skmacy 33180586Skmacy#include <cxgb_include.h> 34180586Skmacy 35180586Skmacy#undef msleep 36180586Skmacy#define msleep t3_os_sleep 37180586Skmacy 38180586Skmacy/* TN1010 PHY specific registers. */ 39180586Skmacyenum { 40180586Skmacy TN1010_VEND1_STAT = 1, 41180586Skmacy}; 42180586Skmacy 43180586Skmacy/* IEEE auto-negotiation 10GBASE-T registers */ 44180586Skmacyenum { 45180586Skmacy ANEG_ADVER = 16, 46180586Skmacy ANEG_LPA = 19, 47180586Skmacy ANEG_10G_CTRL = 32, 48180586Skmacy ANEG_10G_STAT = 33 49180586Skmacy}; 50180586Skmacy 51180586Skmacy#define ADVERTISE_ENPAGE (1 << 12) 52180586Skmacy#define ADVERTISE_10000FULL (1 << 12) 53180586Skmacy#define ADVERTISE_LOOP_TIMING (1 << 0) 54180586Skmacy 55180586Skmacy/* vendor specific status register fields */ 56180586Skmacy#define F_XS_LANE_ALIGN_STAT (1 << 0) 57180586Skmacy#define F_PCS_BLK_LOCK (1 << 1) 58180586Skmacy#define F_PMD_SIGNAL_OK (1 << 2) 59180586Skmacy#define F_LINK_STAT (1 << 3) 60180586Skmacy#define F_ANEG_SPEED_1G (1 << 4) 61180586Skmacy#define F_ANEG_MASTER (1 << 5) 62180586Skmacy 63180586Skmacy#define S_ANEG_STAT 6 64180586Skmacy#define M_ANEG_STAT 0x3 65180586Skmacy#define G_ANEG_STAT(x) (((x) >> S_ANEG_STAT) & M_ANEG_STAT) 66180586Skmacy 67180586Skmacyenum { /* autonegotiation status */ 68180586Skmacy ANEG_IN_PROGR = 0, 69180586Skmacy ANEG_COMPLETE = 1, 70180586Skmacy ANEG_FAILED = 3 71180586Skmacy}; 72180586Skmacy 73180586Skmacy/* 74180586Skmacy * Reset the PHY. May take up to 500ms to complete. 75180586Skmacy */ 76180586Skmacystatic int tn1010_reset(struct cphy *phy, int wait) 77180586Skmacy{ 78180586Skmacy int err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); 79180586Skmacy msleep(500); 80180586Skmacy return err; 81180586Skmacy} 82180586Skmacy 83180586Skmacystatic int tn1010_power_down(struct cphy *phy, int enable) 84180586Skmacy{ 85180586Skmacy return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 86180586Skmacy BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 87180586Skmacy} 88180586Skmacy 89180586Skmacystatic int tn1010_autoneg_enable(struct cphy *phy) 90180586Skmacy{ 91180586Skmacy int err; 92180586Skmacy 93180586Skmacy err = tn1010_power_down(phy, 0); 94180586Skmacy if (!err) 95180586Skmacy err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR, 0, 96180586Skmacy BMCR_ANENABLE | BMCR_ANRESTART); 97180586Skmacy return err; 98180586Skmacy} 99180586Skmacy 100180586Skmacystatic int tn1010_autoneg_restart(struct cphy *phy) 101180586Skmacy{ 102180586Skmacy int err; 103180586Skmacy 104180586Skmacy err = tn1010_power_down(phy, 0); 105180586Skmacy if (!err) 106180586Skmacy err = t3_mdio_change_bits(phy, MDIO_DEV_ANEG, MII_BMCR, 0, 107180586Skmacy BMCR_ANRESTART); 108180586Skmacy return err; 109180586Skmacy} 110180586Skmacy 111180586Skmacystatic int tn1010_advertise(struct cphy *phy, unsigned int advert) 112180586Skmacy{ 113180586Skmacy int err, val; 114180586Skmacy 115180586Skmacy if (!(advert & ADVERTISED_1000baseT_Full)) 116180586Skmacy return -EINVAL; /* PHY can't disable 1000BASE-T */ 117180586Skmacy 118180586Skmacy val = ADVERTISE_CSMA | ADVERTISE_ENPAGE | ADVERTISE_NPAGE; 119180586Skmacy if (advert & ADVERTISED_Pause) 120180586Skmacy val |= ADVERTISE_PAUSE_CAP; 121180586Skmacy if (advert & ADVERTISED_Asym_Pause) 122180586Skmacy val |= ADVERTISE_PAUSE_ASYM; 123180586Skmacy err = mdio_write(phy, MDIO_DEV_ANEG, ANEG_ADVER, val); 124180586Skmacy if (err) 125180586Skmacy return err; 126180586Skmacy 127180586Skmacy val = (advert & ADVERTISED_10000baseT_Full) ? ADVERTISE_10000FULL : 0; 128180586Skmacy return mdio_write(phy, MDIO_DEV_ANEG, ANEG_10G_CTRL, val | 129180586Skmacy ADVERTISE_LOOP_TIMING); 130180586Skmacy} 131180586Skmacy 132276959Snpstatic int tn1010_get_link_status(struct cphy *phy, int *link_state, 133180586Skmacy int *speed, int *duplex, int *fc) 134180586Skmacy{ 135180586Skmacy unsigned int status, lpa, adv; 136180586Skmacy int err, sp = -1, pause = 0; 137180586Skmacy 138180586Skmacy err = mdio_read(phy, MDIO_DEV_VEND1, TN1010_VEND1_STAT, &status); 139180586Skmacy if (err) 140180586Skmacy return err; 141180586Skmacy 142276959Snp if (link_state) 143276959Snp *link_state = status & F_LINK_STAT ? PHY_LINK_UP : 144276959Snp PHY_LINK_DOWN; 145180586Skmacy 146180586Skmacy if (G_ANEG_STAT(status) == ANEG_COMPLETE) { 147180586Skmacy sp = (status & F_ANEG_SPEED_1G) ? SPEED_1000 : SPEED_10000; 148180586Skmacy 149180586Skmacy if (fc) { 150180586Skmacy err = mdio_read(phy, MDIO_DEV_ANEG, ANEG_LPA, &lpa); 151180586Skmacy if (!err) 152180586Skmacy err = mdio_read(phy, MDIO_DEV_ANEG, ANEG_ADVER, 153180586Skmacy &adv); 154180586Skmacy if (err) 155180586Skmacy return err; 156180586Skmacy 157180586Skmacy if (lpa & adv & ADVERTISE_PAUSE_CAP) 158180586Skmacy pause = PAUSE_RX | PAUSE_TX; 159180586Skmacy else if ((lpa & ADVERTISE_PAUSE_CAP) && 160180586Skmacy (lpa & ADVERTISE_PAUSE_ASYM) && 161180586Skmacy (adv & ADVERTISE_PAUSE_ASYM)) 162180586Skmacy pause = PAUSE_TX; 163180586Skmacy else if ((lpa & ADVERTISE_PAUSE_ASYM) && 164180586Skmacy (adv & ADVERTISE_PAUSE_CAP)) 165180586Skmacy pause = PAUSE_RX; 166180586Skmacy } 167180586Skmacy } 168180586Skmacy if (speed) 169180586Skmacy *speed = sp; 170180586Skmacy if (duplex) 171180586Skmacy *duplex = DUPLEX_FULL; 172180586Skmacy if (fc) 173180586Skmacy *fc = pause; 174180586Skmacy return 0; 175180586Skmacy} 176180586Skmacy 177180586Skmacystatic int tn1010_set_speed_duplex(struct cphy *phy, int speed, int duplex) 178180586Skmacy{ 179180586Skmacy return -EINVAL; /* require autoneg */ 180180586Skmacy} 181180586Skmacy 182180586Skmacy#ifdef C99_NOT_SUPPORTED 183180586Skmacystatic struct cphy_ops tn1010_ops = { 184180586Skmacy tn1010_reset, 185180586Skmacy t3_phy_lasi_intr_enable, 186180586Skmacy t3_phy_lasi_intr_disable, 187180586Skmacy t3_phy_lasi_intr_clear, 188180586Skmacy t3_phy_lasi_intr_handler, 189180586Skmacy tn1010_autoneg_enable, 190180586Skmacy tn1010_autoneg_restart, 191180586Skmacy tn1010_advertise, 192180586Skmacy NULL, 193180586Skmacy tn1010_set_speed_duplex, 194180586Skmacy tn1010_get_link_status, 195180586Skmacy tn1010_power_down, 196180586Skmacy}; 197180586Skmacy#else 198180586Skmacystatic struct cphy_ops tn1010_ops = { 199180586Skmacy .reset = tn1010_reset, 200180586Skmacy .intr_enable = t3_phy_lasi_intr_enable, 201180586Skmacy .intr_disable = t3_phy_lasi_intr_disable, 202180586Skmacy .intr_clear = t3_phy_lasi_intr_clear, 203180586Skmacy .intr_handler = t3_phy_lasi_intr_handler, 204180586Skmacy .autoneg_enable = tn1010_autoneg_enable, 205180586Skmacy .autoneg_restart = tn1010_autoneg_restart, 206180586Skmacy .advertise = tn1010_advertise, 207180586Skmacy .set_speed_duplex = tn1010_set_speed_duplex, 208180586Skmacy .get_link_status = tn1010_get_link_status, 209180586Skmacy .power_down = tn1010_power_down, 210180586Skmacy}; 211180586Skmacy#endif 212180586Skmacy 213197791Snpint t3_tn1010_phy_prep(pinfo_t *pinfo, int phy_addr, 214180586Skmacy const struct mdio_ops *mdio_ops) 215180586Skmacy{ 216197791Snp cphy_init(&pinfo->phy, pinfo->adapter, pinfo, phy_addr, &tn1010_ops, mdio_ops, 217180586Skmacy SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | 218180586Skmacy SUPPORTED_Autoneg | SUPPORTED_AUI | SUPPORTED_TP, 219180586Skmacy "1000/10GBASE-T"); 220180586Skmacy msleep(500); /* PHY needs up to 500ms to start responding to MDIO */ 221180586Skmacy return 0; 222180586Skmacy} 223