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/cdefs.h> 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/kernel.h> 37 #include <sys/module.h> 38 #include <sys/resource.h> 39 #include <sys/rman.h> 40 #include <sys/socket.h> 41 42 #include <machine/resource.h> 43 44 #include <net/if.h> 45 #include <net/if_media.h> 46 47 #include <dev/mii/mii.h> 48 #include <dev/mii/miivar.h> 49 50 #include "miidevs.h" 51 #include "miibus_if.h" 52 53 #define BIT(x) (1 << (x)) 54 55 #define DP83867_PHYCR 0x10 56 #define DP83867_PHYSTS 0x11 57 #define DP83867_MICR 0x12 58 #define DP83867_ISR 0x13 59 #define DP83867_CFG3 0x1E 60 #define DP83867_CTRL 0x1F 61 #define DP83867_CFG4 0x31 62 #define DP83867_RGMIICTL 0x32 63 #define DP83867_STRP_STS1 0x6E 64 #define DP83867_STRP_STS2 0x6F 65 66 #define DP83867_PHYSTS_LINK_UP BIT(10) 67 #define DP83867_PHYSTS_ANEG_PENDING BIT(11) 68 #define DP83867_PHYSTS_FD BIT(13) 69 #define DP83867_PHYSTS_SPEED_MASK (BIT(15) | BIT(14)) 70 #define DP83867_PHYSTS_SPEED_1000 BIT(15) 71 #define DP83867_PHYSTS_SPEED_100 BIT(14) 72 #define DP83867_PHYSTS_SPEED_10 0 73 74 #define DP83867_MICR_AN_ERR BIT(15) 75 #define DP83867_MICR_SPEED_CHG BIT(14) 76 #define DP83867_MICR_DP_MODE_CHG BIT(13) 77 #define DP83867_MICR_AN_CMPL BIT(11) 78 #define DP83867_MICR_LINK_CHG BIT(10) 79 80 #define DP83867_CFG3_INT_OE BIT(7) 81 82 #define DP83867_CFG4_TST_MODE1 BIT(7) 83 #define DP83867_CFG4_ANEG_MASK (BIT(5) | BIT(6)) 84 #define DP83867_CFG4_ANEG_16MS (0 << 5) 85 86 #define BMSR_100_MASK (BMSR_100T4 | BMSR_100TXFDX | BMSR_100TXHDX | \ 87 BMSR_100T2FDX | BMSR_100T2HDX) 88 89 static int dp_probe(device_t); 90 static int dp_attach(device_t); 91 92 static int dp_service(struct mii_softc*, struct mii_data*, int); 93 static void dp_status(struct mii_softc*); 94 95 struct dp83867_softc { 96 struct mii_softc mii_sc; 97 struct resource *irq_res; 98 void *irq_cookie; 99 }; 100 101 static const struct mii_phydesc dpphys[] = { 102 MII_PHY_DESC(xxTI, DP83867), 103 MII_PHY_END 104 }; 105 106 static const struct mii_phy_funcs dpphy_funcs = { 107 dp_service, 108 dp_status, 109 mii_phy_reset 110 }; 111 112 static void 113 dp_intr(void *arg) 114 { 115 struct mii_softc *sc = (struct mii_softc *)arg; 116 uint32_t status; 117 118 status = PHY_READ(sc, DP83867_ISR); 119 status &= PHY_READ(sc, DP83867_MICR); 120 if (!status) 121 return; 122 123 PHY_STATUS(sc); 124 mii_phy_update(sc, MII_MEDIACHG); 125 } 126 127 static int 128 dp_probe(device_t dev) 129 { 130 131 return (mii_phy_dev_probe(dev, dpphys, BUS_PROBE_DEFAULT)); 132 } 133 134 static int 135 dp_attach(device_t dev) 136 { 137 struct dp83867_softc *sc; 138 struct mii_softc *mii_sc; 139 uint32_t value, maxspeed; 140 ssize_t size; 141 int rid, error; 142 143 sc = device_get_softc(dev); 144 mii_sc = &sc->mii_sc; 145 146 size = device_get_property(dev, "max-speed", &maxspeed, 147 sizeof(maxspeed), DEVICE_PROP_UINT32); 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 driver_t dp_driver = { 287 "dp83867phy", 288 dp_methods, 289 sizeof(struct dp83867_softc) 290 }; 291 292 DRIVER_MODULE(dp83867phy, miibus, dp_driver, 0, 0); 293