1 /* $NetBSD: ikphy.c,v 1.7 2008/05/04 17:06:09 xtraeme 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.7 2008/05/04 17:06:09 xtraeme 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 if (!pmf_device_register(self, NULL, mii_phy_resume)) 153 aprint_error_dev(self, "couldn't establish power handler\n"); 154 } 155 156 static int 157 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 158 { 159 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 160 int reg; 161 162 switch (cmd) { 163 case MII_POLLSTAT: 164 /* 165 * If we're not polling our PHY instance, just return. 166 */ 167 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 168 return (0); 169 break; 170 171 case MII_MEDIACHG: 172 /* 173 * If the media indicates a different PHY instance, 174 * isolate ourselves. 175 */ 176 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 177 reg = PHY_READ(sc, MII_BMCR); 178 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 179 return (0); 180 } 181 182 /* 183 * If the interface is not up, don't do anything. 184 */ 185 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 186 break; 187 188 ikphy_setmedia(sc); 189 break; 190 191 case MII_TICK: 192 /* 193 * If we're not currently selected, just return. 194 */ 195 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 196 return (0); 197 198 if (mii_phy_tick(sc) == EJUSTRETURN) 199 return (0); 200 break; 201 202 case MII_DOWN: 203 mii_phy_down(sc); 204 return (0); 205 } 206 207 /* Update the media status. */ 208 mii_phy_status(sc); 209 210 /* Callback if something changed. */ 211 mii_phy_update(sc, cmd); 212 return (0); 213 } 214 215 static void 216 ikphy_setmedia(struct mii_softc *sc) 217 { 218 uint16_t phy_data; 219 struct mii_data *mii = sc->mii_pdata; 220 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 221 222 /* Enable CRS on TX for half-duplex operation. */ 223 phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL); 224 phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; 225 /* Use 25MHz for both link down and 1000BASE-T for Tx clock */ 226 phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; 227 PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data); 228 229 /* set mdi/mid-x options */ 230 phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL); 231 phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; 232 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) 233 phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; 234 else 235 phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI; 236 /* set polarity correction */ 237 phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; 238 PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data); 239 240 /* SW Reset the PHY so all changes take effect */ 241 PHY_RESET(sc); 242 243 /* for the i80003 */ 244 phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2); 245 phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; 246 PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data); 247 248 /* Enable Electrical Idle on the PHY */ 249 phy_data = PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL); 250 phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; 251 PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data); 252 253 phy_data = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL); 254 phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; 255 PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data); 256 257 /* 258 * Workaround: Disable padding in Kumeran interface in the MAC 259 * and in the PHY to avoid CRC errors. 260 */ 261 phy_data = PHY_READ(sc, GG82563_PHY_INBAND_CTRL); 262 phy_data |= GG82563_ICR_DIS_PADDING; 263 PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data); 264 265 mii_phy_setmedia(sc); 266 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 267 /* 268 * when not in auto mode, we need to restart nego 269 * anyway, or a switch from a fixed mode to another 270 * fixed mode may not be seen by the switch. 271 */ 272 PHY_WRITE(sc, MII_BMCR, 273 PHY_READ(sc, MII_BMCR) | BMCR_STARTNEG); 274 } 275 phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL); 276 phy_data &= ~GG82563_MSCR_TX_CLK_MASK; 277 switch(IFM_SUBTYPE(ife->ifm_media)) { 278 case IFM_10_T: 279 phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ; 280 break; 281 case IFM_100_TX: 282 phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ; 283 break; 284 case IFM_1000_T: 285 phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; 286 break; 287 } 288 phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; 289 PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data); 290 } 291 292 static void 293 ikphy_status(struct mii_softc *sc) 294 { 295 struct mii_data *mii = sc->mii_pdata; 296 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 297 int pssr, bmcr, gtsr, kmrn; 298 299 mii->mii_media_status = IFM_AVALID; 300 mii->mii_media_active = IFM_ETHER; 301 302 pssr = PHY_READ(sc, GG82563_PHY_SPEC_STATUS); 303 304 if (pssr & GG82563_PSSR_LINK) 305 mii->mii_media_status |= IFM_ACTIVE; 306 307 bmcr = PHY_READ(sc, MII_BMCR); 308 if (bmcr & BMCR_ISO) { 309 mii->mii_media_active |= IFM_NONE; 310 mii->mii_media_status = 0; 311 return; 312 } 313 314 if (bmcr & BMCR_LOOP) 315 mii->mii_media_active |= IFM_LOOP; 316 317 if (bmcr & BMCR_AUTOEN) { 318 /* 319 * The media status bits are only valid of autonegotiation 320 * has completed (or it's disabled). 321 */ 322 if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) { 323 /* Erg, still trying, I guess... */ 324 mii->mii_media_active |= IFM_NONE; 325 return; 326 } 327 328 switch (pssr & GG82563_PSSR_SPEED_MASK) { 329 case GG82563_PSSR_SPEED_1000MBPS: 330 mii->mii_media_active |= IFM_1000_T; 331 gtsr = PHY_READ(sc, MII_100T2SR); 332 if (gtsr & GTSR_MS_RES) 333 mii->mii_media_active |= IFM_ETH_MASTER; 334 break; 335 336 case GG82563_PSSR_SPEED_100MBPS: 337 mii->mii_media_active |= IFM_100_TX; 338 break; 339 340 case GG82563_PSSR_SPEED_10MBPS: 341 mii->mii_media_active |= IFM_10_T; 342 break; 343 344 default: 345 mii->mii_media_active |= IFM_NONE; 346 mii->mii_media_status = 0; 347 return; 348 } 349 350 if (pssr & GG82563_PSSR_DUPLEX) 351 mii->mii_media_active |= 352 IFM_FDX | mii_phy_flowstatus(sc); 353 } else 354 mii->mii_media_active = ife->ifm_media; 355 kmrn = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL); 356 if (mii->mii_media_active & IFM_FDX) 357 kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER; 358 else 359 kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER; 360 PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn); 361 } 362