1*a043e8c7SAdrian Chadd /*- 2*a043e8c7SAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 3*a043e8c7SAdrian Chadd * Copyright (c) 2012 Adrian Chadd. 4*a043e8c7SAdrian Chadd * All rights reserved. 5*a043e8c7SAdrian Chadd * 6*a043e8c7SAdrian Chadd * Redistribution and use in source and binary forms, with or without 7*a043e8c7SAdrian Chadd * modification, are permitted provided that the following conditions 8*a043e8c7SAdrian Chadd * are met: 9*a043e8c7SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 10*a043e8c7SAdrian Chadd * notice, this list of conditions and the following disclaimer. 11*a043e8c7SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 12*a043e8c7SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 13*a043e8c7SAdrian Chadd * documentation and/or other materials provided with the distribution. 14*a043e8c7SAdrian Chadd * 15*a043e8c7SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*a043e8c7SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*a043e8c7SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*a043e8c7SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*a043e8c7SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*a043e8c7SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*a043e8c7SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*a043e8c7SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*a043e8c7SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*a043e8c7SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*a043e8c7SAdrian Chadd * SUCH DAMAGE. 26*a043e8c7SAdrian Chadd * 27*a043e8c7SAdrian Chadd * $FreeBSD$ 28*a043e8c7SAdrian Chadd */ 29*a043e8c7SAdrian Chadd 30*a043e8c7SAdrian Chadd #include <sys/param.h> 31*a043e8c7SAdrian Chadd #include <sys/bus.h> 32*a043e8c7SAdrian Chadd #include <sys/errno.h> 33*a043e8c7SAdrian Chadd #include <sys/kernel.h> 34*a043e8c7SAdrian Chadd #include <sys/module.h> 35*a043e8c7SAdrian Chadd #include <sys/socket.h> 36*a043e8c7SAdrian Chadd #include <sys/sockio.h> 37*a043e8c7SAdrian Chadd #include <sys/sysctl.h> 38*a043e8c7SAdrian Chadd #include <sys/systm.h> 39*a043e8c7SAdrian Chadd 40*a043e8c7SAdrian Chadd #include <net/if.h> 41*a043e8c7SAdrian Chadd #include <net/if_arp.h> 42*a043e8c7SAdrian Chadd #include <net/ethernet.h> 43*a043e8c7SAdrian Chadd #include <net/if_dl.h> 44*a043e8c7SAdrian Chadd #include <net/if_media.h> 45*a043e8c7SAdrian Chadd #include <net/if_types.h> 46*a043e8c7SAdrian Chadd 47*a043e8c7SAdrian Chadd #include <machine/bus.h> 48*a043e8c7SAdrian Chadd #include <dev/iicbus/iic.h> 49*a043e8c7SAdrian Chadd #include <dev/iicbus/iiconf.h> 50*a043e8c7SAdrian Chadd #include <dev/iicbus/iicbus.h> 51*a043e8c7SAdrian Chadd #include <dev/mii/mii.h> 52*a043e8c7SAdrian Chadd #include <dev/mii/miivar.h> 53*a043e8c7SAdrian Chadd #include <dev/etherswitch/mdio.h> 54*a043e8c7SAdrian Chadd 55*a043e8c7SAdrian Chadd #include <dev/etherswitch/etherswitch.h> 56*a043e8c7SAdrian Chadd 57*a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchreg.h> 58*a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchvar.h> 59*a043e8c7SAdrian Chadd 60*a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_reg.h> 61*a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_phy.h> 62*a043e8c7SAdrian Chadd 63*a043e8c7SAdrian Chadd #include "mdio_if.h" 64*a043e8c7SAdrian Chadd #include "miibus_if.h" 65*a043e8c7SAdrian Chadd #include "etherswitch_if.h" 66*a043e8c7SAdrian Chadd 67*a043e8c7SAdrian Chadd #if defined(DEBUG) 68*a043e8c7SAdrian Chadd static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch"); 69*a043e8c7SAdrian Chadd #endif 70*a043e8c7SAdrian Chadd 71*a043e8c7SAdrian Chadd /* 72*a043e8c7SAdrian Chadd * access PHYs integrated into the switch chip through the switch's MDIO 73*a043e8c7SAdrian Chadd * control register. 74*a043e8c7SAdrian Chadd */ 75*a043e8c7SAdrian Chadd int 76*a043e8c7SAdrian Chadd arswitch_readphy(device_t dev, int phy, int reg) 77*a043e8c7SAdrian Chadd { 78*a043e8c7SAdrian Chadd uint32_t data = 0, ctrl; 79*a043e8c7SAdrian Chadd int err, timeout; 80*a043e8c7SAdrian Chadd 81*a043e8c7SAdrian Chadd if (phy < 0 || phy >= 32) 82*a043e8c7SAdrian Chadd return (ENXIO); 83*a043e8c7SAdrian Chadd if (reg < 0 || reg >= 32) 84*a043e8c7SAdrian Chadd return (ENXIO); 85*a043e8c7SAdrian Chadd err = arswitch_writereg_msb(dev, AR8X16_REG_MDIO_CTRL, 86*a043e8c7SAdrian Chadd AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN | 87*a043e8c7SAdrian Chadd AR8X16_MDIO_CTRL_CMD_READ | 88*a043e8c7SAdrian Chadd (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) | 89*a043e8c7SAdrian Chadd (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT)); 90*a043e8c7SAdrian Chadd DEVERR(dev, err, "arswitch_readphy()=%d: phy=%d.%02x\n", phy, reg); 91*a043e8c7SAdrian Chadd if (err != 0) 92*a043e8c7SAdrian Chadd return (-1); 93*a043e8c7SAdrian Chadd for (timeout = 100; timeout--; ) { 94*a043e8c7SAdrian Chadd ctrl = arswitch_readreg_msb(dev, AR8X16_REG_MDIO_CTRL); 95*a043e8c7SAdrian Chadd if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) 96*a043e8c7SAdrian Chadd break; 97*a043e8c7SAdrian Chadd } 98*a043e8c7SAdrian Chadd if (timeout < 0) 99*a043e8c7SAdrian Chadd err = EIO; 100*a043e8c7SAdrian Chadd data = arswitch_readreg_lsb(dev, AR8X16_REG_MDIO_CTRL) & 101*a043e8c7SAdrian Chadd AR8X16_MDIO_CTRL_DATA_MASK; 102*a043e8c7SAdrian Chadd return (data); 103*a043e8c7SAdrian Chadd } 104*a043e8c7SAdrian Chadd 105*a043e8c7SAdrian Chadd int 106*a043e8c7SAdrian Chadd arswitch_writephy(device_t dev, int phy, int reg, int data) 107*a043e8c7SAdrian Chadd { 108*a043e8c7SAdrian Chadd uint32_t ctrl; 109*a043e8c7SAdrian Chadd int err, timeout; 110*a043e8c7SAdrian Chadd 111*a043e8c7SAdrian Chadd if (reg < 0 || reg >= 32) 112*a043e8c7SAdrian Chadd return (ENXIO); 113*a043e8c7SAdrian Chadd err = arswitch_writereg_lsb(dev, AR8X16_REG_MDIO_CTRL, 114*a043e8c7SAdrian Chadd (data & AR8X16_MDIO_CTRL_DATA_MASK)); 115*a043e8c7SAdrian Chadd DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); 116*a043e8c7SAdrian Chadd if (err != 0) 117*a043e8c7SAdrian Chadd return (err); 118*a043e8c7SAdrian Chadd err = arswitch_writereg_msb(dev, AR8X16_REG_MDIO_CTRL, 119*a043e8c7SAdrian Chadd AR8X16_MDIO_CTRL_BUSY | 120*a043e8c7SAdrian Chadd AR8X16_MDIO_CTRL_MASTER_EN | 121*a043e8c7SAdrian Chadd AR8X16_MDIO_CTRL_CMD_WRITE | 122*a043e8c7SAdrian Chadd (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) | 123*a043e8c7SAdrian Chadd (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT)); 124*a043e8c7SAdrian Chadd DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); 125*a043e8c7SAdrian Chadd if (err != 0) 126*a043e8c7SAdrian Chadd return (err); 127*a043e8c7SAdrian Chadd for (timeout = 100; timeout--; ) { 128*a043e8c7SAdrian Chadd ctrl = arswitch_readreg(dev, AR8X16_REG_MDIO_CTRL); 129*a043e8c7SAdrian Chadd if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) 130*a043e8c7SAdrian Chadd break; 131*a043e8c7SAdrian Chadd } 132*a043e8c7SAdrian Chadd if (timeout < 0) 133*a043e8c7SAdrian Chadd err = EIO; 134*a043e8c7SAdrian Chadd DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); 135*a043e8c7SAdrian Chadd return (err); 136*a043e8c7SAdrian Chadd } 137