1 /* $NetBSD: ikphy.c,v 1.8 2008/11/17 03:04:27 dyoung Exp $ */ 2 3 /******************************************************************************* 4 Copyright (c) 2001-2005, Intel Corporation 5 All rights reserved. 6 7 Redistribution and use in source and binary forms, with or without 8 modification, are permitted provided that the following conditions are met: 9 10 1. Redistributions of source code must retain the above copyright notice, 11 this list of conditions and the following disclaimer. 12 13 2. Redistributions in binary form must reproduce the above copyright 14 notice, this list of conditions and the following disclaimer in the 15 documentation and/or other materials provided with the distribution. 16 17 3. Neither the name of the Intel Corporation nor the names of its 18 contributors may be used to endorse or promote products derived from 19 this software without specific prior written permission. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 POSSIBILITY OF SUCH DAMAGE. 32 *******************************************************************************/ 33 /* 34 * Copyright (c) 2006 Manuel Bouyer. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by Manuel Bouyer. 47 * 4. The name of the author may not be used to endorse or promote products 48 * derived from this software without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 53 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 54 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 59 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 /* 63 * driver for Intel's i82563 ethernet 10/100/1000 PHY 64 */ 65 66 #include <sys/cdefs.h> 67 __KERNEL_RCSID(0, "$NetBSD: ikphy.c,v 1.8 2008/11/17 03:04:27 dyoung Exp $"); 68 69 #include <sys/param.h> 70 #include <sys/systm.h> 71 #include <sys/kernel.h> 72 #include <sys/device.h> 73 #include <sys/socket.h> 74 #include <sys/errno.h> 75 76 #include <net/if.h> 77 #include <net/if_media.h> 78 79 #include <dev/mii/mii.h> 80 #include <dev/mii/miivar.h> 81 #include <dev/mii/miidevs.h> 82 83 #include <dev/mii/ikphyreg.h> 84 85 static int ikphymatch(device_t, cfdata_t, void *); 86 static void ikphyattach(device_t, device_t, void *); 87 88 CFATTACH_DECL_NEW(ikphy, sizeof(struct mii_softc), 89 ikphymatch, ikphyattach, mii_phy_detach, mii_phy_activate); 90 91 static int ikphy_service(struct mii_softc *, struct mii_data *, int); 92 static void ikphy_status(struct mii_softc *); 93 static void ikphy_setmedia(struct mii_softc *); 94 95 static const struct mii_phy_funcs ikphy_funcs = { 96 ikphy_service, ikphy_status, mii_phy_reset, 97 }; 98 99 static const struct mii_phydesc ikphys[] = { 100 { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_I82563, 101 MII_STR_xxMARVELL_I82563 }, 102 103 { 0, 0, 104 NULL }, 105 }; 106 107 static int 108 ikphymatch(device_t parent, cfdata_t match, void *aux) 109 { 110 struct mii_attach_args *ma = aux; 111 112 if (mii_phy_match(ma, ikphys) != NULL) 113 return (10); 114 115 return (0); 116 } 117 118 static void 119 ikphyattach(device_t parent, device_t self, void *aux) 120 { 121 struct mii_softc *sc = device_private(self); 122 struct mii_attach_args *ma = aux; 123 struct mii_data *mii = ma->mii_data; 124 const struct mii_phydesc *mpd; 125 126 mpd = mii_phy_match(ma, ikphys); 127 aprint_naive(": Media interface\n"); 128 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 129 130 sc->mii_dev = self; 131 sc->mii_inst = mii->mii_instance; 132 sc->mii_phy = ma->mii_phyno; 133 sc->mii_funcs = &ikphy_funcs; 134 sc->mii_pdata = mii; 135 sc->mii_flags = ma->mii_flags; 136 sc->mii_anegticks = MII_ANEGTICKS; 137 138 PHY_RESET(sc); 139 140 sc->mii_capabilities = 141 PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 142 if (sc->mii_capabilities & BMSR_EXTSTAT) 143 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 144 aprint_normal_dev(self, ""); 145 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 146 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) 147 aprint_error("no media present"); 148 else 149 mii_phy_add_media(sc); 150 aprint_normal("\n"); 151 } 152 153 static int 154 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 155 { 156 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 157 int reg; 158 159 switch (cmd) { 160 case MII_POLLSTAT: 161 /* 162 * If we're not polling our PHY instance, just return. 163 */ 164 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 165 return (0); 166 break; 167 168 case MII_MEDIACHG: 169 /* 170 * If the media indicates a different PHY instance, 171 * isolate ourselves. 172 */ 173 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 174 reg = PHY_READ(sc, MII_BMCR); 175 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 176 return (0); 177 } 178 179 /* 180 * If the interface is not up, don't do anything. 181 */ 182 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 183 break; 184 185 ikphy_setmedia(sc); 186 break; 187 188 case MII_TICK: 189 /* 190 * If we're not currently selected, just return. 191 */ 192 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 193 return (0); 194 195 if (mii_phy_tick(sc) == EJUSTRETURN) 196 return (0); 197 break; 198 199 case MII_DOWN: 200 mii_phy_down(sc); 201 return (0); 202 } 203 204 /* Update the media status. */ 205 mii_phy_status(sc); 206 207 /* Callback if something changed. */ 208 mii_phy_update(sc, cmd); 209 return (0); 210 } 211 212 static void 213 ikphy_setmedia(struct mii_softc *sc) 214 { 215 uint16_t phy_data; 216 struct mii_data *mii = sc->mii_pdata; 217 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 218 219 /* Enable CRS on TX for half-duplex operation. */ 220 phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL); 221 phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; 222 /* Use 25MHz for both link down and 1000BASE-T for Tx clock */ 223 phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; 224 PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data); 225 226 /* set mdi/mid-x options */ 227 phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL); 228 phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; 229 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) 230 phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; 231 else 232 phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI; 233 /* set polarity correction */ 234 phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; 235 PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data); 236 237 /* SW Reset the PHY so all changes take effect */ 238 PHY_RESET(sc); 239 240 /* for the i80003 */ 241 phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2); 242 phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; 243 PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data); 244 245 /* Enable Electrical Idle on the PHY */ 246 phy_data = PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL); 247 phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; 248 PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data); 249 250 phy_data = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL); 251 phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; 252 PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data); 253 254 /* 255 * Workaround: Disable padding in Kumeran interface in the MAC 256 * and in the PHY to avoid CRC errors. 257 */ 258 phy_data = PHY_READ(sc, GG82563_PHY_INBAND_CTRL); 259 phy_data |= GG82563_ICR_DIS_PADDING; 260 PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data); 261 262 mii_phy_setmedia(sc); 263 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 264 /* 265 * when not in auto mode, we need to restart nego 266 * anyway, or a switch from a fixed mode to another 267 * fixed mode may not be seen by the switch. 268 */ 269 PHY_WRITE(sc, MII_BMCR, 270 PHY_READ(sc, MII_BMCR) | BMCR_STARTNEG); 271 } 272 phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL); 273 phy_data &= ~GG82563_MSCR_TX_CLK_MASK; 274 switch(IFM_SUBTYPE(ife->ifm_media)) { 275 case IFM_10_T: 276 phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ; 277 break; 278 case IFM_100_TX: 279 phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ; 280 break; 281 case IFM_1000_T: 282 phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; 283 break; 284 } 285 phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; 286 PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data); 287 } 288 289 static void 290 ikphy_status(struct mii_softc *sc) 291 { 292 struct mii_data *mii = sc->mii_pdata; 293 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 294 int pssr, bmcr, gtsr, kmrn; 295 296 mii->mii_media_status = IFM_AVALID; 297 mii->mii_media_active = IFM_ETHER; 298 299 pssr = PHY_READ(sc, GG82563_PHY_SPEC_STATUS); 300 301 if (pssr & GG82563_PSSR_LINK) 302 mii->mii_media_status |= IFM_ACTIVE; 303 304 bmcr = PHY_READ(sc, MII_BMCR); 305 if (bmcr & BMCR_ISO) { 306 mii->mii_media_active |= IFM_NONE; 307 mii->mii_media_status = 0; 308 return; 309 } 310 311 if (bmcr & BMCR_LOOP) 312 mii->mii_media_active |= IFM_LOOP; 313 314 if (bmcr & BMCR_AUTOEN) { 315 /* 316 * The media status bits are only valid of autonegotiation 317 * has completed (or it's disabled). 318 */ 319 if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) { 320 /* Erg, still trying, I guess... */ 321 mii->mii_media_active |= IFM_NONE; 322 return; 323 } 324 325 switch (pssr & GG82563_PSSR_SPEED_MASK) { 326 case GG82563_PSSR_SPEED_1000MBPS: 327 mii->mii_media_active |= IFM_1000_T; 328 gtsr = PHY_READ(sc, MII_100T2SR); 329 if (gtsr & GTSR_MS_RES) 330 mii->mii_media_active |= IFM_ETH_MASTER; 331 break; 332 333 case GG82563_PSSR_SPEED_100MBPS: 334 mii->mii_media_active |= IFM_100_TX; 335 break; 336 337 case GG82563_PSSR_SPEED_10MBPS: 338 mii->mii_media_active |= IFM_10_T; 339 break; 340 341 default: 342 mii->mii_media_active |= IFM_NONE; 343 mii->mii_media_status = 0; 344 return; 345 } 346 347 if (pssr & GG82563_PSSR_DUPLEX) 348 mii->mii_media_active |= 349 IFM_FDX | mii_phy_flowstatus(sc); 350 } else 351 mii->mii_media_active = ife->ifm_media; 352 kmrn = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL); 353 if (mii->mii_media_active & IFM_FDX) 354 kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER; 355 else 356 kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER; 357 PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn); 358 } 359