38 39enum { 40 AEL100X_TX_DISABLE = 9, 41 AEL100X_TX_CONFIG1 = 0xc002, 42 AEL1002_PWR_DOWN_HI = 0xc011, 43 AEL1002_PWR_DOWN_LO = 0xc012, 44 AEL1002_XFI_EQL = 0xc015, 45 AEL1002_LB_EN = 0xc017, 46 47 LASI_CTRL = 0x9002, 48 LASI_STAT = 0x9005 49}; 50 51static void ael100x_txon(struct cphy *phy) 52{ 53 int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; 54 55 t3_os_sleep(100); 56 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); 57 t3_os_sleep(30); 58} 59 60static int ael1002_power_down(struct cphy *phy, int enable) 61{ 62 int err; 63 64 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); 65 if (!err) 66 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 67 BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 68 return err; 69} 70 71static int ael1002_reset(struct cphy *phy, int wait) 72{ 73 int err; 74 75 if ((err = ael1002_power_down(phy, 0)) || 76 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || 77 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || 78 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || 79 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || 80 (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, 81 0, 1 << 5))) 82 return err; 83 return 0; 84} 85 86static int ael1002_intr_noop(struct cphy *phy) 87{ 88 return 0; 89} 90 91static int ael100x_get_link_status(struct cphy *phy, int *link_ok, 92 int *speed, int *duplex, int *fc) 93{ 94 if (link_ok) { 95 unsigned int status; 96 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); 97 98 /* 99 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it 100 * once more to get the current link state. 101 */ 102 if (!err && !(status & BMSR_LSTATUS)) 103 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, 104 &status); 105 if (err) 106 return err; 107 *link_ok = !!(status & BMSR_LSTATUS); 108 } 109 if (speed) 110 *speed = SPEED_10000; 111 if (duplex) 112 *duplex = DUPLEX_FULL; 113 return 0; 114} 115 116#ifdef C99_NOT_SUPPORTED 117static struct cphy_ops ael1002_ops = { 118 NULL, 119 ael1002_reset, 120 ael1002_intr_noop, 121 ael1002_intr_noop, 122 ael1002_intr_noop, 123 ael1002_intr_noop, 124 NULL, 125 NULL, 126 NULL, 127 NULL, 128 NULL, 129 ael100x_get_link_status, 130 ael1002_power_down, 131}; 132#else 133static struct cphy_ops ael1002_ops = { 134 .reset = ael1002_reset, 135 .intr_enable = ael1002_intr_noop, 136 .intr_disable = ael1002_intr_noop, 137 .intr_clear = ael1002_intr_noop, 138 .intr_handler = ael1002_intr_noop, 139 .get_link_status = ael100x_get_link_status, 140 .power_down = ael1002_power_down, 141}; 142#endif 143 144void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 145 const struct mdio_ops *mdio_ops) 146{ 147 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); 148 ael100x_txon(phy); 149} 150 151static int ael1006_reset(struct cphy *phy, int wait) 152{ 153 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); 154} 155 156static int ael1006_intr_enable(struct cphy *phy) 157{ 158 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); 159} 160 161static int ael1006_intr_disable(struct cphy *phy) 162{ 163 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); 164} 165 166static int ael1006_intr_clear(struct cphy *phy) 167{ 168 u32 val; 169 170 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); 171} 172 173static int ael1006_intr_handler(struct cphy *phy) 174{ 175 unsigned int status; 176 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); 177 178 if (err) 179 return err; 180 return (status & 1) ? cphy_cause_link_change : 0; 181} 182 183static int ael1006_power_down(struct cphy *phy, int enable) 184{ 185 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, 186 BMCR_PDOWN, enable ? BMCR_PDOWN : 0); 187} 188 189#ifdef C99_NOT_SUPPORTED 190static struct cphy_ops ael1006_ops = { 191 NULL, 192 ael1006_reset, 193 ael1006_intr_enable, 194 ael1006_intr_disable, 195 ael1006_intr_clear, 196 ael1006_intr_handler, 197 NULL, 198 NULL, 199 NULL, 200 NULL, 201 NULL, 202 ael100x_get_link_status, 203 ael1006_power_down, 204}; 205#else 206static struct cphy_ops ael1006_ops = { 207 .reset = ael1006_reset, 208 .intr_enable = ael1006_intr_enable, 209 .intr_disable = ael1006_intr_disable, 210 .intr_clear = ael1006_intr_clear, 211 .intr_handler = ael1006_intr_handler, 212 .get_link_status = ael100x_get_link_status, 213 .power_down = ael1006_power_down, 214}; 215#endif 216 217void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 218 const struct mdio_ops *mdio_ops) 219{ 220 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); 221 ael100x_txon(phy); 222} 223 224#ifdef C99_NOT_SUPPORTED 225static struct cphy_ops qt2045_ops = { 226 NULL, 227 ael1006_reset, 228 ael1006_intr_enable, 229 ael1006_intr_disable, 230 ael1006_intr_clear, 231 ael1006_intr_handler, 232 NULL, 233 NULL, 234 NULL, 235 NULL, 236 NULL, 237 ael100x_get_link_status, 238 ael1006_power_down, 239}; 240#else 241static struct cphy_ops qt2045_ops = { 242 .reset = ael1006_reset, 243 .intr_enable = ael1006_intr_enable, 244 .intr_disable = ael1006_intr_disable, 245 .intr_clear = ael1006_intr_clear, 246 .intr_handler = ael1006_intr_handler, 247 .get_link_status = ael100x_get_link_status, 248 .power_down = ael1006_power_down, 249}; 250#endif 251 252void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 253 const struct mdio_ops *mdio_ops) 254{ 255 unsigned int stat; 256 257 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops); 258 259 /* 260 * Some cards where the PHY is supposed to be at address 0 actually 261 * have it at 1. 262 */ 263 if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && 264 stat == 0xffff) 265 phy->addr = 1; 266} 267 268static int xaui_direct_reset(struct cphy *phy, int wait) 269{ 270 return 0; 271} 272 273static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, 274 int *speed, int *duplex, int *fc) 275{ 276 if (link_ok) { 277 unsigned int status; 278 279 status = t3_read_reg(phy->adapter, 280 XGM_REG(A_XGM_SERDES_STAT0, phy->addr)); 281 *link_ok = !(status & F_LOWSIG0); 282 } 283 if (speed) 284 *speed = SPEED_10000; 285 if (duplex) 286 *duplex = DUPLEX_FULL; 287 return 0; 288} 289 290static int xaui_direct_power_down(struct cphy *phy, int enable) 291{ 292 return 0; 293} 294 295#ifdef C99_NOT_SUPPORTED 296static struct cphy_ops xaui_direct_ops = { 297 NULL, 298 xaui_direct_reset, 299 ael1002_intr_noop, 300 ael1002_intr_noop, 301 ael1002_intr_noop, 302 ael1002_intr_noop, 303 NULL, 304 NULL, 305 NULL, 306 NULL, 307 NULL, 308 xaui_direct_get_link_status, 309 xaui_direct_power_down, 310}; 311#else 312static struct cphy_ops xaui_direct_ops = { 313 .reset = xaui_direct_reset, 314 .intr_enable = ael1002_intr_noop, 315 .intr_disable = ael1002_intr_noop, 316 .intr_clear = ael1002_intr_noop, 317 .intr_handler = ael1002_intr_noop, 318 .get_link_status = xaui_direct_get_link_status, 319 .power_down = xaui_direct_power_down, 320}; 321#endif 322 323void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, 324 const struct mdio_ops *mdio_ops) 325{ 326 cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops); 327}
|