cxgb_ael1002.c revision 177340
1/************************************************************************** 2 3Copyright (c) 2007-2008, Chelsio Inc. 4All rights reserved. 5 6Redistribution and use in source and binary forms, with or without 7modification, are permitted provided that the following conditions are met: 8 9 1. Redistributions of source code must retain the above copyright notice, 10 this list of conditions and the following disclaimer. 11 12 2. Neither the name of the Chelsio Corporation nor the names of its 13 contributors may be used to endorse or promote products derived from 14 this software without specific prior written permission. 15 16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26POSSIBILITY OF SUCH DAMAGE. 27 28***************************************************************************/ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_ael1002.c 177340 2008-03-18 03:55:12Z kmacy $"); 32 33#ifdef CONFIG_DEFINED 34#include <cxgb_include.h> 35#else 36#include <dev/cxgb/cxgb_include.h> 37#endif 38 39#undef msleep 40#define msleep t3_os_sleep 41 42enum { 43 AEL100X_TX_DISABLE = 9, 44 AEL100X_TX_CONFIG1 = 0xc002, 45 AEL1002_PWR_DOWN_HI = 0xc011, 46 AEL1002_PWR_DOWN_LO = 0xc012, 47 AEL1002_XFI_EQL = 0xc015, 48 AEL1002_LB_EN = 0xc017, 49 50 LASI_CTRL = 0x9002, 51 LASI_STAT = 0x9005 52}; 53 54static void ael100x_txon(struct cphy *phy) 55{ 56 int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; 57 58 msleep(100); 59 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); 60 msleep(30); 61} 62 63static int ael1002_power_down(struct cphy *phy, int enable) 64{ 65 int err; 66 67 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); 68 if (!err) 69 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 70 BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 71 return err; 72} 73 74static int ael1002_reset(struct cphy *phy, int wait) 75{ 76 int err; 77 78 if ((err = ael1002_power_down(phy, 0)) || 79 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || 80 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || 81 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || 82 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || 83 (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, 84 0, 1 << 5))) 85 return err; 86 return 0; 87} 88 89static int ael1002_intr_noop(struct cphy *phy) 90{ 91 return 0; 92} 93 94static int ael100x_get_link_status(struct cphy *phy, int *link_ok, 95 int *speed, int *duplex, int *fc) 96{ 97 if (link_ok) { 98 unsigned int status; 99 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); 100 101 /* 102 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 103 * once more to get the current link state. 104 */ 105 if (!err && !(status & BMSR_LSTATUS)) 106 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, 107 &status); 108 if (err) 109 return err; 110 *link_ok = !!(status & BMSR_LSTATUS); 111 } 112 if (speed) 113 *speed = SPEED_10000; 114 if (duplex) 115 *duplex = DUPLEX_FULL; 116 return 0; 117} 118 119#ifdef C99_NOT_SUPPORTED 120static struct cphy_ops ael1002_ops = { 121 ael1002_reset, 122 ael1002_intr_noop, 123 ael1002_intr_noop, 124 ael1002_intr_noop, 125 ael1002_intr_noop, 126 NULL, 127 NULL, 128 NULL, 129 NULL, 130 NULL, 131 ael100x_get_link_status, 132 ael1002_power_down, 133}; 134#else 135static struct cphy_ops ael1002_ops = { 136 .reset = ael1002_reset, 137 .intr_enable = ael1002_intr_noop, 138 .intr_disable = ael1002_intr_noop, 139 .intr_clear = ael1002_intr_noop, 140 .intr_handler = ael1002_intr_noop, 141 .get_link_status = ael100x_get_link_status, 142 .power_down = ael1002_power_down, 143}; 144#endif 145 146int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 147 const struct mdio_ops *mdio_ops) 148{ 149 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, 150 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, 151 "10GBASE-R"); 152 ael100x_txon(phy); 153 return 0; 154} 155 156static int ael1006_reset(struct cphy *phy, int wait) 157{ 158 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); 159} 160 161static int ael1006_intr_enable(struct cphy *phy) 162{ 163 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); 164} 165 166static int ael1006_intr_disable(struct cphy *phy) 167{ 168 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); 169} 170 171static int ael1006_intr_clear(struct cphy *phy) 172{ 173 u32 val; 174 175 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); 176} 177 178static int ael1006_intr_handler(struct cphy *phy) 179{ 180 unsigned int status; 181 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); 182 183 if (err) 184 return err; 185 return (status & 1) ? cphy_cause_link_change : 0; 186} 187 188static int ael1006_power_down(struct cphy *phy, int enable) 189{ 190 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 191 BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 192} 193 194#ifdef C99_NOT_SUPPORTED 195static struct cphy_ops ael1006_ops = { 196 ael1006_reset, 197 ael1006_intr_enable, 198 ael1006_intr_disable, 199 ael1006_intr_clear, 200 ael1006_intr_handler, 201 NULL, 202 NULL, 203 NULL, 204 NULL, 205 NULL, 206 ael100x_get_link_status, 207 ael1006_power_down, 208}; 209#else 210static struct cphy_ops ael1006_ops = { 211 .reset = ael1006_reset, 212 .intr_enable = ael1006_intr_enable, 213 .intr_disable = ael1006_intr_disable, 214 .intr_clear = ael1006_intr_clear, 215 .intr_handler = ael1006_intr_handler, 216 .get_link_status = ael100x_get_link_status, 217 .power_down = ael1006_power_down, 218}; 219#endif 220 221int t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 222 const struct mdio_ops *mdio_ops) 223{ 224 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops, 225 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, 226 "10GBASE-SR"); 227 ael100x_txon(phy); 228 return 0; 229} 230 231#ifdef C99_NOT_SUPPORTED 232static struct cphy_ops qt2045_ops = { 233 ael1006_reset, 234 ael1006_intr_enable, 235 ael1006_intr_disable, 236 ael1006_intr_clear, 237 ael1006_intr_handler, 238 NULL, 239 NULL, 240 NULL, 241 NULL, 242 NULL, 243 ael100x_get_link_status, 244 ael1006_power_down, 245}; 246#else 247static struct cphy_ops qt2045_ops = { 248 .reset = ael1006_reset, 249 .intr_enable = ael1006_intr_enable, 250 .intr_disable = ael1006_intr_disable, 251 .intr_clear = ael1006_intr_clear, 252 .intr_handler = ael1006_intr_handler, 253 .get_link_status = ael100x_get_link_status, 254 .power_down = ael1006_power_down, 255}; 256#endif 257 258int t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 259 const struct mdio_ops *mdio_ops) 260{ 261 unsigned int stat; 262 263 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops, 264 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, 265 "10GBASE-CX4"); 266 267 /* 268 * Some cards where the PHY is supposed to be at address 0 actually 269 * have it at 1. 270 */ 271 if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && 272 stat == 0xffff) 273 phy->addr = 1; 274 return 0; 275} 276 277static int xaui_direct_reset(struct cphy *phy, int wait) 278{ 279 return 0; 280} 281 282static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, 283 int *speed, int *duplex, int *fc) 284{ 285 if (link_ok) { 286 unsigned int status; 287 288 status = t3_read_reg(phy->adapter, 289 XGM_REG(A_XGM_SERDES_STAT0, phy->addr)) | 290 t3_read_reg(phy->adapter, 291 XGM_REG(A_XGM_SERDES_STAT1, phy->addr)) | 292 t3_read_reg(phy->adapter, 293 XGM_REG(A_XGM_SERDES_STAT2, phy->addr)) | 294 t3_read_reg(phy->adapter, 295 XGM_REG(A_XGM_SERDES_STAT3, phy->addr)); 296 *link_ok = !(status & F_LOWSIG0); 297 } 298 if (speed) 299 *speed = SPEED_10000; 300 if (duplex) 301 *duplex = DUPLEX_FULL; 302 return 0; 303} 304 305static int xaui_direct_power_down(struct cphy *phy, int enable) 306{ 307 return 0; 308} 309 310#ifdef C99_NOT_SUPPORTED 311static struct cphy_ops xaui_direct_ops = { 312 xaui_direct_reset, 313 ael1002_intr_noop, 314 ael1002_intr_noop, 315 ael1002_intr_noop, 316 ael1002_intr_noop, 317 NULL, 318 NULL, 319 NULL, 320 NULL, 321 NULL, 322 xaui_direct_get_link_status, 323 xaui_direct_power_down, 324}; 325#else 326static struct cphy_ops xaui_direct_ops = { 327 .reset = xaui_direct_reset, 328 .intr_enable = ael1002_intr_noop, 329 .intr_disable = ael1002_intr_noop, 330 .intr_clear = ael1002_intr_noop, 331 .intr_handler = ael1002_intr_noop, 332 .get_link_status = xaui_direct_get_link_status, 333 .power_down = xaui_direct_power_down, 334}; 335#endif 336 337int t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 338 const struct mdio_ops *mdio_ops) 339{ 340 cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, 341 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, 342 "10GBASE-CX4"); 343 return 0; 344} 345