/*
* Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "common.h"
#include "regs.h"
enum {
AEL100X_TX_CONFIG1 = 0xc002,
AEL1002_PWR_DOWN_HI = 0xc011,
AEL1002_PWR_DOWN_LO = 0xc012,
AEL1002_XFI_EQL = 0xc015,
AEL1002_LB_EN = 0xc017,
AEL_OPT_SETTINGS = 0xc017,
AEL_I2C_CTRL = 0xc30a,
AEL_I2C_DATA = 0xc30b,
AEL_I2C_STAT = 0xc30c,
AEL2005_GPIO_CTRL = 0xc214,
AEL2005_GPIO_STAT = 0xc215,
AEL2020_GPIO_INTR = 0xc103, /* Latch High (LH) */
AEL2020_GPIO_CTRL = 0xc108, /* Store Clear (SC) */
AEL2020_GPIO_STAT = 0xc10c, /* Read Only (RO) */
AEL2020_GPIO_CFG = 0xc110, /* Read Write (RW) */
AEL2020_GPIO_SDA = 0, /* IN: i2c serial data */
AEL2020_GPIO_MODDET = 1, /* IN: Module Detect */
AEL2020_GPIO_0 = 3, /* IN: unassigned */
AEL2020_GPIO_1 = 2, /* OUT: unassigned */
AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, /* wired to link status LED */
};
enum { edc_none, edc_sr, edc_twinax };
/* PHY module I2C device address */
enum {
MODULE_DEV_ADDR = 0xa0,
SFF_DEV_ADDR = 0xa2,
};
/* PHY transceiver type */
enum {
phy_transtype_unknown = 0,
phy_transtype_sfp = 3,
phy_transtype_xfp = 6,
};
#define AEL2005_MODDET_IRQ 4
struct reg_val {
unsigned short mmd_addr;
unsigned short reg_addr;
unsigned short clear_bits;
unsigned short set_bits;
};
static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
{
int err;
for (err = 0; rv->mmd_addr && !err; rv++) {
if (rv->clear_bits == 0xffff)
err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr,
rv->set_bits);
else
err = t3_mdio_change_bits(phy, rv->mmd_addr,
rv->reg_addr, rv->clear_bits,
rv->set_bits);
}
return err;
}
static void ael100x_txon(struct cphy *phy)
{
int tx_on_gpio =
phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
msleep(100);
t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
msleep(30);
}
/*
* Read an 8-bit word from a device attached to the PHY's i2c bus.
*/
static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
{
int i, err;
unsigned int stat, data;
err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
(dev_addr << 8) | (1 << 8) | word_addr);
if (err)
return err;
for (i = 0; i < 200; i++) {
msleep(1);
err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
if (err)
return err;
if ((stat & 3) == 1) {
err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
&data);
if (err)
return err;
return data >> 8;
}
}
CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n",
phy->mdio.prtad, dev_addr, word_addr);
return -ETIMEDOUT;
}
static int ael1002_power_down(struct cphy *phy, int enable)
{
int err;
err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable);
if (!err)
err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
MDIO_MMD_PMAPMD, MDIO_CTRL1,
MDIO_CTRL1_LPOWER, enable);
return err;
}
static int ael1002_reset(struct cphy *phy, int wait)
{
int err;
if ((err = ael1002_power_down(phy, 0)) ||
(err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) ||
(err =