root/drivers/net/ethernet/chelsio/cxgb3/aq100x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. aq100x_reset
  2. aq100x_intr_enable
  3. aq100x_intr_disable
  4. aq100x_intr_clear
  5. aq100x_intr_handler
  6. aq100x_power_down
  7. aq100x_autoneg_enable
  8. aq100x_autoneg_restart
  9. aq100x_advertise
  10. aq100x_set_loopback
  11. aq100x_set_speed_duplex
  12. aq100x_get_link_status
  13. t3_aq100x_phy_prep

   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 
  36 enum {
  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 
  55 enum {
  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 
  65 static 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 
  80 static 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 
  90 static int aq100x_intr_disable(struct cphy *phy)
  91 {
  92         return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0);
  93 }
  94 
  95 static 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 
 105 static 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 
 120 static 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 
 127 static 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 
 140 static 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 
 153 static 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 
 194 static 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 
 201 static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
 202 {
 203         /* no can do */
 204         return -1;
 205 }
 206 
 207 static 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 
 250 static 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 
 266 int 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 
 352 done:
 353         return err;
 354 }

/* [<][>][^][v][top][bottom][index][help] */