1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/resource.h> 38 #include <sys/rman.h> 39 #include <sys/socket.h> 40 41 #include <machine/resource.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 49 #include "miidevs.h" 50 #include "miibus_if.h" 51 52 #define BIT(x) (1 << (x)) 53 54 #define DP83867_PHYCR 0x10 55 #define DP83867_PHYSTS 0x11 56 #define DP83867_MICR 0x12 57 #define DP83867_ISR 0x13 58 #define DP83867_CFG3 0x1E 59 #define DP83867_CTRL 0x1F 60 #define DP83867_CFG4 0x31 61 #define DP83867_RGMIICTL 0x32 62 #define DP83867_STRP_STS1 0x6E 63 #define DP83867_STRP_STS2 0x6F 64 65 #define DP83867_PHYSTS_LINK_UP BIT(10) 66 #define DP83867_PHYSTS_ANEG_PENDING BIT(11) 67 #define DP83867_PHYSTS_FD BIT(13) 68 #define DP83867_PHYSTS_SPEED_MASK (BIT(15) | BIT(14)) 69 #define DP83867_PHYSTS_SPEED_1000 BIT(15) 70 #define DP83867_PHYSTS_SPEED_100 BIT(14) 71 #define DP83867_PHYSTS_SPEED_10 0 72 73 #define DP83867_MICR_AN_ERR BIT(15) 74 #define DP83867_MICR_SPEED_CHG BIT(14) 75 #define DP83867_MICR_DP_MODE_CHG BIT(13) 76 #define DP83867_MICR_AN_CMPL BIT(11) 77 #define DP83867_MICR_LINK_CHG BIT(10) 78 79 #define DP83867_CFG3_INT_OE BIT(7) 80 81 #define DP83867_CFG4_TST_MODE1 BIT(7) 82 #define DP83867_CFG4_ANEG_MASK (BIT(5) | BIT(6)) 83 #define DP83867_CFG4_ANEG_16MS (0 << 5) 84 85 #define BMSR_100_MASK (BMSR_100T4 | BMSR_100TXFDX | BMSR_100TXHDX | \ 86 BMSR_100T2FDX | BMSR_100T2HDX) 87 88 static int dp_probe(device_t); 89 static int dp_attach(device_t); 90 91 static int dp_service(struct mii_softc*, struct mii_data*, int); 92 static void dp_status(struct mii_softc*); 93 94 struct dp83867_softc { 95 struct mii_softc mii_sc; 96 struct resource *irq_res; 97 void *irq_cookie; 98 }; 99 100 static const struct mii_phydesc dpphys[] = { 101 MII_PHY_DESC(xxTI, DP83867), 102 MII_PHY_END 103 }; 104 105 static const struct mii_phy_funcs dpphy_funcs = { 106 dp_service, 107 dp_status, 108 mii_phy_reset 109 }; 110 111 static void 112 dp_intr(void *arg) 113 { 114 struct mii_softc *sc = (struct mii_softc *)arg; 115 uint32_t status; 116 117 status = PHY_READ(sc, DP83867_ISR); 118 status &= PHY_READ(sc, DP83867_MICR); 119 if (!status) 120 return; 121 122 PHY_STATUS(sc); 123 mii_phy_update(sc, MII_MEDIACHG); 124 } 125 126 static int 127 dp_probe(device_t dev) 128 { 129 130 return (mii_phy_dev_probe(dev, dpphys, BUS_PROBE_DEFAULT)); 131 } 132 133 static int 134 dp_attach(device_t dev) 135 { 136 struct dp83867_softc *sc; 137 struct mii_softc *mii_sc; 138 uint32_t value, maxspeed; 139 ssize_t size; 140 int rid, error; 141 142 sc = device_get_softc(dev); 143 mii_sc = &sc->mii_sc; 144 145 size = device_get_property(dev, "max-speed", &maxspeed, 146 sizeof(maxspeed), DEVICE_PROP_UINT32); 147 if (size <= 0) 148 maxspeed = 0; 149 150 mii_sc->mii_maxspeed = maxspeed; 151 mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &dpphy_funcs, 1); 152 153 rid = 0; 154 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 155 if (sc->irq_res == NULL) 156 goto no_irq; 157 158 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, 159 NULL, dp_intr, sc, &sc->irq_cookie); 160 if (error != 0) { 161 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 162 sc->irq_res = NULL; 163 goto no_irq; 164 } 165 166 /* Ack and unmask all relevant interrupts. */ 167 (void)PHY_READ(mii_sc, DP83867_ISR); 168 value = DP83867_MICR_AN_ERR | 169 DP83867_MICR_SPEED_CHG | 170 DP83867_MICR_DP_MODE_CHG | 171 DP83867_MICR_AN_CMPL | 172 DP83867_MICR_LINK_CHG; 173 PHY_WRITE(mii_sc, DP83867_MICR, value); 174 175 value = PHY_READ(mii_sc, DP83867_CFG3); 176 value |= DP83867_CFG3_INT_OE; 177 PHY_WRITE(mii_sc, DP83867_CFG3, value); 178 179 no_irq: 180 /* Set autonegotation timeout to max possible value. */ 181 value = PHY_READ(mii_sc, DP83867_CFG4); 182 value &= ~DP83867_CFG4_ANEG_MASK; 183 value &= ~DP83867_CFG4_TST_MODE1; 184 value |= DP83867_CFG4_ANEG_16MS; 185 PHY_WRITE(mii_sc, DP83867_CFG4, value); 186 187 return (0); 188 } 189 190 static int 191 dp_detach(device_t dev) 192 { 193 struct dp83867_softc *sc; 194 195 sc = device_get_softc(dev); 196 197 bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); 198 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 199 200 return (mii_phy_detach(dev)); 201 } 202 203 static int 204 dp_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 205 { 206 207 switch (cmd) { 208 case MII_POLLSTAT: 209 break; 210 case MII_MEDIACHG: 211 mii_phy_setmedia(sc); 212 break; 213 case MII_TICK: 214 if (mii_phy_tick(sc) == EJUSTRETURN) 215 return (0); 216 217 break; 218 } 219 220 PHY_STATUS(sc); 221 mii_phy_update(sc, cmd); 222 return (0); 223 } 224 225 static void 226 dp_status(struct mii_softc *sc) 227 { 228 struct mii_data *mii; 229 int bmsr, bmcr, physts; 230 231 mii = sc->mii_pdata; 232 mii->mii_media_status = IFM_AVALID; 233 mii->mii_media_active = IFM_ETHER; 234 235 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 236 physts = PHY_READ(sc, DP83867_PHYSTS); 237 238 if ((bmsr & BMSR_LINK) && (physts & DP83867_PHYSTS_LINK_UP)) 239 mii->mii_media_status |= IFM_ACTIVE; 240 241 bmcr = PHY_READ(sc, MII_BMCR); 242 if (bmcr & BMCR_ISO) { 243 mii->mii_media_active |= IFM_NONE; 244 mii->mii_media_status = 0; 245 return; 246 } 247 248 if (bmcr & BMCR_LOOP) 249 mii->mii_media_active |= IFM_LOOP; 250 251 /* Autoneg in progress. */ 252 if (!(physts & DP83867_PHYSTS_ANEG_PENDING)) { 253 mii->mii_media_active |= IFM_NONE; 254 return; 255 } 256 257 switch (physts & DP83867_PHYSTS_SPEED_MASK) { 258 case DP83867_PHYSTS_SPEED_1000: 259 mii->mii_media_active |= IFM_1000_T; 260 break; 261 case DP83867_PHYSTS_SPEED_100: 262 mii->mii_media_active |= IFM_100_TX; 263 break; 264 case DP83867_PHYSTS_SPEED_10: 265 mii->mii_media_active |= IFM_10_T; 266 break; 267 default: 268 mii->mii_media_active |= IFM_NONE; 269 break; 270 } 271 if (physts & DP83867_PHYSTS_FD) 272 mii->mii_media_active |= IFM_FDX; 273 else 274 mii->mii_media_active |= IFM_HDX; 275 276 } 277 278 static device_method_t dp_methods[] = { 279 DEVMETHOD(device_probe, dp_probe), 280 DEVMETHOD(device_attach, dp_attach), 281 DEVMETHOD(device_detach, dp_detach), 282 DEVMETHOD_END 283 }; 284 285 static driver_t dp_driver = { 286 "dp83867phy", 287 dp_methods, 288 sizeof(struct dp83867_softc) 289 }; 290 291 DRIVER_MODULE(dp83867phy, miibus, dp_driver, 0, 0); 292