1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 Alstom Group. 5 * Copyright (c) 2021 Semihalf. 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, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * Driver for TI DP83867 Ethernet PHY 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/bus.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/resource.h> 41 #include <sys/rman.h> 42 #include <sys/socket.h> 43 44 #include <machine/resource.h> 45 46 #include <net/if.h> 47 #include <net/if_media.h> 48 49 #include <dev/mii/mii.h> 50 #include <dev/mii/miivar.h> 51 52 #include "miidevs.h" 53 #include "miibus_if.h" 54 55 #define BIT(x) (1 << (x)) 56 57 #define DP83867_PHYCR 0x10 58 #define DP83867_PHYSTS 0x11 59 #define DP83867_MICR 0x12 60 #define DP83867_ISR 0x13 61 #define DP83867_CFG3 0x1E 62 #define DP83867_CTRL 0x1F 63 #define DP83867_CFG4 0x31 64 #define DP83867_RGMIICTL 0x32 65 #define DP83867_STRP_STS1 0x6E 66 #define DP83867_STRP_STS2 0x6F 67 68 #define DP83867_PHYSTS_LINK_UP BIT(10) 69 #define DP83867_PHYSTS_ANEG_PENDING BIT(11) 70 #define DP83867_PHYSTS_FD BIT(13) 71 #define DP83867_PHYSTS_SPEED_MASK (BIT(15) | BIT(14)) 72 #define DP83867_PHYSTS_SPEED_1000 BIT(15) 73 #define DP83867_PHYSTS_SPEED_100 BIT(14) 74 #define DP83867_PHYSTS_SPEED_10 0 75 76 #define DP83867_MICR_AN_ERR BIT(15) 77 #define DP83867_MICR_SPEED_CHG BIT(14) 78 #define DP83867_MICR_DP_MODE_CHG BIT(13) 79 #define DP83867_MICR_AN_CMPL BIT(11) 80 #define DP83867_MICR_LINK_CHG BIT(10) 81 82 #define DP83867_CFG3_INT_OE BIT(7) 83 84 #define DP83867_CFG4_TST_MODE1 BIT(7) 85 #define DP83867_CFG4_ANEG_MASK (BIT(5) | BIT(6)) 86 #define DP83867_CFG4_ANEG_16MS (0 << 5) 87 88 #define BMSR_100_MASK (BMSR_100T4 | BMSR_100TXFDX | BMSR_100TXHDX | \ 89 BMSR_100T2FDX | BMSR_100T2HDX) 90 91 static int dp_probe(device_t); 92 static int dp_attach(device_t); 93 94 static int dp_service(struct mii_softc*, struct mii_data*, int); 95 static void dp_status(struct mii_softc*); 96 97 struct dp83867_softc { 98 struct mii_softc mii_sc; 99 struct resource *irq_res; 100 void *irq_cookie; 101 }; 102 103 static const struct mii_phydesc dpphys[] = { 104 MII_PHY_DESC(xxTI, DP83867), 105 MII_PHY_END 106 }; 107 108 static const struct mii_phy_funcs dpphy_funcs = { 109 dp_service, 110 dp_status, 111 mii_phy_reset 112 }; 113 114 static void 115 dp_intr(void *arg) 116 { 117 struct mii_softc *sc = (struct mii_softc *)arg; 118 uint32_t status; 119 120 status = PHY_READ(sc, DP83867_ISR); 121 status &= PHY_READ(sc, DP83867_MICR); 122 if (!status) 123 return; 124 125 PHY_STATUS(sc); 126 mii_phy_update(sc, MII_MEDIACHG); 127 } 128 129 static int 130 dp_probe(device_t dev) 131 { 132 133 return (mii_phy_dev_probe(dev, dpphys, BUS_PROBE_DEFAULT)); 134 } 135 136 static int 137 dp_attach(device_t dev) 138 { 139 struct dp83867_softc *sc; 140 struct mii_softc *mii_sc; 141 uint32_t value, maxspeed; 142 ssize_t size; 143 int rid, error; 144 145 sc = device_get_softc(dev); 146 mii_sc = &sc->mii_sc; 147 148 size = device_get_property(dev, "max-speed", &maxspeed, sizeof(maxspeed)); 149 if (size <= 0) 150 maxspeed = 0; 151 152 mii_sc->mii_maxspeed = maxspeed; 153 mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &dpphy_funcs, 1); 154 155 rid = 0; 156 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 157 if (sc->irq_res == NULL) 158 goto no_irq; 159 160 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, 161 NULL, dp_intr, sc, &sc->irq_cookie); 162 if (error != 0) { 163 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 164 sc->irq_res = NULL; 165 goto no_irq; 166 } 167 168 /* Ack and unmask all relevant interrupts. */ 169 (void)PHY_READ(mii_sc, DP83867_ISR); 170 value = DP83867_MICR_AN_ERR | 171 DP83867_MICR_SPEED_CHG | 172 DP83867_MICR_DP_MODE_CHG | 173 DP83867_MICR_AN_CMPL | 174 DP83867_MICR_LINK_CHG; 175 PHY_WRITE(mii_sc, DP83867_MICR, value); 176 177 value = PHY_READ(mii_sc, DP83867_CFG3); 178 value |= DP83867_CFG3_INT_OE; 179 PHY_WRITE(mii_sc, DP83867_CFG3, value); 180 181 no_irq: 182 /* Set autonegotation timeout to max possible value. */ 183 value = PHY_READ(mii_sc, DP83867_CFG4); 184 value &= ~DP83867_CFG4_ANEG_MASK; 185 value &= ~DP83867_CFG4_TST_MODE1; 186 value |= DP83867_CFG4_ANEG_16MS; 187 PHY_WRITE(mii_sc, DP83867_CFG4, value); 188 189 return (0); 190 } 191 192 static int 193 dp_detach(device_t dev) 194 { 195 struct dp83867_softc *sc; 196 197 sc = device_get_softc(dev); 198 199 bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); 200 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 201 202 return (mii_phy_detach(dev)); 203 } 204 205 static int 206 dp_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 207 { 208 209 switch (cmd) { 210 case MII_POLLSTAT: 211 break; 212 case MII_MEDIACHG: 213 mii_phy_setmedia(sc); 214 break; 215 case MII_TICK: 216 if (mii_phy_tick(sc) == EJUSTRETURN) 217 return (0); 218 219 break; 220 } 221 222 PHY_STATUS(sc); 223 mii_phy_update(sc, cmd); 224 return (0); 225 } 226 227 static void 228 dp_status(struct mii_softc *sc) 229 { 230 struct mii_data *mii; 231 int bmsr, bmcr, physts; 232 233 mii = sc->mii_pdata; 234 mii->mii_media_status = IFM_AVALID; 235 mii->mii_media_active = IFM_ETHER; 236 237 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 238 physts = PHY_READ(sc, DP83867_PHYSTS); 239 240 if ((bmsr & BMSR_LINK) && (physts & DP83867_PHYSTS_LINK_UP)) 241 mii->mii_media_status |= IFM_ACTIVE; 242 243 bmcr = PHY_READ(sc, MII_BMCR); 244 if (bmcr & BMCR_ISO) { 245 mii->mii_media_active |= IFM_NONE; 246 mii->mii_media_status = 0; 247 return; 248 } 249 250 if (bmcr & BMCR_LOOP) 251 mii->mii_media_active |= IFM_LOOP; 252 253 /* Autoneg in progress. */ 254 if (!(physts & DP83867_PHYSTS_ANEG_PENDING)) { 255 mii->mii_media_active |= IFM_NONE; 256 return; 257 } 258 259 switch (physts & DP83867_PHYSTS_SPEED_MASK) { 260 case DP83867_PHYSTS_SPEED_1000: 261 mii->mii_media_active |= IFM_1000_T; 262 break; 263 case DP83867_PHYSTS_SPEED_100: 264 mii->mii_media_active |= IFM_100_TX; 265 break; 266 case DP83867_PHYSTS_SPEED_10: 267 mii->mii_media_active |= IFM_10_T; 268 break; 269 default: 270 mii->mii_media_active |= IFM_NONE; 271 break; 272 } 273 if (physts & DP83867_PHYSTS_FD) 274 mii->mii_media_active |= IFM_FDX; 275 else 276 mii->mii_media_active |= IFM_HDX; 277 278 } 279 280 static device_method_t dp_methods[] = { 281 DEVMETHOD(device_probe, dp_probe), 282 DEVMETHOD(device_attach, dp_attach), 283 DEVMETHOD(device_detach, dp_detach), 284 DEVMETHOD_END 285 }; 286 287 static devclass_t dp_devclass; 288 289 static driver_t dp_driver = { 290 "dp83867phy", 291 dp_methods, 292 sizeof(struct dp83867_softc) 293 }; 294 295 DRIVER_MODULE(dp83867phy, miibus, dp_driver, dp_devclass, 0, 0); 296