1235288Sadrian/*- 2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke. 3235288Sadrian * All rights reserved. 4235288Sadrian * 5235288Sadrian * Redistribution and use in source and binary forms, with or without 6235288Sadrian * modification, are permitted provided that the following conditions 7235288Sadrian * are met: 8235288Sadrian * 1. Redistributions of source code must retain the above copyright 9235288Sadrian * notice, this list of conditions and the following disclaimer. 10235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright 11235288Sadrian * notice, this list of conditions and the following disclaimer in the 12235288Sadrian * documentation and/or other materials provided with the distribution. 13235288Sadrian * 14235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235288Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235288Sadrian * SUCH DAMAGE. 25235288Sadrian * 26235288Sadrian * $FreeBSD: releng/11.0/sys/dev/etherswitch/arswitch/arswitch_reg.c 292738 2015-12-26 02:31:39Z adrian $ 27235288Sadrian */ 28235288Sadrian 29235288Sadrian#include <sys/param.h> 30235288Sadrian#include <sys/bus.h> 31235288Sadrian#include <sys/errno.h> 32235288Sadrian#include <sys/kernel.h> 33235288Sadrian#include <sys/module.h> 34235288Sadrian#include <sys/socket.h> 35235288Sadrian#include <sys/sockio.h> 36235288Sadrian#include <sys/sysctl.h> 37235288Sadrian#include <sys/systm.h> 38235288Sadrian 39235288Sadrian#include <net/if.h> 40235288Sadrian#include <net/if_arp.h> 41235288Sadrian#include <net/ethernet.h> 42235288Sadrian#include <net/if_dl.h> 43235288Sadrian#include <net/if_media.h> 44235288Sadrian#include <net/if_types.h> 45235288Sadrian 46235288Sadrian#include <machine/bus.h> 47268564Srpaulo#include <dev/iicbus/iic.h> 48235288Sadrian#include <dev/iicbus/iiconf.h> 49235288Sadrian#include <dev/iicbus/iicbus.h> 50235288Sadrian#include <dev/mii/mii.h> 51235288Sadrian#include <dev/mii/miivar.h> 52292738Sadrian#include <dev/mdio/mdio.h> 53235288Sadrian 54235288Sadrian#include <dev/etherswitch/etherswitch.h> 55235288Sadrian 56235288Sadrian#include <dev/etherswitch/arswitch/arswitchreg.h> 57235288Sadrian#include <dev/etherswitch/arswitch/arswitchvar.h> 58235288Sadrian#include <dev/etherswitch/arswitch/arswitch_reg.h> 59235288Sadrian 60235288Sadrian#include "mdio_if.h" 61235288Sadrian#include "miibus_if.h" 62235288Sadrian#include "etherswitch_if.h" 63235288Sadrian 64235288Sadrianstatic inline void 65235288Sadrianarswitch_split_setpage(device_t dev, uint32_t addr, uint16_t *phy, 66235288Sadrian uint16_t *reg) 67235288Sadrian{ 68235288Sadrian struct arswitch_softc *sc = device_get_softc(dev); 69235288Sadrian uint16_t page; 70235288Sadrian 71279767Sadrian page = (addr >> 9) & 0x1ff; 72279767Sadrian *phy = (addr >> 6) & 0x7; 73279767Sadrian *reg = (addr >> 1) & 0x1f; 74235288Sadrian 75253570Sloos if (sc->page != page) { 76253570Sloos MDIO_WRITEREG(device_get_parent(dev), 0x18, 0, page); 77279767Sadrian DELAY(2000); 78253570Sloos sc->page = page; 79253570Sloos } 80235288Sadrian} 81235288Sadrian 82235288Sadrian/* 83235288Sadrian * Read half a register. Some of the registers define control bits, and 84235288Sadrian * the sequence of half-word accesses matters. The register addresses 85235288Sadrian * are word-even (mod 4). 86235288Sadrian */ 87235288Sadrianstatic inline int 88235288Sadrianarswitch_readreg16(device_t dev, int addr) 89235288Sadrian{ 90235288Sadrian uint16_t phy, reg; 91279767Sadrian 92235288Sadrian arswitch_split_setpage(dev, addr, &phy, ®); 93279767Sadrian return (MDIO_READREG(device_get_parent(dev), 0x10 | phy, reg)); 94235288Sadrian} 95235288Sadrian 96235288Sadrian/* 97279767Sadrian * Write half a register. See above! 98279767Sadrian */ 99279767Sadrianstatic inline int 100279767Sadrianarswitch_writereg16(device_t dev, int addr, int data) 101279767Sadrian{ 102279767Sadrian uint16_t phy, reg; 103279767Sadrian 104279767Sadrian arswitch_split_setpage(dev, addr, &phy, ®); 105279767Sadrian return (MDIO_WRITEREG(device_get_parent(dev), 0x10 | phy, reg, data)); 106279767Sadrian} 107279767Sadrian 108279767Sadrian/* 109235288Sadrian * XXX NOTE: 110235288Sadrian * 111235288Sadrian * This may not work for AR7240 series embedded switches - 112235288Sadrian * the per-PHY register space doesn't seem to be exposed. 113235288Sadrian * 114235288Sadrian * In that instance, it may be required to speak via 115235288Sadrian * the internal switch PHY MDIO bus indirection. 116235288Sadrian */ 117235288Sadrianvoid 118235288Sadrianarswitch_writedbg(device_t dev, int phy, uint16_t dbg_addr, 119235288Sadrian uint16_t dbg_data) 120235288Sadrian{ 121235288Sadrian (void) MDIO_WRITEREG(device_get_parent(dev), phy, 122235288Sadrian MII_ATH_DBG_ADDR, dbg_addr); 123235288Sadrian (void) MDIO_WRITEREG(device_get_parent(dev), phy, 124235288Sadrian MII_ATH_DBG_DATA, dbg_data); 125235288Sadrian} 126235288Sadrian 127262010Sadrianvoid 128262010Sadrianarswitch_writemmd(device_t dev, int phy, uint16_t dbg_addr, 129262010Sadrian uint16_t dbg_data) 130262010Sadrian{ 131262010Sadrian (void) MDIO_WRITEREG(device_get_parent(dev), phy, 132262010Sadrian MII_ATH_MMD_ADDR, dbg_addr); 133262010Sadrian (void) MDIO_WRITEREG(device_get_parent(dev), phy, 134262010Sadrian MII_ATH_MMD_DATA, dbg_data); 135262010Sadrian} 136262010Sadrian 137279767Sadrianstatic uint32_t 138279767Sadrianarswitch_reg_read32(device_t dev, int phy, int reg) 139235288Sadrian{ 140279767Sadrian uint16_t lo, hi; 141279767Sadrian lo = MDIO_READREG(device_get_parent(dev), phy, reg); 142279767Sadrian hi = MDIO_READREG(device_get_parent(dev), phy, reg + 1); 143279767Sadrian 144279767Sadrian return (hi << 16) | lo; 145235288Sadrian} 146235288Sadrian 147279767Sadrianstatic int 148279767Sadrianarswitch_reg_write32(device_t dev, int phy, int reg, uint32_t value) 149235288Sadrian{ 150279767Sadrian struct arswitch_softc *sc; 151279767Sadrian int r; 152279767Sadrian uint16_t lo, hi; 153235288Sadrian 154279767Sadrian sc = device_get_softc(dev); 155279767Sadrian lo = value & 0xffff; 156279767Sadrian hi = (uint16_t) (value >> 16); 157279767Sadrian 158279767Sadrian if (sc->mii_lo_first) { 159279767Sadrian r = MDIO_WRITEREG(device_get_parent(dev), 160279767Sadrian phy, reg, lo); 161279767Sadrian r |= MDIO_WRITEREG(device_get_parent(dev), 162279767Sadrian phy, reg + 1, hi); 163279767Sadrian } else { 164279767Sadrian r = MDIO_WRITEREG(device_get_parent(dev), 165279767Sadrian phy, reg + 1, hi); 166279767Sadrian r |= MDIO_WRITEREG(device_get_parent(dev), 167279767Sadrian phy, reg, lo); 168279767Sadrian } 169279767Sadrian 170279767Sadrian return r; 171235288Sadrian} 172235288Sadrian 173235288Sadrianint 174279767Sadrianarswitch_readreg(device_t dev, int addr) 175235288Sadrian{ 176279767Sadrian uint16_t phy, reg; 177235288Sadrian 178279767Sadrian arswitch_split_setpage(dev, addr, &phy, ®); 179279767Sadrian return arswitch_reg_read32(dev, 0x10 | phy, reg); 180235288Sadrian} 181235288Sadrian 182235288Sadrianint 183279767Sadrianarswitch_writereg(device_t dev, int addr, int value) 184235288Sadrian{ 185279767Sadrian struct arswitch_softc *sc; 186279767Sadrian uint16_t phy, reg; 187235288Sadrian 188279767Sadrian sc = device_get_softc(dev); 189279767Sadrian 190279767Sadrian arswitch_split_setpage(dev, addr, &phy, ®); 191279767Sadrian return (arswitch_reg_write32(dev, 0x10 | phy, reg, value)); 192235288Sadrian} 193235288Sadrian 194279767Sadrian/* 195279767Sadrian * Read/write 16 bit values in the switch register space. 196279767Sadrian * 197279767Sadrian * Some of the registers are control registers (eg the MDIO 198279767Sadrian * data versus control space) and so need to be treated 199279767Sadrian * differently. 200279767Sadrian */ 201235288Sadrianint 202279767Sadrianarswitch_readreg_lsb(device_t dev, int addr) 203235288Sadrian{ 204235288Sadrian 205279767Sadrian return (arswitch_readreg16(dev, addr)); 206235288Sadrian} 207235288Sadrian 208235288Sadrianint 209279767Sadrianarswitch_readreg_msb(device_t dev, int addr) 210235288Sadrian{ 211235288Sadrian 212279767Sadrian return (arswitch_readreg16(dev, addr + 2) << 16); 213235288Sadrian} 214235288Sadrian 215235288Sadrianint 216279767Sadrianarswitch_writereg_lsb(device_t dev, int addr, int data) 217235288Sadrian{ 218235288Sadrian 219279767Sadrian return (arswitch_writereg16(dev, addr, data & 0xffff)); 220279767Sadrian} 221262200Sadrian 222279767Sadrianint 223279767Sadrianarswitch_writereg_msb(device_t dev, int addr, int data) 224279767Sadrian{ 225262200Sadrian 226279767Sadrian return (arswitch_writereg16(dev, addr + 2, (data >> 16) & 0xffff)); 227235288Sadrian} 228235288Sadrian 229235288Sadrianint 230235288Sadrianarswitch_modifyreg(device_t dev, int addr, int mask, int set) 231235288Sadrian{ 232235288Sadrian int value; 233279767Sadrian uint16_t phy, reg; 234279767Sadrian 235279767Sadrian arswitch_split_setpage(dev, addr, &phy, ®); 236279767Sadrian 237279767Sadrian value = arswitch_reg_read32(dev, 0x10 | phy, reg); 238235288Sadrian value &= ~mask; 239235288Sadrian value |= set; 240279767Sadrian return (arswitch_reg_write32(dev, 0x10 | phy, reg, value)); 241235288Sadrian} 242253572Sloos 243253572Sloosint 244253572Sloosarswitch_waitreg(device_t dev, int addr, int mask, int val, int timeout) 245253572Sloos{ 246253572Sloos int err, v; 247279767Sadrian uint16_t phy, reg; 248253572Sloos 249279767Sadrian arswitch_split_setpage(dev, addr, &phy, ®); 250279767Sadrian 251253572Sloos err = -1; 252253572Sloos while (1) { 253279767Sadrian v = arswitch_reg_read32(dev, 0x10 | phy, reg); 254253572Sloos v &= mask; 255253572Sloos if (v == val) { 256253572Sloos err = 0; 257253572Sloos break; 258253572Sloos } 259253572Sloos if (!timeout) 260253572Sloos break; 261253572Sloos DELAY(1); 262253572Sloos timeout--; 263253572Sloos } 264253572Sloos return (err); 265253572Sloos} 266