1256752Sbrooks/*- 2256752Sbrooks * Copyright (c) 2012,2013 Bjoern A. Zeeb 3256752Sbrooks * All rights reserved. 4256752Sbrooks * 5256752Sbrooks * This software was developed by SRI International and the University of 6256752Sbrooks * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249) 7256752Sbrooks * ("MRC2"), as part of the DARPA MRC research programme. 8256752Sbrooks * 9256752Sbrooks * Redistribution and use in source and binary forms, with or without 10256752Sbrooks * modification, are permitted provided that the following conditions 11256752Sbrooks * are met: 12256752Sbrooks * 1. Redistributions of source code must retain the above copyright 13256752Sbrooks * notice, this list of conditions and the following disclaimer. 14256752Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 15256752Sbrooks * notice, this list of conditions and the following disclaimer in the 16256752Sbrooks * documentation and/or other materials provided with the distribution. 17256752Sbrooks * 18256752Sbrooks * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19256752Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20256752Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21256752Sbrooks * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22256752Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23256752Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24256752Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25256752Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26256752Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27256752Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28256752Sbrooks * SUCH DAMAGE. 29256752Sbrooks */ 30256752Sbrooks 31256752Sbrooks#include <sys/cdefs.h> 32256752Sbrooks__FBSDID("$FreeBSD$"); 33256752Sbrooks 34256752Sbrooks#include "opt_device_polling.h" 35256752Sbrooks 36256752Sbrooks#include <sys/param.h> 37256752Sbrooks#include <sys/kernel.h> 38256752Sbrooks#include <sys/bus.h> 39256752Sbrooks#include <sys/module.h> 40256752Sbrooks#include <sys/rman.h> 41256752Sbrooks#include <sys/socket.h> 42256752Sbrooks#include <sys/types.h> 43256752Sbrooks 44256752Sbrooks#include <machine/bus.h> 45256752Sbrooks#include <machine/resource.h> 46256752Sbrooks 47256752Sbrooks#include <net/ethernet.h> 48256752Sbrooks#include <net/if.h> 49256752Sbrooks#include <net/if_media.h> 50256752Sbrooks 51256752Sbrooks#include <dev/mii/mii.h> 52256752Sbrooks#include <dev/mii/miivar.h> 53256752Sbrooks 54256752Sbrooks#include <dev/altera/atse/if_atsereg.h> 55256752Sbrooks 56256752Sbrooks/* "device miibus" required. See GENERIC if you get errors here. */ 57256752Sbrooks#include "miibus_if.h" 58256752Sbrooks 59256752SbrooksMODULE_DEPEND(atse, ether, 1, 1, 1); 60256752SbrooksMODULE_DEPEND(atse, miibus, 1, 1, 1); 61256752Sbrooks 62256752Sbrooks/* 63256752Sbrooks * Device routines for interacting with nexus (probe, attach, detach) & helpers. 64256752Sbrooks * XXX We should add suspend/resume later. 65256752Sbrooks */ 66256752Sbrooksstatic int 67256752Sbrooksatse_resource_int(device_t dev, const char *resname, int *v) 68256752Sbrooks{ 69256752Sbrooks int error; 70256752Sbrooks 71256752Sbrooks error = resource_int_value(device_get_name(dev), device_get_unit(dev), 72256752Sbrooks resname, v); 73256752Sbrooks if (error != 0) { 74256752Sbrooks /* If it does not exist, we fail, so not ingoring ENOENT. */ 75256752Sbrooks device_printf(dev, "could not fetch '%s' hint\n", resname); 76256752Sbrooks return (error); 77256752Sbrooks } 78256752Sbrooks 79256752Sbrooks return (0); 80256752Sbrooks} 81256752Sbrooks 82256752Sbrooksstatic int 83256752Sbrooksatse_resource_long(device_t dev, const char *resname, long *v) 84256752Sbrooks{ 85256752Sbrooks int error; 86256752Sbrooks 87256752Sbrooks error = resource_long_value(device_get_name(dev), device_get_unit(dev), 88256752Sbrooks resname, v); 89256752Sbrooks if (error != 0) { 90256752Sbrooks /* If it does not exist, we fail, so not ingoring ENOENT. */ 91256752Sbrooks device_printf(dev, "could not fetch '%s' hint\n", resname); 92256752Sbrooks return (error); 93256752Sbrooks } 94256752Sbrooks 95256752Sbrooks return (0); 96256752Sbrooks} 97256752Sbrooks 98256752Sbrooksstatic int 99256752Sbrooksatse_probe_nexus(device_t dev) 100256752Sbrooks{ 101256752Sbrooks struct resource *res; 102256752Sbrooks long l; 103256752Sbrooks int error, rid; 104256752Sbrooks 105256752Sbrooks /* 106256752Sbrooks * It is almost impossible to properly probe this device. We must 107256752Sbrooks * rely on hints being set correctly. So try to get hints and 108256752Sbrooks * one memory mapping. Must cleanup and do again in attach but 109256752Sbrooks * should not probe successfully if not able to attach later. 110256752Sbrooks */ 111256752Sbrooks error = atse_resource_int(dev, "rx_irq", &rid); 112256752Sbrooks error += atse_resource_long(dev, "rx_maddr", &l); 113256752Sbrooks error += atse_resource_long(dev, "rx_msize", &l); 114256752Sbrooks error += atse_resource_long(dev, "rxc_maddr", &l); 115256752Sbrooks error += atse_resource_long(dev, "rxc_msize", &l); 116256752Sbrooks error += atse_resource_int(dev, "tx_irq", &rid); 117256752Sbrooks error += atse_resource_long(dev, "tx_maddr", &l); 118256752Sbrooks error += atse_resource_long(dev, "tx_msize", &l); 119256752Sbrooks error += atse_resource_long(dev, "txc_maddr", &l); 120256752Sbrooks error += atse_resource_long(dev, "txc_msize", &l); 121256752Sbrooks if (error != 0) 122256752Sbrooks return (ENXIO); 123256752Sbrooks 124256752Sbrooks rid = 0; 125256752Sbrooks res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 126256752Sbrooks if (res == NULL) 127256752Sbrooks return (ENXIO); 128256752Sbrooks bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 129256752Sbrooks 130256752Sbrooks /* Success. */ 131256752Sbrooks device_set_desc(dev, "Altera Triple-Speed Ethernet MegaCore"); 132256752Sbrooks return (BUS_PROBE_DEFAULT); 133256752Sbrooks} 134256752Sbrooks 135256752Sbrooksstatic int 136256752Sbrooksatse_attach_nexus(device_t dev) 137256752Sbrooks{ 138256752Sbrooks struct atse_softc *sc; 139256752Sbrooks int error; 140256752Sbrooks 141256752Sbrooks sc = device_get_softc(dev); 142256752Sbrooks sc->atse_dev = dev; 143256752Sbrooks sc->atse_unit = device_get_unit(dev); 144256752Sbrooks 145256752Sbrooks /* Get RX and TX IRQ and FIFO information from hints. */ 146256752Sbrooks error = atse_resource_int(dev, "rx_irq", &sc->atse_rx_irq); 147256752Sbrooks error += atse_resource_long(dev, "rx_maddr", &sc->atse_rx_maddr); 148256752Sbrooks error += atse_resource_long(dev, "rx_msize", &sc->atse_rx_msize); 149256752Sbrooks error += atse_resource_long(dev, "rxc_maddr", &sc->atse_rxc_maddr); 150256752Sbrooks error += atse_resource_long(dev, "rxc_msize", &sc->atse_rxc_msize); 151256752Sbrooks error += atse_resource_int(dev, "tx_irq", &sc->atse_tx_irq); 152256752Sbrooks error += atse_resource_long(dev, "tx_maddr", &sc->atse_tx_maddr); 153256752Sbrooks error += atse_resource_long(dev, "tx_msize", &sc->atse_tx_msize); 154256752Sbrooks error += atse_resource_long(dev, "txc_maddr", &sc->atse_txc_maddr); 155256752Sbrooks error += atse_resource_long(dev, "txc_msize", &sc->atse_txc_msize); 156256752Sbrooks if (error != 0) 157256752Sbrooks return (error); 158256752Sbrooks 159256752Sbrooks /* Avalon-MM, atse management register region. */ 160256752Sbrooks sc->atse_mem_rid = 0; 161256752Sbrooks sc->atse_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 162256752Sbrooks &sc->atse_mem_rid, RF_ACTIVE); 163256752Sbrooks if (sc->atse_mem_res == NULL) { 164256752Sbrooks device_printf(dev, "failed to map memory for ctrl region\n"); 165256752Sbrooks return (ENXIO); 166256752Sbrooks } 167256752Sbrooks 168256752Sbrooks /* 169256752Sbrooks * (Optional) RX IRQ and memory mapped regions. 170256752Sbrooks * 0x00: 2 * 32bit FIFO data, 171256752Sbrooks * 0x20: 8 * 32bit FIFO ctrl, Avalon-ST Sink to Avalon-MM R-Slave. 172256752Sbrooks */ 173256752Sbrooks sc->atse_rx_irq_rid = 0; 174256752Sbrooks sc->atse_rx_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, 175256752Sbrooks &sc->atse_rx_irq_rid, sc->atse_rx_irq, sc->atse_rx_irq, 1, 176256752Sbrooks RF_ACTIVE | RF_SHAREABLE); 177256752Sbrooks 178256752Sbrooks sc->atse_rx_mem_rid = 0; 179256752Sbrooks sc->atse_rx_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 180256752Sbrooks &sc->atse_rx_mem_rid, sc->atse_rx_maddr, sc->atse_rx_maddr + 181256752Sbrooks sc->atse_rx_msize, sc->atse_rx_msize, RF_ACTIVE); 182256752Sbrooks if (sc->atse_rx_mem_res == NULL) { 183256752Sbrooks device_printf(dev, "failed to map memory for RX\n"); 184256752Sbrooks goto err; 185256752Sbrooks } 186256752Sbrooks sc->atse_rxc_mem_rid = 0; 187256752Sbrooks sc->atse_rxc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 188256752Sbrooks &sc->atse_rxc_mem_rid, sc->atse_rxc_maddr, sc->atse_rxc_maddr + 189256752Sbrooks sc->atse_rxc_msize, sc->atse_rxc_msize, RF_ACTIVE); 190256752Sbrooks if (sc->atse_rxc_mem_res == NULL) { 191256752Sbrooks device_printf(dev, "failed to map memory for RX control\n"); 192256752Sbrooks goto err; 193256752Sbrooks } 194256752Sbrooks 195256752Sbrooks /* 196256752Sbrooks * (Optional) TX IRQ and memory mapped regions. 197256752Sbrooks * 0x00: 2 * 32bit FIFO data, 198256752Sbrooks * 0x20: 8 * 32bit FIFO ctrl, Avalon-MM W-Slave to Avalon-ST Source. 199256752Sbrooks */ 200256752Sbrooks sc->atse_tx_irq_rid = 0; 201256752Sbrooks sc->atse_tx_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, 202256752Sbrooks &sc->atse_tx_irq_rid, sc->atse_tx_irq, sc->atse_tx_irq, 1, 203256752Sbrooks RF_ACTIVE | RF_SHAREABLE); 204256752Sbrooks 205256752Sbrooks sc->atse_tx_mem_rid = 0; 206256752Sbrooks sc->atse_tx_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 207256752Sbrooks &sc->atse_tx_mem_rid, sc->atse_tx_maddr, sc->atse_tx_maddr + 208256752Sbrooks sc->atse_tx_msize, sc->atse_tx_msize, RF_ACTIVE); 209256752Sbrooks if (sc->atse_tx_mem_res == NULL) { 210256752Sbrooks device_printf(dev, "failed to map memory for TX\n"); 211256752Sbrooks goto err; 212256752Sbrooks } 213256752Sbrooks sc->atse_txc_mem_rid = 0; 214256752Sbrooks sc->atse_txc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 215256752Sbrooks &sc->atse_txc_mem_rid, sc->atse_txc_maddr, sc->atse_txc_maddr + 216256752Sbrooks sc->atse_txc_msize, sc->atse_txc_msize, RF_ACTIVE); 217256752Sbrooks if (sc->atse_txc_mem_res == NULL) { 218256752Sbrooks device_printf(dev, "failed to map memory for TX control\n"); 219256752Sbrooks goto err; 220256752Sbrooks } 221256752Sbrooks 222256752Sbrooks error = atse_attach(dev); 223256752Sbrooks if (error) 224256752Sbrooks goto err; 225256752Sbrooks 226256752Sbrooks return (0); 227256752Sbrooks 228256752Sbrookserr: 229256752Sbrooks /* Cleanup. */ 230256752Sbrooks atse_detach_resources(dev); 231256752Sbrooks 232256752Sbrooks return (error); 233256752Sbrooks} 234256752Sbrooks 235256752Sbrooksstatic device_method_t atse_methods_nexus[] = { 236256752Sbrooks /* Device interface */ 237256752Sbrooks DEVMETHOD(device_probe, atse_probe_nexus), 238256752Sbrooks DEVMETHOD(device_attach, atse_attach_nexus), 239256752Sbrooks DEVMETHOD(device_detach, atse_detach_dev), 240256752Sbrooks 241256752Sbrooks /* MII interface */ 242256752Sbrooks DEVMETHOD(miibus_readreg, atse_miibus_readreg), 243256752Sbrooks DEVMETHOD(miibus_writereg, atse_miibus_writereg), 244256752Sbrooks DEVMETHOD(miibus_statchg, atse_miibus_statchg), 245256752Sbrooks 246256752Sbrooks DEVMETHOD_END 247256752Sbrooks}; 248256752Sbrooks 249256752Sbrooksstatic driver_t atse_driver_nexus = { 250256752Sbrooks "atse", 251256752Sbrooks atse_methods_nexus, 252256752Sbrooks sizeof(struct atse_softc) 253256752Sbrooks}; 254256752Sbrooks 255256752SbrooksDRIVER_MODULE(atse, nexus, atse_driver_nexus, atse_devclass, 0, 0); 256256752SbrooksDRIVER_MODULE(miibus, atse, miibus_driver, miibus_devclass, 0, 0); 257256752Sbrooks 258256752Sbrooks/* end */ 259