1 /*- 2 * Copyright (c) 2006, Pyun YongHyeon <yongari@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 /* 33 * Driver for the IC Plus IP1000A/IP1001 10/100/1000 PHY. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/socket.h> 41 #include <sys/bus.h> 42 43 #include <net/if.h> 44 #include <net/if_media.h> 45 46 #include <dev/mii/mii.h> 47 #include <dev/mii/miivar.h> 48 #include "miidevs.h" 49 50 #include <dev/mii/ip1000phyreg.h> 51 52 #include "miibus_if.h" 53 54 #include <machine/bus.h> 55 #include <dev/stge/if_stgereg.h> 56 57 static int ip1000phy_probe(device_t); 58 static int ip1000phy_attach(device_t); 59 60 static device_method_t ip1000phy_methods[] = { 61 /* device interface */ 62 DEVMETHOD(device_probe, ip1000phy_probe), 63 DEVMETHOD(device_attach, ip1000phy_attach), 64 DEVMETHOD(device_detach, mii_phy_detach), 65 DEVMETHOD(device_shutdown, bus_generic_shutdown), 66 DEVMETHOD_END 67 }; 68 69 static devclass_t ip1000phy_devclass; 70 static driver_t ip1000phy_driver = { 71 "ip1000phy", 72 ip1000phy_methods, 73 sizeof(struct mii_softc) 74 }; 75 76 DRIVER_MODULE(ip1000phy, miibus, ip1000phy_driver, ip1000phy_devclass, 0, 0); 77 78 static int ip1000phy_service(struct mii_softc *, struct mii_data *, int); 79 static void ip1000phy_status(struct mii_softc *); 80 static void ip1000phy_reset(struct mii_softc *); 81 static int ip1000phy_mii_phy_auto(struct mii_softc *, int); 82 83 static const struct mii_phydesc ip1000phys[] = { 84 MII_PHY_DESC(xxICPLUS, IP1000A), 85 MII_PHY_DESC(xxICPLUS, IP1001), 86 MII_PHY_END 87 }; 88 89 static const struct mii_phy_funcs ip1000phy_funcs = { 90 ip1000phy_service, 91 ip1000phy_status, 92 ip1000phy_reset 93 }; 94 95 static int 96 ip1000phy_probe(device_t dev) 97 { 98 99 return (mii_phy_dev_probe(dev, ip1000phys, BUS_PROBE_DEFAULT)); 100 } 101 102 static int 103 ip1000phy_attach(device_t dev) 104 { 105 struct mii_attach_args *ma; 106 u_int flags; 107 108 ma = device_get_ivars(dev); 109 flags = MIIF_NOISOLATE | MIIF_NOMANPAUSE; 110 if (MII_MODEL(ma->mii_id2) == MII_MODEL_xxICPLUS_IP1000A && 111 strcmp(ma->mii_data->mii_ifp->if_dname, "stge") == 0 && 112 (miibus_get_flags(dev) & MIIF_MACPRIV0) != 0) 113 flags |= MIIF_PHYPRIV0; 114 mii_phy_dev_attach(dev, flags, &ip1000phy_funcs, 1); 115 return (0); 116 } 117 118 static int 119 ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 120 { 121 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 122 uint32_t gig, reg, speed; 123 124 switch (cmd) { 125 case MII_POLLSTAT: 126 break; 127 128 case MII_MEDIACHG: 129 /* 130 * If the interface is not up, don't do anything. 131 */ 132 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { 133 break; 134 } 135 136 PHY_RESET(sc); 137 switch (IFM_SUBTYPE(ife->ifm_media)) { 138 case IFM_AUTO: 139 (void)ip1000phy_mii_phy_auto(sc, ife->ifm_media); 140 goto done; 141 142 case IFM_1000_T: 143 /* 144 * XXX 145 * Manual 1000baseT setting doesn't seem to work. 146 */ 147 speed = IP1000PHY_BMCR_1000; 148 break; 149 150 case IFM_100_TX: 151 speed = IP1000PHY_BMCR_100; 152 break; 153 154 case IFM_10_T: 155 speed = IP1000PHY_BMCR_10; 156 break; 157 158 default: 159 return (EINVAL); 160 } 161 162 if ((ife->ifm_media & IFM_FDX) != 0) { 163 speed |= IP1000PHY_BMCR_FDX; 164 gig = IP1000PHY_1000CR_1000T_FDX; 165 } else 166 gig = IP1000PHY_1000CR_1000T; 167 168 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 169 gig |= 170 IP1000PHY_1000CR_MASTER | IP1000PHY_1000CR_MANUAL; 171 if ((ife->ifm_media & IFM_ETH_MASTER) != 0) 172 gig |= IP1000PHY_1000CR_MMASTER; 173 } else 174 gig = 0; 175 PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig); 176 PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed); 177 178 done: 179 break; 180 181 case MII_TICK: 182 /* 183 * Is the interface even up? 184 */ 185 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 186 return (0); 187 188 /* 189 * Only used for autonegotiation. 190 */ 191 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 192 sc->mii_ticks = 0; 193 break; 194 } 195 196 /* 197 * check for link. 198 */ 199 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 200 if (reg & BMSR_LINK) { 201 sc->mii_ticks = 0; 202 break; 203 } 204 205 /* Announce link loss right after it happens */ 206 if (sc->mii_ticks++ == 0) 207 break; 208 209 /* 210 * Only retry autonegotiation every mii_anegticks seconds. 211 */ 212 if (sc->mii_ticks <= sc->mii_anegticks) 213 break; 214 215 sc->mii_ticks = 0; 216 ip1000phy_mii_phy_auto(sc, ife->ifm_media); 217 break; 218 } 219 220 /* Update the media status. */ 221 PHY_STATUS(sc); 222 223 /* Callback if something changed. */ 224 mii_phy_update(sc, cmd); 225 return (0); 226 } 227 228 static void 229 ip1000phy_status(struct mii_softc *sc) 230 { 231 struct mii_data *mii = sc->mii_pdata; 232 uint32_t bmsr, bmcr, stat; 233 234 mii->mii_media_status = IFM_AVALID; 235 mii->mii_media_active = IFM_ETHER; 236 237 bmsr = PHY_READ(sc, IP1000PHY_MII_BMSR) | 238 PHY_READ(sc, IP1000PHY_MII_BMSR); 239 if ((bmsr & IP1000PHY_BMSR_LINK) != 0) 240 mii->mii_media_status |= IFM_ACTIVE; 241 242 bmcr = PHY_READ(sc, IP1000PHY_MII_BMCR); 243 if ((bmcr & IP1000PHY_BMCR_LOOP) != 0) 244 mii->mii_media_active |= IFM_LOOP; 245 246 if ((bmcr & IP1000PHY_BMCR_AUTOEN) != 0) { 247 if ((bmsr & IP1000PHY_BMSR_ANEGCOMP) == 0) { 248 /* Erg, still trying, I guess... */ 249 mii->mii_media_active |= IFM_NONE; 250 return; 251 } 252 } 253 254 if (sc->mii_mpd_model == MII_MODEL_xxICPLUS_IP1001) { 255 stat = PHY_READ(sc, IP1000PHY_LSR); 256 switch (stat & IP1000PHY_LSR_SPEED_MASK) { 257 case IP1000PHY_LSR_SPEED_10: 258 mii->mii_media_active |= IFM_10_T; 259 break; 260 case IP1000PHY_LSR_SPEED_100: 261 mii->mii_media_active |= IFM_100_TX; 262 break; 263 case IP1000PHY_LSR_SPEED_1000: 264 mii->mii_media_active |= IFM_1000_T; 265 break; 266 default: 267 mii->mii_media_active |= IFM_NONE; 268 return; 269 } 270 if ((stat & IP1000PHY_LSR_FULL_DUPLEX) != 0) 271 mii->mii_media_active |= IFM_FDX; 272 else 273 mii->mii_media_active |= IFM_HDX; 274 } else { 275 stat = PHY_READ(sc, STGE_PhyCtrl); 276 switch (PC_LinkSpeed(stat)) { 277 case PC_LinkSpeed_Down: 278 mii->mii_media_active |= IFM_NONE; 279 return; 280 case PC_LinkSpeed_10: 281 mii->mii_media_active |= IFM_10_T; 282 break; 283 case PC_LinkSpeed_100: 284 mii->mii_media_active |= IFM_100_TX; 285 break; 286 case PC_LinkSpeed_1000: 287 mii->mii_media_active |= IFM_1000_T; 288 break; 289 default: 290 mii->mii_media_active |= IFM_NONE; 291 return; 292 } 293 if ((stat & PC_PhyDuplexStatus) != 0) 294 mii->mii_media_active |= IFM_FDX; 295 else 296 mii->mii_media_active |= IFM_HDX; 297 } 298 299 if ((mii->mii_media_active & IFM_FDX) != 0) 300 mii->mii_media_active |= mii_phy_flowstatus(sc); 301 302 if ((mii->mii_media_active & IFM_1000_T) != 0) { 303 stat = PHY_READ(sc, IP1000PHY_MII_1000SR); 304 if ((stat & IP1000PHY_1000SR_MASTER) != 0) 305 mii->mii_media_active |= IFM_ETH_MASTER; 306 } 307 } 308 309 static int 310 ip1000phy_mii_phy_auto(struct mii_softc *sc, int media) 311 { 312 uint32_t reg; 313 314 reg = 0; 315 if (sc->mii_mpd_model == MII_MODEL_xxICPLUS_IP1001) { 316 reg = PHY_READ(sc, IP1000PHY_MII_ANAR); 317 reg &= ~(IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE); 318 reg |= IP1000PHY_ANAR_NP; 319 } 320 reg |= IP1000PHY_ANAR_10T | IP1000PHY_ANAR_10T_FDX | 321 IP1000PHY_ANAR_100TX | IP1000PHY_ANAR_100TX_FDX; 322 if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 323 reg |= IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE; 324 PHY_WRITE(sc, IP1000PHY_MII_ANAR, reg | IP1000PHY_ANAR_CSMA); 325 326 reg = IP1000PHY_1000CR_1000T | IP1000PHY_1000CR_1000T_FDX; 327 if (sc->mii_mpd_model != MII_MODEL_xxICPLUS_IP1001) 328 reg |= IP1000PHY_1000CR_MASTER; 329 PHY_WRITE(sc, IP1000PHY_MII_1000CR, reg); 330 PHY_WRITE(sc, IP1000PHY_MII_BMCR, (IP1000PHY_BMCR_FDX | 331 IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_STARTNEG)); 332 333 return (EJUSTRETURN); 334 } 335 336 static void 337 ip1000phy_load_dspcode(struct mii_softc *sc) 338 { 339 340 PHY_WRITE(sc, 31, 0x0001); 341 PHY_WRITE(sc, 27, 0x01e0); 342 PHY_WRITE(sc, 31, 0x0002); 343 PHY_WRITE(sc, 27, 0xeb8e); 344 PHY_WRITE(sc, 31, 0x0000); 345 PHY_WRITE(sc, 30, 0x005e); 346 PHY_WRITE(sc, 9, 0x0700); 347 348 DELAY(50); 349 } 350 351 static void 352 ip1000phy_reset(struct mii_softc *sc) 353 { 354 uint32_t reg; 355 356 mii_phy_reset(sc); 357 358 /* clear autoneg/full-duplex as we don't want it after reset */ 359 reg = PHY_READ(sc, IP1000PHY_MII_BMCR); 360 reg &= ~(IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_FDX); 361 PHY_WRITE(sc, MII_BMCR, reg); 362 363 if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) 364 ip1000phy_load_dspcode(sc); 365 } 366