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 }; 106 107 static const struct mii_phy_funcs dpphy_funcs = { 108 dp_service, 109 dp_status, 110 mii_phy_reset 111 }; 112 113 static void 114 dp_intr(void *arg) 115 { 116 struct mii_softc *sc = (struct mii_softc *)arg; 117 uint32_t status; 118 119 status = PHY_READ(sc, DP83867_ISR); 120 status &= PHY_READ(sc, DP83867_MICR); 121 if (!status) 122 return; 123 124 PHY_STATUS(sc); 125 mii_phy_update(sc, MII_MEDIACHG); 126 } 127 128 static int 129 dp_probe(device_t dev) 130 { 131 132 return (mii_phy_dev_probe(dev, dpphys, BUS_PROBE_DEFAULT)); 133 } 134 135 static int 136 dp_attach(device_t dev) 137 { 138 struct dp83867_softc *sc; 139 struct mii_softc *mii_sc; 140 uint32_t value, maxspeed; 141 ssize_t size; 142 int rid, error; 143 144 sc = device_get_softc(dev); 145 mii_sc = &sc->mii_sc; 146 147 size = device_get_property(dev, "max-speed", &maxspeed, sizeof(maxspeed)); 148 if (size <= 0) 149 maxspeed = 0; 150 151 mii_sc->mii_maxspeed = maxspeed; 152 mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &dpphy_funcs, 1); 153 154 rid = 0; 155 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 156 if (sc->irq_res == NULL) 157 goto no_irq; 158 159 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, 160 NULL, dp_intr, sc, &sc->irq_cookie); 161 if (error != 0) { 162 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 163 sc->irq_res = NULL; 164 goto no_irq; 165 } 166 167 /* Ack and unmask all relevant interrupts. */ 168 (void)PHY_READ(mii_sc, DP83867_ISR); 169 value = DP83867_MICR_AN_ERR | 170 DP83867_MICR_SPEED_CHG | 171 DP83867_MICR_DP_MODE_CHG | 172 DP83867_MICR_AN_CMPL | 173 DP83867_MICR_LINK_CHG; 174 PHY_WRITE(mii_sc, DP83867_MICR, value); 175 176 value = PHY_READ(mii_sc, DP83867_CFG3); 177 value |= DP83867_CFG3_INT_OE; 178 PHY_WRITE(mii_sc, DP83867_CFG3, value); 179 180 no_irq: 181 /* Set autonegotation timeout to max possible value. */ 182 value = PHY_READ(mii_sc, DP83867_CFG4); 183 value &= ~DP83867_CFG4_ANEG_MASK; 184 value &= ~DP83867_CFG4_TST_MODE1; 185 value |= DP83867_CFG4_ANEG_16MS; 186 PHY_WRITE(mii_sc, DP83867_CFG4, value); 187 188 return (0); 189 } 190 191 static int 192 dp_detach(device_t dev) 193 { 194 struct dp83867_softc *sc; 195 196 sc = device_get_softc(dev); 197 198 bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); 199 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 200 201 return (mii_phy_detach(dev)); 202 } 203 204 static int 205 dp_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 206 { 207 208 switch (cmd) { 209 case MII_POLLSTAT: 210 break; 211 case MII_MEDIACHG: 212 mii_phy_setmedia(sc); 213 break; 214 case MII_TICK: 215 if (mii_phy_tick(sc) == EJUSTRETURN) 216 return (0); 217 218 break; 219 } 220 221 PHY_STATUS(sc); 222 mii_phy_update(sc, cmd); 223 return (0); 224 } 225 226 static void 227 dp_status(struct mii_softc *sc) 228 { 229 struct mii_data *mii; 230 int bmsr, bmcr, physts; 231 232 mii = sc->mii_pdata; 233 mii->mii_media_status = IFM_AVALID; 234 mii->mii_media_active = IFM_ETHER; 235 236 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 237 physts = PHY_READ(sc, DP83867_PHYSTS); 238 239 if ((bmsr & BMSR_LINK) && (physts & DP83867_PHYSTS_LINK_UP)) 240 mii->mii_media_status |= IFM_ACTIVE; 241 242 bmcr = PHY_READ(sc, MII_BMCR); 243 if (bmcr & BMCR_ISO) { 244 mii->mii_media_active |= IFM_NONE; 245 mii->mii_media_status = 0; 246 return; 247 } 248 249 if (bmcr & BMCR_LOOP) 250 mii->mii_media_active |= IFM_LOOP; 251 252 /* Autoneg in progress. */ 253 if (!(physts & DP83867_PHYSTS_ANEG_PENDING)) { 254 mii->mii_media_active |= IFM_NONE; 255 return; 256 } 257 258 switch (physts & DP83867_PHYSTS_SPEED_MASK) { 259 case DP83867_PHYSTS_SPEED_1000: 260 mii->mii_media_active |= IFM_1000_T; 261 break; 262 case DP83867_PHYSTS_SPEED_100: 263 mii->mii_media_active |= IFM_100_TX; 264 break; 265 case DP83867_PHYSTS_SPEED_10: 266 mii->mii_media_active |= IFM_10_T; 267 break; 268 default: 269 mii->mii_media_active |= IFM_NONE; 270 break; 271 } 272 if (physts & DP83867_PHYSTS_FD) 273 mii->mii_media_active |= IFM_FDX; 274 else 275 mii->mii_media_active |= IFM_HDX; 276 277 } 278 279 static device_method_t dp_methods[] = { 280 DEVMETHOD(device_probe, dp_probe), 281 DEVMETHOD(device_attach, dp_attach), 282 DEVMETHOD(device_detach, dp_detach), 283 DEVMETHOD_END 284 }; 285 286 static devclass_t dp_devclass; 287 288 static driver_t dp_driver = { 289 "dp83867phy", 290 dp_methods, 291 sizeof(struct dp83867_softc) 292 }; 293 294 DRIVER_MODULE(dp83867phy, miibus, dp_driver, dp_devclass, 0, 0); 295