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