1a043e8c7SAdrian Chadd /*- 2a043e8c7SAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 3a043e8c7SAdrian Chadd * All rights reserved. 4a043e8c7SAdrian Chadd * 5a043e8c7SAdrian Chadd * Redistribution and use in source and binary forms, with or without 6a043e8c7SAdrian Chadd * modification, are permitted provided that the following conditions 7a043e8c7SAdrian Chadd * are met: 8a043e8c7SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 9a043e8c7SAdrian Chadd * notice, this list of conditions and the following disclaimer. 10a043e8c7SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 11a043e8c7SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 12a043e8c7SAdrian Chadd * documentation and/or other materials provided with the distribution. 13a043e8c7SAdrian Chadd * 14a043e8c7SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a043e8c7SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a043e8c7SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a043e8c7SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a043e8c7SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a043e8c7SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a043e8c7SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a043e8c7SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a043e8c7SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a043e8c7SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a043e8c7SAdrian Chadd * SUCH DAMAGE. 25a043e8c7SAdrian Chadd * 26a043e8c7SAdrian Chadd * $FreeBSD$ 27a043e8c7SAdrian Chadd */ 28a043e8c7SAdrian Chadd 29a043e8c7SAdrian Chadd #include <sys/param.h> 30a043e8c7SAdrian Chadd #include <sys/bus.h> 31a043e8c7SAdrian Chadd #include <sys/errno.h> 32a043e8c7SAdrian Chadd #include <sys/kernel.h> 33a043e8c7SAdrian Chadd #include <sys/module.h> 34a043e8c7SAdrian Chadd #include <sys/socket.h> 35a043e8c7SAdrian Chadd #include <sys/sockio.h> 36a043e8c7SAdrian Chadd #include <sys/sysctl.h> 37a043e8c7SAdrian Chadd #include <sys/systm.h> 38a043e8c7SAdrian Chadd 39a043e8c7SAdrian Chadd #include <net/if.h> 40a043e8c7SAdrian Chadd #include <net/if_arp.h> 41a043e8c7SAdrian Chadd #include <net/ethernet.h> 42a043e8c7SAdrian Chadd #include <net/if_dl.h> 43a043e8c7SAdrian Chadd #include <net/if_media.h> 44a043e8c7SAdrian Chadd #include <net/if_types.h> 45a043e8c7SAdrian Chadd 46a043e8c7SAdrian Chadd #include <machine/bus.h> 47a043e8c7SAdrian Chadd #include <dev/iicbus/iic.h> 48a043e8c7SAdrian Chadd #include <dev/iicbus/iiconf.h> 49a043e8c7SAdrian Chadd #include <dev/iicbus/iicbus.h> 50a043e8c7SAdrian Chadd #include <dev/mii/mii.h> 51a043e8c7SAdrian Chadd #include <dev/mii/miivar.h> 52a043e8c7SAdrian Chadd #include <dev/etherswitch/mdio.h> 53a043e8c7SAdrian Chadd 54a043e8c7SAdrian Chadd #include <dev/etherswitch/etherswitch.h> 55a043e8c7SAdrian Chadd 56a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchreg.h> 57a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchvar.h> 58a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_reg.h> 59a043e8c7SAdrian Chadd 60a043e8c7SAdrian Chadd #include "mdio_if.h" 61a043e8c7SAdrian Chadd #include "miibus_if.h" 62a043e8c7SAdrian Chadd #include "etherswitch_if.h" 63a043e8c7SAdrian Chadd 64a043e8c7SAdrian Chadd static inline void 65a043e8c7SAdrian Chadd arswitch_split_setpage(device_t dev, uint32_t addr, uint16_t *phy, 66a043e8c7SAdrian Chadd uint16_t *reg) 67a043e8c7SAdrian Chadd { 68a043e8c7SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 69a043e8c7SAdrian Chadd uint16_t page; 70a043e8c7SAdrian Chadd 71a043e8c7SAdrian Chadd page = ((addr) >> 9) & 0xffff; 72a043e8c7SAdrian Chadd *phy = (((addr) >> 6) & 0x07) | 0x10; 73a043e8c7SAdrian Chadd *reg = ((addr) >> 1) & 0x1f; 74a043e8c7SAdrian Chadd 75a043e8c7SAdrian Chadd if (sc->page != page) { 76a043e8c7SAdrian Chadd MDIO_WRITEREG(device_get_parent(dev), 0x18, 0, page); 77a043e8c7SAdrian Chadd sc->page = page; 78a043e8c7SAdrian Chadd } 79a043e8c7SAdrian Chadd } 80a043e8c7SAdrian Chadd 81a043e8c7SAdrian Chadd /* 82a043e8c7SAdrian Chadd * Read half a register. Some of the registers define control bits, and 83a043e8c7SAdrian Chadd * the sequence of half-word accesses matters. The register addresses 84a043e8c7SAdrian Chadd * are word-even (mod 4). 85a043e8c7SAdrian Chadd */ 86a043e8c7SAdrian Chadd static inline int 87a043e8c7SAdrian Chadd arswitch_readreg16(device_t dev, int addr) 88a043e8c7SAdrian Chadd { 89a043e8c7SAdrian Chadd uint16_t phy, reg; 90a043e8c7SAdrian Chadd 91a043e8c7SAdrian Chadd arswitch_split_setpage(dev, addr, &phy, ®); 92a043e8c7SAdrian Chadd return (MDIO_READREG(device_get_parent(dev), phy, reg)); 93a043e8c7SAdrian Chadd } 94a043e8c7SAdrian Chadd 95a043e8c7SAdrian Chadd /* 96a043e8c7SAdrian Chadd * XXX NOTE: 97a043e8c7SAdrian Chadd * 98a043e8c7SAdrian Chadd * This may not work for AR7240 series embedded switches - 99a043e8c7SAdrian Chadd * the per-PHY register space doesn't seem to be exposed. 100a043e8c7SAdrian Chadd * 101a043e8c7SAdrian Chadd * In that instance, it may be required to speak via 102a043e8c7SAdrian Chadd * the internal switch PHY MDIO bus indirection. 103a043e8c7SAdrian Chadd */ 104a043e8c7SAdrian Chadd void 105a043e8c7SAdrian Chadd arswitch_writedbg(device_t dev, int phy, uint16_t dbg_addr, 106a043e8c7SAdrian Chadd uint16_t dbg_data) 107a043e8c7SAdrian Chadd { 108a043e8c7SAdrian Chadd (void) MDIO_WRITEREG(device_get_parent(dev), phy, 109a043e8c7SAdrian Chadd MII_ATH_DBG_ADDR, dbg_addr); 110a043e8c7SAdrian Chadd (void) MDIO_WRITEREG(device_get_parent(dev), phy, 111a043e8c7SAdrian Chadd MII_ATH_DBG_DATA, dbg_data); 112a043e8c7SAdrian Chadd } 113a043e8c7SAdrian Chadd 114a043e8c7SAdrian Chadd /* 115a043e8c7SAdrian Chadd * Write half a register 116a043e8c7SAdrian Chadd */ 117a043e8c7SAdrian Chadd static inline int 118a043e8c7SAdrian Chadd arswitch_writereg16(device_t dev, int addr, int data) 119a043e8c7SAdrian Chadd { 120a043e8c7SAdrian Chadd uint16_t phy, reg; 121a043e8c7SAdrian Chadd 122a043e8c7SAdrian Chadd arswitch_split_setpage(dev, addr, &phy, ®); 123a043e8c7SAdrian Chadd return (MDIO_WRITEREG(device_get_parent(dev), phy, reg, data)); 124a043e8c7SAdrian Chadd } 125a043e8c7SAdrian Chadd 126a043e8c7SAdrian Chadd int 127a043e8c7SAdrian Chadd arswitch_readreg_lsb(device_t dev, int addr) 128a043e8c7SAdrian Chadd { 129a043e8c7SAdrian Chadd 130a043e8c7SAdrian Chadd return (arswitch_readreg16(dev, addr)); 131a043e8c7SAdrian Chadd } 132a043e8c7SAdrian Chadd 133a043e8c7SAdrian Chadd int 134a043e8c7SAdrian Chadd arswitch_readreg_msb(device_t dev, int addr) 135a043e8c7SAdrian Chadd { 136a043e8c7SAdrian Chadd 137a043e8c7SAdrian Chadd return (arswitch_readreg16(dev, addr + 2) << 16); 138a043e8c7SAdrian Chadd } 139a043e8c7SAdrian Chadd 140a043e8c7SAdrian Chadd int 141a043e8c7SAdrian Chadd arswitch_writereg_lsb(device_t dev, int addr, int data) 142a043e8c7SAdrian Chadd { 143a043e8c7SAdrian Chadd 144a043e8c7SAdrian Chadd return (arswitch_writereg16(dev, addr, data & 0xffff)); 145a043e8c7SAdrian Chadd } 146a043e8c7SAdrian Chadd 147a043e8c7SAdrian Chadd int 148a043e8c7SAdrian Chadd arswitch_writereg_msb(device_t dev, int addr, int data) 149a043e8c7SAdrian Chadd { 150a043e8c7SAdrian Chadd 151*26aff2abSAleksandr Rybalko return (arswitch_writereg16(dev, addr + 2, (data >> 16) & 0xffff)); 152a043e8c7SAdrian Chadd } 153a043e8c7SAdrian Chadd 154a043e8c7SAdrian Chadd int 155a043e8c7SAdrian Chadd arswitch_readreg(device_t dev, int addr) 156a043e8c7SAdrian Chadd { 157a043e8c7SAdrian Chadd 158a043e8c7SAdrian Chadd return (arswitch_readreg_lsb(dev, addr) | 159a043e8c7SAdrian Chadd arswitch_readreg_msb(dev, addr)); 160a043e8c7SAdrian Chadd } 161a043e8c7SAdrian Chadd 162a043e8c7SAdrian Chadd int 163a043e8c7SAdrian Chadd arswitch_writereg(device_t dev, int addr, int value) 164a043e8c7SAdrian Chadd { 165a043e8c7SAdrian Chadd 166a043e8c7SAdrian Chadd /* XXX Check the first write too? */ 167a043e8c7SAdrian Chadd arswitch_writereg_lsb(dev, addr, value); 168a043e8c7SAdrian Chadd return (arswitch_writereg_msb(dev, addr, value)); 169a043e8c7SAdrian Chadd } 170a043e8c7SAdrian Chadd 171a043e8c7SAdrian Chadd int 172a043e8c7SAdrian Chadd arswitch_modifyreg(device_t dev, int addr, int mask, int set) 173a043e8c7SAdrian Chadd { 174a043e8c7SAdrian Chadd int value; 175a043e8c7SAdrian Chadd 176a043e8c7SAdrian Chadd value = arswitch_readreg(dev, addr); 177a043e8c7SAdrian Chadd value &= ~mask; 178a043e8c7SAdrian Chadd value |= set; 179a043e8c7SAdrian Chadd return (arswitch_writereg(dev, addr, value)); 180a043e8c7SAdrian Chadd } 181