Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110737208
D7238.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
115 KB
Referenced Files
None
Subscribers
None
D7238.diff
View Options
Index: head/sys/arm/conf/RT1310
===================================================================
--- head/sys/arm/conf/RT1310
+++ head/sys/arm/conf/RT1310
@@ -0,0 +1,80 @@
+#
+# Custom kernel for RT1310 boards.
+#
+# $FreeBSD$
+#
+
+ident RT1310
+include "std.arm"
+hints "RT1310.hints"
+
+# Flattened Device Tree
+options FDT
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=wzr2-g300n.dts
+
+makeoptions MODULES_OVERRIDE=""
+
+#makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
+makeoptions WERROR="-Werror"
+
+options SCHED_4BSD # 4BSD scheduler
+options INET # InterNETworking
+options FFS # Berkeley Fast Filesystem
+options TMPFS # Efficient memory filesystem
+options MSDOSFS
+
+options ROOTDEVNAME=\"cd9660:/dev/cfid0s.rootfs.uzip\"
+
+options SYSVSHM # SYSV-style shared memory
+options SYSVMSG # SYSV-style message queues
+options SYSVSEM # SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions
+options MUTEX_NOINLINE
+options RWLOCK_NOINLINE
+options NO_FFS_SNAPSHOT
+options NO_SWAPPING
+
+# Debugging
+options ALT_BREAK_TO_DEBUGGER
+options DDB
+#options DEADLKRES # Enable the deadlock resolver
+#options DIAGNOSTIC
+#options INVARIANTS # Enable calls of extra sanity checking
+#options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
+options KDB
+options WITNESS # Enable checks to detect deadlocks and cycles
+options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
+#options WITNESS_KDB
+
+# Pseudo devices
+device loop
+device md
+device pty
+device random
+
+# Serial ports
+device uart
+device uart_ns8250
+
+# Flash
+device cfi
+device cfid
+
+# Networking
+device ether
+device mii
+device bpf
+device fv
+
+# etherswitch
+device mdio
+device etherswitch
+device miiproxy
+device ip17x
+
+# GPIO
+device gpio
+device gpioled
+device rt1310gpio
+
Index: head/sys/arm/ralink/files.ralink
===================================================================
--- head/sys/arm/ralink/files.ralink
+++ head/sys/arm/ralink/files.ralink
@@ -0,0 +1,9 @@
+# $FreeBSD$
+arm/ralink/rt1310_machdep.c standard
+arm/ralink/rt1310_intc.c standard
+arm/ralink/rt1310_gpio.c optional rt1310gpio
+arm/ralink/rt1310_timer.c standard
+arm/ralink/if_fv.c optional fv
+
+kern/kern_clocksource.c standard
+
Index: head/sys/arm/ralink/if_fv.c
===================================================================
--- head/sys/arm/ralink/if_fv.c
+++ head/sys/arm/ralink/if_fv.c
@@ -0,0 +1,1873 @@
+/*-
+ * Copyright (c) 2016 Hiroki Mori. All rights reserved.
+ * Copyright (C) 2007
+ * Oleksandr Tymoshenko <gonzo@freebsd.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWFV IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE FV DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWFV, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: $
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * FV Ethernet interface driver
+ * copy from mips/idt/if_kr.c and netbsd code
+ */
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/socket.h>
+#include <sys/taskqueue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <net/bpf.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+/* Todo: move to options.arm */
+/*#define FV_MDIO*/
+
+#ifdef FV_MDIO
+#include <dev/mdio/mdio.h>
+#include <dev/etherswitch/miiproxy.h>
+#include "mdio_if.h"
+#endif
+
+MODULE_DEPEND(are, ether, 1, 1, 1);
+MODULE_DEPEND(are, miibus, 1, 1, 1);
+#ifdef FV_MDIO
+MODULE_DEPEND(are, mdio, 1, 1, 1);
+#endif
+
+#include "miibus_if.h"
+
+#include <arm/ralink/if_fvreg.h>
+
+#ifdef FV_DEBUG
+void dump_txdesc(struct fv_softc *, int);
+void dump_status_reg(struct fv_softc *);
+#endif
+
+static int fv_attach(device_t);
+static int fv_detach(device_t);
+static int fv_ifmedia_upd(struct ifnet *);
+static void fv_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int fv_ioctl(struct ifnet *, u_long, caddr_t);
+static void fv_init(void *);
+static void fv_init_locked(struct fv_softc *);
+static void fv_link_task(void *, int);
+static int fv_miibus_readreg(device_t, int, int);
+static void fv_miibus_statchg(device_t);
+static int fv_miibus_writereg(device_t, int, int, int);
+static int fv_probe(device_t);
+static void fv_reset(struct fv_softc *);
+static int fv_resume(device_t);
+static int fv_rx_ring_init(struct fv_softc *);
+static int fv_tx_ring_init(struct fv_softc *);
+static int fv_shutdown(device_t);
+static void fv_start(struct ifnet *);
+static void fv_start_locked(struct ifnet *);
+static void fv_stop(struct fv_softc *);
+static int fv_suspend(device_t);
+
+static void fv_rx(struct fv_softc *);
+static void fv_tx(struct fv_softc *);
+static void fv_intr(void *);
+static void fv_tick(void *);
+
+static void fv_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int fv_dma_alloc(struct fv_softc *);
+static void fv_dma_free(struct fv_softc *);
+static int fv_newbuf(struct fv_softc *, int);
+static __inline void fv_fixup_rx(struct mbuf *);
+
+static void fv_hinted_child(device_t bus, const char *dname, int dunit);
+
+static void fv_setfilt(struct fv_softc *sc);
+
+static device_method_t fv_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fv_probe),
+ DEVMETHOD(device_attach, fv_attach),
+ DEVMETHOD(device_detach, fv_detach),
+ DEVMETHOD(device_suspend, fv_suspend),
+ DEVMETHOD(device_resume, fv_resume),
+ DEVMETHOD(device_shutdown, fv_shutdown),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, fv_miibus_readreg),
+ DEVMETHOD(miibus_writereg, fv_miibus_writereg),
+#if !defined(FV_MDIO)
+ DEVMETHOD(miibus_statchg, fv_miibus_statchg),
+#endif
+
+ /* bus interface */
+ DEVMETHOD(bus_add_child, device_add_child_ordered),
+ DEVMETHOD(bus_hinted_child, fv_hinted_child),
+
+ DEVMETHOD_END
+};
+
+static driver_t fv_driver = {
+ "fv",
+ fv_methods,
+ sizeof(struct fv_softc)
+};
+
+static devclass_t fv_devclass;
+
+DRIVER_MODULE(fv, simplebus, fv_driver, fv_devclass, 0, 0);
+#ifdef MII
+DRIVER_MODULE(miibus, fv, miibus_driver, miibus_devclass, 0, 0);
+#endif
+
+static struct mtx miibus_mtx;
+MTX_SYSINIT(miibus_mtx, &miibus_mtx, "are mii lock", MTX_DEF);
+
+#ifdef FV_MDIO
+static int fvmdio_probe(device_t);
+static int fvmdio_attach(device_t);
+static int fvmdio_detach(device_t);
+
+/*
+ * Declare an additional, separate driver for accessing the MDIO bus.
+ */
+static device_method_t fvmdio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fvmdio_probe),
+ DEVMETHOD(device_attach, fvmdio_attach),
+ DEVMETHOD(device_detach, fvmdio_detach),
+
+ /* bus interface */
+ DEVMETHOD(bus_add_child, device_add_child_ordered),
+
+ /* MDIO access */
+ DEVMETHOD(mdio_readreg, fv_miibus_readreg),
+ DEVMETHOD(mdio_writereg, fv_miibus_writereg),
+};
+
+DEFINE_CLASS_0(fvmdio, fvmdio_driver, fvmdio_methods,
+ sizeof(struct fv_softc));
+static devclass_t fvmdio_devclass;
+
+DRIVER_MODULE(miiproxy, fv, miiproxy_driver, miiproxy_devclass, 0, 0);
+DRIVER_MODULE(fvmdio, simplebus, fvmdio_driver, fvmdio_devclass, 0, 0);
+DRIVER_MODULE(mdio, fvmdio, mdio_driver, mdio_devclass, 0, 0);
+#endif
+
+/* setup frame code refer dc code */
+
+static void
+fv_setfilt(struct fv_softc *sc)
+{
+ uint16_t eaddr[(ETHER_ADDR_LEN+1)/2];
+ struct fv_desc *sframe;
+ int i;
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ uint16_t *sp;
+ uint8_t *ma;
+
+ ifp = sc->fv_ifp;
+
+ i = sc->fv_cdata.fv_tx_prod;
+ FV_INC(sc->fv_cdata.fv_tx_prod, FV_TX_RING_CNT);
+ sc->fv_cdata.fv_tx_cnt++;
+ sframe = &sc->fv_rdata.fv_tx_ring[i];
+ sp = (uint16_t *)sc->fv_cdata.fv_sf_buff;
+ memset(sp, 0xff, FV_SFRAME_LEN);
+
+ sframe->fv_addr = sc->fv_rdata.fv_sf_paddr;
+ sframe->fv_devcs = ADCTL_Tx_SETUP | FV_DMASIZE(FV_SFRAME_LEN);
+
+ i = 0;
+ if_maddr_rlock(ifp);
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
+ sp[i] = sp[i+1] = (ma[1] << 8 | ma[0]);
+ i += 2;
+ sp[i] = sp[i+1] = (ma[3] << 8 | ma[2]);
+ i += 2;
+ sp[i] = sp[i+1] = (ma[5] << 8 | ma[4]);
+ i += 2;
+ }
+ if_maddr_runlock(ifp);
+
+ bcopy(IF_LLADDR(sc->fv_ifp), eaddr, ETHER_ADDR_LEN);
+ sp[90] = sp[91] = eaddr[0];
+ sp[92] = sp[93] = eaddr[1];
+ sp[94] = sp[95] = eaddr[2];
+
+ sframe->fv_stat = ADSTAT_OWN;
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->fv_cdata.fv_sf_tag,
+ sc->fv_cdata.fv_sf_buff_map, BUS_DMASYNC_PREWRITE);
+ CSR_WRITE_4(sc, CSR_TXPOLL, 0xFFFFFFFF);
+ DELAY(10000);
+}
+
+static int
+fv_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "fv,ethernet"))
+ return (ENXIO);
+
+ device_set_desc(dev, "FV Ethernet interface");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fv_attach(device_t dev)
+{
+ struct ifnet *ifp;
+ struct fv_softc *sc;
+ int error = 0, rid;
+ int unit;
+ int i;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ sc->fv_dev = dev;
+ sc->fv_ofw = ofw_bus_get_node(dev);
+
+ i = OF_getprop(sc->fv_ofw, "local-mac-address", (void *)&sc->fv_eaddr, 6);
+ if (i != 6) {
+ /* hardcode macaddress */
+ sc->fv_eaddr[0] = 0x00;
+ sc->fv_eaddr[1] = 0x0C;
+ sc->fv_eaddr[2] = 0x42;
+ sc->fv_eaddr[3] = 0x09;
+ sc->fv_eaddr[4] = 0x5E;
+ sc->fv_eaddr[5] = 0x6B;
+ }
+
+ mtx_init(&sc->fv_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ callout_init_mtx(&sc->fv_stat_callout, &sc->fv_mtx, 0);
+ TASK_INIT(&sc->fv_link_task, 0, fv_link_task, sc);
+
+ /* Map control/status registers. */
+ sc->fv_rid = 0;
+ sc->fv_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->fv_rid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ if (sc->fv_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->fv_btag = rman_get_bustag(sc->fv_res);
+ sc->fv_bhandle = rman_get_bushandle(sc->fv_res);
+
+ /* Allocate interrupts */
+ rid = 0;
+ sc->fv_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->fv_irq == NULL) {
+ device_printf(dev, "couldn't map interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate ifnet structure. */
+ ifp = sc->fv_ifp = if_alloc(IFT_ETHER);
+
+ if (ifp == NULL) {
+ device_printf(dev, "couldn't allocate ifnet structure\n");
+ error = ENOSPC;
+ goto fail;
+ }
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = fv_ioctl;
+ ifp->if_start = fv_start;
+ ifp->if_init = fv_init;
+
+ /* ifqmaxlen is sysctl value in net/if.c */
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_capenable = ifp->if_capabilities;
+
+ if (fv_dma_alloc(sc) != 0) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* TODO: calculate prescale */
+/*
+ CSR_WRITE_4(sc, FV_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ CSR_WRITE_4(sc, FV_MIIMCFG, FV_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, FV_MIIMCFG, 0);
+*/
+ CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR);
+ DELAY(1000);
+
+#ifdef FV_MDIO
+ sc->fv_miiproxy = mii_attach_proxy(sc->fv_dev);
+#endif
+
+#ifdef MII
+ /* Do MII setup. */
+ error = mii_attach(dev, &sc->fv_miibus, ifp, fv_ifmedia_upd,
+ fv_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+ if (error != 0) {
+ device_printf(dev, "attaching PHYs failed\n");
+ goto fail;
+ }
+#else
+ ifmedia_init(&sc->fv_ifmedia, 0, fv_ifmedia_upd, fv_ifmedia_sts);
+
+ ifmedia_add(&sc->fv_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->fv_ifmedia, IFM_ETHER | IFM_AUTO);
+#endif
+
+ /* Call MI attach routine. */
+ ether_ifattach(ifp, sc->fv_eaddr);
+
+ /* Hook interrupt last to avoid having to lock softc */
+ error = bus_setup_intr(dev, sc->fv_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, fv_intr, sc, &sc->fv_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+fail:
+ if (error)
+ fv_detach(dev);
+
+ return (error);
+}
+
+static int
+fv_detach(device_t dev)
+{
+ struct fv_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->fv_ifp;
+
+ KASSERT(mtx_initialized(&sc->fv_mtx), ("vr mutex not initialized"));
+
+ /* These should only be active if attach succeeded */
+ if (device_is_attached(dev)) {
+ FV_LOCK(sc);
+ sc->fv_detach = 1;
+ fv_stop(sc);
+ FV_UNLOCK(sc);
+ taskqueue_drain(taskqueue_swi, &sc->fv_link_task);
+ ether_ifdetach(ifp);
+ }
+#ifdef MII
+ if (sc->fv_miibus)
+ device_delete_child(dev, sc->fv_miibus);
+#endif
+ bus_generic_detach(dev);
+
+ if (sc->fv_intrhand)
+ bus_teardown_intr(dev, sc->fv_irq, sc->fv_intrhand);
+ if (sc->fv_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->fv_irq);
+
+ if (sc->fv_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->fv_rid,
+ sc->fv_res);
+
+ if (ifp)
+ if_free(ifp);
+
+ fv_dma_free(sc);
+
+ mtx_destroy(&sc->fv_mtx);
+
+ return (0);
+
+}
+
+static int
+fv_suspend(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+fv_resume(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+fv_shutdown(device_t dev)
+{
+ struct fv_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ FV_LOCK(sc);
+ fv_stop(sc);
+ FV_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+fv_miibus_readbits(struct fv_softc *sc, int count)
+{
+ int result;
+
+ result = 0;
+ while(count--) {
+ result <<= 1;
+ CSR_WRITE_4(sc, CSR_MIIMNG, MII_RD);
+ DELAY(10);
+ CSR_WRITE_4(sc, CSR_MIIMNG, MII_RD | MII_CLK);
+ DELAY(10);
+ if (CSR_READ_4(sc, CSR_MIIMNG) & MII_DIN)
+ result |= 1;
+ }
+
+ return (result);
+}
+
+static int
+fv_miibus_writebits(struct fv_softc *sc, int data, int count)
+{
+ int bit;
+
+ while(count--) {
+ bit = ((data) >> count) & 0x1 ? MII_DOUT : 0;
+ CSR_WRITE_4(sc, CSR_MIIMNG, bit | MII_WR);
+ DELAY(10);
+ CSR_WRITE_4(sc, CSR_MIIMNG, bit | MII_WR | MII_CLK);
+ DELAY(10);
+ }
+
+ return (0);
+}
+
+static void
+fv_miibus_turnaround(struct fv_softc *sc, int cmd)
+{
+ if (cmd == MII_WRCMD) {
+ fv_miibus_writebits(sc, 0x02, 2);
+ } else {
+ fv_miibus_readbits(sc, 1);
+ }
+}
+
+static int
+fv_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct fv_softc * sc = device_get_softc(dev);
+ int result;
+
+ mtx_lock(&miibus_mtx);
+ fv_miibus_writebits(sc, MII_PREAMBLE, 32);
+ fv_miibus_writebits(sc, MII_RDCMD, 4);
+ fv_miibus_writebits(sc, phy, 5);
+ fv_miibus_writebits(sc, reg, 5);
+ fv_miibus_turnaround(sc, MII_RDCMD);
+ result = fv_miibus_readbits(sc, 16);
+ fv_miibus_turnaround(sc, MII_RDCMD);
+ mtx_unlock(&miibus_mtx);
+
+ return (result);
+}
+
+static int
+fv_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct fv_softc * sc = device_get_softc(dev);
+
+ mtx_lock(&miibus_mtx);
+ fv_miibus_writebits(sc, MII_PREAMBLE, 32);
+ fv_miibus_writebits(sc, MII_WRCMD, 4);
+ fv_miibus_writebits(sc, phy, 5);
+ fv_miibus_writebits(sc, reg, 5);
+ fv_miibus_turnaround(sc, MII_WRCMD);
+ fv_miibus_writebits(sc, data, 16);
+ mtx_unlock(&miibus_mtx);
+
+ return (0);
+}
+
+#if !defined(FV_MDIO)
+static void
+fv_miibus_statchg(device_t dev)
+{
+ struct fv_softc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue(taskqueue_swi, &sc->fv_link_task);
+}
+#endif
+
+static void
+fv_link_task(void *arg, int pending)
+{
+#ifdef MII
+ struct fv_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ /* int lfdx, mfdx; */
+
+ sc = (struct fv_softc *)arg;
+
+ FV_LOCK(sc);
+ mii = device_get_softc(sc->fv_miibus);
+ ifp = sc->fv_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ FV_UNLOCK(sc);
+ return;
+ }
+
+ if (mii->mii_media_status & IFM_ACTIVE) {
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->fv_link_status = 1;
+ } else
+ sc->fv_link_status = 0;
+
+ FV_UNLOCK(sc);
+#endif
+}
+
+static void
+fv_reset(struct fv_softc *sc)
+{
+ int i;
+
+ CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR);
+
+ /*
+ * The chip doesn't take itself out of reset automatically.
+ * We need to do so after 2us.
+ */
+ DELAY(1000);
+ CSR_WRITE_4(sc, CSR_BUSMODE, 0);
+
+ for (i = 0; i < 1000; i++) {
+ /*
+ * Wait a bit for the reset to complete before peeking
+ * at the chip again.
+ */
+ DELAY(1000);
+ if ((CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR) == 0)
+ break;
+ }
+
+ if (CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR)
+ device_printf(sc->fv_dev, "reset time out\n");
+
+ DELAY(1000);
+}
+
+static void
+fv_init(void *xsc)
+{
+ struct fv_softc *sc = xsc;
+
+ FV_LOCK(sc);
+ fv_init_locked(sc);
+ FV_UNLOCK(sc);
+}
+
+static void
+fv_init_locked(struct fv_softc *sc)
+{
+ struct ifnet *ifp = sc->fv_ifp;
+#ifdef MII
+ struct mii_data *mii;
+#endif
+
+ FV_LOCK_ASSERT(sc);
+
+#ifdef MII
+ mii = device_get_softc(sc->fv_miibus);
+#endif
+
+ fv_stop(sc);
+ fv_reset(sc);
+
+ /* Init circular RX list. */
+ if (fv_rx_ring_init(sc) != 0) {
+ device_printf(sc->fv_dev,
+ "initialization failed: no memory for rx buffers\n");
+ fv_stop(sc);
+ return;
+ }
+
+ /* Init tx descriptors. */
+ fv_tx_ring_init(sc);
+
+ /*
+ * Initialize the BUSMODE register.
+ */
+ CSR_WRITE_4(sc, CSR_BUSMODE,
+ /* XXX: not sure if this is a good thing or not... */
+ BUSMODE_BAR | BUSMODE_PBL_32LW);
+
+ /*
+ * Initialize the interrupt mask and enable interrupts.
+ */
+ /* normal interrupts */
+ sc->sc_inten = STATUS_TI | STATUS_TU | STATUS_RI | STATUS_NIS;
+
+ /* abnormal interrupts */
+ sc->sc_inten |= STATUS_TPS | STATUS_TJT | STATUS_UNF |
+ STATUS_RU | STATUS_RPS | STATUS_SE | STATUS_AIS;
+
+ sc->sc_rxint_mask = STATUS_RI|STATUS_RU;
+ sc->sc_txint_mask = STATUS_TI|STATUS_UNF|STATUS_TJT;
+
+ sc->sc_rxint_mask &= sc->sc_inten;
+ sc->sc_txint_mask &= sc->sc_inten;
+
+ CSR_WRITE_4(sc, CSR_INTEN, sc->sc_inten);
+ CSR_WRITE_4(sc, CSR_STATUS, 0xffffffff);
+
+ /*
+ * Give the transmit and receive rings to the chip.
+ */
+ CSR_WRITE_4(sc, CSR_TXLIST, FV_TX_RING_ADDR(sc, 0));
+ CSR_WRITE_4(sc, CSR_RXLIST, FV_RX_RING_ADDR(sc, 0));
+
+ /*
+ * Set the station address.
+ */
+ fv_setfilt(sc);
+
+
+ /*
+ * Write out the opmode.
+ */
+ CSR_WRITE_4(sc, CSR_OPMODE, OPMODE_SR | OPMODE_ST |
+ OPMODE_TR_128 | OPMODE_FDX | OPMODE_SPEED);
+ /*
+ * Start the receive process.
+ */
+ CSR_WRITE_4(sc, CSR_RXPOLL, RXPOLL_RPD);
+
+ sc->fv_link_status = 1;
+#ifdef MII
+ mii_mediachg(mii);
+#endif
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->fv_stat_callout, hz, fv_tick, sc);
+}
+
+static void
+fv_start(struct ifnet *ifp)
+{
+ struct fv_softc *sc;
+
+ sc = ifp->if_softc;
+
+ FV_LOCK(sc);
+ fv_start_locked(ifp);
+ FV_UNLOCK(sc);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ * Use Implicit Chain implementation.
+ */
+static int
+fv_encap(struct fv_softc *sc, struct mbuf **m_head)
+{
+ struct fv_txdesc *txd;
+ struct fv_desc *desc;
+ struct mbuf *m;
+ bus_dma_segment_t txsegs[FV_MAXFRAGS];
+ int error, i, nsegs, prod, si;
+ int padlen;
+ int txstat;
+
+ FV_LOCK_ASSERT(sc);
+
+ /*
+ * Some VIA Rhine wants packet buffers to be longword
+ * aligned, but very often our mbufs aren't. Rather than
+ * waste time trying to decide when to copy and when not
+ * to copy, just do it all the time.
+ */
+ m = m_defrag(*m_head, M_NOWAIT);
+ if (m == NULL) {
+ device_printf(sc->fv_dev, "fv_encap m_defrag error\n");
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+
+ /*
+ * The Rhine chip doesn't auto-pad, so we have to make
+ * sure to pad short frames out to the minimum frame length
+ * ourselves.
+ */
+ if ((*m_head)->m_pkthdr.len < FV_MIN_FRAMELEN) {
+ m = *m_head;
+ padlen = FV_MIN_FRAMELEN - m->m_pkthdr.len;
+ if (M_WRITABLE(m) == 0) {
+ /* Get a writable copy. */
+ m = m_dup(*m_head, M_NOWAIT);
+ m_freem(*m_head);
+ if (m == NULL) {
+ device_printf(sc->fv_dev, "fv_encap m_dup error\n");
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+ }
+ if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) {
+ m = m_defrag(m, M_NOWAIT);
+ if (m == NULL) {
+ device_printf(sc->fv_dev, "fv_encap m_defrag error\n");
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ }
+ /*
+ * Manually pad short frames, and zero the pad space
+ * to avoid leaking data.
+ */
+ bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
+ m->m_pkthdr.len += padlen;
+ m->m_len = m->m_pkthdr.len;
+ *m_head = m;
+ }
+
+ prod = sc->fv_cdata.fv_tx_prod;
+ txd = &sc->fv_cdata.fv_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap,
+ *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ device_printf(sc->fv_dev, "fv_encap EFBIG error\n");
+ m = m_defrag(*m_head, M_NOWAIT);
+ if (m == NULL) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+ error = bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_tx_tag,
+ txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (error);
+ }
+
+ } else if (error != 0)
+ return (error);
+ if (nsegs == 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (EIO);
+ }
+
+ /* Check number of available descriptors. */
+ if (sc->fv_cdata.fv_tx_cnt + nsegs >= (FV_TX_RING_CNT - 1)) {
+ bus_dmamap_unload(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap);
+ return (ENOBUFS);
+ }
+
+ txd->tx_m = *m_head;
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ si = prod;
+
+ /*
+ * Make a list of descriptors for this packet.
+ */
+ desc = NULL;
+ for (i = 0; i < nsegs; i++) {
+ desc = &sc->fv_rdata.fv_tx_ring[prod];
+ desc->fv_stat = ADSTAT_OWN;
+ desc->fv_devcs = txsegs[i].ds_len;
+ /* end of descriptor */
+ if (prod == FV_TX_RING_CNT - 1)
+ desc->fv_devcs |= ADCTL_ER;
+ desc->fv_addr = txsegs[i].ds_addr;
+
+ ++sc->fv_cdata.fv_tx_cnt;
+ FV_INC(prod, FV_TX_RING_CNT);
+ }
+
+ /*
+ * Set mark last fragment with Last/Intr flag
+ */
+ if (desc) {
+ desc->fv_devcs |= ADCTL_Tx_IC;
+ desc->fv_devcs |= ADCTL_Tx_LS;
+ }
+
+ /* Update producer index. */
+ sc->fv_cdata.fv_tx_prod = prod;
+
+ /* Sync descriptors. */
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+ if (txstat == 0 || txstat == 6) {
+ /* Transmit Process Stat is stop or suspended */
+ desc = &sc->fv_rdata.fv_tx_ring[si];
+ desc->fv_devcs |= ADCTL_Tx_FS;
+ }
+ else {
+ /* Get previous descriptor */
+ si = (si + FV_TX_RING_CNT - 1) % FV_TX_RING_CNT;
+ desc = &sc->fv_rdata.fv_tx_ring[si];
+ /* join remain data and flugs */
+ desc->fv_devcs &= ~ADCTL_Tx_IC;
+ desc->fv_devcs &= ~ADCTL_Tx_LS;
+ }
+
+
+ return (0);
+}
+
+static void
+fv_start_locked(struct ifnet *ifp)
+{
+ struct fv_softc *sc;
+ struct mbuf *m_head;
+ int enq;
+ int txstat;
+
+ sc = ifp->if_softc;
+
+ FV_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->fv_link_status == 0 )
+ return;
+
+ for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->fv_cdata.fv_tx_cnt < FV_TX_RING_CNT - 2; ) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+ /*
+ * Pack the data into the transmit ring. If we
+ * don't have room, set the OACTIVE flag and wait
+ * for the NIC to drain the ring.
+ */
+ if (fv_encap(sc, &m_head)) {
+ if (m_head == NULL)
+ break;
+ IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+
+ enq++;
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ ETHER_BPF_MTAP(ifp, m_head);
+ }
+
+ if (enq > 0) {
+ txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+ if (txstat == 0 || txstat == 6)
+ CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+ }
+}
+
+static void
+fv_stop(struct fv_softc *sc)
+{
+ struct ifnet *ifp;
+
+ FV_LOCK_ASSERT(sc);
+
+ ifp = sc->fv_ifp;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ callout_stop(&sc->fv_stat_callout);
+
+ /* Disable interrupts. */
+ CSR_WRITE_4(sc, CSR_INTEN, 0);
+
+ /* Stop the transmit and receive processes. */
+ CSR_WRITE_4(sc, CSR_OPMODE, 0);
+ CSR_WRITE_4(sc, CSR_RXLIST, 0);
+ CSR_WRITE_4(sc, CSR_TXLIST, 0);
+
+}
+
+
+static int
+fv_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct fv_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+#ifdef MII
+ struct mii_data *mii;
+#endif
+ int error;
+ int csr;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+ FV_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if ((ifp->if_flags ^ sc->fv_if_flags) &
+ IFF_PROMISC) {
+ csr = CSR_READ_4(sc, CSR_OPMODE);
+ CSR_WRITE_4(sc, CSR_OPMODE, csr |
+ OPMODE_PM | OPMODE_PR);
+ }
+ if ((ifp->if_flags ^ sc->fv_if_flags) &
+ IFF_ALLMULTI) {
+ csr = CSR_READ_4(sc, CSR_OPMODE);
+ CSR_WRITE_4(sc, CSR_OPMODE, csr |
+ OPMODE_PM);
+ }
+ } else {
+ if (sc->fv_detach == 0)
+ fv_init_locked(sc);
+ }
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ fv_stop(sc);
+ }
+ sc->fv_if_flags = ifp->if_flags;
+ FV_UNLOCK(sc);
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#if 0
+ FV_LOCK(sc);
+ fv_set_filter(sc);
+ FV_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+#ifdef MII
+ mii = device_get_softc(sc->fv_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+#else
+ error = ifmedia_ioctl(ifp, ifr, &sc->fv_ifmedia, command);
+#endif
+ break;
+ case SIOCSIFCAP:
+ error = 0;
+#if 0
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ if ((mask & IFCAP_HWCSUM) != 0) {
+ ifp->if_capenable ^= IFCAP_HWCSUM;
+ if ((IFCAP_HWCSUM & ifp->if_capenable) &&
+ (IFCAP_HWCSUM & ifp->if_capabilities))
+ ifp->if_hwassist = FV_CSUM_FEATURES;
+ else
+ ifp->if_hwassist = 0;
+ }
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if (IFCAP_VLAN_HWTAGGING & ifp->if_capenable &&
+ IFCAP_VLAN_HWTAGGING & ifp->if_capabilities &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ FV_LOCK(sc);
+ fv_vlan_setup(sc);
+ FV_UNLOCK(sc);
+ }
+ }
+ VLAN_CAPABILITIES(ifp);
+#endif
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+fv_ifmedia_upd(struct ifnet *ifp)
+{
+#ifdef MII
+ struct fv_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
+ sc = ifp->if_softc;
+ FV_LOCK(sc);
+ mii = device_get_softc(sc->fv_miibus);
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ PHY_RESET(miisc);
+ error = mii_mediachg(mii);
+ FV_UNLOCK(sc);
+
+ return (error);
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Report current media status.
+ */
+static void
+fv_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+#ifdef MII
+ struct fv_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->fv_miibus);
+ FV_LOCK(sc);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ FV_UNLOCK(sc);
+#else
+ ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
+#endif
+}
+
+struct fv_dmamap_arg {
+ bus_addr_t fv_busaddr;
+};
+
+static void
+fv_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct fv_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+ ctx = arg;
+ ctx->fv_busaddr = segs[0].ds_addr;
+}
+
+static int
+fv_dma_alloc(struct fv_softc *sc)
+{
+ struct fv_dmamap_arg ctx;
+ struct fv_txdesc *txd;
+ struct fv_rxdesc *rxd;
+ int error, i;
+
+ /* Create parent DMA tag. */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->fv_dev), /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
+ 0, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_parent_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create parent DMA tag\n");
+ goto fail;
+ }
+ /* Create tag for Tx ring. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ FV_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ FV_TX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ FV_TX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_tx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Tx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx ring. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ FV_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ FV_RX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ FV_RX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_rx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Rx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Tx buffers. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * FV_MAXFRAGS, /* maxsize */
+ FV_MAXFRAGS, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_tx_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Tx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx buffers. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ FV_RX_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES, /* maxsize */
+ 1, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_rx_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create Rx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for setup frame buffers. */
+ error = bus_dma_tag_create(
+ sc->fv_cdata.fv_parent_tag, /* parent */
+ sizeof(uint32_t), 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ FV_SFRAME_LEN + FV_MIN_FRAMELEN, /* maxsize */
+ 1, /* nsegments */
+ FV_SFRAME_LEN + FV_MIN_FRAMELEN, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->fv_cdata.fv_sf_tag);
+ if (error != 0) {
+ device_printf(sc->fv_dev, "failed to create setup frame DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate DMA'able memory and load the DMA map for Tx ring. */
+ error = bus_dmamem_alloc(sc->fv_cdata.fv_tx_ring_tag,
+ (void **)&sc->fv_rdata.fv_tx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_tx_ring_map);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to allocate DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+
+ ctx.fv_busaddr = 0;
+ error = bus_dmamap_load(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map, sc->fv_rdata.fv_tx_ring,
+ FV_TX_RING_SIZE, fv_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.fv_busaddr == 0) {
+ device_printf(sc->fv_dev,
+ "failed to load DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+ sc->fv_rdata.fv_tx_ring_paddr = ctx.fv_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for Rx ring. */
+ error = bus_dmamem_alloc(sc->fv_cdata.fv_rx_ring_tag,
+ (void **)&sc->fv_rdata.fv_rx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_rx_ring_map);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to allocate DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+
+ ctx.fv_busaddr = 0;
+ error = bus_dmamap_load(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map, sc->fv_rdata.fv_rx_ring,
+ FV_RX_RING_SIZE, fv_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.fv_busaddr == 0) {
+ device_printf(sc->fv_dev,
+ "failed to load DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+ sc->fv_rdata.fv_rx_ring_paddr = ctx.fv_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for setup frame. */
+ error = bus_dmamem_alloc(sc->fv_cdata.fv_sf_tag,
+ (void **)&sc->fv_cdata.fv_sf_buff, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_sf_buff_map);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to allocate DMA'able memory for setup frame\n");
+ goto fail;
+ }
+
+ ctx.fv_busaddr = 0;
+ error = bus_dmamap_load(sc->fv_cdata.fv_sf_tag,
+ sc->fv_cdata.fv_sf_buff_map, sc->fv_cdata.fv_sf_buff,
+ FV_SFRAME_LEN, fv_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.fv_busaddr == 0) {
+ device_printf(sc->fv_dev,
+ "failed to load DMA'able memory for setup frame\n");
+ goto fail;
+ }
+ sc->fv_rdata.fv_sf_paddr = ctx.fv_busaddr;
+
+ /* Create DMA maps for Tx buffers. */
+ for (i = 0; i < FV_TX_RING_CNT; i++) {
+ txd = &sc->fv_cdata.fv_txdesc[i];
+ txd->tx_m = NULL;
+ txd->tx_dmamap = NULL;
+ error = bus_dmamap_create(sc->fv_cdata.fv_tx_tag, 0,
+ &txd->tx_dmamap);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to create Tx dmamap\n");
+ goto fail;
+ }
+ }
+ /* Create DMA maps for Rx buffers. */
+ if ((error = bus_dmamap_create(sc->fv_cdata.fv_rx_tag, 0,
+ &sc->fv_cdata.fv_rx_sparemap)) != 0) {
+ device_printf(sc->fv_dev,
+ "failed to create spare Rx dmamap\n");
+ goto fail;
+ }
+ for (i = 0; i < FV_RX_RING_CNT; i++) {
+ rxd = &sc->fv_cdata.fv_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->rx_dmamap = NULL;
+ error = bus_dmamap_create(sc->fv_cdata.fv_rx_tag, 0,
+ &rxd->rx_dmamap);
+ if (error != 0) {
+ device_printf(sc->fv_dev,
+ "failed to create Rx dmamap\n");
+ goto fail;
+ }
+ }
+
+fail:
+ return (error);
+}
+
+static void
+fv_dma_free(struct fv_softc *sc)
+{
+ struct fv_txdesc *txd;
+ struct fv_rxdesc *rxd;
+ int i;
+
+ /* Tx ring. */
+ if (sc->fv_cdata.fv_tx_ring_tag) {
+ if (sc->fv_rdata.fv_tx_ring_paddr)
+ bus_dmamap_unload(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map);
+ if (sc->fv_rdata.fv_tx_ring)
+ bus_dmamem_free(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_rdata.fv_tx_ring,
+ sc->fv_cdata.fv_tx_ring_map);
+ sc->fv_rdata.fv_tx_ring = NULL;
+ sc->fv_rdata.fv_tx_ring_paddr = 0;
+ bus_dma_tag_destroy(sc->fv_cdata.fv_tx_ring_tag);
+ sc->fv_cdata.fv_tx_ring_tag = NULL;
+ }
+ /* Rx ring. */
+ if (sc->fv_cdata.fv_rx_ring_tag) {
+ if (sc->fv_rdata.fv_rx_ring_paddr)
+ bus_dmamap_unload(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map);
+ if (sc->fv_rdata.fv_rx_ring)
+ bus_dmamem_free(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_rdata.fv_rx_ring,
+ sc->fv_cdata.fv_rx_ring_map);
+ sc->fv_rdata.fv_rx_ring = NULL;
+ sc->fv_rdata.fv_rx_ring_paddr = 0;
+ bus_dma_tag_destroy(sc->fv_cdata.fv_rx_ring_tag);
+ sc->fv_cdata.fv_rx_ring_tag = NULL;
+ }
+ /* Tx buffers. */
+ if (sc->fv_cdata.fv_tx_tag) {
+ for (i = 0; i < FV_TX_RING_CNT; i++) {
+ txd = &sc->fv_cdata.fv_txdesc[i];
+ if (txd->tx_dmamap) {
+ bus_dmamap_destroy(sc->fv_cdata.fv_tx_tag,
+ txd->tx_dmamap);
+ txd->tx_dmamap = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->fv_cdata.fv_tx_tag);
+ sc->fv_cdata.fv_tx_tag = NULL;
+ }
+ /* Rx buffers. */
+ if (sc->fv_cdata.fv_rx_tag) {
+ for (i = 0; i < FV_RX_RING_CNT; i++) {
+ rxd = &sc->fv_cdata.fv_rxdesc[i];
+ if (rxd->rx_dmamap) {
+ bus_dmamap_destroy(sc->fv_cdata.fv_rx_tag,
+ rxd->rx_dmamap);
+ rxd->rx_dmamap = NULL;
+ }
+ }
+ if (sc->fv_cdata.fv_rx_sparemap) {
+ bus_dmamap_destroy(sc->fv_cdata.fv_rx_tag,
+ sc->fv_cdata.fv_rx_sparemap);
+ sc->fv_cdata.fv_rx_sparemap = 0;
+ }
+ bus_dma_tag_destroy(sc->fv_cdata.fv_rx_tag);
+ sc->fv_cdata.fv_rx_tag = NULL;
+ }
+
+ if (sc->fv_cdata.fv_parent_tag) {
+ bus_dma_tag_destroy(sc->fv_cdata.fv_parent_tag);
+ sc->fv_cdata.fv_parent_tag = NULL;
+ }
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int
+fv_tx_ring_init(struct fv_softc *sc)
+{
+ struct fv_ring_data *rd;
+ struct fv_txdesc *txd;
+ bus_addr_t addr;
+ int i;
+
+ sc->fv_cdata.fv_tx_prod = 0;
+ sc->fv_cdata.fv_tx_cons = 0;
+ sc->fv_cdata.fv_tx_cnt = 0;
+ sc->fv_cdata.fv_tx_pkts = 0;
+
+ rd = &sc->fv_rdata;
+ bzero(rd->fv_tx_ring, FV_TX_RING_SIZE);
+ for (i = 0; i < FV_TX_RING_CNT; i++) {
+ if (i == FV_TX_RING_CNT - 1)
+ addr = FV_TX_RING_ADDR(sc, 0);
+ else
+ addr = FV_TX_RING_ADDR(sc, i + 1);
+ rd->fv_tx_ring[i].fv_stat = 0;
+ rd->fv_tx_ring[i].fv_devcs = 0;
+ rd->fv_tx_ring[i].fv_addr = 0;
+ rd->fv_tx_ring[i].fv_link = addr;
+ txd = &sc->fv_cdata.fv_txdesc[i];
+ txd->tx_m = NULL;
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int
+fv_rx_ring_init(struct fv_softc *sc)
+{
+ struct fv_ring_data *rd;
+ struct fv_rxdesc *rxd;
+ int i;
+
+ sc->fv_cdata.fv_rx_cons = 0;
+
+ rd = &sc->fv_rdata;
+ bzero(rd->fv_rx_ring, FV_RX_RING_SIZE);
+ for (i = 0; i < FV_RX_RING_CNT; i++) {
+ rxd = &sc->fv_cdata.fv_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->desc = &rd->fv_rx_ring[i];
+ rd->fv_rx_ring[i].fv_stat = ADSTAT_OWN;
+ rd->fv_rx_ring[i].fv_devcs = 0;
+ if (i == FV_RX_RING_CNT - 1)
+ rd->fv_rx_ring[i].fv_devcs |= ADCTL_ER;
+ rd->fv_rx_ring[i].fv_addr = 0;
+ if (fv_newbuf(sc, i) != 0)
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int
+fv_newbuf(struct fv_softc *sc, int idx)
+{
+ struct fv_desc *desc;
+ struct fv_rxdesc *rxd;
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t map;
+ int nsegs;
+
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+ /* tcp header boundary alignment margin */
+ m_adj(m, 4);
+
+ if (bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_rx_tag,
+ sc->fv_cdata.fv_rx_sparemap, m, segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ rxd = &sc->fv_cdata.fv_rxdesc[idx];
+ if (rxd->rx_m != NULL) {
+/* This code make bug. Make scranble on buffer data.
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+*/
+ bus_dmamap_unload(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->fv_cdata.fv_rx_sparemap;
+ sc->fv_cdata.fv_rx_sparemap = map;
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ desc = rxd->desc;
+ desc->fv_addr = segs[0].ds_addr;
+ desc->fv_devcs |= FV_DMASIZE(segs[0].ds_len);
+ rxd->saved_ca = desc->fv_addr ;
+ rxd->saved_ctl = desc->fv_stat ;
+
+ return (0);
+}
+
+static __inline void
+fv_fixup_rx(struct mbuf *m)
+{
+ int i;
+ uint16_t *src, *dst;
+
+ src = mtod(m, uint16_t *);
+ dst = src - 1;
+
+ for (i = 0; i < m->m_len / sizeof(uint16_t); i++) {
+ *dst++ = *src++;
+ }
+
+ if (m->m_len % sizeof(uint16_t))
+ *(uint8_t *)dst = *(uint8_t *)src;
+
+ m->m_data -= ETHER_ALIGN;
+}
+
+
+static void
+fv_tx(struct fv_softc *sc)
+{
+ struct fv_txdesc *txd;
+ struct fv_desc *cur_tx;
+ struct ifnet *ifp;
+ uint32_t ctl, devcs;
+ int cons, prod, prev_cons;
+
+ FV_LOCK_ASSERT(sc);
+
+ cons = sc->fv_cdata.fv_tx_cons;
+ prod = sc->fv_cdata.fv_tx_prod;
+ if (cons == prod)
+ return;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ ifp = sc->fv_ifp;
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ prev_cons = cons;
+ for (; cons != prod; FV_INC(cons, FV_TX_RING_CNT)) {
+ cur_tx = &sc->fv_rdata.fv_tx_ring[cons];
+ ctl = cur_tx->fv_stat;
+ devcs = cur_tx->fv_devcs;
+ /* Check if descriptor has "finished" flag */
+ if (FV_DMASIZE(devcs) == 0)
+ break;
+
+ sc->fv_cdata.fv_tx_cnt--;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ txd = &sc->fv_cdata.fv_txdesc[cons];
+
+ if ((ctl & ADSTAT_Tx_ES) == 0)
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+ else if (ctl & ADSTAT_Tx_UF) { /* only underflow not check collision */
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap);
+
+ /* Free only if it's first descriptor in list */
+ if (txd->tx_m)
+ m_freem(txd->tx_m);
+ txd->tx_m = NULL;
+
+ /* reset descriptor */
+ cur_tx->fv_stat = 0;
+ cur_tx->fv_devcs = 0;
+ cur_tx->fv_addr = 0;
+ }
+
+ sc->fv_cdata.fv_tx_cons = cons;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag,
+ sc->fv_cdata.fv_tx_ring_map, BUS_DMASYNC_PREWRITE);
+}
+
+
+static void
+fv_rx(struct fv_softc *sc)
+{
+ struct fv_rxdesc *rxd;
+ struct ifnet *ifp = sc->fv_ifp;
+ int cons, prog, packet_len, error;
+ struct fv_desc *cur_rx;
+ struct mbuf *m;
+
+ FV_LOCK_ASSERT(sc);
+
+ cons = sc->fv_cdata.fv_rx_cons;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (prog = 0; prog < FV_RX_RING_CNT; FV_INC(cons, FV_RX_RING_CNT)) {
+ cur_rx = &sc->fv_rdata.fv_rx_ring[cons];
+ rxd = &sc->fv_cdata.fv_rxdesc[cons];
+ m = rxd->rx_m;
+
+ if ((cur_rx->fv_stat & ADSTAT_OWN) == ADSTAT_OWN)
+ break;
+
+ prog++;
+
+ if (cur_rx->fv_stat & (ADSTAT_ES | ADSTAT_Rx_TL)) {
+ device_printf(sc->fv_dev,
+ "Receive Descriptor error %x\n", cur_rx->fv_stat);
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ packet_len = 0;
+ } else {
+ packet_len = ADSTAT_Rx_LENGTH(cur_rx->fv_stat);
+ }
+
+ /* Assume it's error */
+ error = 1;
+
+ if (packet_len < 64)
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ else if ((cur_rx->fv_stat & ADSTAT_Rx_DE) == 0) {
+ error = 0;
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ m = rxd->rx_m;
+ /* Skip 4 bytes of CRC */
+ m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
+
+ fv_fixup_rx(m);
+ m->m_pkthdr.rcvif = ifp;
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+
+ FV_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ FV_LOCK(sc);
+ }
+
+ if (error) {
+ /* Restore CONTROL and CA values, reset DEVCS */
+ cur_rx->fv_stat = rxd->saved_ctl;
+ cur_rx->fv_addr = rxd->saved_ca;
+ cur_rx->fv_devcs = 0;
+ }
+ else {
+ /* Reinit descriptor */
+ cur_rx->fv_stat = ADSTAT_OWN;
+ cur_rx->fv_devcs = 0;
+ if (cons == FV_RX_RING_CNT - 1)
+ cur_rx->fv_devcs |= ADCTL_ER;
+ cur_rx->fv_addr = 0;
+ if (fv_newbuf(sc, cons) != 0) {
+ device_printf(sc->fv_dev,
+ "Failed to allocate buffer\n");
+ break;
+ }
+ }
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ }
+
+ if (prog > 0) {
+ sc->fv_cdata.fv_rx_cons = cons;
+
+ bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag,
+ sc->fv_cdata.fv_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+}
+
+static void
+fv_intr(void *arg)
+{
+ struct fv_softc *sc = arg;
+ uint32_t status;
+ struct ifnet *ifp = sc->fv_ifp;
+
+ FV_LOCK(sc);
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ /* mask out interrupts */
+ while((status & sc->sc_inten) != 0) {
+ if (status) {
+ CSR_WRITE_4(sc, CSR_STATUS, status);
+ }
+ if (status & STATUS_UNF) {
+ device_printf(sc->fv_dev, "Transmit Underflow\n");
+ }
+ if (status & sc->sc_rxint_mask) {
+ fv_rx(sc);
+ }
+ if (status & sc->sc_txint_mask) {
+ fv_tx(sc);
+ }
+ if (status & STATUS_AIS) {
+ device_printf(sc->fv_dev, "Abnormal Interrupt %x\n",
+ status);
+ }
+ CSR_WRITE_4(sc, CSR_FULLDUP, FULLDUP_CS |
+ (1 << FULLDUP_TT_SHIFT) | (3 << FULLDUP_NTP_SHIFT) |
+ (2 << FULLDUP_RT_SHIFT) | (2 << FULLDUP_NRP_SHIFT));
+
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ }
+
+ /* Try to get more packets going. */
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ fv_start_locked(ifp);
+
+ FV_UNLOCK(sc);
+}
+
+static void
+fv_tick(void *xsc)
+{
+ struct fv_softc *sc = xsc;
+#ifdef MII
+ struct mii_data *mii;
+
+ FV_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->fv_miibus);
+ mii_tick(mii);
+#endif
+ callout_reset(&sc->fv_stat_callout, hz, fv_tick, sc);
+}
+
+static void
+fv_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ BUS_ADD_CHILD(bus, 0, dname, dunit);
+ device_printf(bus, "hinted child %s%d\n", dname, dunit);
+}
+
+#ifdef FV_MDIO
+static int
+fvmdio_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "fv,mdio"))
+ return (ENXIO);
+
+ device_set_desc(dev, "FV built-in ethernet interface, MDIO controller");
+ return(0);
+}
+
+static int
+fvmdio_attach(device_t dev)
+{
+ struct fv_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->fv_dev = dev;
+ sc->fv_rid = 0;
+ sc->fv_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->fv_rid, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->fv_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->fv_btag = rman_get_bustag(sc->fv_res);
+ sc->fv_bhandle = rman_get_bushandle(sc->fv_res);
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ error = bus_generic_attach(dev);
+fail:
+ return(error);
+}
+
+static int
+fvmdio_detach(device_t dev)
+{
+ return(0);
+}
+#endif
+
+#ifdef FV_DEBUG
+void
+dump_txdesc(struct fv_softc *sc, int pos)
+{
+ struct fv_desc *desc;
+
+ desc = &sc->fv_rdata.fv_tx_ring[pos];
+ device_printf(sc->fv_dev, "CSR_TXLIST %08x\n", CSR_READ_4(sc, CSR_TXLIST));
+ device_printf(sc->fv_dev, "%d TDES0:%08x TDES1:%08x TDES2:%08x TDES3:%08x\n",
+ pos, desc->fv_stat, desc->fv_devcs, desc->fv_addr, desc->fv_link);
+}
+
+void
+dump_status_reg(struct fv_softc *sc)
+{
+ uint32_t status;
+
+ /* mask out interrupts */
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ device_printf(sc->fv_dev, "CSR5 Status Register EB:%d TS:%d RS:%d NIS:%d AIS:%d ER:%d SE:%d LNF:%d TM:%d RWT:%d RPS:%d RU:%d RI:%d UNF:%d LNP/ANC:%d TJT:%d TU:%d TPS:%d TI:%d\n",
+ (status >> 23 ) & 7,
+ (status >> 20 ) & 7,
+ (status >> 17 ) & 7,
+ (status >> 16 ) & 1,
+ (status >> 15 ) & 1,
+ (status >> 14 ) & 1,
+ (status >> 13 ) & 1,
+ (status >> 12 ) & 1,
+ (status >> 11 ) & 1,
+ (status >> 9 ) & 1,
+ (status >> 8 ) & 1,
+ (status >> 7 ) & 1,
+ (status >> 6 ) & 1,
+ (status >> 5 ) & 1,
+ (status >> 4 ) & 1,
+ (status >> 3 ) & 1,
+ (status >> 2 ) & 1,
+ (status >> 1 ) & 1,
+ (status >> 0 ) & 1);
+
+}
+#endif
Index: head/sys/arm/ralink/if_fvreg.h
===================================================================
--- head/sys/arm/ralink/if_fvreg.h
+++ head/sys/arm/ralink/if_fvreg.h
@@ -0,0 +1,452 @@
+/*-
+ * Copyright (C) 2007
+ * Oleksandr Tymoshenko <gonzo@freebsd.org>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWFV IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE FV DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWFV, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef __IF_FVREG_H__
+#define __IF_FVREG_H__
+
+struct fv_desc {
+ uint32_t fv_stat;
+ uint32_t fv_devcs;
+ uint32_t fv_addr;
+ uint32_t fv_link;
+};
+
+#define FV_DMASIZE(len) ((len) & ((1 << 11)-1))
+#define FV_PKTSIZE(len) ((len & 0xffff0000) >> 16)
+
+#define FV_RX_RING_CNT 128
+#define FV_TX_RING_CNT 128
+#define FV_TX_RING_SIZE sizeof(struct fv_desc) * FV_TX_RING_CNT
+#define FV_RX_RING_SIZE sizeof(struct fv_desc) * FV_RX_RING_CNT
+#define FV_RING_ALIGN sizeof(struct fv_desc)
+#define FV_RX_ALIGN sizeof(uint32_t)
+#define FV_MAXFRAGS 8
+#define FV_TX_INTR_THRESH 8
+
+#define FV_TX_RING_ADDR(sc, i) \
+ ((sc)->fv_rdata.fv_tx_ring_paddr + sizeof(struct fv_desc) * (i))
+#define FV_RX_RING_ADDR(sc, i) \
+ ((sc)->fv_rdata.fv_rx_ring_paddr + sizeof(struct fv_desc) * (i))
+#define FV_INC(x,y) (x) = (((x) + 1) % y)
+
+struct fv_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct fv_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct fv_desc *desc;
+ /* Use this values on error instead of allocating new mbuf */
+ uint32_t saved_ctl, saved_ca;
+};
+
+struct fv_chain_data {
+ bus_dma_tag_t fv_parent_tag;
+ bus_dma_tag_t fv_tx_tag;
+ struct fv_txdesc fv_txdesc[FV_TX_RING_CNT];
+ bus_dma_tag_t fv_rx_tag;
+ struct fv_rxdesc fv_rxdesc[FV_RX_RING_CNT];
+ bus_dma_tag_t fv_tx_ring_tag;
+ bus_dma_tag_t fv_rx_ring_tag;
+ bus_dmamap_t fv_tx_ring_map;
+ bus_dmamap_t fv_rx_ring_map;
+ bus_dmamap_t fv_rx_sparemap;
+ int fv_tx_pkts;
+ int fv_tx_prod;
+ int fv_tx_cons;
+ int fv_tx_cnt;
+ int fv_rx_cons;
+
+ bus_dma_tag_t fv_sf_tag;
+ bus_dmamap_t fv_sf_buff_map;
+ uint32_t *fv_sf_buff;
+};
+
+struct fv_ring_data {
+ struct fv_desc *fv_rx_ring;
+ struct fv_desc *fv_tx_ring;
+ bus_addr_t fv_rx_ring_paddr;
+ bus_addr_t fv_tx_ring_paddr;
+ bus_addr_t fv_sf_paddr;
+};
+
+struct fv_softc {
+ struct ifnet *fv_ifp; /* interface info */
+ bus_space_handle_t fv_bhandle; /* bus space handle */
+ bus_space_tag_t fv_btag; /* bus space tag */
+ device_t fv_dev;
+ uint8_t fv_eaddr[ETHER_ADDR_LEN];
+ struct resource *fv_res;
+ int fv_rid;
+ struct resource *fv_irq;
+ void *fv_intrhand;
+ u_int32_t sc_inten; /* copy of CSR_INTEN */
+ u_int32_t sc_rxint_mask; /* mask of Rx interrupts we want */
+ u_int32_t sc_txint_mask; /* mask of Tx interrupts we want */
+#ifdef MII
+ device_t fv_miibus;
+#else
+ struct ifmedia fv_ifmedia;
+#endif
+#ifdef FV_MDIO
+ device_t fv_miiproxy;
+#endif
+ int fv_if_flags;
+ bus_dma_tag_t fv_parent_tag;
+ bus_dma_tag_t fv_tag;
+ struct mtx fv_mtx;
+ phandle_t fv_ofw;
+ struct callout fv_stat_callout;
+ struct task fv_link_task;
+ struct fv_chain_data fv_cdata;
+ struct fv_ring_data fv_rdata;
+ int fv_link_status;
+ int fv_detach;
+};
+
+#define FV_LOCK(_sc) mtx_lock(&(_sc)->fv_mtx)
+#define FV_UNLOCK(_sc) mtx_unlock(&(_sc)->fv_mtx)
+#define FV_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->fv_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->fv_btag, sc->fv_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->fv_btag, sc->fv_bhandle, reg)
+
+
+/* $NetBSD: aereg.h,v 1.2 2008/04/28 20:23:28 martin Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWFV IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE FV DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWFV, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Descriptor Status bits common to transmit and receive.
+ */
+#define ADSTAT_OWN 0x80000000 /* Tulip owns descriptor */
+#define ADSTAT_ES 0x00008000 /* Error Summary */
+
+/*
+ * Descriptor Status bits for Receive Descriptor.
+ */
+#define ADSTAT_Rx_FF 0x40000000 /* Filtering Fail */
+#define ADSTAT_Rx_FL 0x3fff0000 /* Frame Length including CRC */
+#define ADSTAT_Rx_DE 0x00004000 /* Descriptor Error */
+#define ADSTAT_Rx_LE 0x00001000 /* Length Error */
+#define ADSTAT_Rx_RF 0x00000800 /* Runt Frame */
+#define ADSTAT_Rx_MF 0x00000400 /* Multicast Frame */
+#define ADSTAT_Rx_FS 0x00000200 /* First Descriptor */
+#define ADSTAT_Rx_LS 0x00000100 /* Last Descriptor */
+#define ADSTAT_Rx_TL 0x00000080 /* Frame Too Long */
+#define ADSTAT_Rx_CS 0x00000040 /* Collision Seen */
+#define ADSTAT_Rx_RT 0x00000020 /* Frame Type */
+#define ADSTAT_Rx_RW 0x00000010 /* Receive Watchdog */
+#define ADSTAT_Rx_RE 0x00000008 /* Report on MII Error */
+#define ADSTAT_Rx_DB 0x00000004 /* Dribbling Bit */
+#define ADSTAT_Rx_CE 0x00000002 /* CRC Error */
+#define ADSTAT_Rx_ZER 0x00000001 /* Zero (always 0) */
+
+#define ADSTAT_Rx_LENGTH(x) (((x) & ADSTAT_Rx_FL) >> 16)
+
+/*
+ * Descriptor Status bits for Transmit Descriptor.
+ */
+#define ADSTAT_Tx_ES 0x00008000 /* Error Summary */
+#define ADSTAT_Tx_TO 0x00004000 /* Transmit Jabber Timeout */
+#define ADSTAT_Tx_LO 0x00000800 /* Loss of Carrier */
+#define ADSTAT_Tx_NC 0x00000400 /* No Carrier */
+#define ADSTAT_Tx_LC 0x00000200 /* Late Collision */
+#define ADSTAT_Tx_EC 0x00000100 /* Excessive Collisions */
+#define ADSTAT_Tx_HF 0x00000080 /* Heartbeat Fail */
+#define ADSTAT_Tx_CC 0x00000078 /* Collision Count */
+#define ADSTAT_Tx_ED 0x00000004 /* Excessive Deferral */
+#define ADSTAT_Tx_UF 0x00000002 /* Underflow Error */
+#define ADSTAT_Tx_DE 0x00000001 /* Deferred */
+
+#define ADSTAT_Tx_COLLISIONS(x) (((x) & ADSTAT_Tx_CC) >> 3)
+
+/*
+ * Descriptor Control bits common to transmit and receive.
+ */
+#define ADCTL_SIZE1 0x000007ff /* Size of buffer 1 */
+#define ADCTL_SIZE1_SHIFT 0
+
+#define ADCTL_SIZE2 0x003ff800 /* Size of buffer 2 */
+#define ADCTL_SIZE2_SHIFT 11
+
+#define ADCTL_ER 0x02000000 /* End of Ring */
+#define ADCTL_CH 0x01000000 /* Second Address Chained */
+
+/*
+ * Descriptor Control bits for Transmit Descriptor.
+ */
+#define ADCTL_Tx_IC 0x80000000 /* Interrupt on Completion */
+#define ADCTL_Tx_LS 0x40000000 /* Last Segment */
+#define ADCTL_Tx_FS 0x20000000 /* First Segment */
+#define ADCTL_Tx_SETUP 0x08000000 /* Setup frame */
+#define ADCTL_Tx_AC 0x04000000 /* Add CRC Disable */
+#define ADCTL_Tx_DPD 0x00800000 /* Disabled Padding */
+
+/*
+ * Control registers.
+ */
+
+/* tese are registers only found on this part */
+#ifdef NOTUSE
+#define CSR_MACCTL 0x0000 /* mac control */
+#define CSR_MACHI 0x0004
+#define CSR_MACLO 0x0008
+#define CSR_HTHI 0x000C /* multicast table high */
+#define CSR_HTLO 0x0010 /* multicast table low */
+#define CSR_MIIADDR 0x0014 /* mii address */
+#define CSR_MIIDATA 0x0018 /* mii data */
+#define CSR_FLOWC 0x001C /* flow control */
+#define CSR_VL1 0x0020 /* vlan 1 tag */
+#endif
+
+/* these are more or less normal Tulip registers */
+#define CSR_BUSMODE (0x08*0) /* bus mode */
+#define CSR_TXPOLL (0x08*1) /* tx poll demand */
+#define CSR_RXPOLL (0x08*2) /* rx poll demand */
+#define CSR_RXLIST (0x08*3) /* rx base descriptor address */
+#define CSR_TXLIST (0x08*4) /* tx base descriptor address */
+#define CSR_STATUS (0x08*5) /* (interrupt) status */
+#define CSR_OPMODE (0x08*6) /* operation mode */
+#define CSR_INTEN (0x08*7) /* interrupt enable */
+#define CSR_MISSED (0x08*8) /* missed frame counter */
+
+#ifdef NOTUSE
+#define CSR_HTBA 0x1050 /* host tx buffer address (ro) */
+#define CSR_HRBA 0x1054 /* host rx buffer address (ro) */
+#endif
+
+#define CSR_MIIMNG (0x08*9) /* MII Management Register */
+#define CSR_FULLDUP (0x08*11) /* Full Duplex Register */
+
+/* 21143 like register */
+#define FULLDUP_CS 0x80000000 /* Cycle Size */
+#define FULLDUP_TT_SHIFT 27 /* Transmit Timer */
+#define FULLDUP_NTP_SHIFT 24 /* Number of Transmit Packets */
+#define FULLDUP_RT_SHIFT 20 /* Receive Timer */
+#define FULLDUP_NRP_SHIFT 17 /* Number of Receive Packets */
+#define FULLDUP_CON_MODE 0x00010000 /* Continuous Mode */
+#define FULLDUP_TIM_SHIFT 0 /* Timer Value */
+
+/* CSR_MACCTL - Mac Control */
+#define MACCTL_RE 0x00000004 /* rx enable */
+#define MACCTL_TE 0x00000008 /* tx enable */
+#define MACCTL_DC 0x00000020 /* deferral check */
+#define MACCTL_PSTR 0x00000100 /* automatic pad strip */
+#define MACCTL_DTRY 0x00000400 /* disable retry */
+#define MACCTL_DBF 0x00000800 /* disable broadcast frames */
+#define MACCTL_LCC 0x00001000 /* late collision control */
+#define MACCTL_HASH 0x00002000 /* hash filtering enable */
+#define MACCTL_HO 0x00008000 /* disable perfect filtering */
+#define MACCTL_PB 0x00010000 /* pass bad frames */
+#define MACCTL_IF 0x00020000 /* inverse filtering */
+#define MACCTL_PR 0x00040000 /* promiscuous mode */
+#define MACCTL_PM 0x00080000 /* pass all multicast */
+#define MACCTL_FDX 0x00100000 /* full duplex mode */
+#define MACCTL_LOOP 0x00600000 /* loopback mask */
+#define MACCTL_LOOP_INT 0x00200000 /* internal loopback */
+#define MACCTL_LOOP_EXT 0x00400000 /* external loopback */
+#define MACCTL_LOOP_NONE 0x00000000
+#define MACCTL_DRO 0x00800000 /* disable receive own */
+#define MACCTL_PS 0x08000000 /* port select, 0 = mii */
+#define MACCTL_HBD 0x10000000 /* heartbeat disable */
+#define MACCTL_BLE 0x40000000 /* mac big endian */
+#define MACCTL_RA 0x80000000 /* receive all packets */
+
+/* CSR_MIIADDR - MII Addess */
+#define MIIADDR_BUSY 0x00000001 /* mii busy */
+#define MIIADDR_WRITE 0x00000002 /* mii write */
+#define MIIADDR_REG_MASK 0x000007C0 /* mii register */
+#define MIIADDR_REG_SHIFT 6
+#define MIIADDR_PHY_MASK 0x0000F800 /* mii phy */
+#define MIIADDR_PHY_SHIFT 11
+
+#define MIIADDR_GETREG(x) (((x) & MIIADDR_REG) >> 6)
+#define MIIADDR_PUTREG(x) (((x) << 6) & MIIADR_REG)
+#define MIIADDR_GETPHY(x) (((x) & MIIADDR_PHY) >> 11)
+#define MIIADDR_PUTPHY(x) (((x) << 6) & MIIADR_PHY)
+
+/* CSR_FLOWC - Flow Control */
+#define FLOWC_FCB 0x00000001 /* flow control busy */
+#define FLOWC_FCE 0x00000002 /* flow control enable */
+#define FLOWC_PCF 0x00000004 /* pass control frames */
+#define FLOWC_PT 0xffff0000 /* pause time */
+
+/* CSR_BUSMODE - Bus Mode */
+#define BUSMODE_SWR 0x00000001 /* software reset */
+#define BUSMODE_BAR 0x00000002 /* bus arbitration */
+#define BUSMODE_DSL 0x0000007c /* descriptor skip length */
+#define BUSMODE_BLE 0x00000080 /* data buf endian */
+ /* programmable burst length */
+#define BUSMODE_PBL_DEFAULT 0x00000000 /* default value */
+#define BUSMODE_PBL_1LW 0x00000100 /* 1 longword */
+#define BUSMODE_PBL_2LW 0x00000200 /* 2 longwords */
+#define BUSMODE_PBL_4LW 0x00000400 /* 4 longwords */
+#define BUSMODE_PBL_8LW 0x00000800 /* 8 longwords */
+#define BUSMODE_PBL_16LW 0x00001000 /* 16 longwords */
+#define BUSMODE_PBL_32LW 0x00002000 /* 32 longwords */
+#define BUSMODE_TAP_SHIFT 17 /* Transmit Automatic Polling */
+#define BUSMODE_DBO 0x00100000 /* descriptor endian */
+#define BUSMODE_ALIGN_16B 0x01000000 /* force oddhw rx buf align */
+
+/* CSR_TXPOLL - Transmit Poll Demand */
+#define TXPOLL_TPD 0x00000001 /* transmit poll demand */
+
+
+/* CSR_RXPOLL - Receive Poll Demand */
+#define RXPOLL_RPD 0x00000001 /* receive poll demand */
+
+/* CSR_STATUS - Status */
+#define STATUS_TI 0x00000001 /* transmit interrupt */
+#define STATUS_TPS 0x00000002 /* transmit process stopped */
+#define STATUS_TU 0x00000004 /* transmit buffer unavail */
+#define STATUS_TJT 0x00000008 /* transmit jabber timeout */
+#define STATUS_UNF 0x00000020 /* transmit underflow */
+#define STATUS_RI 0x00000040 /* receive interrupt */
+#define STATUS_RU 0x00000080 /* receive buffer unavail */
+#define STATUS_RPS 0x00000100 /* receive process stopped */
+#define STATUS_ETI 0x00000400 /* early transmit interrupt */
+#define STATUS_SE 0x00002000 /* system error */
+#define STATUS_ER 0x00004000 /* early receive (21041) */
+#define STATUS_AIS 0x00008000 /* abnormal intr summary */
+#define STATUS_NIS 0x00010000 /* normal interrupt summary */
+#define STATUS_RS 0x000e0000 /* receive process state */
+#define STATUS_RS_STOPPED 0x00000000 /* Stopped */
+#define STATUS_RS_FETCH 0x00020000 /* Running - fetch receive
+ descriptor */
+#define STATUS_RS_CHECK 0x00040000 /* Running - check for end
+ of receive */
+#define STATUS_RS_WAIT 0x00060000 /* Running - wait for packet */
+#define STATUS_RS_SUSPENDED 0x00080000 /* Suspended */
+#define STATUS_RS_CLOSE 0x000a0000 /* Running - close receive
+ descriptor */
+#define STATUS_RS_FLUSH 0x000c0000 /* Running - flush current
+ frame from FIFO */
+#define STATUS_RS_QUEUE 0x000e0000 /* Running - queue current
+ frame from FIFO into
+ buffer */
+#define STATUS_TS 0x00700000 /* transmit process state */
+#define STATUS_TS_STOPPED 0x00000000 /* Stopped */
+#define STATUS_TS_FETCH 0x00100000 /* Running - fetch transmit
+ descriptor */
+#define STATUS_TS_WAIT 0x00200000 /* Running - wait for end
+ of transmission */
+#define STATUS_TS_READING 0x00300000 /* Running - read buffer from
+ memory and queue into
+ FIFO */
+#define STATUS_TS_SUSPENDED 0x00600000 /* Suspended */
+#define STATUS_TS_CLOSE 0x00700000 /* Running - close transmit
+ descriptor */
+#define STATUS_TX_ABORT 0x00800000 /* Transmit bus abort */
+#define STATUS_RX_ABORT 0x01000000 /* Transmit bus abort */
+
+/* CSR_OPMODE - Operation Mode */
+#define OPMODE_SR 0x00000002 /* start receive */
+#define OPMODE_OSF 0x00000004 /* operate on second frame */
+#define OPMODE_PR 0x00000040 /* promiscuous mode */
+#define OPMODE_PM 0x00000080 /* pass all multicast */
+#define OPMODE_FDX 0x00000200 /* full duplex mode */
+#define OPMODE_ST 0x00002000 /* start transmitter */
+#define OPMODE_TR 0x0000c000 /* threshold control */
+#define OPMODE_TR_32 0x00000000 /* 32 words */
+#define OPMODE_TR_64 0x00004000 /* 64 words */
+#define OPMODE_TR_128 0x00008000 /* 128 words */
+#define OPMODE_TR_256 0x0000c000 /* 256 words */
+#define OPMODE_SF 0x00200000 /* store and forward mode */
+#define OPMODE_SPEED 0x80000000 /* speed 100M:1 10M:0 */
+
+/* CSR_INTEN - Interrupt Enable */
+ /* See bits for CSR_STATUS -- Status */
+
+
+/* CSR_MISSED - Missed Frames */
+#define MISSED_MFC 0xffff0000 /* missed packet count */
+#define MISSED_FOC 0x0000ffff /* fifo overflow counter */
+
+#define MISSED_GETMFC(x) ((x) & MISSED_MFC)
+#define MISSED_GETFOC(x) (((x) & MISSED_FOC) >> 16)
+
+/* setup frame code refer dc code */
+
+#define FV_SFRAME_LEN 192
+#define FV_MIN_FRAMELEN 60
+
+/*
+ * MII Definitions for the 21041 and 21140/21140A/21142
+ * copy from if_devar.h
+ */
+#define MII_PREAMBLE (~0)
+#define MII_TEST 0xAAAAAAAA
+#define MII_RDCMD 0x06
+#define MII_WRCMD 0x05
+#define MII_DIN 0x00080000
+#define MII_RD 0x00040000
+#define MII_WR 0x00000000
+#define MII_DOUT 0x00020000
+#define MII_CLK 0x00010000
+#define MII_CLKON MII_CLK
+#define MII_CLKOFF MII_CLK
+
+#endif /* __IF_FVREG_H__ */
Index: head/sys/arm/ralink/rt1310_gpio.c
===================================================================
--- head/sys/arm/ralink/rt1310_gpio.c
+++ head/sys/arm/ralink/rt1310_gpio.c
@@ -0,0 +1,480 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * GPIO on RT1310A consist of 2 ports:
+ * - PortA with 8 input/output pins
+ * - PortB with 4 input/output pins
+ *
+ * Pins are mapped to logical pin number as follows:
+ * [0..7] -> GPI_00..GPI_07 (port A)
+ * [8..11] -> GPI_08..GPI_11 (port B)
+ *
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <machine/fdt.h>
+
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ralink/rt1310reg.h>
+#include <arm/ralink/rt1310var.h>
+
+#include "gpio_if.h"
+
+struct rt1310_gpio_softc
+{
+ device_t lg_dev;
+ device_t lg_busdev;
+ struct resource * lg_res;
+ bus_space_tag_t lg_bst;
+ bus_space_handle_t lg_bsh;
+};
+
+struct rt1310_gpio_pinmap
+{
+ int lp_start_idx;
+ int lp_pin_count;
+ int lp_port;
+ int lp_start_bit;
+ int lp_flags;
+};
+
+static const struct rt1310_gpio_pinmap rt1310_gpio_pins[] = {
+ { 0, 8, RT_GPIO_PORTA, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+ { 8, 4, RT_GPIO_PORTB, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+ { -1, -1, -1, -1, -1 },
+};
+
+#define RT_GPIO_NPINS 12
+
+#define RT_GPIO_PIN_IDX(_map, _idx) \
+ (_idx - _map->lp_start_idx)
+
+#define RT_GPIO_PIN_BIT(_map, _idx) \
+ (_map->lp_start_bit + RT_GPIO_PIN_IDX(_map, _idx))
+
+static int rt1310_gpio_probe(device_t);
+static int rt1310_gpio_attach(device_t);
+static int rt1310_gpio_detach(device_t);
+
+static device_t rt1310_gpio_get_bus(device_t);
+static int rt1310_gpio_pin_max(device_t, int *);
+static int rt1310_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
+static int rt1310_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
+static int rt1310_gpio_pin_setflags(device_t, uint32_t, uint32_t);
+static int rt1310_gpio_pin_getname(device_t, uint32_t, char *);
+static int rt1310_gpio_pin_get(device_t, uint32_t, uint32_t *);
+static int rt1310_gpio_pin_set(device_t, uint32_t, uint32_t);
+static int rt1310_gpio_pin_toggle(device_t, uint32_t);
+
+static const struct rt1310_gpio_pinmap *rt1310_gpio_get_pinmap(int);
+
+static struct rt1310_gpio_softc *rt1310_gpio_sc = NULL;
+
+#define rt1310_gpio_read_4(_sc, _reg) \
+ bus_space_read_4(_sc->lg_bst, _sc->lg_bsh, _reg)
+#define rt1310_gpio_write_4(_sc, _reg, _val) \
+ bus_space_write_4(_sc->lg_bst, _sc->lg_bsh, _reg, _val)
+
+static int
+rt1310_gpio_probe(device_t dev)
+{
+ phandle_t node;
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "ralink,rt1310-gpio"))
+ return (ENXIO);
+
+ node = ofw_bus_get_node(dev);
+ if (!OF_hasprop(node, "gpio-controller"))
+ return (ENXIO);
+
+ device_set_desc(dev, "RT1310 GPIO");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rt1310_gpio_attach(device_t dev)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->lg_dev = dev;
+
+ rid = 0;
+ sc->lg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->lg_res) {
+ device_printf(dev, "cannot allocate memory window\n");
+ return (ENXIO);
+ }
+
+ sc->lg_bst = rman_get_bustag(sc->lg_res);
+ sc->lg_bsh = rman_get_bushandle(sc->lg_res);
+
+ rt1310_gpio_sc = sc;
+
+ sc->lg_busdev = gpiobus_attach_bus(dev);
+ if (sc->lg_busdev == NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->lg_res);
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+rt1310_gpio_detach(device_t dev)
+{
+ return (EBUSY);
+}
+
+static device_t
+rt1310_gpio_get_bus(device_t dev)
+{
+ struct rt1310_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->lg_busdev);
+}
+
+static int
+rt1310_gpio_pin_max(device_t dev, int *npins)
+{
+ *npins = RT_GPIO_NPINS - 1;
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ const struct rt1310_gpio_pinmap *map;
+
+ if (pin > RT_GPIO_NPINS)
+ return (ENODEV);
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ *caps = map->lp_flags;
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t state;
+ int dir;
+
+ if (pin > RT_GPIO_NPINS)
+ return (ENODEV);
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ /* Check whether it's bidirectional pin */
+ if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ *flags = map->lp_flags;
+ return (0);
+ }
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PADIR);
+ dir = (state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ case RT_GPIO_PORTB:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PBDIR);
+ dir = (state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ default:
+ panic("unknown GPIO port");
+ }
+
+ *flags = dir ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t dir, state;
+ uint32_t port;
+
+ if (pin > RT_GPIO_NPINS)
+ return (ENODEV);
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ /* Check whether it's bidirectional pin */
+ if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
+ return (ENOTSUP);
+
+ if (flags & GPIO_PIN_INPUT)
+ dir = 0;
+
+ if (flags & GPIO_PIN_OUTPUT)
+ dir = 1;
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ port = RT_GPIO_OFF_PADIR;
+ break;
+ case RT_GPIO_PORTB:
+ port = RT_GPIO_OFF_PBDIR;
+ break;
+ }
+
+ state = rt1310_gpio_read_4(sc, port);
+ if (flags & GPIO_PIN_INPUT) {
+ state &= ~(1 << RT_GPIO_PIN_IDX(map, pin));
+ } else {
+ state |= (1 << RT_GPIO_PIN_IDX(map, pin));
+ }
+ rt1310_gpio_write_4(sc, port, state);
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ snprintf(name, GPIOMAXNAME - 1, "GPIO_%02d", pin);
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t state, flags;
+ int dir;
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ if (rt1310_gpio_pin_getflags(dev, pin, &flags))
+ return (ENXIO);
+
+ if (flags & GPIO_PIN_OUTPUT)
+ dir = 1;
+
+ if (flags & GPIO_PIN_INPUT)
+ dir = 0;
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PADR);
+ *value = !!(state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ case RT_GPIO_PORTB:
+ state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PBDR);
+ *value = !!(state & (1 << RT_GPIO_PIN_BIT(map, pin)));
+ break;
+ }
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
+{
+ struct rt1310_gpio_softc *sc = device_get_softc(dev);
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t state, flags;
+ uint32_t port;
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ if (rt1310_gpio_pin_getflags(dev, pin, &flags))
+ return (ENXIO);
+
+ if ((flags & GPIO_PIN_OUTPUT) == 0)
+ return (EINVAL);
+
+ switch (map->lp_port) {
+ case RT_GPIO_PORTA:
+ port = RT_GPIO_OFF_PADR;
+ break;
+ case RT_GPIO_PORTB:
+ port = RT_GPIO_OFF_PBDR;
+ break;
+ }
+
+ state = rt1310_gpio_read_4(sc, port);
+ if (value == 1) {
+ state |= (1 << RT_GPIO_PIN_BIT(map, pin));
+ } else {
+ state &= ~(1 << RT_GPIO_PIN_BIT(map, pin));
+ }
+ rt1310_gpio_write_4(sc, port, state);
+
+ return (0);
+}
+
+static int
+rt1310_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ const struct rt1310_gpio_pinmap *map;
+ uint32_t flags;
+
+ map = rt1310_gpio_get_pinmap(pin);
+
+ if (rt1310_gpio_pin_getflags(dev, pin, &flags))
+ return (ENXIO);
+
+ if ((flags & GPIO_PIN_OUTPUT) == 0)
+ return (EINVAL);
+
+ panic("not implemented yet");
+
+ return (0);
+
+}
+
+static const struct rt1310_gpio_pinmap *
+rt1310_gpio_get_pinmap(int pin)
+{
+ const struct rt1310_gpio_pinmap *map;
+
+ for (map = &rt1310_gpio_pins[0]; map->lp_start_idx != -1; map++) {
+ if (pin >= map->lp_start_idx &&
+ pin < map->lp_start_idx + map->lp_pin_count)
+ return map;
+ }
+
+ panic("pin number %d out of range", pin);
+}
+
+int
+rt1310_gpio_set_flags(device_t dev, int pin, int flags)
+{
+ if (rt1310_gpio_sc == NULL)
+ return (ENXIO);
+
+ return rt1310_gpio_pin_setflags(rt1310_gpio_sc->lg_dev, pin, flags);
+}
+
+int
+rt1310_gpio_set_state(device_t dev, int pin, int state)
+{
+ if (rt1310_gpio_sc == NULL)
+ return (ENXIO);
+
+ return rt1310_gpio_pin_set(rt1310_gpio_sc->lg_dev, pin, state);
+}
+
+int
+rt1310_gpio_get_state(device_t dev, int pin, int *state)
+{
+ if (rt1310_gpio_sc == NULL)
+ return (ENXIO);
+
+ return rt1310_gpio_pin_get(rt1310_gpio_sc->lg_dev, pin, state);
+}
+
+static phandle_t
+rt1310_gpio_get_node(device_t bus, device_t dev)
+{
+ /* We only have one child, the GPIO bus, which needs our own node. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t rt1310_gpio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rt1310_gpio_probe),
+ DEVMETHOD(device_attach, rt1310_gpio_attach),
+ DEVMETHOD(device_detach, rt1310_gpio_detach),
+
+ /* GPIO interface */
+ DEVMETHOD(gpio_get_bus, rt1310_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, rt1310_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getcaps, rt1310_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_getflags, rt1310_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_setflags, rt1310_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_getname, rt1310_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_set, rt1310_gpio_pin_set),
+ DEVMETHOD(gpio_pin_get, rt1310_gpio_pin_get),
+ DEVMETHOD(gpio_pin_toggle, rt1310_gpio_pin_toggle),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, rt1310_gpio_get_node),
+
+ { 0, 0 }
+};
+
+static devclass_t rt1310_gpio_devclass;
+
+static driver_t rt1310_gpio_driver = {
+ "gpio",
+ rt1310_gpio_methods,
+ sizeof(struct rt1310_gpio_softc),
+};
+
+DRIVER_MODULE(rt1310gpio, simplebus, rt1310_gpio_driver, rt1310_gpio_devclass, 0, 0);
+MODULE_VERSION(rt1310gpio, 1);
Index: head/sys/arm/ralink/rt1310_intc.c
===================================================================
--- head/sys/arm/ralink/rt1310_intc.c
+++ head/sys/arm/ralink/rt1310_intc.c
@@ -0,0 +1,441 @@
+/*-
+ * Copyright (c) 2010 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ralink/rt1310reg.h>
+
+#define INTC_NIRQS 32
+
+#ifdef INTRNG
+#include "pic_if.h"
+
+struct rt1310_irqsrc {
+ struct intr_irqsrc ri_isrc;
+ u_int ri_irq;
+};
+#endif
+
+struct rt1310_intc_softc {
+ device_t dev;
+ struct resource * ri_res;
+ bus_space_tag_t ri_bst;
+ bus_space_handle_t ri_bsh;
+#ifdef INTRNG
+ struct rt1310_irqsrc ri_isrcs[INTC_NIRQS];
+#endif
+};
+
+static int rt1310_intc_probe(device_t);
+static int rt1310_intc_attach(device_t);
+#ifndef INTRNG
+static void rt1310_intc_eoi(void *);
+#else
+static int rt1310_pic_attach(struct rt1310_intc_softc *sc);
+#endif
+
+static struct rt1310_intc_softc *intc_softc = NULL;
+
+#define intc_read_4(_sc, _reg) \
+ bus_space_read_4((_sc)->ri_bst, (_sc)->ri_bsh, (_reg))
+#define intc_write_4(_sc, _reg, _val) \
+ bus_space_write_4((_sc)->ri_bst, (_sc)->ri_bsh, (_reg), (_val))
+
+struct rt1310_irqdef {
+ u_int ri_trig;
+ u_int ri_prio;
+};
+
+struct rt1310_irqdef irqdef[INTC_NIRQS] = {
+ {RT_INTC_TRIG_HIGH_LVL, 2}, /* 0 */
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 1}, /* 8 */
+ {RT_INTC_TRIG_HIGH_LVL, 1},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 4},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2}, /* 16 */
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_LOW_LVL, 2},
+ {RT_INTC_TRIG_NEG_EDGE, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 3},
+ {RT_INTC_TRIG_HIGH_LVL, 2}, /* 24 */
+ {RT_INTC_TRIG_POS_EDGE, 2},
+ {RT_INTC_TRIG_POS_EDGE, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_HIGH_LVL, 2},
+ {RT_INTC_TRIG_POS_EDGE, 2},
+ {RT_INTC_TRIG_POS_EDGE, 3},
+ {RT_INTC_TRIG_POS_EDGE, 3},
+};
+
+static int
+rt1310_intc_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "rt,pic"))
+ return (ENXIO);
+
+#ifdef INTRNG
+ device_set_desc(dev, "RT1310 INTRNG Interrupt Controller");
+#else
+ device_set_desc(dev, "RT1310 Interrupt Controller");
+#endif
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rt1310_intc_attach(device_t dev)
+{
+ struct rt1310_intc_softc *sc = device_get_softc(dev);
+ int rid = 0;
+ int i;
+
+ if (intc_softc)
+ return (ENXIO);
+
+ sc->dev = dev;
+
+ sc->ri_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->ri_res) {
+ device_printf(dev, "could not alloc resources\n");
+ return (ENXIO);
+ }
+
+ sc->ri_bst = rman_get_bustag(sc->ri_res);
+ sc->ri_bsh = rman_get_bushandle(sc->ri_res);
+ intc_softc = sc;
+#ifndef INTRNG
+ arm_post_filter = rt1310_intc_eoi;
+#else
+ rt1310_pic_attach(sc);
+#endif
+
+ intc_write_4(sc, RT_INTC_IECR, 0);
+ intc_write_4(sc, RT_INTC_ICCR, ~0);
+
+ for (i = 0; i <= INTC_NIRQS; ++i) {
+ intc_write_4(sc, RT_INTC_SCR0+i*4,
+ (irqdef[i].ri_trig << RT_INTC_TRIG_SHIF) |
+ irqdef[i].ri_prio);
+ intc_write_4(sc, RT_INTC_SVR0+i*4, i);
+ }
+
+ /* Clear interrupt status registers and disable all interrupts */
+ intc_write_4(sc, RT_INTC_ICCR, ~0);
+ intc_write_4(sc, RT_INTC_IMR, 0);
+ return (0);
+}
+
+#ifndef INTRNG
+int
+arm_get_next_irq(int last)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ uint32_t value;
+ int i;
+ value = intc_read_4(sc, RT_INTC_IPR);
+ for (i = 0; i < 32; i++) {
+ if (value & (1 << i))
+ return (i);
+ }
+
+ return (-1);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ uint32_t value;
+
+ /* Make sure that interrupt isn't active already */
+ rt1310_intc_eoi((void *)nb);
+
+ /* Clear bit in ER register */
+ value = intc_read_4(sc, RT_INTC_IECR);
+ value &= ~(1 << nb);
+ intc_write_4(sc, RT_INTC_IECR, value);
+ intc_write_4(sc, RT_INTC_IMR, value);
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << nb);
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ uint32_t value;
+
+ value = intc_read_4(sc, RT_INTC_IECR);
+
+ value |= (1 << nb);
+
+ intc_write_4(sc, RT_INTC_IMR, value);
+ intc_write_4(sc, RT_INTC_IECR, value);
+}
+
+static void
+rt1310_intc_eoi(void *data)
+{
+ struct rt1310_intc_softc *sc = intc_softc;
+ int nb = (int)data;
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << nb);
+ if (nb == 0) {
+ uint32_t value;
+ value = intc_read_4(sc, RT_INTC_IECR);
+ value &= ~(1 << nb);
+ intc_write_4(sc, RT_INTC_IECR, value);
+ intc_write_4(sc, RT_INTC_IMR, value);
+ }
+}
+
+#else
+
+static void
+rt1310_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+ unsigned int value;
+ struct rt1310_intc_softc *sc;
+
+ sc = intc_softc;
+ irq = ((struct rt1310_irqsrc *)isrc)->ri_irq;
+
+ value = intc_read_4(sc, RT_INTC_IECR);
+
+ value |= (1 << irq);
+
+ intc_write_4(sc, RT_INTC_IMR, value);
+ intc_write_4(sc, RT_INTC_IECR, value);
+}
+
+static void
+rt1310_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+ unsigned int value;
+ struct rt1310_intc_softc *sc;
+
+ sc = intc_softc;
+ irq = ((struct rt1310_irqsrc *)isrc)->ri_irq;
+
+ /* Clear bit in ER register */
+ value = intc_read_4(sc, RT_INTC_IECR);
+ value &= ~(1 << irq);
+ intc_write_4(sc, RT_INTC_IECR, value);
+ intc_write_4(sc, RT_INTC_IMR, value);
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << irq);
+}
+
+static int
+rt1310_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct intr_map_data_fdt *daf;
+ struct rt1310_intc_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
+
+ daf = (struct intr_map_data_fdt *)data;
+
+ if (daf->ncells != 1 || daf->cells[0] >= INTC_NIRQS)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ *isrcp = &sc->ri_isrcs[daf->cells[0]].ri_isrc;
+ return (0);
+}
+
+static void
+rt1310_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ arm_irq_memory_barrier(0);
+ rt1310_disable_intr(dev, isrc);
+}
+
+static void
+rt1310_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ arm_irq_memory_barrier(0);
+ rt1310_enable_intr(dev, isrc);
+}
+
+static void
+rt1310_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+ struct rt1310_intc_softc *sc;
+
+ arm_irq_memory_barrier(0);
+ sc = intc_softc;
+ irq = ((struct rt1310_irqsrc *)isrc)->ri_irq;
+
+ intc_write_4(sc, RT_INTC_ICCR, 1 << irq);
+}
+
+static int
+rt1310_intr(void *arg)
+{
+ uint32_t irq;
+ struct rt1310_intc_softc *sc = arg;
+
+ irq = ffs(intc_read_4(sc, RT_INTC_IPR)) - 1;
+
+ if (intr_isrc_dispatch(&sc->ri_isrcs[irq].ri_isrc,
+ curthread->td_intr_frame) != 0) {
+ intc_write_4(sc, RT_INTC_ICCR, 1 << irq);
+ device_printf(sc->dev, "Stray irq %u disabled\n", irq);
+ }
+
+ arm_irq_memory_barrier(0);
+
+ return (FILTER_HANDLED);
+}
+
+static int
+rt1310_pic_attach(struct rt1310_intc_softc *sc)
+{
+ struct intr_pic *pic;
+ int error;
+ uint32_t irq;
+ const char *name;
+ intptr_t xref;
+
+ name = device_get_nameunit(sc->dev);
+ for (irq = 0; irq < INTC_NIRQS; irq++) {
+ sc->ri_isrcs[irq].ri_irq = irq;
+
+ error = intr_isrc_register(&sc->ri_isrcs[irq].ri_isrc,
+ sc->dev, 0, "%s,%u", name, irq);
+ if (error != 0)
+ return (error);
+ }
+
+ xref = OF_xref_from_node(ofw_bus_get_node(sc->dev));
+ pic = intr_pic_register(sc->dev, xref);
+ if (pic == NULL)
+ return (ENXIO);
+
+ return (intr_pic_claim_root(sc->dev, xref, rt1310_intr, sc, 0));
+}
+#endif
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+#ifndef INTRNG
+static int
+fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+ int *pol)
+{
+ if (!fdt_is_compatible(node, "lpc,pic"))
+ return (ENXIO);
+
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+ return (0);
+}
+
+fdt_pic_decode_t fdt_pic_table[] = {
+ &fdt_pic_decode_ic,
+ NULL
+};
+#endif
+
+static device_method_t rt1310_intc_methods[] = {
+ DEVMETHOD(device_probe, rt1310_intc_probe),
+ DEVMETHOD(device_attach, rt1310_intc_attach),
+#ifdef INTRNG
+ DEVMETHOD(pic_disable_intr, rt1310_disable_intr),
+ DEVMETHOD(pic_enable_intr, rt1310_enable_intr),
+ DEVMETHOD(pic_map_intr, rt1310_map_intr),
+ DEVMETHOD(pic_post_filter, rt1310_post_filter),
+ DEVMETHOD(pic_post_ithread, rt1310_post_ithread),
+ DEVMETHOD(pic_pre_ithread, rt1310_pre_ithread),
+#endif
+ { 0, 0 }
+};
+
+static driver_t rt1310_intc_driver = {
+ "pic",
+ rt1310_intc_methods,
+ sizeof(struct rt1310_intc_softc),
+};
+
+static devclass_t rt1310_intc_devclass;
+
+EARLY_DRIVER_MODULE(pic, simplebus, rt1310_intc_driver, rt1310_intc_devclass, 0, 0, BUS_PASS_INTERRUPT);
Index: head/sys/arm/ralink/rt1310_machdep.c
===================================================================
--- head/sys/arm/ralink/rt1310_machdep.c
+++ head/sys/arm/ralink/rt1310_machdep.c
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: FreeBSD: sys/arm/lpc/lpc_machdep.c
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/reboot.h>
+#include <sys/devmap.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/machdep.h>
+#include <machine/platform.h>
+#include <machine/cpu.h>
+
+#include <arm/ralink/rt1310reg.h>
+#include <arm/ralink/rt1310var.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#ifdef EARLY_PRINTF
+early_putc_t *early_putc;
+#endif
+
+
+uint32_t rt1310_master_clock;
+
+vm_offset_t
+platform_lastaddr(void)
+{
+
+ return (devmap_lastaddr());
+}
+
+void
+platform_probe_and_attach(void)
+{
+}
+
+void
+platform_gpio_init(void)
+{
+
+ /*
+ * Set initial values of GPIO output ports
+ */
+}
+
+void
+platform_late_init(void)
+{
+ bootverbose = 1;
+}
+
+/*
+ * Add a single static device mapping.
+ * The values used were taken from the ranges property of the SoC node in the
+ * dts file when this code was converted to arm_devmap_add_entry().
+ */
+int
+platform_devmap_init(void)
+{
+ devmap_add_entry(0x19C00000, 0xE0000);
+ devmap_add_entry(0x1e800000, 0x800000);
+ devmap_add_entry(0x1f000000, 0x400000);
+ return (0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+ return (0);
+}
+
+void
+cpu_reset(void)
+{
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ bst = fdtbus_bs_tag;
+
+ /* Enable WDT */
+ /* Instant assert of RESETOUT_N with pulse length 1ms */
+ bus_space_map(bst, 0x1e8c0000, 0x20000, 0, &bsh);
+ bus_space_write_4(bst, bsh, 0, 13000);
+ bus_space_write_4(bst, bsh, 8, (1<<3) | (1<<4) | 7);
+ bus_space_unmap(bst, bsh, 0x20000);
+
+ for (;;)
+ continue;
+}
+
+#ifdef RALINK_BOOT_DEBUG
+void bootdebug1(int c);
+void bootdebug1(int c)
+{
+ /* direct put uart physical address */
+ uint8_t* uart_base_addr=(uint8_t*)0x1e840000;
+ *(uart_base_addr) = c;
+}
+
+void bootdebug2(int c);
+void bootdebug2(int c)
+{
+#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
+ /* direct put uart map address at locore-v4.S */
+ uint8_t* uart_base_addr=(uint8_t*)0xce840000;
+ *(uart_base_addr) = c;
+#endif
+}
+
+void bootdebug3(int c);
+void bootdebug3(int c)
+{
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+
+ bst = fdtbus_bs_tag;
+ bus_space_map(bst, 0x1e840000, 0x20000, 0, &bsh);
+ bus_space_write_1(bst, bsh, 0, c);
+ bus_space_unmap(bst, bsh, 0x20000);
+}
+#endif
Index: head/sys/arm/ralink/rt1310_timer.c
===================================================================
--- head/sys/arm/ralink/rt1310_timer.c
+++ head/sys/arm/ralink/rt1310_timer.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <sys/timeet.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ralink/rt1310reg.h>
+#include <arm/ralink/rt1310var.h>
+
+struct rt1310_timer_softc {
+ device_t lt_dev;
+ struct eventtimer lt_et;
+ struct resource * lt_res[8];
+ bus_space_tag_t lt_bst0;
+ bus_space_handle_t lt_bsh0;
+ bus_space_tag_t lt_bst1;
+ bus_space_handle_t lt_bsh1;
+ bus_space_tag_t lt_bst2;
+ bus_space_handle_t lt_bsh2;
+ bus_space_tag_t lt_bst3;
+ bus_space_handle_t lt_bsh3;
+ int lt_oneshot;
+ uint32_t lt_period;
+};
+
+static struct resource_spec rt1310_timer_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_MEMORY, 1, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE },
+ { SYS_RES_MEMORY, 3, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static struct rt1310_timer_softc *timer_softc = NULL;
+static int rt1310_timer_initialized = 0;
+static int rt1310_timer_probe(device_t);
+static int rt1310_timer_attach(device_t);
+static int rt1310_timer_start(struct eventtimer *,
+ sbintime_t first, sbintime_t period);
+static int rt1310_timer_stop(struct eventtimer *et);
+static unsigned rt1310_get_timecount(struct timecounter *);
+static int rt1310_hardclock(void *);
+
+#define timer0_read_4(sc, reg) \
+ bus_space_read_4(sc->lt_bst0, sc->lt_bsh0, reg)
+#define timer0_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst0, sc->lt_bsh0, reg, val)
+#define timer0_clear(sc) \
+ do { \
+ timer0_write_4(sc, RT_TIMER_LOAD, 0); \
+ timer0_write_4(sc, RT_TIMER_VALUE, 0); \
+ } while(0)
+
+#define timer1_read_4(sc, reg) \
+ bus_space_read_4(sc->lt_bst1, sc->lt_bsh1, reg)
+#define timer1_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst1, sc->lt_bsh1, reg, val)
+#define timer1_clear(sc) \
+ do { \
+ timer1_write_4(sc, RT_TIMER_LOAD, 0); \
+ timer1_write_4(sc, RT_TIMER_VALUE, 0); \
+ } while(0)
+
+#define timer2_read_4(sc, reg) \
+ bus_space_read_4(sc->lt_bst1, sc->lt_bsh2, reg)
+#define timer2_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst2, sc->lt_bsh2, reg, val)
+#define timer3_write_4(sc, reg, val) \
+ bus_space_write_4(sc->lt_bst3, sc->lt_bsh3, reg, val)
+
+
+static struct timecounter rt1310_timecounter = {
+ .tc_get_timecount = rt1310_get_timecount,
+ .tc_name = "RT1310ATimer1",
+ .tc_frequency = 0, /* will be filled later */
+ .tc_counter_mask = ~0u,
+ .tc_quality = 1000,
+};
+
+static int
+rt1310_timer_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "rt,timer"))
+ return (ENXIO);
+
+ device_set_desc(dev, "RT1310 timer");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rt1310_timer_attach(device_t dev)
+{
+ void *intrcookie;
+ struct rt1310_timer_softc *sc = device_get_softc(dev);
+ phandle_t node;
+ uint32_t freq;
+
+ if (timer_softc)
+ return (ENXIO);
+
+ timer_softc = sc;
+
+ if (bus_alloc_resources(dev, rt1310_timer_spec, sc->lt_res)) {
+ device_printf(dev, "could not allocate resources\n");
+ return (ENXIO);
+ }
+
+ sc->lt_bst0 = rman_get_bustag(sc->lt_res[0]);
+ sc->lt_bsh0 = rman_get_bushandle(sc->lt_res[0]);
+ sc->lt_bst1 = rman_get_bustag(sc->lt_res[1]);
+ sc->lt_bsh1 = rman_get_bushandle(sc->lt_res[1]);
+ sc->lt_bst2 = rman_get_bustag(sc->lt_res[2]);
+ sc->lt_bsh2 = rman_get_bushandle(sc->lt_res[2]);
+ sc->lt_bst3 = rman_get_bustag(sc->lt_res[3]);
+ sc->lt_bsh3 = rman_get_bushandle(sc->lt_res[3]);
+
+ /* Timer2 interrupt */
+ if (bus_setup_intr(dev, sc->lt_res[6], INTR_TYPE_CLK,
+ rt1310_hardclock, NULL, sc, &intrcookie)) {
+ device_printf(dev, "could not setup interrupt handler\n");
+ bus_release_resources(dev, rt1310_timer_spec, sc->lt_res);
+ return (ENXIO);
+ }
+
+ /* Enable timer clock */
+/*
+ rt1310_pwr_write(dev, LPC_CLKPWR_TIMCLK_CTRL1,
+ LPC_CLKPWR_TIMCLK_CTRL1_TIMER0 |
+ LPC_CLKPWR_TIMCLK_CTRL1_TIMER1);
+*/
+
+ /* Get PERIPH_CLK encoded in parent bus 'bus-frequency' property */
+
+ node = ofw_bus_get_node(dev);
+ if (OF_getprop(OF_parent(node), "bus-frequency", &freq,
+ sizeof(pcell_t)) <= 0) {
+ bus_release_resources(dev, rt1310_timer_spec, sc->lt_res);
+ bus_teardown_intr(dev, sc->lt_res[2], intrcookie);
+ device_printf(dev, "could not obtain base clock frequency\n");
+ return (ENXIO);
+ }
+
+ freq = fdt32_to_cpu(freq);
+
+ /* Set desired frequency in event timer and timecounter */
+ sc->lt_et.et_frequency = (uint64_t)freq;
+ rt1310_timecounter.tc_frequency = (uint64_t)freq;
+
+ sc->lt_et.et_name = "RT1310ATimer2";
+ sc->lt_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
+ sc->lt_et.et_quality = 1000;
+ sc->lt_et.et_min_period = (0x00000002LLU << 32) / sc->lt_et.et_frequency;
+ sc->lt_et.et_max_period = (0xfffffffeLLU << 32) / sc->lt_et.et_frequency;
+ sc->lt_et.et_start = rt1310_timer_start;
+ sc->lt_et.et_stop = rt1310_timer_stop;
+ sc->lt_et.et_priv = sc;
+
+ et_register(&sc->lt_et);
+ tc_init(&rt1310_timecounter);
+
+ /* Reset and enable timecounter */
+
+ timer0_write_4(sc, RT_TIMER_CONTROL, 0);
+ timer1_write_4(sc, RT_TIMER_CONTROL, 0);
+ timer2_write_4(sc, RT_TIMER_CONTROL, 0);
+ timer3_write_4(sc, RT_TIMER_CONTROL, 0);
+
+ timer1_write_4(sc, RT_TIMER_LOAD, ~0);
+ timer1_write_4(sc, RT_TIMER_VALUE, ~0);
+ timer1_write_4(sc, RT_TIMER_CONTROL,
+ RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_PERIODCAL);
+
+ /* DELAY() now can work properly */
+ rt1310_timer_initialized = 1;
+
+ return (0);
+}
+
+static int
+rt1310_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
+{
+ struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)et->et_priv;
+ uint32_t ticks;
+
+ if (period == 0) {
+ sc->lt_oneshot = 1;
+ sc->lt_period = 0;
+ } else {
+ sc->lt_oneshot = 0;
+ sc->lt_period = ((uint32_t)et->et_frequency * period) >> 32;
+ }
+
+ if (first == 0)
+ ticks = sc->lt_period;
+ else
+ ticks = ((uint32_t)et->et_frequency * first) >> 32;
+
+ /* Reset timer */
+ timer2_write_4(sc, RT_TIMER_CONTROL, 0);
+
+ /* Start timer */
+ timer2_write_4(sc, RT_TIMER_LOAD, ticks);
+ timer2_write_4(sc, RT_TIMER_VALUE, ticks);
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_INTCTL);
+
+ return (0);
+}
+
+static int
+rt1310_timer_stop(struct eventtimer *et)
+{
+ struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)et->et_priv;
+
+ timer2_write_4(sc, RT_TIMER_CONTROL, 0);
+
+ return (0);
+}
+
+static device_method_t rt1310_timer_methods[] = {
+ DEVMETHOD(device_probe, rt1310_timer_probe),
+ DEVMETHOD(device_attach, rt1310_timer_attach),
+ { 0, 0 }
+};
+
+static driver_t rt1310_timer_driver = {
+ "timer",
+ rt1310_timer_methods,
+ sizeof(struct rt1310_timer_softc),
+};
+
+static devclass_t rt1310_timer_devclass;
+
+EARLY_DRIVER_MODULE(timer, simplebus, rt1310_timer_driver, rt1310_timer_devclass, 0, 0, BUS_PASS_TIMER);
+
+static int
+rt1310_hardclock(void *arg)
+{
+ struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)arg;
+
+ /* Reset pending interrupt */
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ timer2_read_4(sc, RT_TIMER_CONTROL) | 0x08);
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ timer2_read_4(sc, RT_TIMER_CONTROL) & 0x1fb);
+
+ /* Start timer again */
+ if (!sc->lt_oneshot) {
+ timer2_write_4(sc, RT_TIMER_LOAD, sc->lt_period);
+ timer2_write_4(sc, RT_TIMER_VALUE, sc->lt_period);
+ timer2_write_4(sc, RT_TIMER_CONTROL,
+ RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_INTCTL);
+ }
+
+ if (sc->lt_et.et_active)
+ sc->lt_et.et_event_cb(&sc->lt_et, sc->lt_et.et_arg);
+
+ return (FILTER_HANDLED);
+}
+
+static unsigned
+rt1310_get_timecount(struct timecounter *tc)
+{
+ return ~timer1_read_4(timer_softc, RT_TIMER_VALUE);
+}
+
+void
+DELAY(int usec)
+{
+ uint32_t counter;
+ uint32_t first, last;
+ int val = (rt1310_timecounter.tc_frequency / 1000000 + 1) * usec;
+
+ /* Timer is not initialized yet */
+ if (!rt1310_timer_initialized) {
+ for (; usec > 0; usec--)
+ for (counter = 100; counter > 0; counter--)
+ ;
+ return;
+ }
+
+ first = rt1310_get_timecount(&rt1310_timecounter);
+ while (val > 0) {
+ last = rt1310_get_timecount(&rt1310_timecounter);
+ if (last < first) {
+ /* Timer rolled over */
+ last = first;
+ }
+
+ val -= (last - first);
+ first = last;
+ }
+}
Index: head/sys/arm/ralink/rt1310reg.h
===================================================================
--- head/sys/arm/ralink/rt1310reg.h
+++ head/sys/arm/ralink/rt1310reg.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM_RALINK_RT1310REG_H
+#define _ARM_RALINK_RT1310REG_H
+
+/*
+ * Interrupt controller
+ */
+
+#define RT_INTC_SCR0 0x00
+#define RT_INTC_SVR0 0x80
+#define RT_INTC_ISR 0x104
+#define RT_INTC_IPR 0x108
+#define RT_INTC_IMR 0x10c
+#define RT_INTC_IECR 0x114
+#define RT_INTC_ICCR 0x118
+
+#define RT_INTC_TRIG_LOW_LVL (0)
+#define RT_INTC_TRIG_HIGH_LVL (1)
+#define RT_INTC_TRIG_NEG_EDGE (2)
+#define RT_INTC_TRIG_POS_EDGE (3)
+
+#define RT_INTC_TRIG_SHIF 6
+
+/*
+ * Timer 0|1|2|3.
+ */
+
+#define RT_TIMER_LOAD 0x00
+#define RT_TIMER_VALUE 0x04
+#define RT_TIMER_CONTROL 0x08
+
+#define RT_TIMER_CTRL_INTCTL (1 << 1)
+#define RT_TIMER_CTRL_INTCLR (1 << 2)
+#define RT_TIMER_CTRL_INTMASK (1 << 3)
+#define RT_TIMER_CTRL_DIV16 (3 << 4)
+#define RT_TIMER_CTRL_DIV256 (7 << 4)
+#define RT_TIMER_CTRL_PERIODCAL (1 << 7)
+#define RT_TIMER_CTRL_ENABLE (1 << 8)
+
+#define RT_TIMER_INTERVAL (5000*150)
+
+/*
+ * GPIO
+ */
+
+#define RT_GPIO_PORTA (0)
+#define RT_GPIO_PORTB (1)
+
+#define RT_GPIO_OFF_PADR (0x0)
+#define RT_GPIO_OFF_PADIR (0x4)
+#define RT_GPIO_OFF_PBDR (0x8)
+#define RT_GPIO_OFF_PBDIR (0xC)
+
+#endif /* _ARM_RALINK_RT1310REG_H */
Index: head/sys/arm/ralink/rt1310var.h
===================================================================
--- head/sys/arm/ralink/rt1310var.h
+++ head/sys/arm/ralink/rt1310var.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _ARM_RT_RTVAR_H
+#define _ARM_RT_RTVAR_H
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+/* Clocking and power control */
+uint32_t lpc_pwr_read(device_t, int);
+void lpc_pwr_write(device_t, int, uint32_t);
+
+/* GPIO */
+void rt1310_gpio_init(void);
+int rt1310_gpio_set_flags(device_t, int, int);
+int rt1310_gpio_set_state(device_t, int, int);
+int rt1310_gpio_get_state(device_t, int, int *);
+
+/* DMA */
+struct lpc_dmac_channel_config
+{
+ int ldc_fcntl;
+ int ldc_src_periph;
+ int ldc_src_width;
+ int ldc_src_incr;
+ int ldc_src_burst;
+ int ldc_dst_periph;
+ int ldc_dst_width;
+ int ldc_dst_incr;
+ int ldc_dst_burst;
+ void (*ldc_success_handler)(void *);
+ void (*ldc_error_handler)(void *);
+ void * ldc_handler_arg;
+};
+
+int lpc_dmac_config_channel(device_t, int, struct lpc_dmac_channel_config *);
+int lpc_dmac_setup_transfer(device_t, int, bus_addr_t, bus_addr_t, bus_size_t, int);
+int lpc_dmac_enable_channel(device_t, int);
+int lpc_dmac_disable_channel(device_t, int);
+int lpc_dmac_start_burst(device_t, int);
+
+extern uint32_t rt1310_master_clock;
+
+#endif /* _ARM_RT_RTVAR_H */
Index: head/sys/boot/fdt/dts/arm/rt1310a.dtsi
===================================================================
--- head/sys/boot/fdt/dts/arm/rt1310a.dtsi
+++ head/sys/boot/fdt/dts/arm/rt1310a.dtsi
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2011 Jakub Klama <jceel@FreeBSD.org>
+ * Copyright (c) 2015 Hiroki Mori
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Ralink RT1310A Device Tree Source.
+ *
+ * $FreeBSD$
+ */
+
+/ {
+ compatible = "ralink,rt1310a-soc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ serial0 = &serial0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "ARM,926EJ-S";
+ reg = <0x0>;
+ d-cache-line-size = <32>; // 32 bytes
+ i-cache-line-size = <32>; // 32 bytes
+ d-cache-size = <0x4000>; // L1, 16K
+ i-cache-size = <0x4000>; // L1, 16K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x1000000>; // 16M at 0x40000000
+ };
+
+ localbus@1f000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x1f000000 0x400000>;
+ };
+
+ ahb@19C00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x19C00000 0xE0000>;
+ bus-frequency = <13000000>;
+
+ PIC: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x40000 0x20000>;
+ compatible = "rt,pic";
+ };
+
+ fvmdio@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fv,mdio";
+ reg = <0x80000 0x20000>;
+ };
+
+ enet0:fv_mac0@80000 {
+ compatible = "fv,ethernet";
+ reg = <0x80000 0x20000>;
+ interrupts = <7>;
+ interrupt-parent = <&PIC>;
+
+ };
+
+ enet1:fv_mac1@A0000 {
+ compatible = "fv,ethernet";
+ reg = <0xA0000 0x20000>;
+ interrupts = <8>;
+ interrupt-parent = <&PIC>;
+ };
+
+ };
+
+ apb@1E800000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x1E800000 0x800000>;
+ bus-frequency = <75000000>;
+
+ timer@000000 {
+ compatible = "rt,timer";
+ reg = <0x0 0x10
+ 0x10 0x10
+ 0x20 0x10
+ 0x30 0x10>;
+ interrupts = <3 4 5>;
+ interrupt-parent = <&PIC>;
+ };
+
+ rtc@20000 {
+ compatible = "rt,rtc";
+ interrupts = <6>;
+ reg = <0x20000 0x20000>;
+ };
+
+ serial0: serial@40000 {
+ compatible = "ns16550";
+ reg = <0x40000 0x20000>;
+ interrupts = <1>;
+ reg-shift = <2>;
+ clock-frequency = <6758400>;
+ current-speed = <38400>;
+ interrupt-parent = <&PIC>;
+ };
+
+ gpio0: gpio@A0000 {
+ compatible = "ralink,rt1310-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <8>;
+ reg = <0xA0000 0x20000>;
+ };
+ };
+
+
+/*
+ chosen {
+ stdin = "serial0";
+ stdout = "serial0";
+ };
+*/
+};
+
Index: head/sys/boot/fdt/dts/arm/wzr2-g300n.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/wzr2-g300n.dts
+++ head/sys/boot/fdt/dts/arm/wzr2-g300n.dts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015 Hiroki Mori
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Buffalo WZR2-G300N Device Tree Source.
+ *
+ * $FreeBSD$
+ */
+
+/dts-v1/;
+
+#include "rt1310a.dtsi"
+
+/ {
+ compatible = "WZR2-G300N", "ralink,rt1310a-soc";
+ model = "WZR2-G300N";
+
+ flash@1f000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x1f000000 0x400000>; // 4M at 0x1f000000
+
+ partition@0 {
+ reg = <0x00000000 0x0000e000>;
+ label = "uboot";
+ };
+ partition@1 {
+ reg = <0x0000e000 0x00002000>;
+ label = "uboot_env";
+ };
+ partition@2 {
+ reg = <0x00010000 0x000f0000>;
+ label = "kernel";
+ };
+ partition@3 {
+ reg = <0x00100000 0x002d0000>;
+ label = "rootfs";
+ };
+ partition@4 {
+ reg = <0x003d0000 0x00010000>;
+ label = "config";
+ };
+ partition@5 {
+ reg = <0x00010000 0x003c0000>;
+ label = "upgrade";
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ status {
+ label = "status";
+ gpios = <&gpio0 4 0>;
+ };
+ };
+
+ ip17x@0 {
+ compatible = "icplus,ip17x";
+ mii-poll = <0>;
+ };
+
+};
+
+&enet0 {
+ local-mac-address = [ 00 1a f1 01 1f 23 ];
+};
+
+&enet1 {
+ local-mac-address = [ 00 1a f1 01 1f 24 ];
+};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 23, 12:28 PM (11 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16791188
Default Alt Text
D7238.diff (115 KB)
Attached To
Mode
D7238: Add support Ralink RT1310 soc
Attached
Detach File
Event Timeline
Log In to Comment