linux/drivers/net/ethernet/chelsio/cxgb3/aq100x.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include "common.h"
  34#include "regs.h"
  35
  36enum {
  37        /* MDIO_DEV_PMA_PMD registers */
  38        AQ_LINK_STAT    = 0xe800,
  39        AQ_IMASK_PMA    = 0xf000,
  40
  41        /* MDIO_DEV_XGXS registers */
  42        AQ_XAUI_RX_CFG  = 0xc400,
  43        AQ_XAUI_TX_CFG  = 0xe400,
  44
  45        /* MDIO_DEV_ANEG registers */
  46        AQ_1G_CTRL      = 0xc400,
  47        AQ_ANEG_STAT    = 0xc800,
  48
  49        /* MDIO_DEV_VEND1 registers */
  50        AQ_FW_VERSION   = 0x0020,
  51        AQ_IFLAG_GLOBAL = 0xfc00,
  52        AQ_IMASK_GLOBAL = 0xff00,
  53};
  54
  55enum {
  56        IMASK_PMA       = 1 << 2,
  57        IMASK_GLOBAL    = 1 << 15,
  58        ADV_1G_FULL     = 1 << 15,
  59        ADV_1G_HALF     = 1 << 14,
  60        ADV_10G_FULL    = 1 << 12,
  61        AQ_RESET        = (1 << 14) | (1 << 15),
  62        AQ_LOWPOWER     = 1 << 12,
  63};
  64
  65static int aq100x_reset(struct cphy *phy, int wait)
  66{
  67        /*
  68         * Ignore the caller specified wait time; always wait for the reset to
  69         * complete. Can take up to 3s.
  70         */
  71        int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000);
  72
  73        if (err)
  74                CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n",
  75                        phy->mdio.prtad, err);
  76
  77        return err;
  78}
  79
  80static int aq100x_intr_enable(struct cphy *phy)
  81{
  82        int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA);
  83        if (err)
  84                return err;
  85
  86        err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL);
  87        return err;
  88}
  89
  90static int aq100x_intr_disable(struct cphy *phy)
  91{
  92        return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0);
  93}
  94
  95static int aq100x_intr_clear(struct cphy *phy)
  96{
  97        unsigned int v;
  98
  99        t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v);
 100        t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v);
 101
 102        return 0;
 103}
 104
 105static int aq100x_intr_handler(struct cphy *phy)
 106{
 107        int err;
 108        unsigned int cause, v;
 109
 110        err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause);
 111        if (err)
 112                return err;
 113
 114        /* Read (and reset) the latching version of the status */
 115        t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v);
 116
 117        return cphy_cause_link_change;
 118}
 119
 120static int aq100x_power_down(struct cphy *phy, int off)
 121{
 122        return mdio_set_flag(&phy->mdio, phy->mdio.prtad,
 123                             MDIO_MMD_PMAPMD, MDIO_CTRL1,
 124                             MDIO_CTRL1_LPOWER, off);
 125}
 126
 127static int aq100x_autoneg_enable(struct cphy *phy)
 128{
 129        int err;
 130
 131        err = aq100x_power_down(phy, 0);
 132        if (!err)
 133                err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
 134                                    MDIO_MMD_AN, MDIO_CTRL1,
 135                                    BMCR_ANENABLE | BMCR_ANRESTART, 1);
 136
 137        return err;
 138}
 139
 140static int aq100x_autoneg_restart(struct cphy *phy)
 141{
 142        int err;
 143
 144        err = aq100x_power_down(phy, 0);
 145        if (!err)
 146                err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
 147                                    MDIO_MMD_AN, MDIO_CTRL1,
 148                                    BMCR_ANENABLE | BMCR_ANRESTART, 1);
 149
 150        return err;
 151}
 152
 153static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
 154{
 155        unsigned int adv;
 156        int err;
 157
 158        /* 10G advertisement */
 159        adv = 0;
 160        if (advertise_map & ADVERTISED_10000baseT_Full)
 161                adv |= ADV_10G_FULL;
 162        err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
 163                                  ADV_10G_FULL, adv);
 164        if (err)
 165                return err;
 166
 167        /* 1G advertisement */
 168        adv = 0;
 169        if (advertise_map & ADVERTISED_1000baseT_Full)
 170                adv |= ADV_1G_FULL;
 171        if (advertise_map & ADVERTISED_1000baseT_Half)
 172                adv |= ADV_1G_HALF;
 173        err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL,
 174                                  ADV_1G_FULL | ADV_1G_HALF, adv);
 175        if (err)
 176                return err;
 177
 178        /* 100M, pause advertisement */
 179        adv = 0;
 180        if (advertise_map & ADVERTISED_100baseT_Half)
 181                adv |= ADVERTISE_100HALF;
 182        if (advertise_map & ADVERTISED_100baseT_Full)
 183                adv |= ADVERTISE_100FULL;
 184        if (advertise_map & ADVERTISED_Pause)
 185                adv |= ADVERTISE_PAUSE_CAP;
 186        if (advertise_map & ADVERTISED_Asym_Pause)
 187                adv |= ADVERTISE_PAUSE_ASYM;
 188        err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
 189                                  0xfe0, adv);
 190
 191        return err;
 192}
 193
 194static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
 195{
 196        return mdio_set_flag(&phy->mdio, phy->mdio.prtad,
 197                             MDIO_MMD_PMAPMD, MDIO_CTRL1,
 198                             BMCR_LOOPBACK, enable);
 199}
 200
 201static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
 202{
 203        /* no can do */
 204        return -1;
 205}
 206
 207static int aq100x_get_link_status(struct cphy *phy, int *link_ok,
 208                                  int *speed, int *duplex, int *fc)
 209{
 210        int err;
 211        unsigned int v;
 212
 213        if (link_ok) {
 214                err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v);
 215                if (err)
 216                        return err;
 217
 218                *link_ok = v & 1;
 219                if (!*link_ok)
 220                        return 0;
 221        }
 222
 223        err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v);
 224        if (err)
 225                return err;
 226
 227        if (speed) {
 228                switch (v & 0x6) {
 229                case 0x6:
 230                        *speed = SPEED_10000;
 231                        break;
 232                case 0x4:
 233                        *speed = SPEED_1000;
 234                        break;
 235                case 0x2:
 236                        *speed = SPEED_100;
 237                        break;
 238                case 0x0:
 239                        *speed = SPEED_10;
 240                        break;
 241                }
 242        }
 243
 244        if (duplex)
 245                *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
 246
 247        return 0;
 248}
 249
 250static const struct cphy_ops aq100x_ops = {
 251        .reset             = aq100x_reset,
 252        .intr_enable       = aq100x_intr_enable,
 253        .intr_disable      = aq100x_intr_disable,
 254        .intr_clear        = aq100x_intr_clear,
 255        .intr_handler      = aq100x_intr_handler,
 256        .autoneg_enable    = aq100x_autoneg_enable,
 257        .autoneg_restart   = aq100x_autoneg_restart,
 258        .advertise         = aq100x_advertise,
 259        .set_loopback      = aq100x_set_loopback,
 260        .set_speed_duplex  = aq100x_set_speed_duplex,
 261        .get_link_status   = aq100x_get_link_status,
 262        .power_down        = aq100x_power_down,
 263        .mmds              = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 264};
 265
 266int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
 267                       const struct mdio_ops *mdio_ops)
 268{
 269        unsigned int v, v2, gpio, wait;
 270        int err;
 271
 272        cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
 273                  SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
 274                  SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI,
 275                  "1000/10GBASE-T");
 276
 277        /*
 278         * The PHY has been out of reset ever since the system powered up.  So
 279         * we do a hard reset over here.
 280         */
 281        gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
 282        t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
 283        msleep(1);
 284        t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
 285
 286        /*
 287         * Give it enough time to load the firmware and get ready for mdio.
 288         */
 289        msleep(1000);
 290        wait = 500; /* in 10ms increments */
 291        do {
 292                err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v);
 293                if (err || v == 0xffff) {
 294
 295                        /* Allow prep_adapter to succeed when ffff is read */
 296
 297                        CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
 298                                phy_addr, err, v);
 299                        goto done;
 300                }
 301
 302                v &= AQ_RESET;
 303                if (v)
 304                        msleep(10);
 305        } while (v && --wait);
 306        if (v) {
 307                CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
 308                        phy_addr, v);
 309
 310                goto done; /* let prep_adapter succeed */
 311        }
 312
 313        /* Datasheet says 3s max but this has been observed */
 314        wait = (500 - wait) * 10 + 1000;
 315        if (wait > 3000)
 316                CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait);
 317
 318        /* Firmware version check. */
 319        t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
 320        if (v != 101)
 321                CH_WARN(adapter, "PHY%d: unsupported firmware %d\n",
 322                        phy_addr, v);
 323
 324        /*
 325         * The PHY should start in really-low-power mode.  Prepare it for normal
 326         * operations.
 327         */
 328        err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v);
 329        if (err)
 330                return err;
 331        if (v & AQ_LOWPOWER) {
 332                err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1,
 333                                          AQ_LOWPOWER, 0);
 334                if (err)
 335                        return err;
 336                msleep(10);
 337        } else
 338                CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
 339                        phy_addr);
 340
 341        /*
 342         * Verify XAUI settings, but let prep succeed no matter what.
 343         */
 344        v = v2 = 0;
 345        t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v);
 346        t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2);
 347        if (v != 0x1b || v2 != 0x1b)
 348                CH_WARN(adapter,
 349                        "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n",
 350                        phy_addr, v, v2);
 351
 352done:
 353        return err;
 354}
 355