1 /* $OpenBSD: brswphy.c,v 1.1 2014/05/06 17:09:02 pirofti 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_media.h> 97 98 #include <dev/mii/mii.h> 99 #include <dev/mii/miivar.h> 100 #include <dev/mii/miidevs.h> 101 102 #define BRSW_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ 103 104 /* MII registers */ 105 #define REG_MII_PAGE 0x10 /* MII Page register */ 106 #define REG_MII_ADDR 0x11 /* MII Address register */ 107 #define REG_MII_DATA0 0x18 /* MII Data register 0 */ 108 #define REG_MII_DATA1 0x19 /* MII Data register 1 */ 109 #define REG_MII_DATA2 0x1a /* MII Data register 2 */ 110 #define REG_MII_DATA3 0x1b /* MII Data register 3 */ 111 112 #define REG_MII_PAGE_ENABLE 1 113 #define REG_MII_ADDR_WRITE 1 114 #define REG_MII_ADDR_READ 2 115 116 /* Management Port (SMP) Page offsets */ 117 #define BRSW_STAT_PAGE 0x01 /* Status */ 118 /* Link Status Summary Register (16bit) */ 119 #define BRSW_LINK_STAT 0x00 120 121 /* Duplex Status Summary (16 bit) */ 122 #define BRSW_DUPLEX_STAT_FE 0x06 123 #define BRSW_DUPLEX_STAT_GE 0x08 124 #define BRSW_DUPLEX_STAT_63XX 0x0c 125 126 /* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ 127 #define BRSW_SPEED_STAT 0x04 128 #define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) 129 #define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) 130 #define SPEED_STAT_10M 0 131 #define SPEED_STAT_100M 1 132 #define SPEED_STAT_1000M 2 133 134 #define BRSW_CPU_PORT 8 135 136 #define BRSW_PHY_READ(p, r) \ 137 (*(p)->mii_pdata->mii_readreg)((p)->mii_dev.dv_parent, \ 138 BRSW_PSEUDO_PHY, (r)) 139 #define BRSW_PHY_WRITE(p, r, v) \ 140 (*(p)->mii_pdata->mii_writereg)((p)->mii_dev.dv_parent, \ 141 BRSW_PSEUDO_PHY, (r), (v)) 142 143 struct brswphy_softc { 144 struct mii_softc sc_mii; /* common mii device part */ 145 146 uint8_t sc_current_page; 147 }; 148 149 int brswphymatch(struct device *, void *, void *); 150 void brswphyattach(struct device *, struct device *, void *); 151 152 struct cfattach brswphy_ca = { sizeof(struct brswphy_softc), 153 brswphymatch, brswphyattach, mii_phy_detach, 154 }; 155 156 struct cfdriver brswphy_cd = { 157 NULL, "brswphy", DV_DULL 158 }; 159 160 int brswphy_service(struct mii_softc *, struct mii_data *, int); 161 void brswphy_status(struct mii_softc *); 162 void brswphy_reset(struct mii_softc *); 163 164 const struct mii_phy_funcs brswphy_funcs = { 165 brswphy_service, brswphy_status, mii_phy_reset, 166 }; 167 168 static int brswphy_read16(struct mii_softc *sc, uint8_t page, uint8_t reg, 169 uint16_t *val); 170 static int brswphy_read32(struct mii_softc *sc, uint8_t page, uint8_t reg, 171 uint32_t *val); 172 static int brswphy_op(struct mii_softc *sc, uint8_t page, uint8_t reg, 173 uint16_t op); 174 175 static const struct mii_phydesc brswphys[] = { 176 { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM53115, 177 MII_STR_xxBROADCOM2_BCM53115 }, 178 179 { 0, 0, 180 NULL }, 181 }; 182 183 int 184 brswphymatch(struct device *parent, void *match, void *aux) 185 { 186 struct mii_attach_args *ma = aux; 187 188 if (mii_phy_match(ma, brswphys) != NULL) 189 return (10); 190 191 return (0); 192 } 193 194 void 195 brswphyattach(struct device *parent, struct device *self, void *aux) 196 { 197 struct brswphy_softc *bsc = (struct brswphy_softc *)self; 198 struct mii_softc *sc = &bsc->sc_mii; 199 struct mii_attach_args *ma = aux; 200 struct mii_data *mii = ma->mii_data; 201 const struct mii_phydesc *mpd; 202 203 mpd = mii_phy_match(ma, brswphys); 204 printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); 205 206 sc->mii_inst = mii->mii_instance; 207 sc->mii_phy = ma->mii_phyno; 208 sc->mii_funcs = &brswphy_funcs; 209 sc->mii_model = MII_MODEL(ma->mii_id2); 210 sc->mii_rev = MII_REV(ma->mii_id2); 211 sc->mii_pdata = mii; 212 sc->mii_flags = ma->mii_flags; 213 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 214 215 sc->mii_flags |= MIIF_NOISOLATE; 216 217 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; 218 219 if (sc->mii_capabilities & BMSR_EXTSTAT) 220 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); 221 if ((sc->mii_capabilities & BMSR_MEDIAMASK) || 222 (sc->mii_extcapabilities & EXTSR_MEDIAMASK)) 223 mii_phy_add_media(sc); 224 225 PHY_RESET(sc); 226 227 bsc->sc_current_page = 0xff; 228 } 229 230 int 231 brswphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 232 { 233 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 234 int reg; 235 236 if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) 237 return (ENXIO); 238 239 switch (cmd) { 240 case MII_POLLSTAT: 241 /* 242 * If we're not polling our PHY instance, just return. 243 */ 244 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 245 return (0); 246 break; 247 248 case MII_MEDIACHG: 249 /* 250 * If the media indicates a different PHY instance, 251 * isolate ourselves. 252 */ 253 if (IFM_INST(ife->ifm_media) != sc->mii_inst) { 254 reg = PHY_READ(sc, MII_BMCR); 255 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 256 return (0); 257 } 258 259 /* 260 * If the interface is not up, don't do anything. 261 */ 262 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 263 break; 264 265 mii_phy_setmedia(sc); 266 break; 267 268 case MII_TICK: 269 /* 270 * If we're not currently selected, just return. 271 */ 272 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 273 return (0); 274 275 if (mii_phy_tick(sc) == EJUSTRETURN) 276 return (0); 277 break; 278 279 case MII_DOWN: 280 mii_phy_down(sc); 281 return (0); 282 } 283 284 /* Update the media status. */ 285 mii_phy_status(sc); 286 287 /* Callback if something changed. */ 288 mii_phy_update(sc, cmd); 289 return (0); 290 } 291 292 void 293 brswphy_status(struct mii_softc *sc) 294 { 295 struct mii_data *mii = sc->mii_pdata; 296 uint32_t speed; 297 uint16_t link, duplex; 298 299 mii->mii_media_status = IFM_AVALID; 300 mii->mii_media_active = IFM_ETHER; 301 302 /* XXX: check that this is the CPU port when switch support arrives */ 303 304 brswphy_read16(sc, BRSW_STAT_PAGE, BRSW_LINK_STAT, &link); 305 if ((link >> BRSW_CPU_PORT) & 1) 306 mii->mii_media_status |= IFM_ACTIVE; 307 308 brswphy_read16(sc, BRSW_STAT_PAGE, BRSW_DUPLEX_STAT_GE, &duplex); 309 duplex = (duplex >> BRSW_CPU_PORT) & 1; 310 311 brswphy_read32(sc, BRSW_STAT_PAGE, BRSW_SPEED_STAT, &speed); 312 speed = SPEED_PORT_GE(speed, BRSW_CPU_PORT); 313 switch (speed) { 314 case SPEED_STAT_10M: 315 mii->mii_media_active |= IFM_10_T; 316 break; 317 case SPEED_STAT_100M: 318 mii->mii_media_active |= IFM_100_TX; 319 break; 320 case SPEED_STAT_1000M: 321 mii->mii_media_active |= IFM_1000_T; 322 break; 323 } 324 325 if (duplex) 326 mii->mii_media_active |= IFM_FDX; 327 else 328 mii->mii_media_active |= IFM_HDX; 329 330 mii->mii_media_active |= IFM_ETH_MASTER; 331 } 332 333 static int 334 brswphy_op(struct mii_softc *sc, uint8_t page, uint8_t reg, uint16_t op) 335 { 336 struct brswphy_softc *bsc = (struct brswphy_softc *)sc; 337 int i; 338 uint16_t v; 339 340 if (bsc->sc_current_page != page) { 341 /* set page number */ 342 v = (page << 8) | REG_MII_PAGE_ENABLE; 343 BRSW_PHY_WRITE(sc, REG_MII_PAGE, v); 344 bsc->sc_current_page = page; 345 } 346 347 /* set register address */ 348 v = (reg << 8) | op; 349 BRSW_PHY_WRITE(sc, REG_MII_ADDR, v); 350 351 /* check if operation completed */ 352 for (i = 0; i < 5; ++i) { 353 v = BRSW_PHY_READ(sc, REG_MII_ADDR); 354 if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) 355 break; 356 delay(10); 357 } 358 359 if (i == 5) 360 return -EIO; 361 362 return 0; 363 } 364 365 static int 366 brswphy_read16(struct mii_softc *sc, uint8_t page, uint8_t reg, uint16_t *val) 367 { 368 int ret; 369 370 ret = brswphy_op(sc, page, reg, REG_MII_ADDR_READ); 371 if (ret) 372 return ret; 373 374 *val = BRSW_PHY_READ(sc, REG_MII_DATA0); 375 376 return 0; 377 } 378 379 static int 380 brswphy_read32(struct mii_softc *sc, uint8_t page, uint8_t reg, uint32_t *val) 381 { 382 int ret; 383 384 ret = brswphy_op(sc, page, reg, REG_MII_ADDR_READ); 385 if (ret) 386 return ret; 387 388 *val = BRSW_PHY_READ(sc, REG_MII_DATA0); 389 *val |= BRSW_PHY_READ(sc, REG_MII_DATA1) << 16; 390 391 return 0; 392 } 393