355 lines · c
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 two5 * licenses. You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 * Redistribution and use in source and binary forms, with or11 * without modification, are permitted provided that the following12 * conditions are met:13 *14 * - Redistributions of source code must retain the above15 * copyright notice, this list of conditions and the following16 * disclaimer.17 *18 * - Redistributions in binary form must reproduce the above19 * copyright notice, this list of conditions and the following20 * disclaimer in the documentation and/or other materials21 * 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 OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * 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 to69 * 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. So279 * 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 normal326 * 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 } else338 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