1165782Sticso/*- 2165782Sticso * Copyright (c) 1997, 1998, 1999 3165782Sticso * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4165782Sticso * Copyright (c) 2006 Bernd Walter. All rights reserved. 5165782Sticso * 6165782Sticso * Redistribution and use in source and binary forms, with or without 7165782Sticso * modification, are permitted provided that the following conditions 8165782Sticso * are met: 9165782Sticso * 1. Redistributions of source code must retain the above copyright 10165782Sticso * notice, this list of conditions and the following disclaimer. 11165782Sticso * 2. Redistributions in binary form must reproduce the above copyright 12165782Sticso * notice, this list of conditions and the following disclaimer in the 13165782Sticso * documentation and/or other materials provided with the distribution. 14165782Sticso * 3. All advertising materials mentioning features or use of this software 15165782Sticso * must display the following acknowledgement: 16165782Sticso * This product includes software developed by Bill Paul. 17165782Sticso * 4. Neither the name of the author nor the names of any co-contributors 18165782Sticso * may be used to endorse or promote products derived from this software 19165782Sticso * without specific prior written permission. 20165782Sticso * 21165782Sticso * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 22165782Sticso * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23165782Sticso * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24165782Sticso * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 25165782Sticso * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26165782Sticso * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27165782Sticso * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28165782Sticso * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29165782Sticso * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30165782Sticso * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31165782Sticso * THE POSSIBILITY OF SUCH DAMAGE. 32165782Sticso */ 33165782Sticso 34165782Sticso#include <sys/cdefs.h> 35165782Sticso__FBSDID("$FreeBSD$"); 36165782Sticso 37165782Sticso/* 38165782Sticso * driver for RealTek 8305 pseudo PHYs 39165782Sticso */ 40165782Sticso 41165782Sticso#include <sys/param.h> 42165782Sticso#include <sys/systm.h> 43165782Sticso#include <sys/kernel.h> 44165782Sticso#include <sys/module.h> 45165782Sticso#include <sys/socket.h> 46165782Sticso#include <sys/bus.h> 47257184Sglebius#include <sys/taskqueue.h> /* XXXGL: if_rlreg.h contamination */ 48165782Sticso 49165782Sticso#include <net/if.h> 50165782Sticso#include <net/if_arp.h> 51165782Sticso#include <net/if_media.h> 52165782Sticso 53165782Sticso#include <dev/mii/mii.h> 54165782Sticso#include <dev/mii/miivar.h> 55165782Sticso#include "miidevs.h" 56165782Sticso 57165782Sticso#include <machine/bus.h> 58271864Sglebius#include <dev/rl/if_rlreg.h> 59165782Sticso 60165782Sticso#include "miibus_if.h" 61165782Sticso 62165782Sticso//#define RL_DEBUG 63165782Sticso#define RL_VLAN 64165782Sticso 65165782Sticsostatic int rlswitch_probe(device_t); 66165782Sticsostatic int rlswitch_attach(device_t); 67165782Sticso 68165782Sticsostatic device_method_t rlswitch_methods[] = { 69165782Sticso /* device interface */ 70165782Sticso DEVMETHOD(device_probe, rlswitch_probe), 71165782Sticso DEVMETHOD(device_attach, rlswitch_attach), 72165782Sticso DEVMETHOD(device_detach, mii_phy_detach), 73165782Sticso DEVMETHOD(device_shutdown, bus_generic_shutdown), 74227908Smarius DEVMETHOD_END 75165782Sticso}; 76165782Sticso 77165782Sticsostatic devclass_t rlswitch_devclass; 78165782Sticso 79165782Sticsostatic driver_t rlswitch_driver = { 80165782Sticso "rlswitch", 81165782Sticso rlswitch_methods, 82165782Sticso sizeof(struct mii_softc) 83165782Sticso}; 84165782Sticso 85165782SticsoDRIVER_MODULE(rlswitch, miibus, rlswitch_driver, rlswitch_devclass, 0, 0); 86165782Sticso 87165782Sticsostatic int rlswitch_service(struct mii_softc *, struct mii_data *, int); 88165782Sticsostatic void rlswitch_status(struct mii_softc *); 89165782Sticso 90165782Sticso#ifdef RL_DEBUG 91165782Sticsostatic void rlswitch_phydump(device_t dev); 92165782Sticso#endif 93165782Sticso 94165782Sticsostatic const struct mii_phydesc rlswitches[] = { 95221407Smarius MII_PHY_DESC(REALTEK, RTL8305SC), 96165782Sticso MII_PHY_END 97165782Sticso}; 98165782Sticso 99221407Smariusstatic const struct mii_phy_funcs rlswitch_funcs = { 100221407Smarius rlswitch_service, 101221407Smarius rlswitch_status, 102221407Smarius mii_phy_reset 103221407Smarius}; 104221407Smarius 105165782Sticsostatic int 106165782Sticsorlswitch_probe(device_t dev) 107165782Sticso{ 108165782Sticso int rv; 109165782Sticso 110165782Sticso rv = mii_phy_dev_probe(dev, rlswitches, BUS_PROBE_DEFAULT); 111165782Sticso if (rv <= 0) 112165782Sticso return (rv); 113165782Sticso 114165782Sticso return (ENXIO); 115165782Sticso} 116165782Sticso 117165782Sticsostatic int 118165782Sticsorlswitch_attach(device_t dev) 119165782Sticso{ 120165782Sticso struct mii_softc *sc; 121165782Sticso 122165782Sticso sc = device_get_softc(dev); 123165782Sticso 124213364Smarius /* 125213364Smarius * We handle all pseudo PHYs in a single instance. 126213364Smarius */ 127221407Smarius mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, 128221407Smarius &rlswitch_funcs, 0); 129165782Sticso 130221407Smarius sc->mii_capabilities = BMSR_100TXFDX & sc->mii_capmask; 131165782Sticso device_printf(dev, " "); 132165782Sticso mii_phy_add_media(sc); 133165782Sticso printf("\n"); 134165782Sticso#ifdef RL_DEBUG 135165782Sticso rlswitch_phydump(dev); 136165782Sticso#endif 137165782Sticso 138165782Sticso#ifdef RL_VLAN 139165782Sticso int val; 140165782Sticso 141165782Sticso /* Global Control 0 */ 142165782Sticso val = 0; 143165782Sticso val |= 0 << 10; /* enable 802.1q VLAN Tag support */ 144165782Sticso val |= 0 << 9; /* enable VLAN ingress filtering */ 145165782Sticso val |= 1 << 8; /* disable VLAN tag admit control */ 146165782Sticso val |= 1 << 6; /* internal use */ 147165782Sticso val |= 1 << 5; /* internal use */ 148165782Sticso val |= 1 << 4; /* internal use */ 149165782Sticso val |= 1 << 3; /* internal use */ 150165782Sticso val |= 1 << 1; /* reserved */ 151165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 16, val); 152165782Sticso 153165782Sticso /* Global Control 2 */ 154165782Sticso val = 0; 155165782Sticso val |= 1 << 15; /* reserved */ 156165782Sticso val |= 0 << 14; /* enable 1552 Bytes support */ 157165782Sticso val |= 1 << 13; /* enable broadcast input drop */ 158165782Sticso val |= 1 << 12; /* forward reserved control frames */ 159165782Sticso val |= 1 << 11; /* disable forwarding unicast frames to other VLAN's */ 160165782Sticso val |= 1 << 10; /* disable forwarding ARP broadcasts to other VLAN's */ 161165782Sticso val |= 1 << 9; /* enable 48 pass 1 */ 162165782Sticso val |= 0 << 8; /* enable VLAN */ 163165782Sticso val |= 1 << 7; /* reserved */ 164165782Sticso val |= 1 << 6; /* enable defer */ 165165782Sticso val |= 1 << 5; /* 43ms LED blink time */ 166165782Sticso val |= 3 << 3; /* 16:1 queue weight */ 167165782Sticso val |= 1 << 2; /* disable broadcast storm control */ 168165782Sticso val |= 1 << 1; /* enable power-on LED blinking */ 169165782Sticso val |= 1 << 0; /* reserved */ 170165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 18, val); 171165782Sticso 172165782Sticso /* Port 0 Control Register 0 */ 173165782Sticso val = 0; 174165782Sticso val |= 1 << 15; /* reserved */ 175165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 176165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 177165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 178165782Sticso val |= 1 << 6; /* internal use */ 179165782Sticso val |= 3 << 4; /* internal use */ 180165782Sticso val |= 1 << 3; /* internal use */ 181165782Sticso val |= 1 << 2; /* internal use */ 182165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 183165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 22, val); 184165782Sticso 185165782Sticso /* Port 1 Control Register 0 */ 186165782Sticso val = 0; 187165782Sticso val |= 1 << 15; /* reserved */ 188165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 189165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 190165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 191165782Sticso val |= 1 << 6; /* internal use */ 192165782Sticso val |= 3 << 4; /* internal use */ 193165782Sticso val |= 1 << 3; /* internal use */ 194165782Sticso val |= 1 << 2; /* internal use */ 195165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 196165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 22, val); 197165782Sticso 198165782Sticso /* Port 2 Control Register 0 */ 199165782Sticso val = 0; 200165782Sticso val |= 1 << 15; /* reserved */ 201165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 202165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 203165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 204165782Sticso val |= 1 << 6; /* internal use */ 205165782Sticso val |= 3 << 4; /* internal use */ 206165782Sticso val |= 1 << 3; /* internal use */ 207165782Sticso val |= 1 << 2; /* internal use */ 208165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 209165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 22, val); 210165782Sticso 211165782Sticso /* Port 3 Control Register 0 */ 212165782Sticso val = 0; 213165782Sticso val |= 1 << 15; /* reserved */ 214165782Sticso val |= 1 << 11; /* drop received packets with wrong VLAN tag */ 215165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 216165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 217165782Sticso val |= 1 << 6; /* internal use */ 218165782Sticso val |= 3 << 4; /* internal use */ 219165782Sticso val |= 1 << 3; /* internal use */ 220165782Sticso val |= 1 << 2; /* internal use */ 221165782Sticso val |= 1 << 0; /* remove VLAN tags on output */ 222165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 22, val); 223165782Sticso 224165782Sticso /* Port 4 (system port) Control Register 0 */ 225165782Sticso val = 0; 226165782Sticso val |= 1 << 15; /* reserved */ 227165782Sticso val |= 0 << 11; /* don't drop received packets with wrong VLAN tag */ 228165782Sticso val |= 1 << 10; /* disable 802.1p priority classification */ 229165782Sticso val |= 1 << 9; /* disable diffserv priority classification */ 230165782Sticso val |= 1 << 6; /* internal use */ 231165782Sticso val |= 3 << 4; /* internal use */ 232165782Sticso val |= 1 << 3; /* internal use */ 233165782Sticso val |= 1 << 2; /* internal use */ 234165782Sticso val |= 2 << 0; /* add VLAN tags for untagged packets on output */ 235165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 22, val); 236165782Sticso 237165782Sticso /* Port 0 Control Register 1 and VLAN A */ 238165782Sticso val = 0; 239165782Sticso val |= 0x0 << 12; /* Port 0 VLAN Index */ 240165782Sticso val |= 1 << 11; /* internal use */ 241165782Sticso val |= 1 << 10; /* internal use */ 242165782Sticso val |= 1 << 9; /* internal use */ 243165782Sticso val |= 1 << 7; /* internal use */ 244165782Sticso val |= 1 << 6; /* internal use */ 245165782Sticso val |= 0x11 << 0; /* VLAN A membership */ 246165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 24, val); 247165782Sticso 248165782Sticso /* Port 0 Control Register 2 and VLAN A */ 249165782Sticso val = 0; 250165782Sticso val |= 1 << 15; /* internal use */ 251165782Sticso val |= 1 << 14; /* internal use */ 252165782Sticso val |= 1 << 13; /* internal use */ 253165782Sticso val |= 1 << 12; /* internal use */ 254165782Sticso val |= 0x100 << 0; /* VLAN A ID */ 255165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 0, 25, val); 256165782Sticso 257165782Sticso /* Port 1 Control Register 1 and VLAN B */ 258165782Sticso val = 0; 259165782Sticso val |= 0x1 << 12; /* Port 1 VLAN Index */ 260165782Sticso val |= 1 << 11; /* internal use */ 261165782Sticso val |= 1 << 10; /* internal use */ 262165782Sticso val |= 1 << 9; /* internal use */ 263165782Sticso val |= 1 << 7; /* internal use */ 264165782Sticso val |= 1 << 6; /* internal use */ 265165782Sticso val |= 0x12 << 0; /* VLAN B membership */ 266165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 24, val); 267165782Sticso 268165782Sticso /* Port 1 Control Register 2 and VLAN B */ 269165782Sticso val = 0; 270165782Sticso val |= 1 << 15; /* internal use */ 271165782Sticso val |= 1 << 14; /* internal use */ 272165782Sticso val |= 1 << 13; /* internal use */ 273165782Sticso val |= 1 << 12; /* internal use */ 274165782Sticso val |= 0x101 << 0; /* VLAN B ID */ 275165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 1, 25, val); 276165782Sticso 277165782Sticso /* Port 2 Control Register 1 and VLAN C */ 278165782Sticso val = 0; 279165782Sticso val |= 0x2 << 12; /* Port 2 VLAN Index */ 280165782Sticso val |= 1 << 11; /* internal use */ 281165782Sticso val |= 1 << 10; /* internal use */ 282165782Sticso val |= 1 << 9; /* internal use */ 283165782Sticso val |= 1 << 7; /* internal use */ 284165782Sticso val |= 1 << 6; /* internal use */ 285165782Sticso val |= 0x14 << 0; /* VLAN C membership */ 286165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 24, val); 287165782Sticso 288165782Sticso /* Port 2 Control Register 2 and VLAN C */ 289165782Sticso val = 0; 290165782Sticso val |= 1 << 15; /* internal use */ 291165782Sticso val |= 1 << 14; /* internal use */ 292165782Sticso val |= 1 << 13; /* internal use */ 293165782Sticso val |= 1 << 12; /* internal use */ 294165782Sticso val |= 0x102 << 0; /* VLAN C ID */ 295165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 2, 25, val); 296165782Sticso 297165782Sticso /* Port 3 Control Register 1 and VLAN D */ 298165782Sticso val = 0; 299165782Sticso val |= 0x3 << 12; /* Port 3 VLAN Index */ 300165782Sticso val |= 1 << 11; /* internal use */ 301165782Sticso val |= 1 << 10; /* internal use */ 302165782Sticso val |= 1 << 9; /* internal use */ 303165782Sticso val |= 1 << 7; /* internal use */ 304165782Sticso val |= 1 << 6; /* internal use */ 305165782Sticso val |= 0x18 << 0; /* VLAN D membership */ 306165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 24, val); 307165782Sticso 308165782Sticso /* Port 3 Control Register 2 and VLAN D */ 309165782Sticso val = 0; 310165782Sticso val |= 1 << 15; /* internal use */ 311165782Sticso val |= 1 << 14; /* internal use */ 312165782Sticso val |= 1 << 13; /* internal use */ 313165782Sticso val |= 1 << 12; /* internal use */ 314165782Sticso val |= 0x103 << 0; /* VLAN D ID */ 315165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 3, 25, val); 316165782Sticso 317165782Sticso /* Port 4 Control Register 1 and VLAN E */ 318165782Sticso val = 0; 319165782Sticso val |= 0x0 << 12; /* Port 4 VLAN Index */ 320165782Sticso val |= 1 << 11; /* internal use */ 321165782Sticso val |= 1 << 10; /* internal use */ 322165782Sticso val |= 1 << 9; /* internal use */ 323165782Sticso val |= 1 << 7; /* internal use */ 324165782Sticso val |= 1 << 6; /* internal use */ 325165782Sticso val |= 0 << 0; /* VLAN E membership */ 326165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 24, val); 327165782Sticso 328165782Sticso /* Port 4 Control Register 2 and VLAN E */ 329165782Sticso val = 0; 330165782Sticso val |= 1 << 15; /* internal use */ 331165782Sticso val |= 1 << 14; /* internal use */ 332165782Sticso val |= 1 << 13; /* internal use */ 333165782Sticso val |= 1 << 12; /* internal use */ 334165782Sticso val |= 0x104 << 0; /* VLAN E ID */ 335165782Sticso MIIBUS_WRITEREG(sc->mii_dev, 4, 25, val); 336165782Sticso#endif 337165782Sticso 338165782Sticso#ifdef RL_DEBUG 339165782Sticso rlswitch_phydump(dev); 340165782Sticso#endif 341165782Sticso MIIBUS_MEDIAINIT(sc->mii_dev); 342165782Sticso return (0); 343165782Sticso} 344165782Sticso 345165782Sticsostatic int 346165782Sticsorlswitch_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 347165782Sticso{ 348165782Sticso 349165782Sticso switch (cmd) { 350165782Sticso case MII_POLLSTAT: 351165782Sticso break; 352165782Sticso 353165782Sticso case MII_MEDIACHG: 354165782Sticso break; 355165782Sticso 356165782Sticso case MII_TICK: 357165782Sticso break; 358165782Sticso } 359165782Sticso 360165782Sticso /* Update the media status. */ 361221407Smarius PHY_STATUS(sc); 362165782Sticso 363165782Sticso /* Callback if something changed. */ 364165782Sticso // mii_phy_update(sc, cmd); 365165782Sticso return (0); 366165782Sticso} 367165782Sticso 368165782Sticsostatic void 369165782Sticsorlswitch_status(struct mii_softc *phy) 370165782Sticso{ 371165782Sticso struct mii_data *mii = phy->mii_pdata; 372165782Sticso 373165782Sticso mii->mii_media_status = IFM_AVALID; 374165782Sticso mii->mii_media_active = IFM_ETHER; 375165782Sticso mii->mii_media_status |= IFM_ACTIVE; 376221407Smarius mii->mii_media_active |= 377221407Smarius IFM_100_TX | IFM_FDX | mii_phy_flowstatus(phy); 378165782Sticso} 379165782Sticso 380165782Sticso#ifdef RL_DEBUG 381165782Sticsostatic void 382165782Sticsorlswitch_phydump(device_t dev) { 383165782Sticso int phy, reg, val; 384165782Sticso struct mii_softc *sc; 385165782Sticso 386165782Sticso sc = device_get_softc(dev); 387165782Sticso device_printf(dev, "rlswitchphydump\n"); 388165782Sticso for (phy = 0; phy <= 5; phy++) { 389165782Sticso printf("PHY%i:", phy); 390165782Sticso for (reg = 0; reg <= 31; reg++) { 391165782Sticso val = MIIBUS_READREG(sc->mii_dev, phy, reg); 392165782Sticso printf(" 0x%x", val); 393165782Sticso } 394165782Sticso printf("\n"); 395165782Sticso } 396165782Sticso} 397165782Sticso#endif 398