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/taskqueue.h> 42 #include <sys/bus.h> 43 44 #include <net/if.h> 45 #include <net/if_var.h> 46 #include <net/if_media.h> 47 48 #include <dev/mii/mii.h> 49 #include <dev/mii/miivar.h> 50 #include "miidevs.h" 51 52 #include <dev/mii/ip1000phyreg.h> 53 54 #include "miibus_if.h" 55 56 #include <machine/bus.h> 57 #include <dev/stge/if_stgereg.h> 58 59 static int ip1000phy_probe(device_t); 60 static int ip1000phy_attach(device_t); 61 62 static device_method_t ip1000phy_methods[] = { 63 /* device interface */ 64 DEVMETHOD(device_probe, ip1000phy_probe), 65 DEVMETHOD(device_attach, ip1000phy_attach), 66 DEVMETHOD(device_detach, mii_phy_detach), 67 DEVMETHOD(device_shutdown, bus_generic_shutdown), 68 DEVMETHOD_END 69 }; 70 71 static devclass_t ip1000phy_devclass; 72 static driver_t ip1000phy_driver = { 73 "ip1000phy", 74 ip1000phy_methods, 75 sizeof(struct mii_softc) 76 }; 77 78 DRIVER_MODULE(ip1000phy, miibus, ip1000phy_driver, ip1000phy_devclass, 0, 0); 79 80 static int ip1000phy_service(struct mii_softc *, struct mii_data *, int); 81 static void ip1000phy_status(struct mii_softc *); 82 static void ip1000phy_reset(struct mii_softc *); 83 static int ip1000phy_mii_phy_auto(struct mii_softc *, int); 84 85 static const struct mii_phydesc ip1000phys[] = { 86 MII_PHY_DESC(xxICPLUS, IP1000A), 87 MII_PHY_DESC(xxICPLUS, IP1001), 88 MII_PHY_END 89 }; 90 91 static const struct mii_phy_funcs ip1000phy_funcs = { 92 ip1000phy_service, 93 ip1000phy_status, 94 ip1000phy_reset 95 }; 96 97 static int 98 ip1000phy_probe(device_t dev) 99 { 100 101 return (mii_phy_dev_probe(dev, ip1000phys, BUS_PROBE_DEFAULT)); 102 } 103 104 static int 105 ip1000phy_attach(device_t dev) 106 { 107 struct mii_attach_args *ma; 108 u_int flags; 109 110 ma = device_get_ivars(dev); 111 flags = MIIF_NOISOLATE | MIIF_NOMANPAUSE; 112 if (MII_MODEL(ma->mii_id2) == MII_MODEL_xxICPLUS_IP1000A && 113 mii_dev_mac_match(dev, "stge") && 114 (miibus_get_flags(dev) & MIIF_MACPRIV0) != 0) 115 flags |= MIIF_PHYPRIV0; 116 mii_phy_dev_attach(dev, flags, &ip1000phy_funcs, 1); 117 return (0); 118 } 119 120 static int 121 ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 122 { 123 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 124 uint32_t gig, reg, speed; 125 126 switch (cmd) { 127 case MII_POLLSTAT: 128 break; 129 130 case MII_MEDIACHG: 131 PHY_RESET(sc); 132 switch (IFM_SUBTYPE(ife->ifm_media)) { 133 case IFM_AUTO: 134 (void)ip1000phy_mii_phy_auto(sc, ife->ifm_media); 135 goto done; 136 137 case IFM_1000_T: 138 /* 139 * XXX 140 * Manual 1000baseT setting doesn't seem to work. 141 */ 142 speed = IP1000PHY_BMCR_1000; 143 break; 144 145 case IFM_100_TX: 146 speed = IP1000PHY_BMCR_100; 147 break; 148 149 case IFM_10_T: 150 speed = IP1000PHY_BMCR_10; 151 break; 152 153 default: 154 return (EINVAL); 155 } 156 157 if ((ife->ifm_media & IFM_FDX) != 0) { 158 speed |= IP1000PHY_BMCR_FDX; 159 gig = IP1000PHY_1000CR_1000T_FDX; 160 } else 161 gig = IP1000PHY_1000CR_1000T; 162 163 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 164 gig |= 165 IP1000PHY_1000CR_MASTER | IP1000PHY_1000CR_MANUAL; 166 if ((ife->ifm_media & IFM_ETH_MASTER) != 0) 167 gig |= IP1000PHY_1000CR_MMASTER; 168 } else 169 gig = 0; 170 PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig); 171 PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed); 172 173 done: 174 break; 175 176 case MII_TICK: 177 /* 178 * Only used for autonegotiation. 179 */ 180 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 181 sc->mii_ticks = 0; 182 break; 183 } 184 185 /* 186 * check for link. 187 */ 188 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 189 if (reg & BMSR_LINK) { 190 sc->mii_ticks = 0; 191 break; 192 } 193 194 /* Announce link loss right after it happens */ 195 if (sc->mii_ticks++ == 0) 196 break; 197 198 /* 199 * Only retry autonegotiation every mii_anegticks seconds. 200 */ 201 if (sc->mii_ticks <= sc->mii_anegticks) 202 break; 203 204 sc->mii_ticks = 0; 205 ip1000phy_mii_phy_auto(sc, ife->ifm_media); 206 break; 207 } 208 209 /* Update the media status. */ 210 PHY_STATUS(sc); 211 212 /* Callback if something changed. */ 213 mii_phy_update(sc, cmd); 214 return (0); 215 } 216 217 static void 218 ip1000phy_status(struct mii_softc *sc) 219 { 220 struct mii_data *mii = sc->mii_pdata; 221 uint32_t bmsr, bmcr, stat; 222 223 mii->mii_media_status = IFM_AVALID; 224 mii->mii_media_active = IFM_ETHER; 225 226 bmsr = PHY_READ(sc, IP1000PHY_MII_BMSR) | 227 PHY_READ(sc, IP1000PHY_MII_BMSR); 228 if ((bmsr & IP1000PHY_BMSR_LINK) != 0) 229 mii->mii_media_status |= IFM_ACTIVE; 230 231 bmcr = PHY_READ(sc, IP1000PHY_MII_BMCR); 232 if ((bmcr & IP1000PHY_BMCR_LOOP) != 0) 233 mii->mii_media_active |= IFM_LOOP; 234 235 if ((bmcr & IP1000PHY_BMCR_AUTOEN) != 0) { 236 if ((bmsr & IP1000PHY_BMSR_ANEGCOMP) == 0) { 237 /* Erg, still trying, I guess... */ 238 mii->mii_media_active |= IFM_NONE; 239 return; 240 } 241 } 242 243 if (sc->mii_mpd_model == MII_MODEL_xxICPLUS_IP1001) { 244 stat = PHY_READ(sc, IP1000PHY_LSR); 245 switch (stat & IP1000PHY_LSR_SPEED_MASK) { 246 case IP1000PHY_LSR_SPEED_10: 247 mii->mii_media_active |= IFM_10_T; 248 break; 249 case IP1000PHY_LSR_SPEED_100: 250 mii->mii_media_active |= IFM_100_TX; 251 break; 252 case IP1000PHY_LSR_SPEED_1000: 253 mii->mii_media_active |= IFM_1000_T; 254 break; 255 default: 256 mii->mii_media_active |= IFM_NONE; 257 return; 258 } 259 if ((stat & IP1000PHY_LSR_FULL_DUPLEX) != 0) 260 mii->mii_media_active |= IFM_FDX; 261 else 262 mii->mii_media_active |= IFM_HDX; 263 } else { 264 stat = PHY_READ(sc, STGE_PhyCtrl); 265 switch (PC_LinkSpeed(stat)) { 266 case PC_LinkSpeed_Down: 267 mii->mii_media_active |= IFM_NONE; 268 return; 269 case PC_LinkSpeed_10: 270 mii->mii_media_active |= IFM_10_T; 271 break; 272 case PC_LinkSpeed_100: 273 mii->mii_media_active |= IFM_100_TX; 274 break; 275 case PC_LinkSpeed_1000: 276 mii->mii_media_active |= IFM_1000_T; 277 break; 278 default: 279 mii->mii_media_active |= IFM_NONE; 280 return; 281 } 282 if ((stat & PC_PhyDuplexStatus) != 0) 283 mii->mii_media_active |= IFM_FDX; 284 else 285 mii->mii_media_active |= IFM_HDX; 286 } 287 288 if ((mii->mii_media_active & IFM_FDX) != 0) 289 mii->mii_media_active |= mii_phy_flowstatus(sc); 290 291 if ((mii->mii_media_active & IFM_1000_T) != 0) { 292 stat = PHY_READ(sc, IP1000PHY_MII_1000SR); 293 if ((stat & IP1000PHY_1000SR_MASTER) != 0) 294 mii->mii_media_active |= IFM_ETH_MASTER; 295 } 296 } 297 298 static int 299 ip1000phy_mii_phy_auto(struct mii_softc *sc, int media) 300 { 301 uint32_t reg; 302 303 reg = 0; 304 if (sc->mii_mpd_model == MII_MODEL_xxICPLUS_IP1001) { 305 reg = PHY_READ(sc, IP1000PHY_MII_ANAR); 306 reg &= ~(IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE); 307 reg |= IP1000PHY_ANAR_NP; 308 } 309 reg |= IP1000PHY_ANAR_10T | IP1000PHY_ANAR_10T_FDX | 310 IP1000PHY_ANAR_100TX | IP1000PHY_ANAR_100TX_FDX; 311 if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 312 reg |= IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE; 313 PHY_WRITE(sc, IP1000PHY_MII_ANAR, reg | IP1000PHY_ANAR_CSMA); 314 315 reg = IP1000PHY_1000CR_1000T | IP1000PHY_1000CR_1000T_FDX; 316 if (sc->mii_mpd_model != MII_MODEL_xxICPLUS_IP1001) 317 reg |= IP1000PHY_1000CR_MASTER; 318 PHY_WRITE(sc, IP1000PHY_MII_1000CR, reg); 319 PHY_WRITE(sc, IP1000PHY_MII_BMCR, (IP1000PHY_BMCR_FDX | 320 IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_STARTNEG)); 321 322 return (EJUSTRETURN); 323 } 324 325 static void 326 ip1000phy_load_dspcode(struct mii_softc *sc) 327 { 328 329 PHY_WRITE(sc, 31, 0x0001); 330 PHY_WRITE(sc, 27, 0x01e0); 331 PHY_WRITE(sc, 31, 0x0002); 332 PHY_WRITE(sc, 27, 0xeb8e); 333 PHY_WRITE(sc, 31, 0x0000); 334 PHY_WRITE(sc, 30, 0x005e); 335 PHY_WRITE(sc, 9, 0x0700); 336 337 DELAY(50); 338 } 339 340 static void 341 ip1000phy_reset(struct mii_softc *sc) 342 { 343 uint32_t reg; 344 345 mii_phy_reset(sc); 346 347 /* clear autoneg/full-duplex as we don't want it after reset */ 348 reg = PHY_READ(sc, IP1000PHY_MII_BMCR); 349 reg &= ~(IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_FDX); 350 PHY_WRITE(sc, MII_BMCR, reg); 351 352 if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) 353 ip1000phy_load_dspcode(sc); 354 } 355