Home | History | Annotate | Line # | Download | only in cxgb
cxgb_vsc8211.c revision 1.1.2.2
      1  1.1.2.2  uebayasi /**************************************************************************
      2  1.1.2.2  uebayasi 
      3  1.1.2.2  uebayasi Copyright (c) 2007, Chelsio Inc.
      4  1.1.2.2  uebayasi All rights reserved.
      5  1.1.2.2  uebayasi 
      6  1.1.2.2  uebayasi Redistribution and use in source and binary forms, with or without
      7  1.1.2.2  uebayasi modification, are permitted provided that the following conditions are met:
      8  1.1.2.2  uebayasi 
      9  1.1.2.2  uebayasi  1. Redistributions of source code must retain the above copyright notice,
     10  1.1.2.2  uebayasi     this list of conditions and the following disclaimer.
     11  1.1.2.2  uebayasi 
     12  1.1.2.2  uebayasi  2. Neither the name of the Chelsio Corporation nor the names of its
     13  1.1.2.2  uebayasi     contributors may be used to endorse or promote products derived from
     14  1.1.2.2  uebayasi     this software without specific prior written permission.
     15  1.1.2.2  uebayasi 
     16  1.1.2.2  uebayasi THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17  1.1.2.2  uebayasi AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1.2.2  uebayasi IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1.2.2  uebayasi ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     20  1.1.2.2  uebayasi LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1.2.2  uebayasi CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1.2.2  uebayasi SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1.2.2  uebayasi INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1.2.2  uebayasi CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1.2.2  uebayasi ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1.2.2  uebayasi POSSIBILITY OF SUCH DAMAGE.
     27  1.1.2.2  uebayasi 
     28  1.1.2.2  uebayasi ***************************************************************************/
     29  1.1.2.2  uebayasi 
     30  1.1.2.2  uebayasi #include <sys/cdefs.h>
     31  1.1.2.2  uebayasi __KERNEL_RCSID(0, "$NetBSD: cxgb_vsc8211.c,v 1.1.2.2 2010/04/30 14:43:45 uebayasi Exp $");
     32  1.1.2.2  uebayasi 
     33  1.1.2.2  uebayasi #ifdef CONFIG_DEFINED
     34  1.1.2.2  uebayasi #include <cxgb_include.h>
     35  1.1.2.2  uebayasi #else
     36  1.1.2.2  uebayasi #include <dev/pci/cxgb/cxgb_include.h>
     37  1.1.2.2  uebayasi #endif
     38  1.1.2.2  uebayasi 
     39  1.1.2.2  uebayasi /* VSC8211 PHY specific registers. */
     40  1.1.2.2  uebayasi enum {
     41  1.1.2.2  uebayasi     VSC8211_INTR_ENABLE   = 25,
     42  1.1.2.2  uebayasi     VSC8211_INTR_STATUS   = 26,
     43  1.1.2.2  uebayasi     VSC8211_AUX_CTRL_STAT = 28,
     44  1.1.2.2  uebayasi };
     45  1.1.2.2  uebayasi 
     46  1.1.2.2  uebayasi enum {
     47  1.1.2.2  uebayasi     VSC_INTR_RX_ERR     = 1 << 0,
     48  1.1.2.2  uebayasi     VSC_INTR_MS_ERR     = 1 << 1,  /* master/slave resolution error */
     49  1.1.2.2  uebayasi     VSC_INTR_CABLE      = 1 << 2,  /* cable impairment */
     50  1.1.2.2  uebayasi     VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
     51  1.1.2.2  uebayasi     VSC_INTR_MEDIA_CHG  = 1 << 4,  /* AMS media change */
     52  1.1.2.2  uebayasi     VSC_INTR_RX_FIFO    = 1 << 5,  /* Rx FIFO over/underflow */
     53  1.1.2.2  uebayasi     VSC_INTR_TX_FIFO    = 1 << 6,  /* Tx FIFO over/underflow */
     54  1.1.2.2  uebayasi     VSC_INTR_DESCRAMBL  = 1 << 7,  /* descrambler lock-lost */
     55  1.1.2.2  uebayasi     VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
     56  1.1.2.2  uebayasi     VSC_INTR_NEG_DONE   = 1 << 10, /* autoneg done */
     57  1.1.2.2  uebayasi     VSC_INTR_NEG_ERR    = 1 << 11, /* autoneg error */
     58  1.1.2.2  uebayasi     VSC_INTR_LINK_CHG   = 1 << 13, /* link change */
     59  1.1.2.2  uebayasi     VSC_INTR_ENABLE     = 1 << 15, /* interrupt enable */
     60  1.1.2.2  uebayasi };
     61  1.1.2.2  uebayasi 
     62  1.1.2.2  uebayasi #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
     63  1.1.2.2  uebayasi                VSC_INTR_NEG_DONE)
     64  1.1.2.2  uebayasi #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
     65  1.1.2.2  uebayasi            VSC_INTR_ENABLE)
     66  1.1.2.2  uebayasi 
     67  1.1.2.2  uebayasi /* PHY specific auxiliary control & status register fields */
     68  1.1.2.2  uebayasi #define S_ACSR_ACTIPHY_TMR    0
     69  1.1.2.2  uebayasi #define M_ACSR_ACTIPHY_TMR    0x3
     70  1.1.2.2  uebayasi #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
     71  1.1.2.2  uebayasi 
     72  1.1.2.2  uebayasi #define S_ACSR_SPEED    3
     73  1.1.2.2  uebayasi #define M_ACSR_SPEED    0x3
     74  1.1.2.2  uebayasi #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
     75  1.1.2.2  uebayasi 
     76  1.1.2.2  uebayasi #define S_ACSR_DUPLEX 5
     77  1.1.2.2  uebayasi #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
     78  1.1.2.2  uebayasi 
     79  1.1.2.2  uebayasi #define S_ACSR_ACTIPHY 6
     80  1.1.2.2  uebayasi #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
     81  1.1.2.2  uebayasi 
     82  1.1.2.2  uebayasi /*
     83  1.1.2.2  uebayasi  * Reset the PHY.  This PHY completes reset immediately so we never wait.
     84  1.1.2.2  uebayasi  */
     85  1.1.2.2  uebayasi static int vsc8211_reset(struct cphy *cphy, int wait)
     86  1.1.2.2  uebayasi {
     87  1.1.2.2  uebayasi     return t3_phy_reset(cphy, 0, 0);
     88  1.1.2.2  uebayasi }
     89  1.1.2.2  uebayasi 
     90  1.1.2.2  uebayasi static int vsc8211_intr_enable(struct cphy *cphy)
     91  1.1.2.2  uebayasi {
     92  1.1.2.2  uebayasi     return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
     93  1.1.2.2  uebayasi }
     94  1.1.2.2  uebayasi 
     95  1.1.2.2  uebayasi static int vsc8211_intr_disable(struct cphy *cphy)
     96  1.1.2.2  uebayasi {
     97  1.1.2.2  uebayasi     return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
     98  1.1.2.2  uebayasi }
     99  1.1.2.2  uebayasi 
    100  1.1.2.2  uebayasi static int vsc8211_intr_clear(struct cphy *cphy)
    101  1.1.2.2  uebayasi {
    102  1.1.2.2  uebayasi     u32 val;
    103  1.1.2.2  uebayasi 
    104  1.1.2.2  uebayasi     /* Clear PHY interrupts by reading the register. */
    105  1.1.2.2  uebayasi     return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
    106  1.1.2.2  uebayasi }
    107  1.1.2.2  uebayasi 
    108  1.1.2.2  uebayasi static int vsc8211_autoneg_enable(struct cphy *cphy)
    109  1.1.2.2  uebayasi {
    110  1.1.2.2  uebayasi     return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
    111  1.1.2.2  uebayasi                    BMCR_ANENABLE | BMCR_ANRESTART);
    112  1.1.2.2  uebayasi }
    113  1.1.2.2  uebayasi 
    114  1.1.2.2  uebayasi static int vsc8211_autoneg_restart(struct cphy *cphy)
    115  1.1.2.2  uebayasi {
    116  1.1.2.2  uebayasi     return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
    117  1.1.2.2  uebayasi                    BMCR_ANRESTART);
    118  1.1.2.2  uebayasi }
    119  1.1.2.2  uebayasi 
    120  1.1.2.2  uebayasi static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
    121  1.1.2.2  uebayasi                      int *speed, int *duplex, int *fc)
    122  1.1.2.2  uebayasi {
    123  1.1.2.2  uebayasi     unsigned int bmcr, status, lpa, adv;
    124  1.1.2.2  uebayasi     int err, sp = -1, dplx = -1, pause = 0;
    125  1.1.2.2  uebayasi 
    126  1.1.2.2  uebayasi     err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
    127  1.1.2.2  uebayasi     if (!err)
    128  1.1.2.2  uebayasi         err = mdio_read(cphy, 0, MII_BMSR, &status);
    129  1.1.2.2  uebayasi     if (err)
    130  1.1.2.2  uebayasi         return err;
    131  1.1.2.2  uebayasi 
    132  1.1.2.2  uebayasi     if (link_ok) {
    133  1.1.2.2  uebayasi         /*
    134  1.1.2.2  uebayasi          * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
    135  1.1.2.2  uebayasi          * once more to get the current link state.
    136  1.1.2.2  uebayasi          */
    137  1.1.2.2  uebayasi         if (!(status & BMSR_LSTATUS))
    138  1.1.2.2  uebayasi             err = mdio_read(cphy, 0, MII_BMSR, &status);
    139  1.1.2.2  uebayasi         if (err)
    140  1.1.2.2  uebayasi             return err;
    141  1.1.2.2  uebayasi         *link_ok = (status & BMSR_LSTATUS) != 0;
    142  1.1.2.2  uebayasi     }
    143  1.1.2.2  uebayasi     if (!(bmcr & BMCR_ANENABLE)) {
    144  1.1.2.2  uebayasi         dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
    145  1.1.2.2  uebayasi         if (bmcr & BMCR_SPEED1000)
    146  1.1.2.2  uebayasi             sp = SPEED_1000;
    147  1.1.2.2  uebayasi         else if (bmcr & BMCR_SPEED100)
    148  1.1.2.2  uebayasi             sp = SPEED_100;
    149  1.1.2.2  uebayasi         else
    150  1.1.2.2  uebayasi             sp = SPEED_10;
    151  1.1.2.2  uebayasi     } else if (status & BMSR_ANEGCOMPLETE) {
    152  1.1.2.2  uebayasi         err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
    153  1.1.2.2  uebayasi         if (err)
    154  1.1.2.2  uebayasi             return err;
    155  1.1.2.2  uebayasi 
    156  1.1.2.2  uebayasi         dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
    157  1.1.2.2  uebayasi         sp = G_ACSR_SPEED(status);
    158  1.1.2.2  uebayasi         if (sp == 0)
    159  1.1.2.2  uebayasi             sp = SPEED_10;
    160  1.1.2.2  uebayasi         else if (sp == 1)
    161  1.1.2.2  uebayasi             sp = SPEED_100;
    162  1.1.2.2  uebayasi         else
    163  1.1.2.2  uebayasi             sp = SPEED_1000;
    164  1.1.2.2  uebayasi 
    165  1.1.2.2  uebayasi         if (fc && dplx == DUPLEX_FULL) {
    166  1.1.2.2  uebayasi             err = mdio_read(cphy, 0, MII_LPA, &lpa);
    167  1.1.2.2  uebayasi             if (!err)
    168  1.1.2.2  uebayasi                 err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
    169  1.1.2.2  uebayasi             if (err)
    170  1.1.2.2  uebayasi                 return err;
    171  1.1.2.2  uebayasi 
    172  1.1.2.2  uebayasi             if (lpa & adv & ADVERTISE_PAUSE_CAP)
    173  1.1.2.2  uebayasi                 pause = PAUSE_RX | PAUSE_TX;
    174  1.1.2.2  uebayasi             else if ((lpa & ADVERTISE_PAUSE_CAP) &&
    175  1.1.2.2  uebayasi                  (lpa & ADVERTISE_PAUSE_ASYM) &&
    176  1.1.2.2  uebayasi                  (adv & ADVERTISE_PAUSE_ASYM))
    177  1.1.2.2  uebayasi                 pause = PAUSE_TX;
    178  1.1.2.2  uebayasi             else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
    179  1.1.2.2  uebayasi                  (adv & ADVERTISE_PAUSE_CAP))
    180  1.1.2.2  uebayasi                 pause = PAUSE_RX;
    181  1.1.2.2  uebayasi         }
    182  1.1.2.2  uebayasi     }
    183  1.1.2.2  uebayasi     if (speed)
    184  1.1.2.2  uebayasi         *speed = sp;
    185  1.1.2.2  uebayasi     if (duplex)
    186  1.1.2.2  uebayasi         *duplex = dplx;
    187  1.1.2.2  uebayasi     if (fc)
    188  1.1.2.2  uebayasi         *fc = pause;
    189  1.1.2.2  uebayasi     return 0;
    190  1.1.2.2  uebayasi }
    191  1.1.2.2  uebayasi 
    192  1.1.2.2  uebayasi static int vsc8211_power_down(struct cphy *cphy, int enable)
    193  1.1.2.2  uebayasi {
    194  1.1.2.2  uebayasi     return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
    195  1.1.2.2  uebayasi                    enable ? BMCR_PDOWN : 0);
    196  1.1.2.2  uebayasi }
    197  1.1.2.2  uebayasi 
    198  1.1.2.2  uebayasi static int vsc8211_intr_handler(struct cphy *cphy)
    199  1.1.2.2  uebayasi {
    200  1.1.2.2  uebayasi     unsigned int cause;
    201  1.1.2.2  uebayasi     int err, cphy_cause = 0;
    202  1.1.2.2  uebayasi 
    203  1.1.2.2  uebayasi     err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
    204  1.1.2.2  uebayasi     if (err)
    205  1.1.2.2  uebayasi         return err;
    206  1.1.2.2  uebayasi 
    207  1.1.2.2  uebayasi     cause &= INTR_MASK;
    208  1.1.2.2  uebayasi     if (cause & CFG_CHG_INTR_MASK)
    209  1.1.2.2  uebayasi         cphy_cause |= cphy_cause_link_change;
    210  1.1.2.2  uebayasi     if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
    211  1.1.2.2  uebayasi         cphy_cause |= cphy_cause_fifo_error;
    212  1.1.2.2  uebayasi     return cphy_cause;
    213  1.1.2.2  uebayasi }
    214  1.1.2.2  uebayasi 
    215  1.1.2.2  uebayasi #ifdef C99_NOT_SUPPORTED
    216  1.1.2.2  uebayasi static struct cphy_ops vsc8211_ops = {
    217  1.1.2.2  uebayasi     NULL,
    218  1.1.2.2  uebayasi     vsc8211_reset,
    219  1.1.2.2  uebayasi     vsc8211_intr_enable,
    220  1.1.2.2  uebayasi     vsc8211_intr_disable,
    221  1.1.2.2  uebayasi     vsc8211_intr_clear,
    222  1.1.2.2  uebayasi     vsc8211_intr_handler,
    223  1.1.2.2  uebayasi     vsc8211_autoneg_enable,
    224  1.1.2.2  uebayasi     vsc8211_autoneg_restart,
    225  1.1.2.2  uebayasi     t3_phy_advertise,
    226  1.1.2.2  uebayasi     NULL,
    227  1.1.2.2  uebayasi     t3_set_phy_speed_duplex,
    228  1.1.2.2  uebayasi     vsc8211_get_link_status,
    229  1.1.2.2  uebayasi     vsc8211_power_down,
    230  1.1.2.2  uebayasi };
    231  1.1.2.2  uebayasi #else
    232  1.1.2.2  uebayasi static struct cphy_ops vsc8211_ops = {
    233  1.1.2.2  uebayasi     .reset             = vsc8211_reset,
    234  1.1.2.2  uebayasi     .intr_enable       = vsc8211_intr_enable,
    235  1.1.2.2  uebayasi     .intr_disable      = vsc8211_intr_disable,
    236  1.1.2.2  uebayasi     .intr_clear        = vsc8211_intr_clear,
    237  1.1.2.2  uebayasi     .intr_handler      = vsc8211_intr_handler,
    238  1.1.2.2  uebayasi     .autoneg_enable    = vsc8211_autoneg_enable,
    239  1.1.2.2  uebayasi     .autoneg_restart   = vsc8211_autoneg_restart,
    240  1.1.2.2  uebayasi     .advertise         = t3_phy_advertise,
    241  1.1.2.2  uebayasi     .set_speed_duplex  = t3_set_phy_speed_duplex,
    242  1.1.2.2  uebayasi     .get_link_status   = vsc8211_get_link_status,
    243  1.1.2.2  uebayasi     .power_down        = vsc8211_power_down,
    244  1.1.2.2  uebayasi };
    245  1.1.2.2  uebayasi #endif
    246  1.1.2.2  uebayasi 
    247  1.1.2.2  uebayasi void t3_vsc8211_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
    248  1.1.2.2  uebayasi              const struct mdio_ops *mdio_ops)
    249  1.1.2.2  uebayasi {
    250  1.1.2.2  uebayasi     cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
    251  1.1.2.2  uebayasi     t3_os_sleep(20);       /* PHY needs ~10ms to start responding to MDIO */
    252  1.1.2.2  uebayasi }
    253