1 /* $OpenBSD: brswphy.c,v 1.2 2014/12/05 15:50:04 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Paul Irofti <pirofti@openbsd.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 20 * 21 * Permission to use, copy, modify, and/or distribute this software for any 22 * purpose with or without fee is hereby granted, provided that the above 23 * copyright notice and this permission notice appear in all copies. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 26 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 28 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 */ 33 34 /*- 35 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 36 * All rights reserved. 37 * 38 * This code is derived from software contributed to The NetBSD Foundation 39 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 40 * NASA Ames Research Center, and by Frank van der Linden. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 52 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 61 * POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 /* 65 * Copyright (c) 1997 Manuel Bouyer. All rights reserved. 66 * 67 * Redistribution and use in source and binary forms, with or without 68 * modification, are permitted provided that the following conditions 69 * are met: 70 * 1. Redistributions of source code must retain the above copyright 71 * notice, this list of conditions and the following disclaimer. 72 * 2. Redistributions in binary form must reproduce the above copyright 73 * notice, this list of conditions and the following disclaimer in the 74 * documentation and/or other materials provided with the distribution. 75 * 76 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 77 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 78 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 79 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 80 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 81 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 82 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 83 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 84 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 85 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 86 */ 87 88 #include <sys/param.h> 89 #include <sys/systm.h> 90 #include <sys/kernel.h> 91 #include <sys/device.h> 92 #include <sys/socket.h> 93 #include <sys/errno.h> 94 95 #include <net/if.h> 96 #include <net/if_var.h> 97 #include <net/if_media.h> 98 99 #include <dev/mii/mii.h> 100 #include <dev/mii/miivar.h> 101 #include <dev/mii/miidevs.h> 102 103 #define BRSW_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ 104 105 /* MII registers */ 106 #define REG_MII_PAGE 0x10 /* MII Page register */ 107 #define REG_MII_ADDR 0x11 /* MII Address register */ 108 #define REG_MII_DATA0 0x18 /* MII Data register 0 */ 109 #define REG_MII_DATA1 0x19 /* MII Data register 1 */ 110 #define REG_MII_DATA2 0x1a /* MII Data register 2 */ 111 #define REG_MII_DATA3 0x1b /* MII Data register 3 */ 112 113 #define REG_MII_PAGE_ENABLE 1 114 #define REG_MII_ADDR_WRITE 1 115 #define REG_MII_ADDR_READ 2 116 117 /* Management Port (SMP) Page offsets */ 118 #define BRSW_STAT_PAGE 0x01 /* Status */ 119 /* Link Status Summary Register (16bit) */ 120 #define BRSW_LINK_STAT 0x00 121 122 /* Duplex Status Summary (16 bit) */ 123 #define BRSW_DUPLEX_STAT_FE 0x06 124 #define BRSW_DUPLEX_STAT_GE 0x08 125 #define BRSW_DUPLEX_STAT_63XX 0x0c 126 127 /* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ 128 #define BRSW_SPEED_STAT 0x04 129 #define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) 130 #define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) 131 #define SPEED_STAT_10M 0 132 #define SPEED_STAT_100M 1 133 #define SPEED_STAT_1000M 2 134 135 #define BRSW_CPU_PORT 8 136 137 #define BRSW_PHY_READ(p, r) \ 138 (*(p)->mii_pdata->mii_readreg)((p)->mii_dev.dv_parent, \ 139 BRSW_PSEUDO_PHY, (r)) 140 #define BRSW_PHY_WRITE(p, r, v) \ 141 (*(p)->mii_pdata->mii_writereg)((p)->mii_dev.dv_parent, \ 142 BRSW_PSEUDO_PHY, (r), (v)) 143 144 struct brswphy_softc { 145 struct mii_softc sc_mii; /* common mii device part */ 146 147 uint8_t sc_current_page; 148 }; 149 150 int brswphymatch(struct device *, void *, void *); 151 void brswphyattach(struct device *, struct device *, void *); 152 153 struct cfattach brswphy_ca = { sizeof(struct brswphy_softc), 154 brswphymatch, brswphyattach, mii_phy_detach, 155 }; 156 157 struct cfdriver brswphy_cd = { 158 NULL, "brswphy", DV_DULL 159 }; 160 161 int brswphy_service(struct mii_softc *, struct mii_data *, int); 162 void brswphy_status(struct mii_softc *); 163 void brswphy_reset(struct mii_softc *); 164 165 const struct mii_phy_funcs brswphy_funcs = { 166 brswphy_service, brswphy_status, mii_phy_reset, 167 }; 168 169 static int brswphy_read16(struct mii_softc *sc, uint8_t page, uint8_t reg, 170 uint16_t *val); 171 static int brswphy_read32(struct mii_softc *sc, uint8_t page, uint8_t reg, 172 uint32_t *val); 173 static int brswphy_op(struct mii_softc *sc, uint8_t page, uint8_t reg, 174 uint16_t op); 175 176 static const struct mii_phydesc brswphys[] = { 177 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM53115, 178 MII_STR_xxBROADCOM2_BCM53115 }, 179 180 { 0, 0, 181 NULL }, 182 }; 183 184 int 185 brswphymatch(struct device *parent, void *match, void *aux) 186 { 187 struct mii_attach_args *ma = aux; 188 189 if (mii_phy_match(ma, brswphys) != NULL) 190 return (10); 191 192 return (0); 193 } 194 195 void 196 brswphyattach(struct device *parent, struct device *self, void *aux) 197 { 198 struct brswphy_softc *bsc = (struct brswphy_softc *)self; 199 struct mii_softc *sc = &bsc->sc_mii; 200 struct mii_attach_args *ma = aux; 201 struct mii_data *mii = ma->mii_data; 202 const struct mii_phydesc *mpd; 203 204 mpd = mii_phy_match(ma, brswphys); 205 printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 206 207 sc->mii_inst = mii->mii_instance; 208 sc->mii_phy = ma->mii_phyno; 209 sc->mii_funcs = &brswphy_funcs; 210 sc->mii_model = MII_MODEL(ma->mii_id2); 211 sc->mii_rev = MII_REV(ma->mii_id2); 212 sc->mii_pdata = mii; 213 sc->mii_flags = ma->mii_flags; 214 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 215 216 sc->mii_flags |= MIIF_NOISOLATE; 217 218 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 219 220 if (sc->mii_capabilities & BMSR_EXTSTAT) 221 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 222 if ((sc->mii_capabilities & BMSR_MEDIAMASK) || 223 (sc->mii_extcapabilities & EXTSR_MEDIAMASK)) 224 mii_phy_add_media(sc); 225 226 PHY_RESET(sc); 227 228 bsc->sc_current_page = 0xff; 229 } 230 231 int 232 brswphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 233 { 234 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 235 int reg; 236 237 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 238 return (ENXIO); 239 240 switch (cmd) { 241 case MII_POLLSTAT: 242 /* 243 * If we're not polling our PHY instance, just return. 244 */ 245 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 246 return (0); 247 break; 248 249 case MII_MEDIACHG: 250 /* 251 * If the media indicates a different PHY instance, 252 * isolate ourselves. 253 */ 254 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 255 reg = PHY_READ(sc, MII_BMCR); 256 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 257 return (0); 258 } 259 260 /* 261 * If the interface is not up, don't do anything. 262 */ 263 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 264 break; 265 266 mii_phy_setmedia(sc); 267 break; 268 269 case MII_TICK: 270 /* 271 * If we're not currently selected, just return. 272 */ 273 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 274 return (0); 275 276 if (mii_phy_tick(sc) == EJUSTRETURN) 277 return (0); 278 break; 279 280 case MII_DOWN: 281 mii_phy_down(sc); 282 return (0); 283 } 284 285 /* Update the media status. */ 286 mii_phy_status(sc); 287 288 /* Callback if something changed. */ 289 mii_phy_update(sc, cmd); 290 return (0); 291 } 292 293 void 294 brswphy_status(struct mii_softc *sc) 295 { 296 struct mii_data *mii = sc->mii_pdata; 297 uint32_t speed; 298 uint16_t link, duplex; 299 300 mii->mii_media_status = IFM_AVALID; 301 mii->mii_media_active = IFM_ETHER; 302 303 /* XXX: check that this is the CPU port when switch support arrives */ 304 305 brswphy_read16(sc, BRSW_STAT_PAGE, BRSW_LINK_STAT, &link); 306 if ((link >> BRSW_CPU_PORT) & 1) 307 mii->mii_media_status |= IFM_ACTIVE; 308 309 brswphy_read16(sc, BRSW_STAT_PAGE, BRSW_DUPLEX_STAT_GE, &duplex); 310 duplex = (duplex >> BRSW_CPU_PORT) & 1; 311 312 brswphy_read32(sc, BRSW_STAT_PAGE, BRSW_SPEED_STAT, &speed); 313 speed = SPEED_PORT_GE(speed, BRSW_CPU_PORT); 314 switch (speed) { 315 case SPEED_STAT_10M: 316 mii->mii_media_active |= IFM_10_T; 317 break; 318 case SPEED_STAT_100M: 319 mii->mii_media_active |= IFM_100_TX; 320 break; 321 case SPEED_STAT_1000M: 322 mii->mii_media_active |= IFM_1000_T; 323 break; 324 } 325 326 if (duplex) 327 mii->mii_media_active |= IFM_FDX; 328 else 329 mii->mii_media_active |= IFM_HDX; 330 331 mii->mii_media_active |= IFM_ETH_MASTER; 332 } 333 334 static int 335 brswphy_op(struct mii_softc *sc, uint8_t page, uint8_t reg, uint16_t op) 336 { 337 struct brswphy_softc *bsc = (struct brswphy_softc *)sc; 338 int i; 339 uint16_t v; 340 341 if (bsc->sc_current_page != page) { 342 /* set page number */ 343 v = (page << 8) | REG_MII_PAGE_ENABLE; 344 BRSW_PHY_WRITE(sc, REG_MII_PAGE, v); 345 bsc->sc_current_page = page; 346 } 347 348 /* set register address */ 349 v = (reg << 8) | op; 350 BRSW_PHY_WRITE(sc, REG_MII_ADDR, v); 351 352 /* check if operation completed */ 353 for (i = 0; i < 5; ++i) { 354 v = BRSW_PHY_READ(sc, REG_MII_ADDR); 355 if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) 356 break; 357 delay(10); 358 } 359 360 if (i == 5) 361 return -EIO; 362 363 return 0; 364 } 365 366 static int 367 brswphy_read16(struct mii_softc *sc, uint8_t page, uint8_t reg, uint16_t *val) 368 { 369 int ret; 370 371 ret = brswphy_op(sc, page, reg, REG_MII_ADDR_READ); 372 if (ret) 373 return ret; 374 375 *val = BRSW_PHY_READ(sc, REG_MII_DATA0); 376 377 return 0; 378 } 379 380 static int 381 brswphy_read32(struct mii_softc *sc, uint8_t page, uint8_t reg, uint32_t *val) 382 { 383 int ret; 384 385 ret = brswphy_op(sc, page, reg, REG_MII_ADDR_READ); 386 if (ret) 387 return ret; 388 389 *val = BRSW_PHY_READ(sc, REG_MII_DATA0); 390 *val |= BRSW_PHY_READ(sc, REG_MII_DATA1) << 16; 391 392 return 0; 393 } 394