linux/drivers/net/cxgb3/ael1002.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#include "common.h"
  33#include "regs.h"
  34
  35enum {
  36        AEL100X_TX_CONFIG1 = 0xc002,
  37        AEL1002_PWR_DOWN_HI = 0xc011,
  38        AEL1002_PWR_DOWN_LO = 0xc012,
  39        AEL1002_XFI_EQL = 0xc015,
  40        AEL1002_LB_EN = 0xc017,
  41        AEL_OPT_SETTINGS = 0xc017,
  42        AEL_I2C_CTRL = 0xc30a,
  43        AEL_I2C_DATA = 0xc30b,
  44        AEL_I2C_STAT = 0xc30c,
  45        AEL2005_GPIO_CTRL = 0xc214,
  46        AEL2005_GPIO_STAT = 0xc215,
  47
  48        AEL2020_GPIO_INTR   = 0xc103,   /* Latch High (LH) */
  49        AEL2020_GPIO_CTRL   = 0xc108,   /* Store Clear (SC) */
  50        AEL2020_GPIO_STAT   = 0xc10c,   /* Read Only (RO) */
  51        AEL2020_GPIO_CFG    = 0xc110,   /* Read Write (RW) */
  52
  53        AEL2020_GPIO_SDA    = 0,        /* IN: i2c serial data */
  54        AEL2020_GPIO_MODDET = 1,        /* IN: Module Detect */
  55        AEL2020_GPIO_0      = 3,        /* IN: unassigned */
  56        AEL2020_GPIO_1      = 2,        /* OUT: unassigned */
  57        AEL2020_GPIO_LSTAT  = AEL2020_GPIO_1, /* wired to link status LED */
  58};
  59
  60enum { edc_none, edc_sr, edc_twinax };
  61
  62/* PHY module I2C device address */
  63enum {
  64        MODULE_DEV_ADDR = 0xa0,
  65        SFF_DEV_ADDR    = 0xa2,
  66};
  67
  68/* PHY transceiver type */
  69enum {
  70        phy_transtype_unknown = 0,
  71        phy_transtype_sfp     = 3,
  72        phy_transtype_xfp     = 6,
  73};
  74
  75#define AEL2005_MODDET_IRQ 4
  76
  77struct reg_val {
  78        unsigned short mmd_addr;
  79        unsigned short reg_addr;
  80        unsigned short clear_bits;
  81        unsigned short set_bits;
  82};
  83
  84static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
  85{
  86        int err;
  87
  88        for (err = 0; rv->mmd_addr && !err; rv++) {
  89                if (rv->clear_bits == 0xffff)
  90                        err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr,
  91                                            rv->set_bits);
  92                else
  93                        err = t3_mdio_change_bits(phy, rv->mmd_addr,
  94                                                  rv->reg_addr, rv->clear_bits,
  95                                                  rv->set_bits);
  96        }
  97        return err;
  98}
  99
 100static void ael100x_txon(struct cphy *phy)
 101{
 102        int tx_on_gpio =
 103                phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
 104
 105        msleep(100);
 106        t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
 107        msleep(30);
 108}
 109
 110/*
 111 * Read an 8-bit word from a device attached to the PHY's i2c bus.
 112 */
 113static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
 114{
 115        int i, err;
 116        unsigned int stat, data;
 117
 118        err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
 119                            (dev_addr << 8) | (1 << 8) | word_addr);
 120        if (err)
 121                return err;
 122
 123        for (i = 0; i < 200; i++) {
 124                msleep(1);
 125                err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
 126                if (err)
 127                        return err;
 128                if ((stat & 3) == 1) {
 129                        err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
 130                                           &data);
 131                        if (err)
 132                                return err;
 133                        return data >> 8;
 134                }
 135        }
 136        CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n",
 137                phy->mdio.prtad, dev_addr, word_addr);
 138        return -ETIMEDOUT;
 139}
 140
 141static int ael1002_power_down(struct cphy *phy, int enable)
 142{
 143        int err;
 144
 145        err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable);
 146        if (!err)
 147                err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
 148                                    MDIO_MMD_PMAPMD, MDIO_CTRL1,
 149                                    MDIO_CTRL1_LPOWER, enable);
 150        return err;
 151}
 152
 153static int ael1002_reset(struct cphy *phy, int wait)
 154{
 155        int err;
 156
 157        if ((err = ael1002_power_down(phy, 0)) ||
 158            (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) ||
 159            (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) ||
 160            (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) ||
 161            (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) ||
 162            (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN,
 163                                       0, 1 << 5)))
 164                return err;
 165        return 0;
 166}
 167
 168static int ael1002_intr_noop(struct cphy *phy)
 169{
 170        return 0;
 171}
 172
 173/*
 174 * Get link status for a 10GBASE-R device.
 175 */
 176static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
 177                             int *duplex, int *fc)
 178{
 179        if (link_ok) {
 180                unsigned int stat0, stat1, stat2;
 181                int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
 182                                       MDIO_PMA_RXDET, &stat0);
 183
 184                if (!err)
 185                        err = t3_mdio_read(phy, MDIO_MMD_PCS,
 186                                           MDIO_PCS_10GBRT_STAT1, &stat1);
 187                if (!err)
 188                        err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
 189                                           MDIO_PHYXS_LNSTAT, &stat2);
 190                if (err)
 191                        return err;
 192                *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
 193        }
 194        if (speed)
 195                *speed = SPEED_10000;
 196        if (duplex)
 197                *duplex = DUPLEX_FULL;
 198        return 0;
 199}
 200
 201static struct cphy_ops ael1002_ops = {
 202        .reset = ael1002_reset,
 203        .intr_enable = ael1002_intr_noop,
 204        .intr_disable = ael1002_intr_noop,
 205        .intr_clear = ael1002_intr_noop,
 206        .intr_handler = ael1002_intr_noop,
 207        .get_link_status = get_link_status_r,
 208        .power_down = ael1002_power_down,
 209        .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 210};
 211
 212int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
 213                        int phy_addr, const struct mdio_ops *mdio_ops)
 214{
 215        cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
 216                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
 217                   "10GBASE-R");
 218        ael100x_txon(phy);
 219        return 0;
 220}
 221
 222static int ael1006_reset(struct cphy *phy, int wait)
 223{
 224        return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
 225}
 226
 227static struct cphy_ops ael1006_ops = {
 228        .reset = ael1006_reset,
 229        .intr_enable = t3_phy_lasi_intr_enable,
 230        .intr_disable = t3_phy_lasi_intr_disable,
 231        .intr_clear = t3_phy_lasi_intr_clear,
 232        .intr_handler = t3_phy_lasi_intr_handler,
 233        .get_link_status = get_link_status_r,
 234        .power_down = ael1002_power_down,
 235        .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 236};
 237
 238int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
 239                             int phy_addr, const struct mdio_ops *mdio_ops)
 240{
 241        cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
 242                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
 243                   "10GBASE-SR");
 244        ael100x_txon(phy);
 245        return 0;
 246}
 247
 248/*
 249 * Decode our module type.
 250 */
 251static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms)
 252{
 253        int v;
 254
 255        if (delay_ms)
 256                msleep(delay_ms);
 257
 258        /* see SFF-8472 for below */
 259        v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3);
 260        if (v < 0)
 261                return v;
 262
 263        if (v == 0x10)
 264                return phy_modtype_sr;
 265        if (v == 0x20)
 266                return phy_modtype_lr;
 267        if (v == 0x40)
 268                return phy_modtype_lrm;
 269
 270        v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6);
 271        if (v < 0)
 272                return v;
 273        if (v != 4)
 274                goto unknown;
 275
 276        v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10);
 277        if (v < 0)
 278                return v;
 279
 280        if (v & 0x80) {
 281                v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
 282                if (v < 0)
 283                        return v;
 284                return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
 285        }
 286unknown:
 287        return phy_modtype_unknown;
 288}
 289
 290/*
 291 * Code to support the Aeluros/NetLogic 2005 10Gb PHY.
 292 */
 293static int ael2005_setup_sr_edc(struct cphy *phy)
 294{
 295        static struct reg_val regs[] = {
 296                { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 },
 297                { MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a },
 298                { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
 299                { 0, 0, 0, 0 }
 300        };
 301
 302        int i, err;
 303
 304        err = set_phy_regs(phy, regs);
 305        if (err)
 306                return err;
 307
 308        msleep(50);
 309
 310        if (phy->priv != edc_sr)
 311                err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
 312                                    EDC_OPT_AEL2005_SIZE);
 313        if (err)
 314                return err;
 315
 316        for (i = 0; i <  EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
 317                err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
 318                                    phy->phy_cache[i],
 319                                    phy->phy_cache[i + 1]);
 320        if (!err)
 321                phy->priv = edc_sr;
 322        return err;
 323}
 324
 325static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
 326{
 327        static struct reg_val regs[] = {
 328                { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 },
 329                { 0, 0, 0, 0 }
 330        };
 331        static struct reg_val preemphasis[] = {
 332                { MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 },
 333                { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
 334                { 0, 0, 0, 0 }
 335        };
 336        int i, err;
 337
 338        err = set_phy_regs(phy, regs);
 339        if (!err && modtype == phy_modtype_twinax_long)
 340                err = set_phy_regs(phy, preemphasis);
 341        if (err)
 342                return err;
 343
 344        msleep(50);
 345
 346        if (phy->priv != edc_twinax)
 347                err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
 348                                    EDC_TWX_AEL2005_SIZE);
 349        if (err)
 350                return err;
 351
 352        for (i = 0; i <  EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
 353                err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
 354                                    phy->phy_cache[i],
 355                                    phy->phy_cache[i + 1]);
 356        if (!err)
 357                phy->priv = edc_twinax;
 358        return err;
 359}
 360
 361static int ael2005_get_module_type(struct cphy *phy, int delay_ms)
 362{
 363        int v;
 364        unsigned int stat;
 365
 366        v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat);
 367        if (v)
 368                return v;
 369
 370        if (stat & (1 << 8))                    /* module absent */
 371                return phy_modtype_none;
 372
 373        return ael2xxx_get_module_type(phy, delay_ms);
 374}
 375
 376static int ael2005_intr_enable(struct cphy *phy)
 377{
 378        int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200);
 379        return err ? err : t3_phy_lasi_intr_enable(phy);
 380}
 381
 382static int ael2005_intr_disable(struct cphy *phy)
 383{
 384        int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100);
 385        return err ? err : t3_phy_lasi_intr_disable(phy);
 386}
 387
 388static int ael2005_intr_clear(struct cphy *phy)
 389{
 390        int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00);
 391        return err ? err : t3_phy_lasi_intr_clear(phy);
 392}
 393
 394static int ael2005_reset(struct cphy *phy, int wait)
 395{
 396        static struct reg_val regs0[] = {
 397                { MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 },
 398                { MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 },
 399                { MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 },
 400                { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
 401                { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 },
 402                { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
 403                { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 },
 404                { 0, 0, 0, 0 }
 405        };
 406        static struct reg_val regs1[] = {
 407                { MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 },
 408                { MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 },
 409                { 0, 0, 0, 0 }
 410        };
 411
 412        int err;
 413        unsigned int lasi_ctrl;
 414
 415        err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
 416                           &lasi_ctrl);
 417        if (err)
 418                return err;
 419
 420        err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0);
 421        if (err)
 422                return err;
 423
 424        msleep(125);
 425        phy->priv = edc_none;
 426        err = set_phy_regs(phy, regs0);
 427        if (err)
 428                return err;
 429
 430        msleep(50);
 431
 432        err = ael2005_get_module_type(phy, 0);
 433        if (err < 0)
 434                return err;
 435        phy->modtype = err;
 436
 437        if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
 438                err = ael2005_setup_twinax_edc(phy, err);
 439        else
 440                err = ael2005_setup_sr_edc(phy);
 441        if (err)
 442                return err;
 443
 444        err = set_phy_regs(phy, regs1);
 445        if (err)
 446                return err;
 447
 448        /* reset wipes out interrupts, reenable them if they were on */
 449        if (lasi_ctrl & 1)
 450                err = ael2005_intr_enable(phy);
 451        return err;
 452}
 453
 454static int ael2005_intr_handler(struct cphy *phy)
 455{
 456        unsigned int stat;
 457        int ret, edc_needed, cause = 0;
 458
 459        ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat);
 460        if (ret)
 461                return ret;
 462
 463        if (stat & AEL2005_MODDET_IRQ) {
 464                ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL,
 465                                    0xd00);
 466                if (ret)
 467                        return ret;
 468
 469                /* modules have max 300 ms init time after hot plug */
 470                ret = ael2005_get_module_type(phy, 300);
 471                if (ret < 0)
 472                        return ret;
 473
 474                phy->modtype = ret;
 475                if (ret == phy_modtype_none)
 476                        edc_needed = phy->priv;       /* on unplug retain EDC */
 477                else if (ret == phy_modtype_twinax ||
 478                         ret == phy_modtype_twinax_long)
 479                        edc_needed = edc_twinax;
 480                else
 481                        edc_needed = edc_sr;
 482
 483                if (edc_needed != phy->priv) {
 484                        ret = ael2005_reset(phy, 0);
 485                        return ret ? ret : cphy_cause_module_change;
 486                }
 487                cause = cphy_cause_module_change;
 488        }
 489
 490        ret = t3_phy_lasi_intr_handler(phy);
 491        if (ret < 0)
 492                return ret;
 493
 494        ret |= cause;
 495        return ret ? ret : cphy_cause_link_change;
 496}
 497
 498static struct cphy_ops ael2005_ops = {
 499        .reset           = ael2005_reset,
 500        .intr_enable     = ael2005_intr_enable,
 501        .intr_disable    = ael2005_intr_disable,
 502        .intr_clear      = ael2005_intr_clear,
 503        .intr_handler    = ael2005_intr_handler,
 504        .get_link_status = get_link_status_r,
 505        .power_down      = ael1002_power_down,
 506        .mmds            = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 507};
 508
 509int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
 510                        int phy_addr, const struct mdio_ops *mdio_ops)
 511{
 512        cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
 513                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
 514                  SUPPORTED_IRQ, "10GBASE-R");
 515        msleep(125);
 516        return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0,
 517                                   1 << 5);
 518}
 519
 520/*
 521 * Setup EDC and other parameters for operation with an optical module.
 522 */
 523static int ael2020_setup_sr_edc(struct cphy *phy)
 524{
 525        static struct reg_val regs[] = {
 526                /* set CDR offset to 10 */
 527                { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a },
 528
 529                /* adjust 10G RX bias current */
 530                { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 },
 531                { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 },
 532                { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 },
 533
 534                /* end */
 535                { 0, 0, 0, 0 }
 536        };
 537        int err;
 538
 539        err = set_phy_regs(phy, regs);
 540        msleep(50);
 541        if (err)
 542                return err;
 543
 544        phy->priv = edc_sr;
 545        return 0;
 546}
 547
 548/*
 549 * Setup EDC and other parameters for operation with an TWINAX module.
 550 */
 551static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
 552{
 553        /* set uC to 40MHz */
 554        static struct reg_val uCclock40MHz[] = {
 555                { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 },
 556                { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 },
 557                { 0, 0, 0, 0 }
 558        };
 559
 560        /* activate uC clock */
 561        static struct reg_val uCclockActivate[] = {
 562                { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 },
 563                { 0, 0, 0, 0 }
 564        };
 565
 566        /* set PC to start of SRAM and activate uC */
 567        static struct reg_val uCactivate[] = {
 568                { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 },
 569                { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
 570                { 0, 0, 0, 0 }
 571        };
 572        int i, err;
 573
 574        /* set uC clock and activate it */
 575        err = set_phy_regs(phy, uCclock40MHz);
 576        msleep(500);
 577        if (err)
 578                return err;
 579        err = set_phy_regs(phy, uCclockActivate);
 580        msleep(500);
 581        if (err)
 582                return err;
 583
 584        if (phy->priv != edc_twinax)
 585                err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
 586                                    EDC_TWX_AEL2020_SIZE);
 587        if (err)
 588                return err;
 589
 590        for (i = 0; i <  EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
 591                err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
 592                                    phy->phy_cache[i],
 593                                    phy->phy_cache[i + 1]);
 594        /* activate uC */
 595        err = set_phy_regs(phy, uCactivate);
 596        if (!err)
 597                phy->priv = edc_twinax;
 598        return err;
 599}
 600
 601/*
 602 * Return Module Type.
 603 */
 604static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
 605{
 606        int v;
 607        unsigned int stat;
 608
 609        v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat);
 610        if (v)
 611                return v;
 612
 613        if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) {
 614                /* module absent */
 615                return phy_modtype_none;
 616        }
 617
 618        return ael2xxx_get_module_type(phy, delay_ms);
 619}
 620
 621/*
 622 * Enable PHY interrupts.  We enable "Module Detection" interrupts (on any
 623 * state transition) and then generic Link Alarm Status Interrupt (LASI).
 624 */
 625static int ael2020_intr_enable(struct cphy *phy)
 626{
 627        struct reg_val regs[] = {
 628                /* output Module's Loss Of Signal (LOS) to LED */
 629                { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
 630                        0xffff, 0x4 },
 631                { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
 632                        0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
 633
 634                 /* enable module detect status change interrupts */
 635                { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
 636                        0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
 637
 638                /* end */
 639                { 0, 0, 0, 0 }
 640        };
 641        int err, link_ok = 0;
 642
 643        /* set up "link status" LED and enable module change interrupts */
 644        err = set_phy_regs(phy, regs);
 645        if (err)
 646                return err;
 647
 648        err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
 649        if (err)
 650                return err;
 651        if (link_ok)
 652                t3_link_changed(phy->adapter,
 653                                phy2portid(phy));
 654
 655        err = t3_phy_lasi_intr_enable(phy);
 656        if (err)
 657                return err;
 658
 659        return 0;
 660}
 661
 662/*
 663 * Disable PHY interrupts.  The mirror of the above ...
 664 */
 665static int ael2020_intr_disable(struct cphy *phy)
 666{
 667        struct reg_val regs[] = {
 668                /* reset "link status" LED to "off" */
 669                { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
 670                        0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
 671
 672                /* disable module detect status change interrupts */
 673                { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
 674                        0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
 675
 676                /* end */
 677                { 0, 0, 0, 0 }
 678        };
 679        int err;
 680
 681        /* turn off "link status" LED and disable module change interrupts */
 682        err = set_phy_regs(phy, regs);
 683        if (err)
 684                return err;
 685
 686        return t3_phy_lasi_intr_disable(phy);
 687}
 688
 689/*
 690 * Clear PHY interrupt state.
 691 */
 692static int ael2020_intr_clear(struct cphy *phy)
 693{
 694        /*
 695         * The GPIO Interrupt register on the AEL2020 is a "Latching High"
 696         * (LH) register which is cleared to the current state when it's read.
 697         * Thus, we simply read the register and discard the result.
 698         */
 699        unsigned int stat;
 700        int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
 701        return err ? err : t3_phy_lasi_intr_clear(phy);
 702}
 703
 704static struct reg_val ael2020_reset_regs[] = {
 705        /* Erratum #2: CDRLOL asserted, causing PMA link down status */
 706        { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
 707
 708        /* force XAUI to send LF when RX_LOS is asserted */
 709        { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
 710
 711        /* allow writes to transceiver module EEPROM on i2c bus */
 712        { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
 713        { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
 714        { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
 715
 716        /* end */
 717        { 0, 0, 0, 0 }
 718};
 719/*
 720 * Reset the PHY and put it into a canonical operating state.
 721 */
 722static int ael2020_reset(struct cphy *phy, int wait)
 723{
 724        int err;
 725        unsigned int lasi_ctrl;
 726
 727        /* grab current interrupt state */
 728        err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
 729                           &lasi_ctrl);
 730        if (err)
 731                return err;
 732
 733        err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125);
 734        if (err)
 735                return err;
 736        msleep(100);
 737
 738        /* basic initialization for all module types */
 739        phy->priv = edc_none;
 740        err = set_phy_regs(phy, ael2020_reset_regs);
 741        if (err)
 742                return err;
 743
 744        /* determine module type and perform appropriate initialization */
 745        err = ael2020_get_module_type(phy, 0);
 746        if (err < 0)
 747                return err;
 748        phy->modtype = (u8)err;
 749        if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
 750                err = ael2020_setup_twinax_edc(phy, err);
 751        else
 752                err = ael2020_setup_sr_edc(phy);
 753        if (err)
 754                return err;
 755
 756        /* reset wipes out interrupts, reenable them if they were on */
 757        if (lasi_ctrl & 1)
 758                err = ael2005_intr_enable(phy);
 759        return err;
 760}
 761
 762/*
 763 * Handle a PHY interrupt.
 764 */
 765static int ael2020_intr_handler(struct cphy *phy)
 766{
 767        unsigned int stat;
 768        int ret, edc_needed, cause = 0;
 769
 770        ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
 771        if (ret)
 772                return ret;
 773
 774        if (stat & (0x1 << AEL2020_GPIO_MODDET)) {
 775                /* modules have max 300 ms init time after hot plug */
 776                ret = ael2020_get_module_type(phy, 300);
 777                if (ret < 0)
 778                        return ret;
 779
 780                phy->modtype = (u8)ret;
 781                if (ret == phy_modtype_none)
 782                        edc_needed = phy->priv;       /* on unplug retain EDC */
 783                else if (ret == phy_modtype_twinax ||
 784                         ret == phy_modtype_twinax_long)
 785                        edc_needed = edc_twinax;
 786                else
 787                        edc_needed = edc_sr;
 788
 789                if (edc_needed != phy->priv) {
 790                        ret = ael2020_reset(phy, 0);
 791                        return ret ? ret : cphy_cause_module_change;
 792                }
 793                cause = cphy_cause_module_change;
 794        }
 795
 796        ret = t3_phy_lasi_intr_handler(phy);
 797        if (ret < 0)
 798                return ret;
 799
 800        ret |= cause;
 801        return ret ? ret : cphy_cause_link_change;
 802}
 803
 804static struct cphy_ops ael2020_ops = {
 805        .reset           = ael2020_reset,
 806        .intr_enable     = ael2020_intr_enable,
 807        .intr_disable    = ael2020_intr_disable,
 808        .intr_clear      = ael2020_intr_clear,
 809        .intr_handler    = ael2020_intr_handler,
 810        .get_link_status = get_link_status_r,
 811        .power_down      = ael1002_power_down,
 812        .mmds            = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 813};
 814
 815int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
 816                        const struct mdio_ops *mdio_ops)
 817{
 818        int err;
 819
 820        cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
 821                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
 822                  SUPPORTED_IRQ, "10GBASE-R");
 823        msleep(125);
 824
 825        err = set_phy_regs(phy, ael2020_reset_regs);
 826        if (err)
 827                return err;
 828        return 0;
 829}
 830
 831/*
 832 * Get link status for a 10GBASE-X device.
 833 */
 834static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
 835                             int *duplex, int *fc)
 836{
 837        if (link_ok) {
 838                unsigned int stat0, stat1, stat2;
 839                int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
 840                                       MDIO_PMA_RXDET, &stat0);
 841
 842                if (!err)
 843                        err = t3_mdio_read(phy, MDIO_MMD_PCS,
 844                                           MDIO_PCS_10GBX_STAT1, &stat1);
 845                if (!err)
 846                        err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
 847                                           MDIO_PHYXS_LNSTAT, &stat2);
 848                if (err)
 849                        return err;
 850                *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
 851        }
 852        if (speed)
 853                *speed = SPEED_10000;
 854        if (duplex)
 855                *duplex = DUPLEX_FULL;
 856        return 0;
 857}
 858
 859static struct cphy_ops qt2045_ops = {
 860        .reset = ael1006_reset,
 861        .intr_enable = t3_phy_lasi_intr_enable,
 862        .intr_disable = t3_phy_lasi_intr_disable,
 863        .intr_clear = t3_phy_lasi_intr_clear,
 864        .intr_handler = t3_phy_lasi_intr_handler,
 865        .get_link_status = get_link_status_x,
 866        .power_down = ael1002_power_down,
 867        .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
 868};
 869
 870int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
 871                       int phy_addr, const struct mdio_ops *mdio_ops)
 872{
 873        unsigned int stat;
 874
 875        cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
 876                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
 877                  "10GBASE-CX4");
 878
 879        /*
 880         * Some cards where the PHY is supposed to be at address 0 actually
 881         * have it at 1.
 882         */
 883        if (!phy_addr &&
 884            !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) &&
 885            stat == 0xffff)
 886                phy->mdio.prtad = 1;
 887        return 0;
 888}
 889
 890static int xaui_direct_reset(struct cphy *phy, int wait)
 891{
 892        return 0;
 893}
 894
 895static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
 896                                       int *speed, int *duplex, int *fc)
 897{
 898        if (link_ok) {
 899                unsigned int status;
 900                int prtad = phy->mdio.prtad;
 901
 902                status = t3_read_reg(phy->adapter,
 903                                     XGM_REG(A_XGM_SERDES_STAT0, prtad)) |
 904                    t3_read_reg(phy->adapter,
 905                                    XGM_REG(A_XGM_SERDES_STAT1, prtad)) |
 906                    t3_read_reg(phy->adapter,
 907                                XGM_REG(A_XGM_SERDES_STAT2, prtad)) |
 908                    t3_read_reg(phy->adapter,
 909                                XGM_REG(A_XGM_SERDES_STAT3, prtad));
 910                *link_ok = !(status & F_LOWSIG0);
 911        }
 912        if (speed)
 913                *speed = SPEED_10000;
 914        if (duplex)
 915                *duplex = DUPLEX_FULL;
 916        return 0;
 917}
 918
 919static int xaui_direct_power_down(struct cphy *phy, int enable)
 920{
 921        return 0;
 922}
 923
 924static struct cphy_ops xaui_direct_ops = {
 925        .reset = xaui_direct_reset,
 926        .intr_enable = ael1002_intr_noop,
 927        .intr_disable = ael1002_intr_noop,
 928        .intr_clear = ael1002_intr_noop,
 929        .intr_handler = ael1002_intr_noop,
 930        .get_link_status = xaui_direct_get_link_status,
 931        .power_down = xaui_direct_power_down,
 932};
 933
 934int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
 935                            int phy_addr, const struct mdio_ops *mdio_ops)
 936{
 937        cphy_init(phy, adapter, MDIO_PRTAD_NONE, &xaui_direct_ops, mdio_ops,
 938                  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
 939                  "10GBASE-CX4");
 940        return 0;
 941}
 942