Home | History | Annotate | Line # | Download | only in cxgb
      1  1.1  jklos /**************************************************************************
      2  1.1  jklos 
      3  1.1  jklos Copyright (c) 2007, Chelsio Inc.
      4  1.1  jklos All rights reserved.
      5  1.1  jklos 
      6  1.1  jklos Redistribution and use in source and binary forms, with or without
      7  1.1  jklos modification, are permitted provided that the following conditions are met:
      8  1.1  jklos 
      9  1.1  jklos  1. Redistributions of source code must retain the above copyright notice,
     10  1.1  jklos     this list of conditions and the following disclaimer.
     11  1.1  jklos 
     12  1.1  jklos  2. Neither the name of the Chelsio Corporation nor the names of its
     13  1.1  jklos     contributors may be used to endorse or promote products derived from
     14  1.1  jklos     this software without specific prior written permission.
     15  1.1  jklos 
     16  1.1  jklos THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17  1.1  jklos AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1  jklos IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1  jklos ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     20  1.1  jklos LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1  jklos CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1  jklos SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1  jklos INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1  jklos CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1  jklos ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1  jklos POSSIBILITY OF SUCH DAMAGE.
     27  1.1  jklos 
     28  1.1  jklos ***************************************************************************/
     29  1.1  jklos 
     30  1.1  jklos #include <sys/cdefs.h>
     31  1.1  jklos __KERNEL_RCSID(0, "$NetBSD: cxgb_ael1002.c,v 1.1 2010/03/21 21:11:13 jklos Exp $");
     32  1.1  jklos 
     33  1.1  jklos #ifdef CONFIG_DEFINED
     34  1.1  jklos #include <cxgb_include.h>
     35  1.1  jklos #else
     36  1.1  jklos #include <dev/pci/cxgb/cxgb_include.h>
     37  1.1  jklos #endif
     38  1.1  jklos 
     39  1.1  jklos enum {
     40  1.1  jklos     AEL100X_TX_DISABLE  = 9,
     41  1.1  jklos     AEL100X_TX_CONFIG1  = 0xc002,
     42  1.1  jklos     AEL1002_PWR_DOWN_HI = 0xc011,
     43  1.1  jklos     AEL1002_PWR_DOWN_LO = 0xc012,
     44  1.1  jklos     AEL1002_XFI_EQL     = 0xc015,
     45  1.1  jklos     AEL1002_LB_EN       = 0xc017,
     46  1.1  jklos 
     47  1.1  jklos     LASI_CTRL   = 0x9002,
     48  1.1  jklos     LASI_STAT   = 0x9005
     49  1.1  jklos };
     50  1.1  jklos 
     51  1.1  jklos static void ael100x_txon(struct cphy *phy)
     52  1.1  jklos {
     53  1.1  jklos     int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
     54  1.1  jklos 
     55  1.1  jklos     t3_os_sleep(100);
     56  1.1  jklos     t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
     57  1.1  jklos     t3_os_sleep(30);
     58  1.1  jklos }
     59  1.1  jklos 
     60  1.1  jklos static int ael1002_power_down(struct cphy *phy, int enable)
     61  1.1  jklos {
     62  1.1  jklos     int err;
     63  1.1  jklos 
     64  1.1  jklos     err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
     65  1.1  jklos     if (!err)
     66  1.1  jklos         err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
     67  1.1  jklos                       BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
     68  1.1  jklos     return err;
     69  1.1  jklos }
     70  1.1  jklos 
     71  1.1  jklos static int ael1002_reset(struct cphy *phy, int wait)
     72  1.1  jklos {
     73  1.1  jklos     int err;
     74  1.1  jklos 
     75  1.1  jklos     if ((err = ael1002_power_down(phy, 0)) ||
     76  1.1  jklos         (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
     77  1.1  jklos         (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
     78  1.1  jklos         (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
     79  1.1  jklos         (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
     80  1.1  jklos         (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
     81  1.1  jklos                        0, 1 << 5)))
     82  1.1  jklos         return err;
     83  1.1  jklos     return 0;
     84  1.1  jklos }
     85  1.1  jklos 
     86  1.1  jklos static int ael1002_intr_noop(struct cphy *phy)
     87  1.1  jklos {
     88  1.1  jklos     return 0;
     89  1.1  jklos }
     90  1.1  jklos 
     91  1.1  jklos static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
     92  1.1  jklos                    int *speed, int *duplex, int *fc)
     93  1.1  jklos {
     94  1.1  jklos     if (link_ok) {
     95  1.1  jklos         unsigned int status;
     96  1.1  jklos         int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
     97  1.1  jklos 
     98  1.1  jklos         /*
     99  1.1  jklos          * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
    100  1.1  jklos          * once more to get the current link state.
    101  1.1  jklos          */
    102  1.1  jklos         if (!err && !(status & BMSR_LSTATUS))
    103  1.1  jklos             err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
    104  1.1  jklos                     &status);
    105  1.1  jklos         if (err)
    106  1.1  jklos             return err;
    107  1.1  jklos         *link_ok = !!(status & BMSR_LSTATUS);
    108  1.1  jklos     }
    109  1.1  jklos     if (speed)
    110  1.1  jklos         *speed = SPEED_10000;
    111  1.1  jklos     if (duplex)
    112  1.1  jklos         *duplex = DUPLEX_FULL;
    113  1.1  jklos     return 0;
    114  1.1  jklos }
    115  1.1  jklos 
    116  1.1  jklos #ifdef C99_NOT_SUPPORTED
    117  1.1  jklos static struct cphy_ops ael1002_ops = {
    118  1.1  jklos     NULL,
    119  1.1  jklos     ael1002_reset,
    120  1.1  jklos     ael1002_intr_noop,
    121  1.1  jklos     ael1002_intr_noop,
    122  1.1  jklos     ael1002_intr_noop,
    123  1.1  jklos     ael1002_intr_noop,
    124  1.1  jklos     NULL,
    125  1.1  jklos     NULL,
    126  1.1  jklos     NULL,
    127  1.1  jklos     NULL,
    128  1.1  jklos     NULL,
    129  1.1  jklos     ael100x_get_link_status,
    130  1.1  jklos     ael1002_power_down,
    131  1.1  jklos };
    132  1.1  jklos #else
    133  1.1  jklos static struct cphy_ops ael1002_ops = {
    134  1.1  jklos     .reset           = ael1002_reset,
    135  1.1  jklos     .intr_enable     = ael1002_intr_noop,
    136  1.1  jklos     .intr_disable    = ael1002_intr_noop,
    137  1.1  jklos     .intr_clear      = ael1002_intr_noop,
    138  1.1  jklos     .intr_handler    = ael1002_intr_noop,
    139  1.1  jklos     .get_link_status = ael100x_get_link_status,
    140  1.1  jklos     .power_down      = ael1002_power_down,
    141  1.1  jklos };
    142  1.1  jklos #endif
    143  1.1  jklos 
    144  1.1  jklos void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
    145  1.1  jklos              const struct mdio_ops *mdio_ops)
    146  1.1  jklos {
    147  1.1  jklos     cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
    148  1.1  jklos     ael100x_txon(phy);
    149  1.1  jklos }
    150  1.1  jklos 
    151  1.1  jklos static int ael1006_reset(struct cphy *phy, int wait)
    152  1.1  jklos {
    153  1.1  jklos     return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
    154  1.1  jklos }
    155  1.1  jklos 
    156  1.1  jklos static int ael1006_intr_enable(struct cphy *phy)
    157  1.1  jklos {
    158  1.1  jklos     return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
    159  1.1  jklos }
    160  1.1  jklos 
    161  1.1  jklos static int ael1006_intr_disable(struct cphy *phy)
    162  1.1  jklos {
    163  1.1  jklos     return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
    164  1.1  jklos }
    165  1.1  jklos 
    166  1.1  jklos static int ael1006_intr_clear(struct cphy *phy)
    167  1.1  jklos {
    168  1.1  jklos     u32 val;
    169  1.1  jklos 
    170  1.1  jklos     return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
    171  1.1  jklos }
    172  1.1  jklos 
    173  1.1  jklos static int ael1006_intr_handler(struct cphy *phy)
    174  1.1  jklos {
    175  1.1  jklos     unsigned int status;
    176  1.1  jklos     int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
    177  1.1  jklos 
    178  1.1  jklos     if (err)
    179  1.1  jklos         return err;
    180  1.1  jklos     return (status & 1) ?  cphy_cause_link_change : 0;
    181  1.1  jklos }
    182  1.1  jklos 
    183  1.1  jklos static int ael1006_power_down(struct cphy *phy, int enable)
    184  1.1  jklos {
    185  1.1  jklos     return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
    186  1.1  jklos                    BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
    187  1.1  jklos }
    188  1.1  jklos 
    189  1.1  jklos #ifdef C99_NOT_SUPPORTED
    190  1.1  jklos static struct cphy_ops ael1006_ops = {
    191  1.1  jklos     NULL,
    192  1.1  jklos     ael1006_reset,
    193  1.1  jklos     ael1006_intr_enable,
    194  1.1  jklos     ael1006_intr_disable,
    195  1.1  jklos     ael1006_intr_clear,
    196  1.1  jklos     ael1006_intr_handler,
    197  1.1  jklos     NULL,
    198  1.1  jklos     NULL,
    199  1.1  jklos     NULL,
    200  1.1  jklos     NULL,
    201  1.1  jklos     NULL,
    202  1.1  jklos     ael100x_get_link_status,
    203  1.1  jklos     ael1006_power_down,
    204  1.1  jklos };
    205  1.1  jklos #else
    206  1.1  jklos static struct cphy_ops ael1006_ops = {
    207  1.1  jklos     .reset           = ael1006_reset,
    208  1.1  jklos     .intr_enable     = ael1006_intr_enable,
    209  1.1  jklos     .intr_disable    = ael1006_intr_disable,
    210  1.1  jklos     .intr_clear      = ael1006_intr_clear,
    211  1.1  jklos     .intr_handler    = ael1006_intr_handler,
    212  1.1  jklos     .get_link_status = ael100x_get_link_status,
    213  1.1  jklos     .power_down      = ael1006_power_down,
    214  1.1  jklos };
    215  1.1  jklos #endif
    216  1.1  jklos 
    217  1.1  jklos void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
    218  1.1  jklos              const struct mdio_ops *mdio_ops)
    219  1.1  jklos {
    220  1.1  jklos     cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
    221  1.1  jklos     ael100x_txon(phy);
    222  1.1  jklos }
    223  1.1  jklos 
    224  1.1  jklos #ifdef C99_NOT_SUPPORTED
    225  1.1  jklos static struct cphy_ops qt2045_ops = {
    226  1.1  jklos     NULL,
    227  1.1  jklos     ael1006_reset,
    228  1.1  jklos     ael1006_intr_enable,
    229  1.1  jklos     ael1006_intr_disable,
    230  1.1  jklos     ael1006_intr_clear,
    231  1.1  jklos     ael1006_intr_handler,
    232  1.1  jklos     NULL,
    233  1.1  jklos     NULL,
    234  1.1  jklos     NULL,
    235  1.1  jklos     NULL,
    236  1.1  jklos     NULL,
    237  1.1  jklos     ael100x_get_link_status,
    238  1.1  jklos     ael1006_power_down,
    239  1.1  jklos };
    240  1.1  jklos #else
    241  1.1  jklos static struct cphy_ops qt2045_ops = {
    242  1.1  jklos     .reset           = ael1006_reset,
    243  1.1  jklos     .intr_enable     = ael1006_intr_enable,
    244  1.1  jklos     .intr_disable    = ael1006_intr_disable,
    245  1.1  jklos     .intr_clear      = ael1006_intr_clear,
    246  1.1  jklos     .intr_handler    = ael1006_intr_handler,
    247  1.1  jklos     .get_link_status = ael100x_get_link_status,
    248  1.1  jklos     .power_down      = ael1006_power_down,
    249  1.1  jklos };
    250  1.1  jklos #endif
    251  1.1  jklos 
    252  1.1  jklos void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
    253  1.1  jklos             const struct mdio_ops *mdio_ops)
    254  1.1  jklos {
    255  1.1  jklos     unsigned int stat;
    256  1.1  jklos 
    257  1.1  jklos     cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
    258  1.1  jklos 
    259  1.1  jklos     /*
    260  1.1  jklos      * Some cards where the PHY is supposed to be at address 0 actually
    261  1.1  jklos      * have it at 1.
    262  1.1  jklos      */
    263  1.1  jklos     if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
    264  1.1  jklos         stat == 0xffff)
    265  1.1  jklos         phy->addr = 1;
    266  1.1  jklos }
    267  1.1  jklos 
    268  1.1  jklos static int xaui_direct_reset(struct cphy *phy, int wait)
    269  1.1  jklos {
    270  1.1  jklos     return 0;
    271  1.1  jklos }
    272  1.1  jklos 
    273  1.1  jklos static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
    274  1.1  jklos                        int *speed, int *duplex, int *fc)
    275  1.1  jklos {
    276  1.1  jklos     if (link_ok) {
    277  1.1  jklos         unsigned int status;
    278  1.1  jklos 
    279  1.1  jklos         status = t3_read_reg(phy->adapter,
    280  1.1  jklos                      XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) |
    281  1.1  jklos              t3_read_reg(phy->adapter,
    282  1.1  jklos                      XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) |
    283  1.1  jklos              t3_read_reg(phy->adapter,
    284  1.1  jklos                      XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) |
    285  1.1  jklos              t3_read_reg(phy->adapter,
    286  1.1  jklos                      XGM_REG(A_XGM_SERDES_STAT3, phy->addr));
    287  1.1  jklos         *link_ok = !(status & F_LOWSIG0);
    288  1.1  jklos     }
    289  1.1  jklos     if (speed)
    290  1.1  jklos         *speed = SPEED_10000;
    291  1.1  jklos     if (duplex)
    292  1.1  jklos         *duplex = DUPLEX_FULL;
    293  1.1  jklos     return 0;
    294  1.1  jklos }
    295  1.1  jklos 
    296  1.1  jklos static int xaui_direct_power_down(struct cphy *phy, int enable)
    297  1.1  jklos {
    298  1.1  jklos     return 0;
    299  1.1  jklos }
    300  1.1  jklos 
    301  1.1  jklos #ifdef C99_NOT_SUPPORTED
    302  1.1  jklos static struct cphy_ops xaui_direct_ops = {
    303  1.1  jklos     NULL,
    304  1.1  jklos     xaui_direct_reset,
    305  1.1  jklos     ael1002_intr_noop,
    306  1.1  jklos     ael1002_intr_noop,
    307  1.1  jklos     ael1002_intr_noop,
    308  1.1  jklos     ael1002_intr_noop,
    309  1.1  jklos     NULL,
    310  1.1  jklos     NULL,
    311  1.1  jklos     NULL,
    312  1.1  jklos     NULL,
    313  1.1  jklos     NULL,
    314  1.1  jklos     xaui_direct_get_link_status,
    315  1.1  jklos     xaui_direct_power_down,
    316  1.1  jklos };
    317  1.1  jklos #else
    318  1.1  jklos static struct cphy_ops xaui_direct_ops = {
    319  1.1  jklos     .reset           = xaui_direct_reset,
    320  1.1  jklos     .intr_enable     = ael1002_intr_noop,
    321  1.1  jklos     .intr_disable    = ael1002_intr_noop,
    322  1.1  jklos     .intr_clear      = ael1002_intr_noop,
    323  1.1  jklos     .intr_handler    = ael1002_intr_noop,
    324  1.1  jklos     .get_link_status = xaui_direct_get_link_status,
    325  1.1  jklos     .power_down      = xaui_direct_power_down,
    326  1.1  jklos };
    327  1.1  jklos #endif
    328  1.1  jklos 
    329  1.1  jklos void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
    330  1.1  jklos                  const struct mdio_ops *mdio_ops)
    331  1.1  jklos {
    332  1.1  jklos     cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops);
    333  1.1  jklos }
    334