Page MenuHomeFreeBSD

D7237.id19435.diff
No OneTemporary

D7237.id19435.diff

Index: sys/conf/options.mips
===================================================================
--- sys/conf/options.mips
+++ sys/conf/options.mips
@@ -118,6 +118,17 @@
AR71XX_ATH_EEPROM opt_ar71xx.h
#
+# Options for AR531X SOC. AR531X_1ST_GENERATION is AR5311 to AR5314.
+#
+
+AR531X_1ST_GENERATION opt_ar531x.h
+AR531X_REALMEM opt_ar531x.h
+AR531X_ENV_UBOOT opt_ar531x.h
+AR531X_APB_DEBUG opt_ar531x.h
+ARE_MDIO opt_ar531x.h
+ARE_MII opt_ar531x.h
+
+#
# Options that control the Ralink RT305xF Etherenet MAC.
#
IF_RT_DEBUG opt_if_rt.h
Index: sys/geom/geom_redboot.c
===================================================================
--- sys/geom/geom_redboot.c
+++ sys/geom/geom_redboot.c
@@ -40,6 +40,7 @@
#include <sys/bio.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/bus.h>
#include <sys/sbuf.h>
#include <geom/geom.h>
@@ -246,6 +247,16 @@
u_int blksize; /* NB: flash block size stored as stripesize */
u_char *buf;
off_t offset;
+ const char *value;
+ char *op;
+
+ offset = 0;
+ if (resource_string_value("redboot", 0, "fisoffset", &value) == 0) {
+ offset = strtouq(value, &op, 0);
+ if (*op != '\0') {
+ offset = 0;
+ }
+ }
g_trace(G_T_TOPOLOGY, "redboot_taste(%s,%s)", mp->name, pp->name);
g_topology_assert();
@@ -278,7 +289,8 @@
return (NULL);
g_topology_unlock();
head = NULL;
- offset = cp->provider->mediasize - blksize;
+ if(offset == 0)
+ offset = cp->provider->mediasize - blksize;
again:
buf = g_read_data(cp, offset, blksize, NULL);
if (buf != NULL)
Index: sys/mips/atheros/ar531x/apb.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/apb.c
@@ -0,0 +1,756 @@
+/*-
+ * Copyright (c) 2016, Hiroki Mori
+ * Copyright (c) 2009, 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 unmodified, 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 "opt_platform.h"
+#include "opt_ar531x.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/mips/atheros/apb.c 233318 2012-03-22 17:47:52Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+
+#include <machine/bus.h>
+#ifdef INTRNG
+#include <machine/intr.h>
+#else
+#include <machine/intr_machdep.h>
+#endif
+
+#ifdef INTRNG
+#include "pic_if.h"
+
+#define PIC_INTR_ISRC(sc, irq) (&(sc)->pic_irqs[(irq)].isrc)
+#endif
+
+#include <mips/atheros/ar531x/apbvar.h>
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5312reg.h>
+#include <mips/atheros/ar531x/ar5315_setup.h>
+
+#ifdef AR531X_APB_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif /* AR531X_APB_DEBUG */
+
+static int apb_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static device_t apb_add_child(device_t, u_int, const char *, int);
+static struct resource *
+ apb_alloc_resource(device_t, device_t, int, int *, rman_res_t,
+ rman_res_t, rman_res_t, u_int);
+static int apb_attach(device_t);
+static int apb_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static struct resource_list *
+ apb_get_resource_list(device_t, device_t);
+static void apb_hinted_child(device_t, const char *, int);
+static int apb_filter(void *);
+static int apb_probe(device_t);
+static int apb_release_resource(device_t, device_t, int, int,
+ struct resource *);
+#ifndef INTRNG
+static int apb_setup_intr(device_t, device_t, struct resource *, int,
+ driver_filter_t *, driver_intr_t *, void *, void **);
+static int apb_teardown_intr(device_t, device_t, struct resource *,
+ void *);
+#endif
+
+static void
+apb_mask_irq(void *source)
+{
+ unsigned int irq = (unsigned int)source;
+ uint32_t reg;
+
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ reg = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTMASK);
+ ATH_WRITE_REG(AR5315_SYSREG_BASE
+ + AR5315_SYSREG_MISC_INTMASK, reg & ~(1 << irq));
+ } else {
+ reg = ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTMASK);
+ ATH_WRITE_REG(AR5312_SYSREG_BASE
+ + AR5312_SYSREG_MISC_INTMASK, reg & ~(1 << irq));
+ }
+}
+
+static void
+apb_unmask_irq(void *source)
+{
+ uint32_t reg;
+ unsigned int irq = (unsigned int)source;
+
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ reg = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTMASK);
+ ATH_WRITE_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTMASK, reg | (1 << irq));
+ } else {
+ reg = ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTMASK);
+ ATH_WRITE_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTMASK, reg | (1 << irq));
+ }
+}
+
+#ifdef INTRNG
+static int
+apb_pic_register_isrcs(struct apb_softc *sc)
+{
+ int error;
+ uint32_t irq;
+ struct intr_irqsrc *isrc;
+ const char *name;
+
+ name = device_get_nameunit(sc->apb_dev);
+ for (irq = 0; irq < APB_NIRQS; irq++) {
+ sc->pic_irqs[irq].irq = irq;
+ isrc = PIC_INTR_ISRC(sc, irq);
+ error = intr_isrc_register(isrc, sc->apb_dev, 0, "%s", name);
+ if (error != 0) {
+ /* XXX call intr_isrc_deregister */
+ device_printf(sc->apb_dev, "%s failed", __func__);
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static inline intptr_t
+pic_xref(device_t dev)
+{
+ return (0);
+}
+#endif
+
+static int
+apb_probe(device_t dev)
+{
+#ifdef INTRNG
+ device_set_desc(dev, "APB Bus bridge INTRNG");
+#else
+ device_set_desc(dev, "APB Bus bridge");
+#endif
+
+ return (0);
+}
+
+static int
+apb_attach(device_t dev)
+{
+ struct apb_softc *sc = device_get_softc(dev);
+#ifdef INTRNG
+ intptr_t xref = pic_xref(dev);
+ int miscirq;
+#else
+ int rid = 0;
+#endif
+
+ sc->apb_dev = dev;
+
+ sc->apb_mem_rman.rm_type = RMAN_ARRAY;
+ sc->apb_mem_rman.rm_descr = "APB memory window";
+
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ if (rman_init(&sc->apb_mem_rman) != 0 ||
+ rman_manage_region(&sc->apb_mem_rman,
+ AR5315_APB_BASE,
+ AR5315_APB_BASE + AR5315_APB_SIZE - 1) != 0)
+ panic("apb_attach: failed to set up memory rman");
+ } else {
+ if (rman_init(&sc->apb_mem_rman) != 0 ||
+ rman_manage_region(&sc->apb_mem_rman,
+ AR5312_APB_BASE,
+ AR5312_APB_BASE + AR5312_APB_SIZE - 1) != 0)
+ panic("apb_attach: failed to set up memory rman");
+ }
+
+ sc->apb_irq_rman.rm_type = RMAN_ARRAY;
+ sc->apb_irq_rman.rm_descr = "APB IRQ";
+
+ if (rman_init(&sc->apb_irq_rman) != 0 ||
+ rman_manage_region(&sc->apb_irq_rman,
+ APB_IRQ_BASE, APB_IRQ_END) != 0)
+ panic("apb_attach: failed to set up IRQ rman");
+
+#ifndef INTRNG
+ if ((sc->sc_misc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC,
+ apb_filter, NULL, sc, &sc->sc_misc_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+#else
+ /* Register the interrupts */
+ if (apb_pic_register_isrcs(sc) != 0) {
+ device_printf(dev, "could not register PIC ISRCs\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Now, when everything is initialized, it's right time to
+ * register interrupt controller to interrupt framefork.
+ */
+ if (intr_pic_register(dev, xref) == NULL) {
+ device_printf(dev, "could not register PIC\n");
+ return (ENXIO);
+ }
+
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ miscirq = AR5315_CPU_IRQ_MISC;
+ } else {
+ miscirq = AR5312_IRQ_MISC;
+ }
+ cpu_establish_hardintr("aric", apb_filter, NULL, sc, miscirq,
+ INTR_TYPE_MISC, NULL);
+#endif
+
+ /* mask all misc interrupt */
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ ATH_WRITE_REG(AR5315_SYSREG_BASE
+ + AR5315_SYSREG_MISC_INTMASK, 0);
+ } else {
+ ATH_WRITE_REG(AR5312_SYSREG_BASE
+ + AR5312_SYSREG_MISC_INTMASK, 0);
+ }
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+apb_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct apb_softc *sc = device_get_softc(bus);
+ struct apb_ivar *ivar = device_get_ivars(child);
+ struct resource *rv;
+ struct resource_list_entry *rle;
+ struct rman *rm;
+ int isdefault, needactivate, passthrough;
+
+ isdefault = (RMAN_IS_DEFAULT_RANGE(start, end));
+ needactivate = flags & RF_ACTIVE;
+ /*
+ * Pass memory requests to nexus device
+ */
+ passthrough = (device_get_parent(child) != bus);
+ rle = NULL;
+
+ dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %jd, %d)\n",
+ __func__, bus, child, type, *rid, (void *)(intptr_t)start,
+ (void *)(intptr_t)end, count, flags);
+
+ if (passthrough)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
+ rid, start, end, count, flags));
+
+ /*
+ * If this is an allocation of the "default" range for a given RID,
+ * and we know what the resources for this device are (ie. they aren't
+ * maintained by a child bus), then work out the start/end values.
+ */
+
+ if (isdefault) {
+ rle = resource_list_find(&ivar->resources, type, *rid);
+ if (rle == NULL) {
+ return (NULL);
+ }
+
+ if (rle->res != NULL) {
+ panic("%s: resource entry is busy", __func__);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+
+ dprintf("%s: default resource (%p, %p, %jd)\n",
+ __func__, (void *)(intptr_t)start,
+ (void *)(intptr_t)end, count);
+ }
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->apb_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->apb_mem_rman;
+ break;
+ default:
+ printf("%s: unknown resource type %d\n", __func__, type);
+ return (0);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == 0) {
+ printf("%s: could not reserve resource %d\n", __func__, type);
+ return (0);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ printf("%s: could not activate resource\n", __func__);
+ rman_release_resource(rv);
+ return (0);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+apb_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /* XXX: should we mask/unmask IRQ here? */
+ return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
+ type, rid, r));
+}
+
+static int
+apb_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /* XXX: should we mask/unmask IRQ here? */
+ return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
+ type, rid, r));
+}
+
+static int
+apb_release_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ rl = apb_get_resource_list(dev, child);
+ if (rl == NULL)
+ return (EINVAL);
+ rle = resource_list_find(rl, type, rid);
+ if (rle == NULL)
+ return (EINVAL);
+ rman_release_resource(r);
+ rle->res = NULL;
+
+ return (0);
+}
+
+
+static int
+apb_setup_intr(device_t bus, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+ struct apb_softc *sc = device_get_softc(bus);
+ int error;
+ int irq;
+#ifndef INTRNG
+ struct intr_event *event;
+#endif
+
+#ifdef INTRNG
+ struct intr_irqsrc *isrc;
+ const char *name;
+
+ if ((rman_get_flags(ires) & RF_SHAREABLE) == 0)
+ flags |= INTR_EXCL;
+
+ irq = rman_get_start(ires);
+ isrc = PIC_INTR_ISRC(sc, irq);
+ if(isrc->isrc_event == 0) {
+ error = intr_event_create(&isrc->isrc_event, (void *)irq,
+ 0, irq, apb_mask_irq, apb_unmask_irq,
+ NULL, NULL, "apb intr%d:", irq);
+ if(error != 0)
+ return(error);
+ }
+ name = device_get_nameunit(child);
+ error = intr_event_add_handler(isrc->isrc_event, name, filt, handler,
+ arg, intr_priority(flags), flags, cookiep);
+ return(error);
+#else
+ irq = rman_get_start(ires);
+
+ if (irq > APB_IRQ_END)
+ panic("%s: bad irq %d", __func__, irq);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0, irq,
+ apb_mask_irq, apb_unmask_irq,
+ NULL, NULL,
+ "apb intr%d:", irq);
+
+ if (error == 0) {
+ sc->sc_eventstab[irq] = event;
+ sc->sc_intr_counter[irq] =
+ mips_intrcnt_create(event->ie_name);
+ }
+ else
+ return (error);
+ }
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+ mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname);
+
+ apb_unmask_irq((void*)irq);
+
+ return (0);
+#endif
+}
+
+#ifndef INTRNG
+static int
+apb_teardown_intr(device_t dev, device_t child, struct resource *ires,
+ void *cookie)
+{
+#ifdef INTRNG
+ return (intr_teardown_irq(child, ires, cookie));
+#else
+ struct apb_softc *sc = device_get_softc(dev);
+ int irq, result;
+
+ irq = rman_get_start(ires);
+ if (irq > APB_IRQ_END)
+ panic("%s: bad irq %d", __func__, irq);
+
+ if (sc->sc_eventstab[irq] == NULL)
+ panic("Trying to teardown unoccupied IRQ");
+
+ apb_mask_irq((void*)irq);
+
+ result = intr_event_remove_handler(cookie);
+ if (!result)
+ sc->sc_eventstab[irq] = NULL;
+
+ return (result);
+#endif
+}
+
+
+static int
+apb_filter(void *arg)
+{
+ struct apb_softc *sc = arg;
+ struct intr_event *event;
+ uint32_t reg, irq;
+
+ if(ar531x_soc >= AR531X_SOC_AR5315)
+ reg = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTSTAT);
+ else
+ reg = ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTSTAT);
+
+ for (irq = 0; irq < APB_NIRQS; irq++) {
+ if (reg & (1 << irq)) {
+
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ ATH_WRITE_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTSTAT,
+ reg & ~(1 << irq));
+ } else {
+ ATH_WRITE_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTSTAT,
+ reg & ~(1 << irq));
+ }
+
+ event = sc->sc_eventstab[irq];
+ if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
+ if(irq == 1 && ar531x_soc < AR531X_SOC_AR5315) {
+ ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_AHBPERR);
+ ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_AHBDMAE);
+ }
+ /* Ignore non handle interrupts */
+ if (irq != 0 && irq != 6)
+ printf("Stray APB IRQ %d\n", irq);
+
+ continue;
+ }
+
+ intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame);
+ mips_intrcnt_inc(sc->sc_intr_counter[irq]);
+ }
+ }
+
+ return (FILTER_HANDLED);
+}
+#else
+static int
+apb_filter(void *arg)
+{
+ struct apb_softc *sc = arg;
+ struct thread *td;
+ uint32_t i, intr;
+
+ td = curthread;
+ /* Workaround: do not inflate intr nesting level */
+ td->td_intr_nesting_level--;
+
+ if(ar531x_soc >= AR531X_SOC_AR5315)
+ intr = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTSTAT);
+ else
+ intr = ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTSTAT);
+
+ while ((i = fls(intr)) != 0) {
+ i--;
+ intr &= ~(1u << i);
+
+ if(i == 1 && ar531x_soc < AR531X_SOC_AR5315) {
+ ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_AHBPERR);
+ ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_AHBDMAE);
+ }
+
+ if (intr_isrc_dispatch(PIC_INTR_ISRC(sc, i),
+ curthread->td_intr_frame) != 0) {
+ device_printf(sc->apb_dev,
+ "Stray interrupt %u detected\n", i);
+ apb_mask_irq((void*)i);
+ continue;
+ }
+ }
+
+ KASSERT(i == 0, ("all interrupts handled"));
+
+ td->td_intr_nesting_level++;
+
+ return (FILTER_HANDLED);
+
+}
+
+#endif
+
+static void
+apb_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ device_t child;
+ long maddr;
+ int msize;
+ int irq;
+ int result;
+ int mem_hints_count;
+
+ child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+
+ /*
+ * Set hard-wired resources for hinted child using
+ * specific RIDs.
+ */
+ mem_hints_count = 0;
+ if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
+ mem_hints_count++;
+ if (resource_int_value(dname, dunit, "msize", &msize) == 0)
+ mem_hints_count++;
+
+ /* check if all info for mem resource has been provided */
+ if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
+ printf("Either maddr or msize hint is missing for %s%d\n",
+ dname, dunit);
+ } else if (mem_hints_count) {
+ result = bus_set_resource(child, SYS_RES_MEMORY, 0,
+ maddr, msize);
+ if (result != 0)
+ device_printf(bus,
+ "warning: bus_set_resource() failed\n");
+ }
+
+ if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
+ result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (result != 0)
+ device_printf(bus,
+ "warning: bus_set_resource() failed\n");
+ }
+}
+
+static device_t
+apb_add_child(device_t bus, u_int order, const char *name, int unit)
+{
+ device_t child;
+ struct apb_ivar *ivar;
+
+ ivar = malloc(sizeof(struct apb_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (ivar == NULL) {
+ printf("Failed to allocate ivar\n");
+ return (0);
+ }
+ resource_list_init(&ivar->resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+ if (child == NULL) {
+ printf("Can't add child %s%d ordered\n", name, unit);
+ return (0);
+ }
+
+ device_set_ivars(child, ivar);
+
+ return (child);
+}
+
+/*
+ * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
+ * Provides pointer to resource_list for these routines
+ */
+static struct resource_list *
+apb_get_resource_list(device_t dev, device_t child)
+{
+ struct apb_ivar *ivar;
+
+ ivar = device_get_ivars(child);
+ return (&(ivar->resources));
+}
+
+#ifdef INTRNG
+static void
+apb_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+
+ irq = ((struct apb_pic_irqsrc *)isrc)->irq;
+ apb_unmask_irq((void*)irq);
+}
+
+static void
+apb_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq;
+
+ irq = ((struct apb_pic_irqsrc *)isrc)->irq;
+ apb_mask_irq((void*)irq);
+}
+
+static void
+apb_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ apb_pic_disable_intr(dev, isrc);
+}
+
+static void
+apb_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ apb_pic_enable_intr(dev, isrc);
+}
+
+static void
+apb_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ uint32_t reg, irq;
+
+ irq = ((struct apb_pic_irqsrc *)isrc)->irq;
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ reg = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_MISC_INTSTAT);
+ ATH_WRITE_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_MISC_INTSTAT,
+ reg & ~(1 << irq));
+ } else {
+ reg = ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_MISC_INTSTAT);
+ ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_MISC_INTSTAT,
+ reg & ~(1 << irq));
+ }
+}
+
+static int
+apb_pic_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ return (ENOTSUP);
+}
+
+#endif
+
+static device_method_t apb_methods[] = {
+ DEVMETHOD(bus_activate_resource, apb_activate_resource),
+ DEVMETHOD(bus_add_child, apb_add_child),
+ DEVMETHOD(bus_alloc_resource, apb_alloc_resource),
+ DEVMETHOD(bus_deactivate_resource, apb_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, apb_get_resource_list),
+ DEVMETHOD(bus_hinted_child, apb_hinted_child),
+ DEVMETHOD(bus_release_resource, apb_release_resource),
+ DEVMETHOD(device_attach, apb_attach),
+ DEVMETHOD(device_probe, apb_probe),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+#ifdef INTRNG
+ DEVMETHOD(pic_disable_intr, apb_pic_disable_intr),
+ DEVMETHOD(pic_enable_intr, apb_pic_enable_intr),
+ DEVMETHOD(pic_map_intr, apb_pic_map_intr),
+ DEVMETHOD(pic_post_filter, apb_pic_post_filter),
+ DEVMETHOD(pic_post_ithread, apb_pic_post_ithread),
+ DEVMETHOD(pic_pre_ithread, apb_pic_pre_ithread),
+
+// DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+#else
+ DEVMETHOD(bus_teardown_intr, apb_teardown_intr),
+#endif
+ DEVMETHOD(bus_setup_intr, apb_setup_intr),
+
+ DEVMETHOD_END
+};
+
+static driver_t apb_driver = {
+ "apb",
+ apb_methods,
+ sizeof(struct apb_softc),
+};
+static devclass_t apb_devclass;
+
+EARLY_DRIVER_MODULE(apb, nexus, apb_driver, apb_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
Index: sys/mips/atheros/ar531x/apbvar.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/apbvar.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2009, 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 unmodified, 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 _APBVAR_H_
+#define _APBVAR_H_
+
+#define APB_IRQ_BASE 0
+#define APB_IRQ_END 31
+#define APB_NIRQS 32
+
+struct apb_pic_irqsrc {
+ struct intr_irqsrc isrc;
+ u_int irq;
+};
+
+struct apb_softc {
+ device_t apb_dev;
+ struct rman apb_irq_rman;
+ struct rman apb_mem_rman;
+ /* IRQ events structs for child devices */
+ struct intr_event *sc_eventstab[APB_NIRQS];
+#ifndef INTRNG
+ mips_intrcnt_t sc_intr_counter[APB_NIRQS];
+#endif
+ /* Resources and cookies for MIPS CPU INTs */
+ struct resource *sc_misc_irq;
+ void *sc_misc_ih;
+#ifdef INTRNG
+ struct apb_pic_irqsrc pic_irqs[APB_NIRQS];
+#endif
+};
+
+struct apb_ivar {
+ struct resource_list resources;
+};
+
+#endif /* _APBVAR_H_ */
Index: sys/mips/atheros/ar531x/ar5312_chip.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5312_chip.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2010 Adrian Chadd
+ * 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: head/sys/mips/atheros/ar5315_chip.h 234326 2012-04-15 22:34:22Z adrian $ */
+
+#ifndef __AR5312_CHIP_H__
+#define __AR5312_CHIP_H__
+
+extern struct ar5315_cpu_def ar5312_chip_def;
+
+#endif
Index: sys/mips/atheros/ar531x/ar5312_chip.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5312_chip.c
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 2016 Hiroki Mori
+ * Copyright (c) 2010 Adrian Chadd
+ * 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: head/sys/mips/atheros/ar5312_chip.c 234326 2012-04-15 22:34:22Z adrian $");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <net/ethernet.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/md_var.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#include <mips/atheros/ar531x/ar5312reg.h>
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+#include <mips/atheros/ar531x/ar5315_setup.h>
+
+static void
+ar5312_chip_detect_mem_size(void)
+{
+ uint32_t memsize;
+ uint32_t memcfg, bank0, bank1;
+
+ /*
+ * Determine the memory size as established by system
+ * firmware.
+ *
+ * NB: we allow compile time override
+ */
+ memcfg = ATH_READ_REG(AR5312_SDRAMCTL_BASE + AR5312_SDRAMCTL_MEM_CFG1);
+ bank0 = __SHIFTOUT(memcfg, AR5312_MEM_CFG1_BANK0);
+ bank1 = __SHIFTOUT(memcfg, AR5312_MEM_CFG1_BANK1);
+
+ memsize = (bank0 ? (1 << (bank0 + 1)) : 0) +
+ (bank1 ? (1 << (bank1 + 1)) : 0);
+ memsize <<= 20;
+
+ realmem = memsize;
+}
+
+static void
+ar5312_chip_detect_sys_frequency(void)
+{
+ uint32_t predivisor;
+ uint32_t multiplier;
+
+
+ const uint32_t clockctl = ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_CLOCKCTL);
+ if(ar531x_soc == AR531X_SOC_AR5313) {
+ predivisor = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_PREDIVIDE);
+ multiplier = __SHIFTOUT(clockctl, AR2313_CLOCKCTL_MULTIPLIER);
+ } else {
+ predivisor = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_PREDIVIDE);
+ multiplier = __SHIFTOUT(clockctl, AR5312_CLOCKCTL_MULTIPLIER);
+ }
+
+ const uint32_t divisor = (0x5421 >> (predivisor * 4)) & 15;
+
+ const uint32_t cpufreq = (40000000 / divisor) * multiplier;
+
+ u_ar531x_cpu_freq = cpufreq;
+ u_ar531x_ahb_freq = cpufreq / 4;
+ u_ar531x_ddr_freq = 0;
+}
+
+/*
+ * This does not lock the CPU whilst doing the work!
+ */
+static void
+ar5312_chip_device_reset(void)
+{
+ ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_RESETCTL,
+ AR5312_RESET_SYSTEM);
+}
+
+static void
+ar5312_chip_device_start(void)
+{
+ uint32_t cfg0, cfg1;
+ uint32_t bank0, bank1;
+ uint32_t size0, size1;
+
+ cfg0 = ATH_READ_REG(AR5312_SDRAMCTL_BASE + AR5312_SDRAMCTL_MEM_CFG0);
+ cfg1 = ATH_READ_REG(AR5312_SDRAMCTL_BASE + AR5312_SDRAMCTL_MEM_CFG1);
+
+ bank0 = __SHIFTOUT(cfg1, AR5312_MEM_CFG1_BANK0);
+ bank1 = __SHIFTOUT(cfg1, AR5312_MEM_CFG1_BANK1);
+
+ size0 = bank0 ? (1 << (bank0 + 1)) : 0;
+ size1 = bank1 ? (1 << (bank1 + 1)) : 0;
+
+ size0 <<= 20;
+ size1 <<= 20;
+
+ printf("SDRMCTL %x %x %x %x\n", cfg0, cfg1, size0, size1);
+
+ ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_AHBPERR);
+ ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_AHBDMAE);
+// ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_WDOG_CTL, 0);
+ ATH_WRITE_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_ENABLE, 0);
+
+ ATH_WRITE_REG(AR5312_SYSREG_BASE+AR5312_SYSREG_ENABLE,
+ ATH_READ_REG(AR5312_SYSREG_BASE+AR5312_SYSREG_ENABLE) |
+ AR5312_ENABLE_ENET0 | AR5312_ENABLE_ENET1);
+
+}
+
+static int
+ar5312_chip_device_stopped(uint32_t mask)
+{
+ uint32_t reg;
+
+ reg = ATH_READ_REG(AR5312_SYSREG_BASE + AR5312_SYSREG_RESETCTL);
+ return ((reg & mask) == mask);
+}
+
+static void
+ar5312_chip_set_mii_speed(uint32_t unit, uint32_t speed)
+{
+}
+
+/* Speed is either 10, 100 or 1000 */
+static void
+ar5312_chip_set_pll_ge(int unit, int speed)
+{
+}
+
+static void
+ar5312_chip_ddr_flush_ge(int unit)
+{
+}
+
+static void
+ar5312_chip_soc_init(void)
+{
+
+ u_ar531x_uart_addr = MIPS_PHYS_TO_KSEG1(AR5312_UART0_BASE);
+
+ u_ar531x_gpio_di = AR5312_GPIO_DI;
+ u_ar531x_gpio_do = AR5312_GPIO_DO;
+ u_ar531x_gpio_cr = AR5312_GPIO_CR;
+ u_ar531x_gpio_pins = AR5312_GPIO_PINS;
+
+ u_ar531x_wdog_ctl = AR5312_SYSREG_WDOG_CTL;
+ u_ar531x_wdog_timer = AR5312_SYSREG_WDOG_TIMER;
+
+}
+
+static uint32_t
+ar5312_chip_get_eth_pll(unsigned int mac, int speed)
+{
+ return 0;
+}
+
+struct ar5315_cpu_def ar5312_chip_def = {
+ &ar5312_chip_detect_mem_size,
+ &ar5312_chip_detect_sys_frequency,
+ &ar5312_chip_device_reset,
+ &ar5312_chip_device_start,
+ &ar5312_chip_device_stopped,
+ &ar5312_chip_set_pll_ge,
+ &ar5312_chip_set_mii_speed,
+ &ar5312_chip_ddr_flush_ge,
+ &ar5312_chip_get_eth_pll,
+ &ar5312_chip_soc_init,
+};
Index: sys/mips/atheros/ar531x/ar5312reg.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5312reg.h
@@ -0,0 +1,237 @@
+/* $Id: ar5312reg.h,v 1.4 2011/07/07 05:06:44 matt Exp $ */
+/*
+ * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
+ * Copyright (c) 2006 Garrett D'Amore.
+ * All rights reserved.
+ *
+ * This code was written by Garrett D'Amore for the Champaign-Urbana
+ * Community Wireless Network Project.
+ *
+ * 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 acknowledgements:
+ * This product includes software developed by the Urbana-Champaign
+ * Independent Media Center.
+ * This product includes software developed by Garrett D'Amore.
+ * 4. Urbana-Champaign Independent Media Center's name and Garrett
+ * D'Amore's name may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER AND GARRETT D'AMORE ``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 URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER OR GARRETT D'AMORE 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.
+ */
+
+#ifndef _MIPS_ATHEROS_AR5312REG_H_
+#define _MIPS_ATHEROS_AR5312REG_H_
+
+#define AR5312_MEM0_BASE 0x00000000 /* sdram */
+#define AR5312_MEM1_BASE 0x08000000 /* sdram/flash */
+#define AR5312_MEM3_BASE 0x10000000 /* flash */
+#define AR5312_WLAN0_BASE 0x18000000
+#define AR5312_ENET0_BASE 0x18100000
+#define AR5312_ENET1_BASE 0x18200000
+#define AR5312_SDRAMCTL_BASE 0x18300000
+#define AR5312_FLASHCTL_BASE 0x18400000
+#define AR5312_WLAN1_BASE 0x18500000
+#define AR5312_UART0_BASE 0x1C000000 /* high speed */
+#define AR5312_UART1_BASE 0x1C001000
+#define AR5312_GPIO_BASE 0x1C002000
+#define AR5312_SYSREG_BASE 0x1C003000
+#define AR5312_UARTDMA_BASE 0x1C004000
+#define AR5312_FLASH_BASE 0x1E000000
+#define AR5312_FLASH_END 0x20000000 /* possibly aliased */
+
+/*
+ * FLASHCTL registers -- offset relative to AR531X_FLASHCTL_BASE
+ */
+#define AR5312_FLASHCTL_0 0x00
+#define AR5312_FLASHCTL_1 0x04
+#define AR5312_FLASHCTL_2 0x08
+
+#define AR5312_FLASHCTL_IDCY __BITS(0,3) /* idle cycle turn */
+#define AR5312_FLASHCTL_WST1 __BITS(5,9) /* wait state 1 */
+#define AR5312_FLASHCTL_RBLE __BIT(10) /* rd byte enable */
+#define AR5312_FLASHCTL_WST2 __BITS(11,15) /* wait state 1 */
+#define AR5312_FLASHCTL_AC __BITS(16,18) /* addr chk */
+#define AR5312_FLASHCTL_AC_128K 0
+#define AR5312_FLASHCTL_AC_256K 1
+#define AR5312_FLASHCTL_AC_512K 2
+#define AR5312_FLASHCTL_AC_1M 3
+#define AR5312_FLASHCTL_AC_2M 4
+#define AR5312_FLASHCTL_AC_4M 5
+#define AR5312_FLASHCTL_AC_8M 6
+#define AR5312_FLASHCTL_AC_16M 7
+#define AR5312_FLASHCTL_E __BIT(19) /* enable */
+#define AR5312_FLASHCTL_BUSERR __BIT(24) /* buserr */
+#define AR5312_FLASHCTL_WPERR __BIT(25) /* wperr */
+#define AR5312_FLASHCTL_WP __BIT(26) /* wp */
+#define AR5312_FLASHCTL_BM __BIT(27) /* bm */
+#define AR5312_FLASHCTL_MW __BITS(28,29) /* mem width */
+#define AR5312_FLASHCTL_AT __BITS(31,30) /* access type */
+
+/*
+ * GPIO registers -- offset relative to AR531X_GPIO_BASE
+ */
+#define AR5312_GPIO_DO 0
+#define AR5312_GPIO_DI 4
+#define AR5312_GPIO_CR 8
+
+#define AR5312_GPIO_PINS 8
+
+/*
+ * SYSREG registers -- offset relative to AR531X_SYSREG_BASE
+ */
+#define AR5312_SYSREG_TIMER 0x0000
+#define AR5312_SYSREG_TIMER_RELOAD 0x0004
+#define AR5312_SYSREG_WDOG_CTL 0x0008
+#define AR5312_SYSREG_WDOG_TIMER 0x000c
+#define AR5312_SYSREG_MISC_INTSTAT 0x0010
+#define AR5312_SYSREG_MISC_INTMASK 0x0014
+#define AR5312_SYSREG_INTSTAT 0x0018
+#define AR5312_SYSREG_RESETCTL 0x0020
+#define AR5312_SYSREG_CLOCKCTL 0x0064
+#define AR5312_SYSREG_SCRATCH 0x006c
+#define AR5312_SYSREG_AHBPERR 0x0070
+#define AR5312_SYSREG_PROC 0x0074
+#define AR5312_SYSREG_AHBDMAE 0x0078
+#define AR5312_SYSREG_ENABLE 0x0080
+#define AR5312_SYSREG_REVISION 0x0090
+
+/* WDOG_CTL watchdog control bits */
+#define AR5312_WDOG_CTL_IGNORE 0x0000
+#define AR5312_WDOG_CTL_NMI 0x0001
+#define AR5312_WDOG_CTL_RESET 0x0002
+
+/* Resets */
+#define AR5312_RESET_SYSTEM __BIT(0)
+#define AR5312_RESET_CPU __BIT(1)
+#define AR5312_RESET_WLAN0 __BIT(2) /* mac & bb */
+#define AR5312_RESET_PHY0 __BIT(3) /* enet phy */
+#define AR5312_RESET_PHY1 __BIT(4) /* enet phy */
+#define AR5312_RESET_ENET0 __BIT(5) /* mac */
+#define AR5312_RESET_ENET1 __BIT(6) /* mac */
+#define AR5312_RESET_UART0 __BIT(8) /* mac */
+#define AR5312_RESET_WLAN1 __BIT(9) /* mac & bb */
+#define AR5312_RESET_APB __BIT(10) /* bridge */
+#define AR5312_RESET_WARM_CPU __BIT(16)
+#define AR5312_RESET_WARM_WLAN0_MAC __BIT(17)
+#define AR5312_RESET_WARM_WLAN0_BB __BIT(18)
+#define AR5312_RESET_NMI __BIT(20)
+#define AR5312_RESET_WARM_WLAN1_MAC __BIT(21)
+#define AR5312_RESET_WARM_WLAN1_BB __BIT(22)
+#define AR5312_RESET_LOCAL_BUS __BIT(23)
+#define AR5312_RESET_WDOG __BIT(24)
+
+/* AR5312/2312 clockctl bits */
+#define AR5312_CLOCKCTL_PREDIVIDE __BITS(4,5)
+#define AR5312_CLOCKCTL_MULTIPLIER __BITS(8,12)
+#define AR5312_CLOCKCTL_DOUBLER __BIT(16)
+
+/* AR2313 clockctl */
+#define AR2313_CLOCKCTL_PREDIVIDE __BITS(12,13)
+#define AR2313_CLOCKCTL_MULTIPLIER __BITS(16,20)
+
+/* Enables */
+#define AR5312_ENABLE_WLAN0 __BIT(0)
+#define AR5312_ENABLE_ENET0 __BIT(1)
+#define AR5312_ENABLE_ENET1 __BIT(2)
+#define AR5312_ENABLE_WLAN1 __BITS(7,8) /* both DMA and PIO */
+
+/* Revision ids */
+#define AR5312_REVISION_WMAC_MAJOR(x) (((x) >> 12) & 0xf)
+#define AR5312_REVISION_WMAC_MINOR(x) (((x) >> 8) & 0xf)
+#define AR5312_REVISION_WMAC(x) (((x) >> 8) & 0xff)
+#define AR5312_REVISION_MAJOR(x) (((x) >> 4) & 0xf)
+#define AR5312_REVISION_MINOR(x) (((x) >> 0) & 0xf)
+
+#define AR5312_REVISION_MAJ_AR5311 0x1
+#define AR5312_REVISION_MAJ_AR5312 0x4
+#define AR5312_REVISION_MAJ_AR2313 0x5
+#define AR5312_REVISION_MAJ_AR5315 0xB
+
+/*
+ * SDRAMCTL registers -- offset relative to SDRAMCTL
+ */
+#define AR5312_SDRAMCTL_MEM_CFG0 0x0000
+#define AR5312_SDRAMCTL_MEM_CFG1 0x0004
+
+/* memory config 1 bits */
+#define AR5312_MEM_CFG1_BANK0 __BITS(8,10)
+#define AR5312_MEM_CFG1_BANK1 __BITS(12,15)
+
+/* helper macro for accessing system registers without bus space */
+#define REGVAL(x) *((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
+#define GETSYSREG(x) REGVAL((x) + AR5312_SYSREG_BASE)
+#define PUTSYSREG(x,v) (REGVAL((x) + AR5312_SYSREG_BASE)) = (v)
+#define GETSDRAMREG(x) REGVAL((x) + AR5312_SDRAMCTL_BASE)
+#define PUTSDRAMREG(x,v) (REGVAL((x) + AR5312_SDRAMCTL_BASE)) = (v)
+
+/*
+ * Interrupts.
+ */
+#define AR5312_IRQ_WLAN0 0
+#define AR5312_IRQ_ENET0 1
+#define AR5312_IRQ_ENET1 2
+#define AR5312_IRQ_WLAN1 3
+#define AR5312_IRQ_MISC 4
+
+#define AR5312_MISC_IRQ_TIMER 1
+#define AR5312_MISC_IRQ_AHBPERR 2
+#define AR5312_MISC_IRQ_AHBDMAE 3
+#define AR5312_MISC_IRQ_GPIO 4
+#define AR5312_MISC_IRQ_UART0 5
+#define AR5312_MISC_IRQ_UART0_DMA 6
+#define AR5312_MISC_IRQ_WDOG 7
+
+/*
+ * Board data. This is located in flash somewhere, ar531x_board_info
+ * locates it.
+ */
+#include <dev/ath/ath_hal/ah_soc.h> /* XXX really doesn't belong in hal */
+
+/* XXX write-around for now */
+#define AR5312_BOARD_MAGIC AR531X_BD_MAGIC
+
+/* config bits */
+#define AR5312_BOARD_CONFIG_ENET0 BD_ENET0
+#define AR5312_BOARD_CONFIG_ENET1 BD_ENET1
+#define AR5312_BOARD_CONFIG_UART1 BD_UART1
+#define AR5312_BOARD_CONFIG_UART0 BD_UART0
+#define AR5312_BOARD_CONFIG_RSTFACTORY BD_RSTFACTORY
+#define AR5312_BOARD_CONFIG_SYSLED BD_SYSLED
+#define AR5312_BOARD_CONFIG_EXTUARTCLK BD_EXTUARTCLK
+#define AR5312_BOARD_CONFIG_CPUFREQ BD_CPUFREQ
+#define AR5312_BOARD_CONFIG_SYSFREQ BD_SYSFREQ
+#define AR5312_BOARD_CONFIG_WLAN0 BD_WLAN0
+#define AR5312_BOARD_CONFIG_MEMCAP BD_MEMCAP
+#define AR5312_BOARD_CONFIG_DISWDOG BD_DISWATCHDOG
+#define AR5312_BOARD_CONFIG_WLAN1 BD_WLAN1
+#define AR5312_BOARD_CONFIG_AR2312 BD_ISCASPER
+#define AR5312_BOARD_CONFIG_WLAN0_2G BD_WLAN0_2G_EN
+#define AR5312_BOARD_CONFIG_WLAN0_5G BD_WLAN0_5G_EN
+#define AR5312_BOARD_CONFIG_WLAN1_2G BD_WLAN1_2G_EN
+#define AR5312_BOARD_CONFIG_WLAN1_5G BD_WLAN1_5G_EN
+
+#define AR5312_APB_BASE AR5312_UART0_BASE
+#define AR5312_APB_SIZE 0x02000000
+
+#endif /* _MIPS_ATHEROS_AR531XREG_H_ */
Index: sys/mips/atheros/ar531x/ar5315_chip.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_chip.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2010 Adrian Chadd
+ * 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: head/sys/mips/atheros/ar5315_chip.h 234326 2012-04-15 22:34:22Z adrian $ */
+
+#ifndef __AR5315_CHIP_H__
+#define __AR5315_CHIP_H__
+
+extern struct ar5315_cpu_def ar5315_chip_def;
+
+#endif
Index: sys/mips/atheros/ar531x/ar5315_chip.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_chip.c
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 2010 Adrian Chadd
+ * All rights reserved.
+ * Copyright (c) 2016, 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/mips/atheros/ar5315_chip.c 234326 2012-04-15 22:34:22Z adrian $");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <net/ethernet.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/md_var.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5315_chip.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+
+/* XXX these shouldn't be in here - this file is a per-chip file */
+/* XXX these should be in the top-level ar5315 type, not ar5315 -chip */
+uint32_t u_ar531x_cpu_freq;
+uint32_t u_ar531x_ahb_freq;
+uint32_t u_ar531x_ddr_freq;
+
+uint32_t u_ar531x_uart_addr;
+
+uint32_t u_ar531x_gpio_di;
+uint32_t u_ar531x_gpio_do;
+uint32_t u_ar531x_gpio_cr;
+uint32_t u_ar531x_gpio_pins;
+
+uint32_t u_ar531x_wdog_ctl;
+uint32_t u_ar531x_wdog_timer;
+
+static void
+ar5315_chip_detect_mem_size(void)
+{
+ uint32_t memsize = 0;
+ uint32_t memcfg, cw, rw, dw;
+
+ /*
+ * Determine the memory size. We query the board info.
+ */
+ memcfg = ATH_READ_REG(AR5315_SDRAMCTL_BASE + AR5315_SDRAMCTL_MEM_CFG);
+ cw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_COL_WIDTH);
+ cw += 1;
+ rw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_ROW_WIDTH);
+ rw += 1;
+
+ /* XXX: according to redboot, this could be wrong if DDR SDRAM */
+ dw = __SHIFTOUT(memcfg, AR5315_MEM_CFG_DATA_WIDTH);
+ dw += 1;
+ dw *= 8; /* bits */
+
+ /* not too sure about this math, but it _seems_ to add up */
+ memsize = (1 << cw) * (1 << rw) * dw;
+#if 0
+ printf("SDRAM_MEM_CFG =%x, cw=%d rw=%d dw=%d xmemsize=%d\n", memcfg,
+ cw, rw, dw, memsize);
+#endif
+ realmem = memsize;
+}
+
+static void
+ar5315_chip_detect_sys_frequency(void)
+{
+ uint32_t freq_ref, freq_pll;
+ static const uint8_t pll_divide_table[] = {
+ 2, 3, 4, 6, 3,
+ /*
+ * these entries are bogus, but it avoids a possible
+ * bad table dereference
+ */
+ 1, 1, 1
+ };
+ static const uint8_t pre_divide_table[] = {
+ 1, 2, 4, 5
+ };
+
+ const uint32_t pllc = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_PLLC_CTL);
+
+ const uint32_t refdiv = pre_divide_table[AR5315_PLLC_REF_DIV(pllc)];
+ const uint32_t fbdiv = AR5315_PLLC_FB_DIV(pllc);
+ const uint32_t div2 = (AR5315_PLLC_DIV_2(pllc) + 1) * 2; /* results in 2 or 4 */
+
+ freq_ref = 40000000;
+
+ /* 40MHz reference clk, reference and feedback dividers */
+ freq_pll = (freq_ref / refdiv) * div2 * fbdiv;
+
+ const uint32_t pllout[4] = {
+ /* CLKM select */
+ [0] = freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)],
+ [1] = freq_pll / pll_divide_table[AR5315_PLLC_CLKM(pllc)],
+
+ /* CLKC select */
+ [2] = freq_pll / pll_divide_table[AR5315_PLLC_CLKC(pllc)],
+
+ /* ref_clk select */
+ [3] = freq_ref, /* use original reference clock */
+ };
+
+ const uint32_t amba_clkctl = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_AMBACLK);
+ uint32_t ambadiv = AR5315_CLOCKCTL_DIV(amba_clkctl);
+ ambadiv = ambadiv ? (ambadiv * 2) : 1;
+ u_ar531x_ahb_freq = pllout[AR5315_CLOCKCTL_SELECT(amba_clkctl)] / ambadiv;
+
+ const uint32_t cpu_clkctl = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_CPUCLK);
+ uint32_t cpudiv = AR5315_CLOCKCTL_DIV(cpu_clkctl);
+ cpudiv = cpudiv ? (cpudiv * 2) : 1;
+ u_ar531x_cpu_freq = pllout[AR5315_CLOCKCTL_SELECT(cpu_clkctl)] / cpudiv;
+
+ u_ar531x_ddr_freq = 0;
+}
+
+/*
+ * This does not lock the CPU whilst doing the work!
+ */
+static void
+ar5315_chip_device_reset(void)
+{
+ ATH_WRITE_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_COLDRESET,
+ AR5315_COLD_AHB | AR5315_COLD_APB | AR5315_COLD_CPU);
+}
+
+static void
+ar5315_chip_device_start(void)
+{
+ ATH_WRITE_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_AHB_ERR0,
+ AR5315_AHB_ERROR_DET);
+ ATH_READ_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_AHB_ERR1);
+ ATH_WRITE_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_WDOG_CTL,
+ AR5315_WDOG_CTL_IGNORE);
+
+ // set Ethernet AHB master arbitration control
+ // Maybe RedBoot was enabled. But to make sure.
+ ATH_WRITE_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_AHB_ARB_CTL,
+ ATH_READ_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_AHB_ARB_CTL) |
+ AR5315_ARB_ENET);
+
+ // set Ethernet controller byteswap control
+/*
+ ATH_WRITE_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_ENDIAN,
+ ATH_READ_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_ENDIAN) |
+ AR5315_ENDIAN_ENET);
+*/
+ /* Disable interrupts for all gpio pins. */
+ ATH_WRITE_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_GPIO_INT, 0);
+
+ printf("AHB Master Arbitration Control %08x\n",
+ ATH_READ_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_AHB_ARB_CTL));
+ printf("Byteswap Control %08x\n",
+ ATH_READ_REG(AR5315_SYSREG_BASE+AR5315_SYSREG_ENDIAN));
+}
+
+static int
+ar5315_chip_device_stopped(uint32_t mask)
+{
+ uint32_t reg;
+
+ reg = ATH_READ_REG(AR5315_SYSREG_BASE + AR5315_SYSREG_COLDRESET);
+ return ((reg & mask) == mask);
+}
+
+static void
+ar5315_chip_set_mii_speed(uint32_t unit, uint32_t speed)
+{
+}
+
+/* Speed is either 10, 100 or 1000 */
+static void
+ar5315_chip_set_pll_ge(int unit, int speed)
+{
+}
+
+static void
+ar5315_chip_ddr_flush_ge(int unit)
+{
+}
+
+static void
+ar5315_chip_soc_init(void)
+{
+ u_ar531x_uart_addr = MIPS_PHYS_TO_KSEG1(AR5315_UART_BASE);
+
+ u_ar531x_gpio_di = AR5315_SYSREG_GPIO_DI;
+ u_ar531x_gpio_do = AR5315_SYSREG_GPIO_DO;
+ u_ar531x_gpio_cr = AR5315_SYSREG_GPIO_CR;
+ u_ar531x_gpio_pins = AR5315_GPIO_PINS;
+
+ u_ar531x_wdog_ctl = AR5315_SYSREG_WDOG_CTL;
+ u_ar531x_wdog_timer = AR5315_SYSREG_WDOG_TIMER;
+}
+
+static uint32_t
+ar5315_chip_get_eth_pll(unsigned int mac, int speed)
+{
+ return 0;
+}
+
+struct ar5315_cpu_def ar5315_chip_def = {
+ &ar5315_chip_detect_mem_size,
+ &ar5315_chip_detect_sys_frequency,
+ &ar5315_chip_device_reset,
+ &ar5315_chip_device_start,
+ &ar5315_chip_device_stopped,
+ &ar5315_chip_set_pll_ge,
+ &ar5315_chip_set_mii_speed,
+ &ar5315_chip_ddr_flush_ge,
+ &ar5315_chip_get_eth_pll,
+ &ar5315_chip_soc_init,
+};
Index: sys/mips/atheros/ar531x/ar5315_cpudef.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_cpudef.h
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 2010 Adrian Chadd
+ * 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: head/sys/mips/atheros/ar5315_cpudef.h 233081 2012-03-17 07:25:23Z adrian $ */
+
+#ifndef __AR5315_CPUDEF_H__
+#define __AR5315_CPUDEF_H__
+
+struct ar5315_cpu_def {
+ void (* detect_mem_size) (void);
+ void (* detect_sys_frequency) (void);
+ void (* ar5315_chip_device_reset) (void);
+ void (* ar5315_chip_device_start) (void);
+ int (* ar5315_chip_device_stopped) (uint32_t);
+ void (* ar5315_chip_set_pll_ge) (int, int);
+ void (* ar5315_chip_set_mii_speed) (uint32_t, uint32_t);
+ void (* ar5315_chip_ddr_flush_ge) (int);
+ uint32_t (* ar5315_chip_get_eth_pll) (unsigned int, int);
+ void (* ar5315_chip_soc_init) (void);
+
+ /*
+ * Allow to change MII bus mode:
+ * AR5315_ARGE_MII_MODE_MII
+ * AR5315_ARGE_MII_MODE_RMII
+ * AR5315_ARGE_MII_MODE_GMII
+ * AR5315_ARGE_MII_MODE_RGMII
+ * mii_mode(unit, mode);
+ */
+#define AR5315_ARGE_MII_MODE_MII 0x0100
+#define AR5315_ARGE_MII_MODE_RMII 0x0101
+#define AR5315_ARGE_MII_MODE_GMII 0x1000
+#define AR5315_ARGE_MII_MODE_RGMII 0x1001
+ void (* ar5315_chip_set_mii_mode) (int, int, int);
+};
+
+extern struct ar5315_cpu_def * ar5315_cpu_ops;
+
+static inline void ar531x_detect_mem_size(void)
+{
+ ar5315_cpu_ops->detect_mem_size();
+}
+
+static inline void ar531x_detect_sys_frequency(void)
+{
+ ar5315_cpu_ops->detect_sys_frequency();
+}
+
+static inline void ar531x_device_reset(void)
+{
+ ar5315_cpu_ops->ar5315_chip_device_reset();
+}
+
+static inline void ar531x_device_start(void)
+{
+ ar5315_cpu_ops->ar5315_chip_device_start();
+}
+
+static inline int ar531x_device_stopped(uint32_t mask)
+{
+ return ar5315_cpu_ops->ar5315_chip_device_stopped(mask);
+}
+
+static inline void ar531x_device_set_pll_ge(int unit, int speed)
+{
+ ar5315_cpu_ops->ar5315_chip_set_pll_ge(unit, speed);
+}
+
+static inline void ar531x_device_set_mii_speed(int unit, int speed)
+{
+ ar5315_cpu_ops->ar5315_chip_set_mii_speed(unit, speed);
+}
+
+static inline void ar531x_device_flush_ddr_ge(int unit)
+{
+ ar5315_cpu_ops->ar5315_chip_ddr_flush_ge(unit);
+}
+
+static inline void ar531x_device_soc_init(void)
+{
+ ar5315_cpu_ops->ar5315_chip_soc_init();
+}
+
+static inline void ar531x_device_set_mii_mode(int unit, int mode, int speed)
+{
+ ar5315_cpu_ops->ar5315_chip_set_mii_mode(unit, mode, speed);
+}
+
+/* XXX shouldn't be here! */
+extern uint32_t u_ar531x_cpu_freq;
+extern uint32_t u_ar531x_ahb_freq;
+extern uint32_t u_ar531x_ddr_freq;
+
+extern uint32_t u_ar531x_uart_addr;
+
+extern uint32_t u_ar531x_gpio_di;
+extern uint32_t u_ar531x_gpio_do;
+extern uint32_t u_ar531x_gpio_cr;
+extern uint32_t u_ar531x_gpio_pins;
+
+extern uint32_t u_ar531x_wdog_ctl;
+extern uint32_t u_ar531x_wdog_timer;
+
+static inline uint32_t ar531x_cpu_freq(void) { return u_ar531x_cpu_freq; }
+static inline uint32_t ar531x_ahb_freq(void) { return u_ar531x_ahb_freq; }
+static inline uint32_t ar531x_ddr_freq(void) { return u_ar531x_ddr_freq; }
+
+static inline uint32_t ar531x_uart_addr(void) { return u_ar531x_uart_addr; }
+
+static inline uint32_t ar531x_gpio_di(void) { return u_ar531x_gpio_di; }
+static inline uint32_t ar531x_gpio_cr(void) { return u_ar531x_gpio_cr; }
+static inline uint32_t ar531x_gpio_do(void) { return u_ar531x_gpio_do; }
+static inline uint32_t ar531x_gpio_pins(void) { return u_ar531x_gpio_pins; }
+
+static inline uint32_t ar531x_wdog_ctl(void) { return u_ar531x_wdog_ctl; }
+static inline uint32_t ar531x_wdog_timer(void) { return u_ar531x_wdog_timer; }
+#endif
Index: sys/mips/atheros/ar531x/ar5315_gpio.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_gpio.c
@@ -0,0 +1,534 @@
+/*-
+ * Copyright (c) 2016, Hiroki Mori
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * Copyright (c) 2009, Luiz Otavio O Souza.
+ * 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 unmodified, 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 driver for AR5315
+ */
+
+#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/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+#include <mips/atheros/ar531x/ar5315_gpiovar.h>
+#include <dev/gpio/gpiobusvar.h>
+
+#include "gpio_if.h"
+
+#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
+
+/*
+ * Helpers
+ */
+static void ar5315_gpio_function_enable(struct ar5315_gpio_softc *sc,
+ uint32_t mask);
+static void ar5315_gpio_function_disable(struct ar5315_gpio_softc *sc,
+ uint32_t mask);
+static void ar5315_gpio_pin_configure(struct ar5315_gpio_softc *sc,
+ struct gpio_pin *pin, uint32_t flags);
+
+/*
+ * Driver stuff
+ */
+static int ar5315_gpio_probe(device_t dev);
+static int ar5315_gpio_attach(device_t dev);
+static int ar5315_gpio_detach(device_t dev);
+static int ar5315_gpio_filter(void *arg);
+static void ar5315_gpio_intr(void *arg);
+
+/*
+ * GPIO interface
+ */
+static device_t ar5315_gpio_get_bus(device_t);
+static int ar5315_gpio_pin_max(device_t dev, int *maxpin);
+static int ar5315_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
+static int ar5315_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
+ *flags);
+static int ar5315_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
+static int ar5315_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
+static int ar5315_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
+static int ar5315_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
+static int ar5315_gpio_pin_toggle(device_t dev, uint32_t pin);
+
+/*
+ * Enable/disable the GPIO function control space.
+ *
+ * This is primarily for the AR5315, which has SPI CS1/CS2, UART, SLIC, I2S
+ * as GPIO pin options.
+ */
+static void
+ar5315_gpio_function_enable(struct ar5315_gpio_softc *sc, uint32_t mask)
+{
+// GPIO_SET_BITS(sc, AR5315_GPIO_FUNCTION, mask);
+}
+
+static void
+ar5315_gpio_function_disable(struct ar5315_gpio_softc *sc, uint32_t mask)
+{
+// GPIO_CLEAR_BITS(sc, AR5315_GPIO_FUNCTION, mask);
+}
+
+static void
+ar5315_gpio_pin_configure(struct ar5315_gpio_softc *sc, struct gpio_pin *pin,
+ unsigned int flags)
+{
+ uint32_t mask;
+
+ mask = 1 << pin->gp_pin;
+
+ /*
+ * Manage input/output
+ */
+ if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
+ pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
+ if (flags & GPIO_PIN_OUTPUT) {
+ pin->gp_flags |= GPIO_PIN_OUTPUT;
+ GPIO_SET_BITS(sc, ar531x_gpio_cr(), mask);
+ }
+ else {
+ pin->gp_flags |= GPIO_PIN_INPUT;
+ GPIO_CLEAR_BITS(sc, ar531x_gpio_cr(), mask);
+ }
+ }
+}
+
+static device_t
+ar5315_gpio_get_bus(device_t dev)
+{
+ struct ar5315_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->busdev);
+}
+
+static int
+ar5315_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+ *maxpin = ar531x_gpio_pins() - 1;
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ if (sc->gpio_pins[i].gp_pin == pin)
+ break;
+ }
+
+ if (i >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ *caps = sc->gpio_pins[i].gp_caps;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+ int i;
+ int dir;
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ if (sc->gpio_pins[i].gp_pin == pin)
+ break;
+ }
+
+ if (i >= sc->gpio_npins)
+ return (EINVAL);
+
+ dir = GPIO_READ(sc, ar531x_gpio_cr()) & (1 << pin);
+
+ *flags = dir ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
+
+/*
+ GPIO_LOCK(sc);
+ *flags = sc->gpio_pins[i].gp_flags;
+ GPIO_UNLOCK(sc);
+*/
+
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ if (sc->gpio_pins[i].gp_pin == pin)
+ break;
+ }
+
+ if (i >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ int i;
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ if (sc->gpio_pins[i].gp_pin == pin)
+ break;
+ }
+
+ if (i >= sc->gpio_npins)
+ return (EINVAL);
+
+ ar5315_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
+
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+ uint32_t state;
+
+ state = GPIO_READ(sc, ar531x_gpio_do());
+
+ if(value == 1) {
+ state |= (1 << pin);
+ } else {
+ state &= ~(1 << pin);
+ }
+
+ GPIO_WRITE(sc, ar531x_gpio_do(), state);
+
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ if (sc->gpio_pins[i].gp_pin == pin)
+ break;
+ }
+
+ if (i >= sc->gpio_npins)
+ return (EINVAL);
+
+ *val = (GPIO_READ(sc, ar531x_gpio_di()) & (1 << pin)) ? 1 : 0;
+
+ return (0);
+}
+
+static int
+ar5315_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ int res, i;
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ if (sc->gpio_pins[i].gp_pin == pin)
+ break;
+ }
+
+ if (i >= sc->gpio_npins)
+ return (EINVAL);
+
+ res = (GPIO_READ(sc, ar531x_gpio_do()) & (1 << pin)) ? 1 : 0;
+ if (res)
+ GPIO_CLEAR_BITS(sc, ar531x_gpio_do(), pin);
+ else
+ GPIO_SET_BITS(sc, ar531x_gpio_do(), pin);
+
+ return (0);
+}
+
+static int
+ar5315_gpio_filter(void *arg)
+{
+
+ /* TODO: something useful */
+ return (FILTER_STRAY);
+}
+
+
+
+static void
+ar5315_gpio_intr(void *arg)
+{
+ struct ar5315_gpio_softc *sc = arg;
+ GPIO_LOCK(sc);
+ /* TODO: something useful */
+ GPIO_UNLOCK(sc);
+}
+
+static int
+ar5315_gpio_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Atheros AR531x GPIO driver");
+ return (0);
+}
+
+static int
+ar5315_gpio_attach(device_t dev)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+ int i, j, maxpin;
+ int mask, pinon;
+ uint32_t oe;
+
+ KASSERT((device_get_unit(dev) == 0),
+ ("ar5315_gpio: Only one gpio module supported"));
+
+ mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ /* Map control/status registers. */
+ sc->gpio_mem_rid = 0;
+ sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->gpio_mem_rid, RF_ACTIVE);
+
+ if (sc->gpio_mem_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ ar5315_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ ar5315_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC,
+ ar5315_gpio_filter, ar5315_gpio_intr, sc, &sc->gpio_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ ar5315_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ sc->dev = dev;
+
+ /* Enable function bits that are required */
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "function_set", &mask) == 0) {
+ device_printf(dev, "function_set: 0x%x\n", mask);
+ ar5315_gpio_function_enable(sc, mask);
+ }
+ /* Disable function bits that are required */
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "function_clear", &mask) == 0) {
+ device_printf(dev, "function_clear: 0x%x\n", mask);
+ ar5315_gpio_function_disable(sc, mask);
+ }
+
+ /* Initialise all pins specified in the mask, up to the pin count */
+ (void) ar5315_gpio_pin_max(dev, &maxpin);
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "pinmask", &mask) != 0)
+ mask = 0;
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "pinon", &pinon) != 0)
+ pinon = 0;
+ device_printf(dev, "gpio pinmask=0x%x\n", mask);
+ for (j = 0; j <= maxpin; j++) {
+ if ((mask & (1 << j)) == 0)
+ continue;
+ sc->gpio_npins++;
+ }
+
+ /* Iniatilize the GPIO pins, keep the loader settings. */
+ oe = GPIO_READ(sc, ar531x_gpio_cr());
+ sc->gpio_pins = malloc(sizeof(struct gpio_pin) * sc->gpio_npins,
+ M_DEVBUF, M_WAITOK | M_ZERO);
+ for (i = 0, j = 0; j <= maxpin; j++) {
+ if ((mask & (1 << j)) == 0)
+ continue;
+ snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
+ "pin %d", j);
+ sc->gpio_pins[i].gp_pin = j;
+ sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
+ if (oe & (1 << j))
+ sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT;
+ else
+ sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT;
+ i++;
+ }
+
+#if 0
+ /* Turn on the hinted pins. */
+ for (i = 0; i < sc->gpio_npins; i++) {
+ j = sc->gpio_pins[i].gp_pin;
+ if ((pinon & (1 << j)) != 0) {
+ ar5315_gpio_pin_setflags(dev, j, GPIO_PIN_OUTPUT);
+ ar5315_gpio_pin_set(dev, j, 1);
+ }
+ }
+
+ /*
+ * Search through the function hints, in case there's some
+ * overrides such as LNA control.
+ *
+ * hint.gpio.X.func.<pin>.gpiofunc=<func value>
+ * hint.gpio.X.func.<pin>.gpiomode=1 (for output, default low)
+ */
+ for (i = 0; i <= maxpin; i++) {
+ char buf[32];
+ int gpiofunc, gpiomode;
+
+ snprintf(buf, 32, "func.%d.gpiofunc", i);
+ if (resource_int_value(device_get_name(dev),
+ device_get_unit(dev),
+ buf,
+ &gpiofunc) != 0)
+ continue;
+ /* Get the mode too */
+ snprintf(buf, 32, "func.%d.gpiomode", i);
+ if (resource_int_value(device_get_name(dev),
+ device_get_unit(dev),
+ buf,
+ &gpiomode) != 0)
+ continue;
+
+ /* We only handle mode=1 for now */
+ if (gpiomode != 1)
+ continue;
+
+ device_printf(dev, "%s: GPIO %d: func=%d, mode=%d\n",
+ __func__,
+ i,
+ gpiofunc,
+ gpiomode);
+
+ /* Set output (bit == 0) */
+ oe = GPIO_READ(sc, ar531x_gpio_cr());
+ oe &= ~ (1 << i);
+ GPIO_WRITE(sc, ar531x_gpio_cr(), oe);
+
+ /* Set pin value = 0, so it stays low by default */
+ oe = GPIO_READ(sc, ar531x_gpio_do());
+ oe &= ~ (1 << i);
+ GPIO_WRITE(sc, ar531x_gpio_do(), oe);
+
+ /* Finally: Set the output config */
+// ar5315_gpio_ouput_configure(i, gpiofunc);
+ }
+#endif
+
+ sc->busdev = gpiobus_attach_bus(dev);
+ if (sc->busdev == NULL) {
+ ar5315_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+ar5315_gpio_detach(device_t dev)
+{
+ struct ar5315_gpio_softc *sc = device_get_softc(dev);
+
+ KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized"));
+
+ gpiobus_detach_bus(dev);
+ if (sc->gpio_ih)
+ bus_teardown_intr(dev, sc->gpio_irq_res, sc->gpio_ih);
+ if (sc->gpio_irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ, sc->gpio_irq_rid,
+ sc->gpio_irq_res);
+ if (sc->gpio_mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid,
+ sc->gpio_mem_res);
+ if (sc->gpio_pins)
+ free(sc->gpio_pins, M_DEVBUF);
+ mtx_destroy(&sc->gpio_mtx);
+
+ return(0);
+}
+
+static device_method_t ar5315_gpio_methods[] = {
+ DEVMETHOD(device_probe, ar5315_gpio_probe),
+ DEVMETHOD(device_attach, ar5315_gpio_attach),
+ DEVMETHOD(device_detach, ar5315_gpio_detach),
+
+ /* GPIO protocol */
+ DEVMETHOD(gpio_get_bus, ar5315_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, ar5315_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, ar5315_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, ar5315_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, ar5315_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, ar5315_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, ar5315_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, ar5315_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, ar5315_gpio_pin_toggle),
+ {0, 0},
+};
+
+static driver_t ar5315_gpio_driver = {
+ "gpio",
+ ar5315_gpio_methods,
+ sizeof(struct ar5315_gpio_softc),
+};
+static devclass_t ar5315_gpio_devclass;
+
+DRIVER_MODULE(ar5315_gpio, apb, ar5315_gpio_driver, ar5315_gpio_devclass, 0, 0);
Index: sys/mips/atheros/ar531x/ar5315_gpiovar.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_gpiovar.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * Copyright (c) 2009, Luiz Otavio O Souza.
+ * 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 unmodified, 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 __AR5315_GPIOVAR_H__
+#define __AR5315_GPIOVAR_H__
+
+#include <sys/timepps.h>
+
+#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->gpio_mtx)
+#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->gpio_mtx)
+#define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->gpio_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define GPIO_WRITE(sc, reg, val) do { \
+ bus_write_4(sc->gpio_mem_res, (reg), (val)); \
+ } while (0)
+
+#define GPIO_READ(sc, reg) bus_read_4(sc->gpio_mem_res, (reg))
+
+#define GPIO_SET_BITS(sc, reg, bits) \
+ GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) | (bits))
+
+#define GPIO_CLEAR_BITS(sc, reg, bits) \
+ GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) & ~(bits))
+
+#define AR5315_GPIO_PINS 23
+#define AR5312_GPIO_PINS 8
+
+struct ar5315_gpio_softc {
+ device_t dev;
+ device_t busdev;
+ struct mtx gpio_mtx;
+ struct resource *gpio_mem_res;
+ int gpio_mem_rid;
+ struct resource *gpio_irq_res;
+ int gpio_irq_rid;
+ void *gpio_ih;
+ int gpio_npins;
+ struct gpio_pin *gpio_pins;
+ int gpio_ppspin;
+ struct pps_state gpio_pps;
+ uint32_t gpio_ppsenable;
+};
+
+#endif /* __AR5315_GPIOVAR_H__ */
Index: sys/mips/atheros/ar531x/ar5315_machdep.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_machdep.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 2016, Hiroki Mori
+ * Copyright (c) 2009 Oleksandr Tymoshenko
+ * 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: head/sys/mips/atheros/ar71xx_machdep.c 232853 2012-03-12 07:34:15Z jmallett $");
+
+#include "opt_ddb.h"
+#include "opt_ar531x.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <net/ethernet.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/md_var.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+
+#include <mips/atheros/ar531x/ar5315_setup.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+
+extern char edata[], end[];
+
+uint32_t ar711_base_mac[ETHER_ADDR_LEN];
+/* 4KB static data aread to keep a copy of the bootload env until
+ the dynamic kenv is setup */
+char boot1_env[4096];
+
+/*
+ * We get a string in from Redboot with the all the arguments together,
+ * "foo=bar bar=baz". Split them up and save in kenv.
+ */
+static void
+parse_argv(char *str)
+{
+ char *n, *v;
+
+ while ((v = strsep(&str, " ")) != NULL) {
+ if (*v == '\0')
+ continue;
+ if (*v == '-') {
+ while (*v != '\0') {
+ v++;
+ switch (*v) {
+ case 'a': boothowto |= RB_ASKNAME; break;
+ case 'd': boothowto |= RB_KDB; break;
+ case 'g': boothowto |= RB_GDB; break;
+ case 's': boothowto |= RB_SINGLE; break;
+ case 'v': boothowto |= RB_VERBOSE; break;
+ }
+ }
+ } else {
+ n = strsep(&v, "=");
+ if (v == NULL)
+ kern_setenv(n, "1");
+ else
+ kern_setenv(n, v);
+ }
+ }
+}
+
+void
+platform_cpu_init()
+{
+ /* Nothing special */
+}
+
+void
+platform_reset(void)
+{
+ ar531x_device_reset();
+ /* Wait for reset */
+ while(1)
+ ;
+}
+
+/*
+ * Obtain the MAC address via the Redboot environment.
+ */
+static void
+ar5315_redboot_get_macaddr(void)
+{
+ char *var;
+ int count = 0;
+
+ /*
+ * "ethaddr" is passed via envp on RedBoot platforms
+ * "kmac" is passed via argv on RouterBOOT platforms
+ */
+ if ((var = kern_getenv("ethaddr")) != NULL ||
+ (var = kern_getenv("kmac")) != NULL) {
+ count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
+ &ar711_base_mac[0], &ar711_base_mac[1],
+ &ar711_base_mac[2], &ar711_base_mac[3],
+ &ar711_base_mac[4], &ar711_base_mac[5]);
+ if (count < 6)
+ memset(ar711_base_mac, 0,
+ sizeof(ar711_base_mac));
+ freeenv(var);
+ }
+}
+
+#if defined(SOC_VENDOR) || defined(SOC_MODEL) || defined(SOC_REV)
+static SYSCTL_NODE(_hw, OID_AUTO, soc, CTLFLAG_RD, 0,
+ "System on Chip information");
+#endif
+#if defined(SOC_VENDOR)
+static char hw_soc_vendor[] = SOC_VENDOR;
+SYSCTL_STRING(_hw_soc, OID_AUTO, vendor, CTLFLAG_RD, hw_soc_vendor, 0,
+ "SoC vendor");
+#endif
+#if defined(SOC_MODEL)
+static char hw_soc_model[] = SOC_MODEL;
+SYSCTL_STRING(_hw_soc, OID_AUTO, model, CTLFLAG_RD, hw_soc_model, 0,
+ "SoC model");
+#endif
+#if defined(SOC_REV)
+static char hw_soc_revision[] = SOC_REV;
+SYSCTL_STRING(_hw_soc, OID_AUTO, revision, CTLFLAG_RD, hw_soc_revision, 0,
+ "SoC revision");
+#endif
+
+#if defined(DEVICE_VENDOR) || defined(DEVICE_MODEL) || defined(DEVICE_REV)
+static SYSCTL_NODE(_hw, OID_AUTO, device, CTLFLAG_RD, 0, "Board information");
+#endif
+#if defined(DEVICE_VENDOR)
+static char hw_device_vendor[] = DEVICE_VENDOR;
+SYSCTL_STRING(_hw_device, OID_AUTO, vendor, CTLFLAG_RD, hw_device_vendor, 0,
+ "Board vendor");
+#endif
+#if defined(DEVICE_MODEL)
+static char hw_device_model[] = DEVICE_MODEL;
+SYSCTL_STRING(_hw_device, OID_AUTO, model, CTLFLAG_RD, hw_device_model, 0,
+ "Board model");
+#endif
+#if defined(DEVICE_REV)
+static char hw_device_revision[] = DEVICE_REV;
+SYSCTL_STRING(_hw_device, OID_AUTO, revision, CTLFLAG_RD, hw_device_revision, 0,
+ "Board revision");
+#endif
+
+void
+platform_start(__register_t a0 __unused, __register_t a1 __unused,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ uint64_t platform_counter_freq;
+ int argc = 0, i;
+ char **argv = NULL;
+#ifndef AR531X_ENV_UBOOT
+ char **envp = NULL;
+#endif
+ vm_offset_t kernend;
+
+ /*
+ * clear the BSS and SBSS segments, this should be first call in
+ * the function
+ */
+ kernend = (vm_offset_t)&end;
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ mips_postboot_fixup();
+
+ /* Initialize pcpu stuff */
+ mips_pcpu0_init();
+
+ /*
+ * Until some more sensible abstractions for uboot/redboot
+ * environment handling, we have to make this a compile-time
+ * hack. The existing code handles the uboot environment
+ * very incorrectly so we should just ignore initialising
+ * the relevant pointers.
+ */
+#ifndef AR531X_ENV_UBOOT
+ argc = a0;
+ argv = (char**)a1;
+ envp = (char**)a2;
+#endif
+ /*
+ * Protect ourselves from garbage in registers
+ */
+ if (MIPS_IS_VALID_PTR(envp)) {
+ for (i = 0; envp[i]; i += 2) {
+ if (strcmp(envp[i], "memsize") == 0)
+ realmem = btoc(strtoul(envp[i+1], NULL, 16));
+ }
+ }
+
+ ar5315_detect_sys_type();
+
+// RedBoot SDRAM Detect is missing
+// ar531x_detect_mem_size();
+
+ /*
+ * Just wild guess. RedBoot let us down and didn't reported
+ * memory size
+ */
+ if (realmem == 0)
+ realmem = btoc(16*1024*1024);
+
+ /*
+ * Allow build-time override in case Redboot lies
+ * or in other situations (eg where there's u-boot)
+ * where there isn't (yet) a convienent method of
+ * being told how much RAM is available.
+ *
+ * This happens on at least the Ubiquiti LS-SR71A
+ * board, where redboot says there's 16mb of RAM
+ * but in fact there's 32mb.
+ */
+#if defined(AR531X_REALMEM)
+ realmem = btoc(AR531X_REALMEM);
+#endif
+
+ /* phys_avail regions are in bytes */
+ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
+ phys_avail[1] = ctob(realmem);
+
+ dump_avail[0] = phys_avail[0];
+ dump_avail[1] = phys_avail[1] - phys_avail[0];
+
+ physmem = realmem;
+
+ /*
+ * ns8250 uart code uses DELAY so ticker should be inititalized
+ * before cninit. And tick_init_params refers to hz, so * init_param1
+ * should be called first.
+ */
+ init_param1();
+ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */
+// boothowto |= RB_VERBOSE;
+// boothowto |= (RB_SINGLE);
+
+ /* Detect the system type - this is needed for subsequent chipset-specific calls */
+
+
+ ar531x_device_soc_init();
+ ar531x_detect_sys_frequency();
+
+ platform_counter_freq = ar531x_cpu_freq();
+ mips_timer_init_params(platform_counter_freq, 1);
+ cninit();
+ init_static_kenv(boot1_env, sizeof(boot1_env));
+
+ printf("CPU platform: %s\n", ar5315_get_system_type());
+ printf("CPU Frequency=%d MHz\n", ar531x_cpu_freq() / 1000000);
+ printf("CPU DDR Frequency=%d MHz\n", ar531x_ddr_freq() / 1000000);
+ printf("CPU AHB Frequency=%d MHz\n", ar531x_ahb_freq() / 1000000);
+
+ printf("platform frequency: %lld\n", platform_counter_freq);
+ printf("arguments: \n");
+ printf(" a0 = %08x\n", a0);
+ printf(" a1 = %08x\n", a1);
+ printf(" a2 = %08x\n", a2);
+ printf(" a3 = %08x\n", a3);
+
+ /*
+ * XXX this code is very redboot specific.
+ */
+ printf("Cmd line:");
+ if (MIPS_IS_VALID_PTR(argv)) {
+ for (i = 0; i < argc; i++) {
+ printf(" %s", argv[i]);
+ parse_argv(argv[i]);
+ }
+ }
+ else
+ printf ("argv is invalid");
+ printf("\n");
+
+ printf("Environment:\n");
+#if 0
+ if (MIPS_IS_VALID_PTR(envp)) {
+ if (envp[0] && strchr(envp[0], '=') ) {
+ char *env_val; //
+ for (i = 0; envp[i]; i++) {
+ env_val = strchr(envp[i], '=');
+ /* Not sure if we correct to change data, but env in RAM */
+ *(env_val++) = '\0';
+ printf("= %s = %s\n", envp[i], env_val);
+ kern_setenv(envp[i], env_val);
+ }
+ } else {
+ for (i = 0; envp[i]; i+=2) {
+ printf(" %s = %s\n", envp[i], envp[i+1]);
+ kern_setenv(envp[i], envp[i+1]);
+ }
+ }
+ }
+ else
+ printf ("envp is invalid\n");
+#else
+ printf ("envp skiped\n");
+#endif
+
+ /* Redboot if_are MAC address is in the environment */
+ ar5315_redboot_get_macaddr();
+
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+
+ ar531x_device_start();
+
+ kdb_init();
+#ifdef KDB
+ if (boothowto & RB_KDB)
+ kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
+#endif
+
+}
Index: sys/mips/atheros/ar531x/ar5315_setup.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_setup.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2010 Adrian Chadd
+ * 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 __AR5315_SETUP_H__
+#define __AR5315_SETUP_H__
+
+enum ar531x_soc_type {
+ AR531X_SOC_UNKNOWN,
+ AR531X_SOC_AR5311,
+ AR531X_SOC_AR5312,
+ AR531X_SOC_AR5313,
+ AR531X_SOC_AR5314,
+ AR531X_SOC_AR5315,
+ AR531X_SOC_AR5316,
+ AR531X_SOC_AR5317,
+ AR531X_SOC_AR5318,
+};
+extern enum ar531x_soc_type ar531x_soc;
+
+extern void ar5315_detect_sys_type(void);
+extern const char *ar5315_get_system_type(void);
+
+#define AR_FIRST_GEN 1
+#define AR_SECOND_GEN 2
+
+#endif
Index: sys/mips/atheros/ar531x/ar5315_setup.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_setup.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2016, Hiroki Mori
+ * Copyright (c) 2010 Adrian Chadd
+ * 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: head/sys/mips/atheros/ar5315_setup.c 223562 2011-06-26 10:07:48Z kevlo $");
+
+#include "opt_ddb.h"
+#include "opt_ar531x.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <net/ethernet.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/md_var.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5312reg.h>
+#include <mips/atheros/ar531x/ar5315_setup.h>
+
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+
+#include <mips/atheros/ar531x/ar5315_chip.h>
+#include <mips/atheros/ar531x/ar5312_chip.h>
+#include <mips/atheros/ar724x_chip.h>
+#include <mips/atheros/ar91xx_chip.h>
+
+#include <dev/ath/ath_hal/ah_soc.h>
+
+#define AR5315_SYS_TYPE_LEN 128
+
+static char ar5315_sys_type[AR5315_SYS_TYPE_LEN];
+enum ar531x_soc_type ar531x_soc;
+struct ar5315_cpu_def * ar5315_cpu_ops = NULL;
+
+void
+ar5315_detect_sys_type(void)
+{
+ char *chip = "????";
+ uint32_t ver = 0;
+ uint32_t rev = 0;
+#if 0
+ const uint8_t *ptr, *end;
+ static const struct ar531x_boarddata *board = NULL;
+
+ ptr = (const uint8_t *) MIPS_PHYS_TO_KSEG1(AR5315_CONFIG_END
+ - 0x1000);
+
+ end = (const uint8_t *)AR5315_CONFIG_BASE;
+
+ for (; ptr > end; ptr -= 0x1000) {
+ if (*(const uint32_t *)ptr == AR531X_BD_MAGIC) {
+ board = (const struct ar531x_boarddata *) ptr;
+ rev = board->major;
+ break;
+ }
+ }
+#endif
+ int soctype;
+
+#ifdef AR531X_1ST_GENERATION
+ soctype = AR_FIRST_GEN;
+#else
+ soctype = AR_SECOND_GEN;
+#endif
+
+ if(soctype == AR_SECOND_GEN) {
+ ar5315_cpu_ops = &ar5315_chip_def;
+
+ ver = ATH_READ_REG(AR5315_SYSREG_BASE +
+ AR5315_SYSREG_SREV);
+
+ switch (ver) {
+ case 0x86:
+ ar531x_soc = AR531X_SOC_AR5315;
+ chip = "2315";
+ break;
+ case 0x87:
+ ar531x_soc = AR531X_SOC_AR5316;
+ chip = "2316";
+ break;
+ case 0x90:
+ ar531x_soc = AR531X_SOC_AR5317;
+ chip = "2317";
+ break;
+ case 0x91:
+ ar531x_soc = AR531X_SOC_AR5318;
+ chip = "2318";
+ break;
+ }
+ } else {
+ ar5315_cpu_ops = &ar5312_chip_def;
+
+ ver = ATH_READ_REG(AR5312_SYSREG_BASE +
+ AR5312_SYSREG_REVISION);
+ rev = AR5312_REVISION_MINOR(ver);
+
+ switch (AR5312_REVISION_MAJOR(ver)) {
+ case AR5312_REVISION_MAJ_AR5311:
+ ar531x_soc = AR531X_SOC_AR5311;
+ chip = "5311";
+ break;
+ case AR5312_REVISION_MAJ_AR5312:
+ ar531x_soc = AR531X_SOC_AR5312;
+ chip = "5312";
+ break;
+ case AR5312_REVISION_MAJ_AR2313:
+ ar531x_soc = AR531X_SOC_AR5313;
+ chip = "2313";
+ break;
+ }
+ }
+
+ sprintf(ar5315_sys_type, "Atheros AR%s rev %u", chip, rev);
+}
+
+const char *
+ar5315_get_system_type(void)
+{
+ return ar5315_sys_type;
+}
+
Index: sys/mips/atheros/ar531x/ar5315_spi.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_spi.c
@@ -0,0 +1,287 @@
+/*-
+ * Copyright (c) 2016, Hiroki Mori
+ * Copyright (c) 2009, 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 unmodified, 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: head/sys/mips/atheros/ar5315_spi.c 202723 2010-01-21 00:15:59Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include <dev/spibus/spi.h>
+#include <dev/spibus/spibusvar.h>
+#include "spibus_if.h"
+
+#include <mips/atheros/ar531x/arspireg.h>
+#include <mips/atheros/ar531x/ar5315reg.h>
+
+#undef AR531X_SPI_DEBUG
+#ifdef AR531X_SPI_DEBUG
+#define dprintf printf
+#else
+#define dprintf(x, arg...)
+#endif
+
+/*
+ * register space access macros
+ */
+#define SPI_WRITE(sc, reg, val) do { \
+ bus_write_4(sc->sc_mem_res, (reg), (val)); \
+ } while (0)
+
+#define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg))
+
+#define SPI_SET_BITS(sc, reg, bits) \
+ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
+
+#define SPI_CLEAR_BITS(sc, reg, bits) \
+ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
+
+struct ar5315_spi_softc {
+ device_t sc_dev;
+ struct resource *sc_mem_res;
+ uint32_t sc_reg_ctrl;
+ uint32_t sc_debug;
+};
+
+static void
+ar5315_spi_attach_sysctl(device_t dev)
+{
+ struct ar5315_spi_softc *sc;
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+
+ sc = device_get_softc(dev);
+ ctx = device_get_sysctl_ctx(dev);
+ tree = device_get_sysctl_tree(dev);
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->sc_debug, 0,
+ "ar5315_spi debugging flags");
+}
+
+static int
+ar5315_spi_probe(device_t dev)
+{
+ device_set_desc(dev, "AR5315 SPI");
+ return (0);
+}
+
+static int
+ar5315_spi_attach(device_t dev)
+{
+ struct ar5315_spi_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->sc_dev = dev;
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_mem_res) {
+ device_printf(dev, "Could not map memory\n");
+ return (ENXIO);
+ }
+
+ device_add_child(dev, "spibus", 0);
+ ar5315_spi_attach_sysctl(dev);
+
+ return (bus_generic_attach(dev));
+}
+
+static void
+ar5315_spi_chip_activate(struct ar5315_spi_softc *sc, int cs)
+{
+}
+
+static void
+ar5315_spi_chip_deactivate(struct ar5315_spi_softc *sc, int cs)
+{
+}
+
+static int
+ar5315_spi_get_block(off_t offset, caddr_t data, off_t count)
+{
+ int i;
+ for(i = 0; i < count / 4; ++i) {
+ *((uint32_t *)data + i) = ATH_READ_REG(AR5315_MEM1_BASE + offset + i * 4);
+ }
+// printf("ar5315_spi_get_blockr: %x %x %x\n",
+// (int)offset, (int)count, *(uint32_t *)data);
+ return (0);
+}
+
+static int
+ar5315_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
+{
+ struct ar5315_spi_softc *sc;
+ uint8_t *buf_in, *buf_out;
+ struct spibus_ivar *devi = SPIBUS_IVAR(child);
+ int lin, lout;
+ uint32_t ctl, cnt, op, rdat;
+ int i, j;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_debug & 0x8000)
+ printf("ar5315_spi_transfer: CMD ");
+
+ /* Open SPI controller interface */
+ ar5315_spi_chip_activate(sc, devi->cs);
+
+ do {
+ ctl = SPI_READ(sc, ARSPI_REG_CTL);
+ } while (ctl & ARSPI_CTL_BUSY);
+
+ /*
+ * Transfer command
+ */
+ buf_out = (uint8_t *)cmd->tx_cmd;
+ op = buf_out[0];
+ if(op == 0x0b) {
+ int offset = buf_out[1] << 16 | buf_out[2] << 8 | buf_out[3];
+ ar5315_spi_get_block(offset, cmd->rx_data, cmd->rx_data_sz);
+ return (0);
+ }
+ do {
+ ctl = SPI_READ(sc, ARSPI_REG_CTL);
+ } while (ctl & ARSPI_CTL_BUSY);
+ if (sc->sc_debug & 0x8000) {
+ printf("%08x ", op);
+ printf("tx_cmd_sz=%d rx_cmd_sz=%d ", cmd->tx_cmd_sz,
+ cmd->rx_cmd_sz);
+ if(cmd->tx_cmd_sz != 1) {
+ printf("%08x ", *((uint32_t *)cmd->tx_cmd));
+ printf("%08x ", *((uint32_t *)cmd->tx_cmd + 1));
+ }
+ }
+ SPI_WRITE(sc, ARSPI_REG_OPCODE, op);
+
+ /* clear all of the tx and rx bits */
+ ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK);
+
+ /* now set txcnt */
+ cnt = 1;
+
+ ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT);
+
+ cnt = 24;
+ /* now set txcnt */
+ if(cmd->rx_cmd_sz < 24)
+ cnt = cmd->rx_cmd_sz;
+ ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT);
+
+ ctl |= ARSPI_CTL_START;
+
+ SPI_WRITE(sc, ARSPI_REG_CTL, ctl);
+
+ if(op == 0x0b)
+ SPI_WRITE(sc, ARSPI_REG_DATA, 0);
+ if (sc->sc_debug & 0x8000)
+ printf("\nDATA ");
+ /*
+ * Receive/transmit data (depends on command)
+ */
+// buf_out = (uint8_t *)cmd->tx_data;
+ buf_in = (uint8_t *)cmd->rx_cmd;
+// lout = cmd->tx_data_sz;
+ lin = cmd->rx_cmd_sz;
+ if (sc->sc_debug & 0x8000)
+ printf("t%d r%d ", lout, lin);
+ for(i = 0; i <= (cnt - 1) / 4; ++i) {
+ do {
+ ctl = SPI_READ(sc, ARSPI_REG_CTL);
+ } while (ctl & ARSPI_CTL_BUSY);
+
+ rdat = SPI_READ(sc, ARSPI_REG_DATA);
+ if (sc->sc_debug & 0x8000)
+ printf("I%08x ", rdat);
+
+ for(j = 0; j < 4; ++j) {
+ buf_in[i * 4 + j + 1] = 0xff & (rdat >> (8 * j));
+ if(i * 4 + j + 2 == cnt)
+ break;
+ }
+ }
+
+ ar5315_spi_chip_deactivate(sc, devi->cs);
+ /*
+ * Close SPI controller interface, restore flash memory mapped access.
+ */
+ if (sc->sc_debug & 0x8000)
+ printf("\n");
+
+ return (0);
+}
+
+static int
+ar5315_spi_detach(device_t dev)
+{
+ struct ar5315_spi_softc *sc = device_get_softc(dev);
+
+ if (sc->sc_mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+
+ return (0);
+}
+
+static device_method_t ar5315_spi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ar5315_spi_probe),
+ DEVMETHOD(device_attach, ar5315_spi_attach),
+ DEVMETHOD(device_detach, ar5315_spi_detach),
+
+ DEVMETHOD(spibus_transfer, ar5315_spi_transfer),
+// DEVMETHOD(spibus_get_block, ar5315_spi_get_block),
+
+ DEVMETHOD_END
+};
+
+static driver_t ar5315_spi_driver = {
+ "spi",
+ ar5315_spi_methods,
+ sizeof(struct ar5315_spi_softc),
+};
+
+static devclass_t ar5315_spi_devclass;
+
+DRIVER_MODULE(ar5315_spi, nexus, ar5315_spi_driver, ar5315_spi_devclass, 0, 0);
Index: sys/mips/atheros/ar531x/ar5315_wdog.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315_wdog.c
@@ -0,0 +1,150 @@
+/*-
+ * Copyright (c) 2016, Hiroki Mori
+ * Copyright (c) 2009, 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 unmodified, 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.
+ */
+
+/*
+ * Watchdog driver for AR5315
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/watchdog.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+
+struct ar5315_wdog_softc {
+ device_t dev;
+ int armed;
+ int reboot_from_watchdog;
+ int debug;
+};
+
+static void
+ar5315_wdog_watchdog_fn(void *private, u_int cmd, int *error)
+{
+ struct ar5315_wdog_softc *sc = private;
+ uint64_t timer_val;
+
+ cmd &= WD_INTERVAL;
+ if (sc->debug)
+ device_printf(sc->dev, "ar5315_wdog_watchdog_fn: cmd: %x\n", cmd);
+ if (cmd > 0) {
+ timer_val = (uint64_t)(1ULL << cmd) * ar531x_ahb_freq() /
+ 1000000000;
+ if (sc->debug)
+ device_printf(sc->dev, "ar5315_wdog_watchdog_fn: programming timer: %jx\n", (uintmax_t) timer_val);
+ /*
+ * Load timer with large enough value to prevent spurious
+ * reset
+ */
+ ATH_WRITE_REG(ar531x_wdog_timer(),
+ ar531x_ahb_freq() * 10);
+ ATH_WRITE_REG(ar531x_wdog_ctl(),
+ AR5315_WDOG_CTL_RESET);
+ ATH_WRITE_REG(ar531x_wdog_timer(),
+ (timer_val & 0xffffffff));
+ sc->armed = 1;
+ *error = 0;
+ } else {
+ if (sc->debug)
+ device_printf(sc->dev, "ar5315_wdog_watchdog_fn: disarming\n");
+ if (sc->armed) {
+ ATH_WRITE_REG(ar531x_wdog_ctl(),
+ AR5315_WDOG_CTL_IGNORE);
+ sc->armed = 0;
+ }
+ }
+}
+
+static int
+ar5315_wdog_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Atheros AR531x watchdog timer");
+ return (0);
+}
+
+static void
+ar5315_wdog_sysctl(device_t dev)
+{
+ struct ar5315_wdog_softc *sc = device_get_softc(dev);
+
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->dev);
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->debug, 0,
+ "enable watchdog debugging");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "armed", CTLFLAG_RD, &sc->armed, 0,
+ "whether the watchdog is armed");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "reboot_from_watchdog", CTLFLAG_RD, &sc->reboot_from_watchdog, 0,
+ "whether the system rebooted from the watchdog");
+}
+
+
+static int
+ar5315_wdog_attach(device_t dev)
+{
+ struct ar5315_wdog_softc *sc = device_get_softc(dev);
+
+ /* Initialise */
+ sc->reboot_from_watchdog = 0;
+ sc->armed = 0;
+ sc->debug = 0;
+ ATH_WRITE_REG(ar531x_wdog_ctl(), AR5315_WDOG_CTL_IGNORE);
+
+ sc->dev = dev;
+ EVENTHANDLER_REGISTER(watchdog_list, ar5315_wdog_watchdog_fn, sc, 0);
+ ar5315_wdog_sysctl(dev);
+
+ return (0);
+}
+
+static device_method_t ar5315_wdog_methods[] = {
+ DEVMETHOD(device_probe, ar5315_wdog_probe),
+ DEVMETHOD(device_attach, ar5315_wdog_attach),
+ DEVMETHOD_END
+};
+
+static driver_t ar5315_wdog_driver = {
+ "ar5315_wdog",
+ ar5315_wdog_methods,
+ sizeof(struct ar5315_wdog_softc),
+};
+static devclass_t ar5315_wdog_devclass;
+
+DRIVER_MODULE(ar5315_wdog, apb, ar5315_wdog_driver, ar5315_wdog_devclass, 0, 0);
Index: sys/mips/atheros/ar531x/ar5315reg.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/ar5315reg.h
@@ -0,0 +1,242 @@
+/* $Id: ar5315reg.h,v 1.3 2011/07/07 05:06:44 matt Exp $ */
+/*
+ * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
+ * Copyright (c) 2006 Garrett D'Amore.
+ * All rights reserved.
+ *
+ * This code was written by Garrett D'Amore for the Champaign-Urbana
+ * Community Wireless Network Project.
+ *
+ * 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 acknowledgements:
+ * This product includes software developed by the Urbana-Champaign
+ * Independent Media Center.
+ * This product includes software developed by Garrett D'Amore.
+ * 4. Urbana-Champaign Independent Media Center's name and Garrett
+ * D'Amore's name may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER AND GARRETT D'AMORE ``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 URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER OR GARRETT D'AMORE 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.
+ */
+
+#ifndef _MIPS_ATHEROS_AR5315REG_H_
+#define _MIPS_ATHEROS_AR5315REG_H_
+
+#define AR5315_MEM0_BASE 0x00000000 /* sdram */
+#define AR5315_MEM1_BASE 0x08000000 /* spi flash */
+#define AR5315_WLAN_BASE 0x10000000
+#define AR5315_PCI_BASE 0x10100000
+#define AR5315_SDRAMCTL_BASE 0x10300000
+#define AR5315_LOCAL_BASE 0x10400000 /* local bus */
+#define AR5315_ENET_BASE 0x10500000
+#define AR5315_SYSREG_BASE 0x11000000
+#define AR5315_UART_BASE 0x11100000
+#define AR5315_SPI_BASE 0x11300000 /* spi flash */
+#define AR5315_BOOTROM_BASE 0x1FC00000 /* boot rom */
+#define AR5315_CONFIG_BASE 0x087D0000 /* flash start */
+#define AR5315_CONFIG_END 0x087FF000 /* flash end */
+#define AR5315_RADIO_END 0x1FFFF000 /* radio end */
+
+#if 0
+#define AR5315_PCIEXT_BASE 0x80000000 /* pci external */
+#define AR5315_RAM2_BASE 0xc0000000
+#define AR5315_RAM3_BASE 0xe0000000
+#endif
+
+/*
+ * SYSREG registers -- offset relative to AR531X_SYSREG_BASE
+ */
+#define AR5315_SYSREG_COLDRESET 0x0000
+#define AR5315_SYSREG_RESETCTL 0x0004
+#define AR5315_SYSREG_AHB_ARB_CTL 0x0008
+#define AR5315_SYSREG_ENDIAN 0x000c
+#define AR5315_SYSREG_NMI_CTL 0x0010
+#define AR5315_SYSREG_SREV 0x0014
+#define AR5315_SYSREG_IF_CTL 0x0018
+#define AR5315_SYSREG_MISC_INTSTAT 0x0020
+#define AR5315_SYSREG_MISC_INTMASK 0x0024
+#define AR5315_SYSREG_GISR 0x0028
+#define AR5315_SYSREG_TIMER 0x0030
+#define AR5315_SYSREG_RELOAD 0x0034
+#define AR5315_SYSREG_WDOG_TIMER 0x0038
+#define AR5315_SYSREG_WDOG_CTL 0x003c
+#define AR5315_SYSREG_PERFCNT0 0x0048
+#define AR5315_SYSREG_PERFCNT1 0x004c
+#define AR5315_SYSREG_AHB_ERR0 0x0050
+#define AR5315_SYSREG_AHB_ERR1 0x0054
+#define AR5315_SYSREG_AHB_ERR2 0x0058
+#define AR5315_SYSREG_AHB_ERR3 0x005c
+#define AR5315_SYSREG_AHB_ERR4 0x0060
+#define AR5315_SYSREG_PLLC_CTL 0x0064
+#define AR5315_SYSREG_PLLV_CTL 0x0068
+#define AR5315_SYSREG_CPUCLK 0x006c
+#define AR5315_SYSREG_AMBACLK 0x0070
+#define AR5315_SYSREG_SYNCCLK 0x0074
+#define AR5315_SYSREG_DSL_SLEEP_CTL 0x0080
+#define AR5315_SYSREG_DSL_SLEEP_DUR 0x0084
+#define AR5315_SYSREG_GPIO_DI 0x0088
+#define AR5315_SYSREG_GPIO_DO 0x0090
+#define AR5315_SYSREG_GPIO_CR 0x0098
+#define AR5315_SYSREG_GPIO_INT 0x00a0
+
+#define AR5315_GPIO_PINS 23
+
+/* Cold resets (AR5315_SYSREG_COLDRESET) */
+#define AR5315_COLD_AHB 0x00000001
+#define AR5315_COLD_APB 0x00000002
+#define AR5315_COLD_CPU 0x00000004
+#define AR5315_COLD_CPU_WARM 0x00000008
+
+/* Resets (AR5315_SYSREG_RESETCTL) */
+#define AR5315_RESET_WARM_WLAN0_MAC 0x00000001
+#define AR5315_RESET_WARM_WLAN0_BB 0x00000002
+#define AR5315_RESET_MPEGTS 0x00000004 /* MPEG-TS */
+#define AR5315_RESET_PCIDMA 0x00000008 /* PCI dma */
+#define AR5315_RESET_MEMCTL 0x00000010
+#define AR5315_RESET_LOCAL 0x00000020 /* local bus */
+#define AR5315_RESET_I2C 0x00000040 /* i2c */
+#define AR5315_RESET_SPI 0x00000080 /* SPI */
+#define AR5315_RESET_UART 0x00000100
+#define AR5315_RESET_IR 0x00000200 /* infrared */
+#define AR5315_RESET_PHY0 0x00000400 /* enet phy */
+#define AR5315_RESET_ENET0 0x00000800
+
+/* Watchdog control (AR5315_SYSREG_WDOG_CTL) */
+#define AR5315_WDOG_CTL_IGNORE 0x0000
+#define AR5315_WDOG_CTL_NMI 0x0001
+#define AR5315_WDOG_CTL_RESET 0x0002
+
+/* AR5315 AHB arbitration control (AR5315_SYSREG_AHB_ARB_CTL) */
+#define AR5315_ARB_CPU 0x00001
+#define AR5315_ARB_WLAN 0x00002
+#define AR5315_ARB_MPEGTS 0x00004
+#define AR5315_ARB_LOCAL 0x00008
+#define AR5315_ARB_PCI 0x00010
+#define AR5315_ARB_ENET 0x00020
+#define AR5315_ARB_RETRY 0x00100
+
+/* AR5315 endianness control (AR5315_SYSREG_ENDIAN) */
+#define AR5315_ENDIAN_AHB 0x00001
+#define AR5315_ENDIAN_WLAN 0x00002
+#define AR5315_ENDIAN_MPEGTS 0x00004
+#define AR5315_ENDIAN_PCI 0x00008
+#define AR5315_ENDIAN_MEMCTL 0x00010
+#define AR5315_ENDIAN_LOCAL 0x00020
+#define AR5315_ENDIAN_ENET 0x00040
+#define AR5315_ENDIAN_MERGE 0x00200
+#define AR5315_ENDIAN_CPU 0x00400
+#define AR5315_ENDIAN_PCIAHB 0x00800
+#define AR5315_ENDIAN_PCIAHB_BRIDGE 0x01000
+#define AR5315_ENDIAN_SPI 0x08000
+#define AR5315_ENDIAN_CPU_DRAM 0x10000
+#define AR5315_ENDIAN_CPU_PCI 0x20000
+#define AR5315_ENDIAN_CPU_MMR 0x40000
+
+/* AR5315 AHB error bits */
+#define AR5315_AHB_ERROR_DET 1 /* error detected */
+#define AR5315_AHB_ERROR_OVR 2 /* AHB overflow */
+#define AR5315_AHB_ERROR_WDT 4 /* wdt (not hresp) */
+
+/* AR5315 clocks */
+#define AR5315_PLLC_REF_DIV(reg) ((reg) & 0x3)
+#define AR5315_PLLC_FB_DIV(reg) (((reg) & 0x7c) >> 2)
+#define AR5315_PLLC_DIV_2(reg) (((reg) & 0x80) >> 7)
+#define AR5315_PLLC_CLKC(reg) (((reg) & 0x1c000) >> 14)
+#define AR5315_PLLC_CLKM(reg) (((reg) & 0x700000) >> 20)
+
+#define AR5315_CLOCKCTL_SELECT(reg) ((reg) & 0x3)
+#define AR5315_CLOCKCTL_DIV(reg) (((reg) & 0xc) >> 2)
+
+/*
+ * SDRAMCTL registers -- offset relative to SDRAMCTL
+ */
+#define AR5315_SDRAMCTL_MEM_CFG 0x0000
+#define AR5315_MEM_CFG_DATA_WIDTH __BITS(13,14)
+#define AR5315_MEM_CFG_COL_WIDTH __BITS(9,12)
+#define AR5315_MEM_CFG_ROW_WIDTH __BITS(5,8)
+
+/* memory config 1 bits */
+#define AR531X_MEM_CFG1_BANK0 __BITS(8,10)
+#define AR531X_MEM_CFG1_BANK1 __BITS(12,14)
+
+/*
+ * PCI configuration stuff. I don't pretend to fully understand these
+ * registers, they seem to be magic numbers in the Linux code.
+ */
+#define AR5315_PCI_MAC_RC 0x4000
+#define AR5315_PCI_MAC_SCR 0x4004
+#define AR5315_PCI_MAC_INTPEND 0x4008
+#define AR5315_PCI_MAC_SFR 0x400c
+#define AR5315_PCI_MAC_PCICFG 0x4010
+#define AR5315_PCI_MAC_SREV 0x4020
+
+#define PCI_MAC_RC_MAC 0x1
+#define PCI_MAC_RC_BB 0x2
+
+#define PCI_MAC_SCR_SLM_MASK 0x00030000
+#define PCI_MAC_SCR_SLM_FWAKE 0x00000000
+#define PCI_MAC_SCR_SLM_FSLEEP 0x00010000
+#define PCI_MAC_SCR_SLM_NORMAL 0x00020000
+
+#define PCI_MAC_PCICFG_SPWR_DN 0x00010000
+
+/* IRQS */
+#define AR5315_CPU_IRQ_MISC 0
+#define AR5315_CPU_IRQ_WLAN 1
+#define AR5315_CPU_IRQ_ENET 2
+
+#define AR5315_MISC_IRQ_UART 0
+#define AR5315_MISC_IRQ_I2C 1
+#define AR5315_MISC_IRQ_SPI 2
+#define AR5315_MISC_IRQ_AHBE 3
+#define AR5315_MISC_IRQ_AHPE 4
+#define AR5315_MISC_IRQ_TIMER 5
+#define AR5315_MISC_IRQ_GPIO 6
+#define AR5315_MISC_IRQ_WDOG 7
+#define AR5315_MISC_IRQ_IR 8
+
+#define AR5315_APB_BASE AR5315_SYSREG_BASE
+#define AR5315_APB_SIZE 0x06000000
+
+#define ATH_READ_REG(reg) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg)))
+
+#define ATH_WRITE_REG(reg, val) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg))) = (val)
+
+/* Helpers from NetBSD cdefs.h */
+/* __BIT(n): nth bit, where __BIT(0) == 0x1. */
+#define __BIT(__n) \
+ (((__n) >= NBBY * sizeof(uintmax_t)) ? 0 : ((uintmax_t)1 << (__n)))
+
+/* __BITS(m, n): bits m through n, m < n. */
+#define __BITS(__m, __n) \
+ ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1))
+
+/* find least significant bit that is set */
+#define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask))
+
+#define __SHIFTOUT(__x, __mask) (((__x) & (__mask)) / __LOWEST_SET_BIT(__mask))
+#define __SHIFTOUT_MASK(__mask) __SHIFTOUT((__mask), (__mask))
+#endif /* _MIPS_ATHEROS_AR531XREG_H_ */
Index: sys/mips/atheros/ar531x/arspireg.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/arspireg.h
@@ -0,0 +1,60 @@
+/* $NetBSD: arspireg.h,v 1.1 2006/10/14 15:33:23 gdamore Exp $ */
+
+/*-
+ * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
+ * Copyright (c) 2006 Garrett D'Amore.
+ * All rights reserved.
+ *
+ * Portions of this code were written by Garrett D'Amore for the
+ * Champaign-Urbana Community Wireless Network Project.
+ *
+ * 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 acknowledgements:
+ * This product includes software developed by the Urbana-Champaign
+ * Independent Media Center.
+ * This product includes software developed by Garrett D'Amore.
+ * 4. Urbana-Champaign Independent Media Center's name and Garrett
+ * D'Amore's name may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER AND GARRETT D'AMORE ``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 URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER OR GARRETT D'AMORE 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.
+ */
+
+#ifndef _MIPS_ATHEROS_DEV_ARSPIREG_H
+#define _MIPS_ATHEROS_DEV_ARSPIREG_H
+
+#define ARSPI_REG_CTL 0x00
+#define ARSPI_REG_OPCODE 0x04
+#define ARSPI_REG_DATA 0x08
+
+#define ARSPI_CTL_START 0x00000100
+#define ARSPI_CTL_BUSY 0x00010000
+#define ARSPI_CTL_TXCNT_MASK 0x0000000f
+#define ARSPI_CTL_TXCNT_SHIFT 0
+#define ARSPI_CTL_RXCNT_MASK 0x000000f0
+#define ARSPI_CTL_RXCNT_SHIFT 4
+#define ARSPI_CTL_SIZE_MASK 0x00060000
+#define ARSPI_CTL_CLKSEL_MASK 0x03000000
+
+#endif /* _MIPS_ATHEROS_DEV_ARSPIREG_H */
Index: sys/mips/atheros/ar531x/files.ar5315
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/files.ar5315
@@ -0,0 +1,30 @@
+# $FreeBSD: head/sys/mips/atheros/files.ar71xx 234485 2012-04-20 08:26:05Z adrian $
+
+mips/atheros/ar531x/apb.c standard
+mips/atheros/ar531x/if_are.c standard
+mips/atheros/ar531x/ar5315_spi.c optional ar5315_spi
+mips/atheros/ar531x/ar5315_wdog.c optional ar5315_wdog
+mips/atheros/ar531x/ar5315_gpio.c optional gpio
+mips/atheros/ar531x/ar5315_machdep.c standard
+mips/atheros/ar531x/ar5315_chip.c standard
+mips/atheros/ar531x/ar5315_setup.c standard
+mips/atheros/ar531x/uart_bus_ar5315.c optional uart_ar5315
+mips/atheros/ar531x/uart_cpu_ar5315.c optional uart_ar5315
+
+mips/atheros/ar531x/ar5312_chip.c standard
+
+mips/atheros/ar71xx_bus_space_reversed.c standard
+#mips/mips/intr_machdep.c standard
+mips/mips/tick.c standard
+
+dev/etherswitch/e6000sw/e6060sw.c optional etherswitch
+dev/etherswitch/realtek/rtl830x.c optional etherswitch
+
+# Hack to reuse ARM intrng code
+kern/subr_intr.c standard
+kern/msi_if.m standard
+kern/pic_if.m standard
+
+# Intrng compatible MIPS32 interrupt controller
+mips/mips/mips_pic.c standard
+
Index: sys/mips/atheros/ar531x/if_are.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/if_are.c
@@ -0,0 +1,1685 @@
+/*-
+ * 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 SOFTWARE 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 ARE 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 SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: $
+ *
+ */
+
+#include "opt_platform.h"
+#include "opt_ar531x.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * AR231x 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 <sys/kdb.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 <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#ifdef INTRNG
+#include <machine/intr.h>
+#endif
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#ifdef ARE_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);
+
+#include "miibus_if.h"
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5312reg.h>
+#include <mips/atheros/ar531x/ar5315_setup.h>
+#include <mips/atheros/ar531x/if_arereg.h>
+
+//#define ARE_DEBUG
+
+#ifdef ARE_DEBUG
+void dump_txdesc(struct are_softc *, int);
+void dump_status_reg(struct are_softc *);
+#endif
+
+static int are_attach(device_t);
+static int are_detach(device_t);
+static int are_ifmedia_upd(struct ifnet *);
+static void are_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int are_ioctl(struct ifnet *, u_long, caddr_t);
+static void are_init(void *);
+static void are_init_locked(struct are_softc *);
+static void are_link_task(void *, int);
+static int are_miibus_readreg(device_t, int, int);
+static void are_miibus_statchg(device_t);
+static int are_miibus_writereg(device_t, int, int, int);
+static int are_probe(device_t);
+static void are_reset(struct are_softc *);
+static int are_resume(device_t);
+static int are_rx_ring_init(struct are_softc *);
+static int are_tx_ring_init(struct are_softc *);
+static int are_shutdown(device_t);
+static void are_start(struct ifnet *);
+static void are_start_locked(struct ifnet *);
+static void are_stop(struct are_softc *);
+static int are_suspend(device_t);
+
+static void are_rx(struct are_softc *);
+static void are_tx(struct are_softc *);
+static void are_intr(void *);
+static void are_tick(void *);
+
+static void are_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int are_dma_alloc(struct are_softc *);
+static void are_dma_free(struct are_softc *);
+static int are_newbuf(struct are_softc *, int);
+static __inline void are_fixup_rx(struct mbuf *);
+
+static void are_hinted_child(device_t bus, const char *dname, int dunit);
+
+static device_method_t are_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, are_probe),
+ DEVMETHOD(device_attach, are_attach),
+ DEVMETHOD(device_detach, are_detach),
+ DEVMETHOD(device_suspend, are_suspend),
+ DEVMETHOD(device_resume, are_resume),
+ DEVMETHOD(device_shutdown, are_shutdown),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, are_miibus_readreg),
+ DEVMETHOD(miibus_writereg, are_miibus_writereg),
+ DEVMETHOD(miibus_statchg, are_miibus_statchg),
+
+ /* bus interface */
+ DEVMETHOD(bus_add_child, device_add_child_ordered),
+ DEVMETHOD(bus_hinted_child, are_hinted_child),
+
+ DEVMETHOD_END
+};
+
+static driver_t are_driver = {
+ "are",
+ are_methods,
+ sizeof(struct are_softc)
+};
+
+static devclass_t are_devclass;
+
+DRIVER_MODULE(are, nexus, are_driver, are_devclass, 0, 0);
+#ifdef ARE_MII
+DRIVER_MODULE(miibus, are, miibus_driver, miibus_devclass, 0, 0);
+#endif
+
+#ifdef ARE_MDIO
+static int aremdio_probe(device_t);
+static int aremdio_attach(device_t);
+static int aremdio_detach(device_t);
+
+/*
+ * Declare an additional, separate driver for accessing the MDIO bus.
+ */
+static device_method_t aremdio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, aremdio_probe),
+ DEVMETHOD(device_attach, aremdio_attach),
+ DEVMETHOD(device_detach, aremdio_detach),
+
+ /* bus interface */
+ DEVMETHOD(bus_add_child, device_add_child_ordered),
+
+ /* MDIO access */
+ DEVMETHOD(mdio_readreg, are_miibus_readreg),
+ DEVMETHOD(mdio_writereg, are_miibus_writereg),
+};
+
+DEFINE_CLASS_0(aremdio, aremdio_driver, aremdio_methods,
+ sizeof(struct are_softc));
+static devclass_t aremdio_devclass;
+
+DRIVER_MODULE(miiproxy, are, miiproxy_driver, miiproxy_devclass, 0, 0);
+DRIVER_MODULE(aremdio, nexus, aremdio_driver, aremdio_devclass, 0, 0);
+DRIVER_MODULE(mdio, aremdio, mdio_driver, mdio_devclass, 0, 0);
+#endif
+
+
+static int
+are_probe(device_t dev)
+{
+
+ device_set_desc(dev, "AR531x Ethernet interface");
+ return (0);
+}
+
+static int
+are_attach(device_t dev)
+{
+ struct ifnet *ifp;
+ struct are_softc *sc;
+ int error = 0;
+#ifdef INTRNG
+ int enetirq;
+#else
+ int rid;
+#endif
+ int unit;
+ char * local_macstr;
+ int count;
+ int i;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ sc->are_dev = dev;
+
+ // hardcode macaddress
+ sc->are_eaddr[0] = 0x00;
+ sc->are_eaddr[1] = 0x0C;
+ sc->are_eaddr[2] = 0x42;
+ sc->are_eaddr[3] = 0x09;
+ sc->are_eaddr[4] = 0x5E;
+ sc->are_eaddr[5] = 0x6B;
+
+ // try to get from hints
+ if (!resource_string_value(device_get_name(dev),
+ device_get_unit(dev), "macaddr", (const char **)&local_macstr)) {
+ uint32_t tmpmac[ETHER_ADDR_LEN];
+
+ /* Have a MAC address; should use it */
+ device_printf(dev, "Overriding MAC address from environment: '%s'\n",
+ local_macstr);
+
+ /* Extract out the MAC address */
+ /* XXX this should all be a generic method */
+ count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
+ &tmpmac[0], &tmpmac[1],
+ &tmpmac[2], &tmpmac[3],
+ &tmpmac[4], &tmpmac[5]);
+ if (count == 6) {
+ /* Valid! */
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ sc->are_eaddr[i] = tmpmac[i];
+ }
+ }
+
+ mtx_init(&sc->are_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ callout_init_mtx(&sc->are_stat_callout, &sc->are_mtx, 0);
+ TASK_INIT(&sc->are_link_task, 0, are_link_task, sc);
+
+ /* Map control/status registers. */
+ sc->are_rid = 0;
+ sc->are_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->are_rid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ if (sc->are_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->are_btag = rman_get_bustag(sc->are_res);
+ sc->are_bhandle = rman_get_bushandle(sc->are_res);
+
+#ifndef INTRNG
+ /* Allocate interrupts */
+ rid = 0;
+ sc->are_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->are_irq == NULL) {
+ device_printf(dev, "couldn't map interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+#endif
+
+ /* Allocate ifnet structure. */
+ ifp = sc->are_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 = are_ioctl;
+ ifp->if_start = are_start;
+ ifp->if_init = are_init;
+
+ /* XXX: add real size */
+ IFQ_SET_MAXLEN(&ifp->if_snd, 9);
+ ifp->if_snd.ifq_maxlen = 9;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_capenable = ifp->if_capabilities;
+
+ if (are_dma_alloc(sc) != 0) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* TODO: calculate prescale */
+/*
+ CSR_WRITE_4(sc, ARE_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ CSR_WRITE_4(sc, ARE_MIIMCFG, ARE_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, ARE_MIIMCFG, 0);
+*/
+ CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR);
+ DELAY(1000);
+
+#ifdef ARE_MDIO
+ sc->are_miiproxy = mii_attach_proxy(sc->are_dev);
+#endif
+
+#ifdef ARE_MII
+ /* Do MII setup. */
+ error = mii_attach(dev, &sc->are_miibus, ifp, are_ifmedia_upd,
+ are_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->are_ifmedia, 0, are_ifmedia_upd, are_ifmedia_sts);
+
+ ifmedia_add(&sc->are_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->are_ifmedia, IFM_ETHER | IFM_AUTO);
+#endif
+
+ /* Call MI attach routine. */
+ ether_ifattach(ifp, sc->are_eaddr);
+
+#ifdef INTRNG
+ char *name;
+ if(ar531x_soc >= AR531X_SOC_AR5315) {
+ enetirq = AR5315_CPU_IRQ_ENET;
+ name = "enet";
+ } else {
+ if(device_get_unit(dev) == 0) {
+ enetirq = AR5312_IRQ_ENET0;
+ name = "enet0";
+ } else {
+ enetirq = AR5312_IRQ_ENET1;
+ name = "enet1";
+ }
+ }
+ cpu_establish_hardintr(name, NULL, are_intr, sc, enetirq,
+ INTR_TYPE_NET, NULL);
+#else
+ /* Hook interrupt last to avoid having to lock softc */
+ error = bus_setup_intr(dev, sc->are_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, are_intr, sc, &sc->are_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+#endif
+
+fail:
+ if (error)
+ are_detach(dev);
+
+ return (error);
+}
+
+static int
+are_detach(device_t dev)
+{
+ struct are_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->are_ifp;
+
+ KASSERT(mtx_initialized(&sc->are_mtx), ("vr mutex not initialized"));
+
+ /* These should only be active if attach succeeded */
+ if (device_is_attached(dev)) {
+ ARE_LOCK(sc);
+ sc->are_detach = 1;
+ are_stop(sc);
+ ARE_UNLOCK(sc);
+ taskqueue_drain(taskqueue_swi, &sc->are_link_task);
+ ether_ifdetach(ifp);
+ }
+#ifdef ARE_MII
+ if (sc->are_miibus)
+ device_delete_child(dev, sc->are_miibus);
+#endif
+ bus_generic_detach(dev);
+
+ if (sc->are_intrhand)
+ bus_teardown_intr(dev, sc->are_irq, sc->are_intrhand);
+ if (sc->are_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->are_irq);
+
+ if (sc->are_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->are_rid,
+ sc->are_res);
+
+ if (ifp)
+ if_free(ifp);
+
+ are_dma_free(sc);
+
+ mtx_destroy(&sc->are_mtx);
+
+ return (0);
+
+}
+
+static int
+are_suspend(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+are_resume(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+are_shutdown(device_t dev)
+{
+ struct are_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ ARE_LOCK(sc);
+ are_stop(sc);
+ ARE_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+are_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct are_softc * sc = device_get_softc(dev);
+ uint32_t addr;
+ int i;
+
+ addr = (phy << MIIADDR_PHY_SHIFT) | (reg << MIIADDR_REG_SHIFT);
+ CSR_WRITE_4(sc, CSR_MIIADDR, addr);
+// AE_BARRIER(sc);
+ for (i = 0; i < 100000000; i++) {
+ if ((CSR_READ_4(sc, CSR_MIIADDR) & MIIADDR_BUSY) == 0)
+ break;
+ }
+
+ return (CSR_READ_4(sc, CSR_MIIDATA) & 0xffff);
+}
+
+static int
+are_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct are_softc * sc = device_get_softc(dev);
+ uint32_t addr;
+ int i;
+
+ /* write the data register */
+ CSR_WRITE_4(sc, CSR_MIIDATA, data);
+
+ /* write the address to latch it in */
+ addr = (phy << MIIADDR_PHY_SHIFT) | (reg << MIIADDR_REG_SHIFT) |
+ MIIADDR_WRITE;
+ CSR_WRITE_4(sc, CSR_MIIADDR, addr);
+// AE_BARRIER(sc);
+
+ for (i = 0; i < 100000000; i++) {
+ if ((CSR_READ_4(sc, CSR_MIIADDR) & MIIADDR_BUSY) == 0)
+ break;
+ }
+
+ return (0);
+}
+
+static void
+are_miibus_statchg(device_t dev)
+{
+ struct are_softc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue(taskqueue_swi, &sc->are_link_task);
+}
+
+static void
+are_link_task(void *arg, int pending)
+{
+#ifdef ARE_MII
+ struct are_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ /* int lfdx, mfdx; */
+
+ sc = (struct are_softc *)arg;
+
+ ARE_LOCK(sc);
+ mii = device_get_softc(sc->are_miibus);
+ ifp = sc->are_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ ARE_UNLOCK(sc);
+ return;
+ }
+
+ if (mii->mii_media_status & IFM_ACTIVE) {
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->are_link_status = 1;
+ } else
+ sc->are_link_status = 0;
+
+ ARE_UNLOCK(sc);
+#endif
+}
+
+static void
+are_reset(struct are_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(10);
+ 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(10);
+ if ((CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR) == 0)
+ break;
+ }
+
+ if (CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR)
+ device_printf(sc->are_dev, "reset time out\n");
+
+ DELAY(1000);
+}
+
+static void
+are_init(void *xsc)
+{
+ struct are_softc *sc = xsc;
+
+ ARE_LOCK(sc);
+ are_init_locked(sc);
+ ARE_UNLOCK(sc);
+}
+
+static void
+are_init_locked(struct are_softc *sc)
+{
+ struct ifnet *ifp = sc->are_ifp;
+#ifdef ARE_MII
+ struct mii_data *mii;
+#endif
+
+ ARE_LOCK_ASSERT(sc);
+
+#ifdef ARE_MII
+ mii = device_get_softc(sc->are_miibus);
+#endif
+
+ are_stop(sc);
+ are_reset(sc);
+
+ /* Init circular RX list. */
+ if (are_rx_ring_init(sc) != 0) {
+ device_printf(sc->are_dev,
+ "initialization failed: no memory for rx buffers\n");
+ are_stop(sc);
+ return;
+ }
+
+ /* Init tx descriptors. */
+ are_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_ALIGN_16B |
+ BUSMODE_BAR | BUSMODE_BLE | BUSMODE_PBL_4LW);
+
+ /*
+ * 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, ARE_TX_RING_ADDR(sc, 0));
+ CSR_WRITE_4(sc, CSR_RXLIST, ARE_RX_RING_ADDR(sc, 0));
+
+ /*
+ * Set the station address.
+ */
+ CSR_WRITE_4(sc, CSR_MACHI, sc->are_eaddr[5] << 16 | sc->are_eaddr[4]);
+ CSR_WRITE_4(sc, CSR_MACLO, sc->are_eaddr[3] << 24 |
+ sc->are_eaddr[2] << 16 | sc->are_eaddr[1] << 8 | sc->are_eaddr[0]);
+
+ /*
+ * Start the mac.
+ */
+ CSR_WRITE_4(sc, CSR_MACCTL, CSR_READ_4(sc, CSR_MACCTL) |
+ (MACCTL_RE | MACCTL_TE));
+
+ /*
+ * Write out the opmode.
+ */
+ CSR_WRITE_4(sc, CSR_OPMODE, OPMODE_SR | OPMODE_ST |
+// ae_txthresh[sc->sc_txthresh].txth_opmode);
+ OPMODE_TR_64);
+ /*
+ * Start the receive process.
+ */
+ CSR_WRITE_4(sc, CSR_RXPOLL, RXPOLL_RPD);
+
+ sc->are_link_status = 1;
+#ifdef ARE_MII
+ mii_mediachg(mii);
+#endif
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->are_stat_callout, hz, are_tick, sc);
+}
+
+static void
+are_start(struct ifnet *ifp)
+{
+ struct are_softc *sc;
+
+ sc = ifp->if_softc;
+
+ ARE_LOCK(sc);
+ are_start_locked(ifp);
+ ARE_UNLOCK(sc);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int
+are_encap(struct are_softc *sc, struct mbuf **m_head)
+{
+ struct are_txdesc *txd;
+ struct are_desc *desc, *prev_desc;
+ bus_dma_segment_t txsegs[ARE_MAXFRAGS];
+ uint32_t link_addr;
+ int error, i, nsegs, prod, si, prev_prod;
+ int txstat;
+
+ ARE_LOCK_ASSERT(sc);
+
+ prod = sc->are_cdata.are_tx_prod;
+ txd = &sc->are_cdata.are_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, txd->tx_dmamap,
+ *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ panic("EFBIG");
+ } 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->are_cdata.are_tx_cnt + nsegs >= (ARE_TX_RING_CNT - 1)) {
+ bus_dmamap_unload(sc->are_cdata.are_tx_tag, txd->tx_dmamap);
+ return (ENOBUFS);
+ }
+
+ txd->tx_m = *m_head;
+ bus_dmamap_sync(sc->are_cdata.are_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ si = prod;
+
+ /*
+ * Make a list of descriptors for this packet. DMA controller will
+ * walk through it while are_link is not zero. The last one should
+ * have COF flag set, to pickup next chain from NDPTR
+ */
+ prev_prod = prod;
+ desc = prev_desc = NULL;
+ for (i = 0; i < nsegs; i++) {
+ desc = &sc->are_rdata.are_tx_ring[prod];
+ desc->are_stat = ADSTAT_OWN;
+ desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len) | ADCTL_CH;
+ if (i == 0)
+ desc->are_devcs |= ADCTL_Tx_FS;
+ desc->are_addr = txsegs[i].ds_addr;
+// desc->are_link = 0;
+ /* link with previous descriptor */
+ if (prev_desc)
+ prev_desc->are_link = ARE_TX_RING_ADDR(sc, prod);
+
+ sc->are_cdata.are_tx_cnt++;
+ prev_desc = desc;
+ ARE_INC(prod, ARE_TX_RING_CNT);
+ }
+
+ /*
+ * Set mark last fragment with LD flag
+ */
+ if (desc) {
+ desc->are_devcs |= ADCTL_Tx_IC;
+ desc->are_devcs |= ADCTL_Tx_LS;
+ }
+
+ /* Update producer index. */
+ sc->are_cdata.are_tx_prod = prod;
+
+ /* Sync descriptors. */
+ bus_dmamap_sync(sc->are_cdata.are_tx_ring_tag,
+ sc->are_cdata.are_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Start transmitting */
+ /* Check if new list is queued in NDPTR */
+ txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+ if (txstat == 0 || txstat == 6) {
+ /* Transmit Process Stat is stop or suspended */
+ CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+ }
+ else {
+ link_addr = ARE_TX_RING_ADDR(sc, si);
+ /* Get previous descriptor */
+ si = (si + ARE_TX_RING_CNT - 1) % ARE_TX_RING_CNT;
+ desc = &sc->are_rdata.are_tx_ring[si];
+ desc->are_link = link_addr;
+ }
+
+ return (0);
+}
+
+static void
+are_start_locked(struct ifnet *ifp)
+{
+ struct are_softc *sc;
+ struct mbuf *m_head;
+ int enq;
+
+ sc = ifp->if_softc;
+
+ ARE_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->are_link_status == 0 )
+ return;
+
+ for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->are_cdata.are_tx_cnt < ARE_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 (are_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);
+ }
+}
+
+static void
+are_stop(struct are_softc *sc)
+{
+ struct ifnet *ifp;
+
+ ARE_LOCK_ASSERT(sc);
+
+ ifp = sc->are_ifp;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ callout_stop(&sc->are_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);
+ CSR_WRITE_4(sc, CSR_MACCTL,
+ CSR_READ_4(sc, CSR_MACCTL) & ~(MACCTL_TE | MACCTL_RE));
+
+}
+
+
+static int
+are_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct are_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+#ifdef ARE_MII
+ struct mii_data *mii;
+#endif
+ int error;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+#if 0
+ ARE_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if ((ifp->if_flags ^ sc->are_if_flags) &
+ (IFF_PROMISC | IFF_ALLMULTI))
+ are_set_filter(sc);
+ } else {
+ if (sc->are_detach == 0)
+ are_init_locked(sc);
+ }
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ are_stop(sc);
+ }
+ sc->are_if_flags = ifp->if_flags;
+ ARE_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#if 0
+ ARE_LOCK(sc);
+ are_set_filter(sc);
+ ARE_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+#ifdef ARE_MII
+ mii = device_get_softc(sc->are_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+#else
+ error = ifmedia_ioctl(ifp, ifr, &sc->are_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 = ARE_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) {
+ ARE_LOCK(sc);
+ are_vlan_setup(sc);
+ ARE_UNLOCK(sc);
+ }
+ }
+ VLAN_CAPABILITIES(ifp);
+#endif
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+are_ifmedia_upd(struct ifnet *ifp)
+{
+#ifdef ARE_MII
+ struct are_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
+ sc = ifp->if_softc;
+ ARE_LOCK(sc);
+ mii = device_get_softc(sc->are_miibus);
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ PHY_RESET(miisc);
+ error = mii_mediachg(mii);
+ ARE_UNLOCK(sc);
+
+ return (error);
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Report current media status.
+ */
+static void
+are_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+#ifdef ARE_MII
+ struct are_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->are_miibus);
+ ARE_LOCK(sc);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ ARE_UNLOCK(sc);
+#else
+ ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
+#endif
+}
+
+struct are_dmamap_arg {
+ bus_addr_t are_busaddr;
+};
+
+static void
+are_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct are_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+ ctx = arg;
+ ctx->are_busaddr = segs[0].ds_addr;
+}
+
+static int
+are_dma_alloc(struct are_softc *sc)
+{
+ struct are_dmamap_arg ctx;
+ struct are_txdesc *txd;
+ struct are_rxdesc *rxd;
+ int error, i;
+
+ /* Create parent DMA tag. */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->are_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->are_cdata.are_parent_tag);
+ if (error != 0) {
+ device_printf(sc->are_dev, "failed to create parent DMA tag\n");
+ goto fail;
+ }
+ /* Create tag for Tx ring. */
+ error = bus_dma_tag_create(
+ sc->are_cdata.are_parent_tag, /* parent */
+ ARE_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ ARE_TX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ ARE_TX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->are_cdata.are_tx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->are_dev, "failed to create Tx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx ring. */
+ error = bus_dma_tag_create(
+ sc->are_cdata.are_parent_tag, /* parent */
+ ARE_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ ARE_RX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ ARE_RX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->are_cdata.are_rx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->are_dev, "failed to create Rx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Tx buffers. */
+ error = bus_dma_tag_create(
+ sc->are_cdata.are_parent_tag, /* parent */
+ sizeof(uint32_t), 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * ARE_MAXFRAGS, /* maxsize */
+ ARE_MAXFRAGS, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->are_cdata.are_tx_tag);
+ if (error != 0) {
+ device_printf(sc->are_dev, "failed to create Tx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx buffers. */
+ error = bus_dma_tag_create(
+ sc->are_cdata.are_parent_tag, /* parent */
+ ARE_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->are_cdata.are_rx_tag);
+ if (error != 0) {
+ device_printf(sc->are_dev, "failed to create Rx DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate DMA'able memory and load the DMA map for Tx ring. */
+ error = bus_dmamem_alloc(sc->are_cdata.are_tx_ring_tag,
+ (void **)&sc->are_rdata.are_tx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->are_cdata.are_tx_ring_map);
+ if (error != 0) {
+ device_printf(sc->are_dev,
+ "failed to allocate DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+
+ ctx.are_busaddr = 0;
+ error = bus_dmamap_load(sc->are_cdata.are_tx_ring_tag,
+ sc->are_cdata.are_tx_ring_map, sc->are_rdata.are_tx_ring,
+ ARE_TX_RING_SIZE, are_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.are_busaddr == 0) {
+ device_printf(sc->are_dev,
+ "failed to load DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+ sc->are_rdata.are_tx_ring_paddr = ctx.are_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for Rx ring. */
+ error = bus_dmamem_alloc(sc->are_cdata.are_rx_ring_tag,
+ (void **)&sc->are_rdata.are_rx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->are_cdata.are_rx_ring_map);
+ if (error != 0) {
+ device_printf(sc->are_dev,
+ "failed to allocate DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+
+ ctx.are_busaddr = 0;
+ error = bus_dmamap_load(sc->are_cdata.are_rx_ring_tag,
+ sc->are_cdata.are_rx_ring_map, sc->are_rdata.are_rx_ring,
+ ARE_RX_RING_SIZE, are_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.are_busaddr == 0) {
+ device_printf(sc->are_dev,
+ "failed to load DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+ sc->are_rdata.are_rx_ring_paddr = ctx.are_busaddr;
+
+ /* Create DMA maps for Tx buffers. */
+ for (i = 0; i < ARE_TX_RING_CNT; i++) {
+ txd = &sc->are_cdata.are_txdesc[i];
+ txd->tx_m = NULL;
+ txd->tx_dmamap = NULL;
+ error = bus_dmamap_create(sc->are_cdata.are_tx_tag, 0,
+ &txd->tx_dmamap);
+ if (error != 0) {
+ device_printf(sc->are_dev,
+ "failed to create Tx dmamap\n");
+ goto fail;
+ }
+ }
+ /* Create DMA maps for Rx buffers. */
+ if ((error = bus_dmamap_create(sc->are_cdata.are_rx_tag, 0,
+ &sc->are_cdata.are_rx_sparemap)) != 0) {
+ device_printf(sc->are_dev,
+ "failed to create spare Rx dmamap\n");
+ goto fail;
+ }
+ for (i = 0; i < ARE_RX_RING_CNT; i++) {
+ rxd = &sc->are_cdata.are_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->rx_dmamap = NULL;
+ error = bus_dmamap_create(sc->are_cdata.are_rx_tag, 0,
+ &rxd->rx_dmamap);
+ if (error != 0) {
+ device_printf(sc->are_dev,
+ "failed to create Rx dmamap\n");
+ goto fail;
+ }
+ }
+
+fail:
+ return (error);
+}
+
+static void
+are_dma_free(struct are_softc *sc)
+{
+ struct are_txdesc *txd;
+ struct are_rxdesc *rxd;
+ int i;
+
+ /* Tx ring. */
+ if (sc->are_cdata.are_tx_ring_tag) {
+ if (sc->are_rdata.are_tx_ring_paddr)
+ bus_dmamap_unload(sc->are_cdata.are_tx_ring_tag,
+ sc->are_cdata.are_tx_ring_map);
+ if (sc->are_rdata.are_tx_ring)
+ bus_dmamem_free(sc->are_cdata.are_tx_ring_tag,
+ sc->are_rdata.are_tx_ring,
+ sc->are_cdata.are_tx_ring_map);
+ sc->are_rdata.are_tx_ring = NULL;
+ sc->are_rdata.are_tx_ring_paddr = 0;
+ bus_dma_tag_destroy(sc->are_cdata.are_tx_ring_tag);
+ sc->are_cdata.are_tx_ring_tag = NULL;
+ }
+ /* Rx ring. */
+ if (sc->are_cdata.are_rx_ring_tag) {
+ if (sc->are_rdata.are_rx_ring_paddr)
+ bus_dmamap_unload(sc->are_cdata.are_rx_ring_tag,
+ sc->are_cdata.are_rx_ring_map);
+ if (sc->are_rdata.are_rx_ring)
+ bus_dmamem_free(sc->are_cdata.are_rx_ring_tag,
+ sc->are_rdata.are_rx_ring,
+ sc->are_cdata.are_rx_ring_map);
+ sc->are_rdata.are_rx_ring = NULL;
+ sc->are_rdata.are_rx_ring_paddr = 0;
+ bus_dma_tag_destroy(sc->are_cdata.are_rx_ring_tag);
+ sc->are_cdata.are_rx_ring_tag = NULL;
+ }
+ /* Tx buffers. */
+ if (sc->are_cdata.are_tx_tag) {
+ for (i = 0; i < ARE_TX_RING_CNT; i++) {
+ txd = &sc->are_cdata.are_txdesc[i];
+ if (txd->tx_dmamap) {
+ bus_dmamap_destroy(sc->are_cdata.are_tx_tag,
+ txd->tx_dmamap);
+ txd->tx_dmamap = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->are_cdata.are_tx_tag);
+ sc->are_cdata.are_tx_tag = NULL;
+ }
+ /* Rx buffers. */
+ if (sc->are_cdata.are_rx_tag) {
+ for (i = 0; i < ARE_RX_RING_CNT; i++) {
+ rxd = &sc->are_cdata.are_rxdesc[i];
+ if (rxd->rx_dmamap) {
+ bus_dmamap_destroy(sc->are_cdata.are_rx_tag,
+ rxd->rx_dmamap);
+ rxd->rx_dmamap = NULL;
+ }
+ }
+ if (sc->are_cdata.are_rx_sparemap) {
+ bus_dmamap_destroy(sc->are_cdata.are_rx_tag,
+ sc->are_cdata.are_rx_sparemap);
+ sc->are_cdata.are_rx_sparemap = 0;
+ }
+ bus_dma_tag_destroy(sc->are_cdata.are_rx_tag);
+ sc->are_cdata.are_rx_tag = NULL;
+ }
+
+ if (sc->are_cdata.are_parent_tag) {
+ bus_dma_tag_destroy(sc->are_cdata.are_parent_tag);
+ sc->are_cdata.are_parent_tag = NULL;
+ }
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int
+are_tx_ring_init(struct are_softc *sc)
+{
+ struct are_ring_data *rd;
+ struct are_txdesc *txd;
+ bus_addr_t addr;
+ int i;
+
+ sc->are_cdata.are_tx_prod = 0;
+ sc->are_cdata.are_tx_cons = 0;
+ sc->are_cdata.are_tx_cnt = 0;
+ sc->are_cdata.are_tx_pkts = 0;
+
+ rd = &sc->are_rdata;
+ bzero(rd->are_tx_ring, ARE_TX_RING_SIZE);
+ for (i = 0; i < ARE_TX_RING_CNT; i++) {
+ if (i == ARE_TX_RING_CNT - 1)
+ addr = ARE_TX_RING_ADDR(sc, 0);
+ else
+ addr = ARE_TX_RING_ADDR(sc, i + 1);
+ rd->are_tx_ring[i].are_stat = 0;
+ rd->are_tx_ring[i].are_devcs = 0;
+ rd->are_tx_ring[i].are_addr = 0;
+ rd->are_tx_ring[i].are_link = addr;
+ txd = &sc->are_cdata.are_txdesc[i];
+ txd->tx_m = NULL;
+ }
+
+ bus_dmamap_sync(sc->are_cdata.are_tx_ring_tag,
+ sc->are_cdata.are_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
+are_rx_ring_init(struct are_softc *sc)
+{
+ struct are_ring_data *rd;
+ struct are_rxdesc *rxd;
+ bus_addr_t addr;
+ int i;
+
+ sc->are_cdata.are_rx_cons = 0;
+
+ rd = &sc->are_rdata;
+ bzero(rd->are_rx_ring, ARE_RX_RING_SIZE);
+ for (i = 0; i < ARE_RX_RING_CNT; i++) {
+ rxd = &sc->are_cdata.are_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->desc = &rd->are_rx_ring[i];
+ if (i == ARE_RX_RING_CNT - 1)
+ addr = ARE_RX_RING_ADDR(sc, 0);
+ else
+ addr = ARE_RX_RING_ADDR(sc, i + 1);
+ rd->are_rx_ring[i].are_stat = ADSTAT_OWN;
+ rd->are_rx_ring[i].are_devcs = ADCTL_CH;
+ if (i == ARE_RX_RING_CNT - 1)
+ rd->are_rx_ring[i].are_devcs |= ADCTL_ER;
+ rd->are_rx_ring[i].are_addr = 0;
+ rd->are_rx_ring[i].are_link = addr;
+ if (are_newbuf(sc, i) != 0)
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->are_cdata.are_rx_ring_tag,
+ sc->are_cdata.are_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int
+are_newbuf(struct are_softc *sc, int idx)
+{
+ struct are_desc *desc;
+ struct are_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 margin
+ m_adj(m, 4);
+
+ if (bus_dmamap_load_mbuf_sg(sc->are_cdata.are_rx_tag,
+ sc->are_cdata.are_rx_sparemap, m, segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ rxd = &sc->are_cdata.are_rxdesc[idx];
+ if (rxd->rx_m != NULL) {
+// This code make bug. Make scranble on buffer data.
+// bus_dmamap_sync(sc->are_cdata.are_rx_tag, rxd->rx_dmamap,
+// BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->are_cdata.are_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->are_cdata.are_rx_sparemap;
+ sc->are_cdata.are_rx_sparemap = map;
+ bus_dmamap_sync(sc->are_cdata.are_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ desc = rxd->desc;
+ desc->are_addr = segs[0].ds_addr;
+ desc->are_devcs |= ARE_DMASIZE(segs[0].ds_len);
+ rxd->saved_ca = desc->are_addr ;
+ rxd->saved_ctl = desc->are_stat ;
+
+ return (0);
+}
+
+static __inline void
+are_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
+are_tx(struct are_softc *sc)
+{
+ struct are_txdesc *txd;
+ struct are_desc *cur_tx;
+ struct ifnet *ifp;
+ uint32_t ctl, devcs;
+ int cons, prod;
+
+ ARE_LOCK_ASSERT(sc);
+
+ cons = sc->are_cdata.are_tx_cons;
+ prod = sc->are_cdata.are_tx_prod;
+ if (cons == prod)
+ return;
+
+ bus_dmamap_sync(sc->are_cdata.are_tx_ring_tag,
+ sc->are_cdata.are_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ ifp = sc->are_ifp;
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ for (; cons != prod; ARE_INC(cons, ARE_TX_RING_CNT)) {
+ cur_tx = &sc->are_rdata.are_tx_ring[cons];
+ ctl = cur_tx->are_stat;
+ devcs = cur_tx->are_devcs;
+ /* Check if descriptor has "finished" flag */
+ if (ARE_DMASIZE(devcs) == 0)
+ break;
+
+ sc->are_cdata.are_tx_cnt--;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ txd = &sc->are_cdata.are_txdesc[cons];
+
+ if ((ctl & ADSTAT_Tx_ES) == 0)
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+ else {
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ }
+
+ bus_dmamap_sync(sc->are_cdata.are_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->are_cdata.are_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->are_stat = 0;
+ cur_tx->are_devcs = 0;
+ cur_tx->are_addr = 0;
+ }
+
+ sc->are_cdata.are_tx_cons = cons;
+
+ bus_dmamap_sync(sc->are_cdata.are_tx_ring_tag,
+ sc->are_cdata.are_tx_ring_map, BUS_DMASYNC_PREWRITE);
+}
+
+
+static void
+are_rx(struct are_softc *sc)
+{
+ struct are_rxdesc *rxd;
+ struct ifnet *ifp = sc->are_ifp;
+ int cons, prog, packet_len, error;
+ struct are_desc *cur_rx;
+ struct mbuf *m;
+
+ ARE_LOCK_ASSERT(sc);
+
+ cons = sc->are_cdata.are_rx_cons;
+
+ bus_dmamap_sync(sc->are_cdata.are_rx_ring_tag,
+ sc->are_cdata.are_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (prog = 0; prog < ARE_RX_RING_CNT; ARE_INC(cons, ARE_RX_RING_CNT)) {
+ cur_rx = &sc->are_rdata.are_rx_ring[cons];
+ rxd = &sc->are_cdata.are_rxdesc[cons];
+ m = rxd->rx_m;
+
+ if ((cur_rx->are_stat & ADSTAT_OWN) == ADSTAT_OWN)
+ break;
+
+ prog++;
+
+ packet_len = ADSTAT_Rx_LENGTH(cur_rx->are_stat);
+ /* Assume it's error */
+ error = 1;
+
+ if (packet_len < 64)
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ else if ((cur_rx->are_stat & ADSTAT_Rx_DE) == 0) {
+ error = 0;
+ bus_dmamap_sync(sc->are_cdata.are_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;
+ are_fixup_rx(m);
+ m->m_pkthdr.rcvif = ifp;
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
+
+ ARE_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ ARE_LOCK(sc);
+ }
+
+ if (error) {
+ /* Restore CONTROL and CA values, reset DEVCS */
+ cur_rx->are_stat = rxd->saved_ctl;
+ cur_rx->are_addr = rxd->saved_ca;
+ cur_rx->are_devcs = 0;
+ }
+ else {
+ /* Reinit descriptor */
+ cur_rx->are_stat = ADSTAT_OWN;
+ cur_rx->are_devcs = 0;
+ if (cons == ARE_RX_RING_CNT - 1)
+ cur_rx->are_devcs |= ADCTL_ER;
+ cur_rx->are_addr = 0;
+ if (are_newbuf(sc, cons) != 0) {
+ device_printf(sc->are_dev,
+ "Failed to allocate buffer\n");
+ break;
+ }
+ }
+
+ bus_dmamap_sync(sc->are_cdata.are_rx_ring_tag,
+ sc->are_cdata.are_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ }
+
+ if (prog > 0) {
+ sc->are_cdata.are_rx_cons = cons;
+
+ bus_dmamap_sync(sc->are_cdata.are_rx_ring_tag,
+ sc->are_cdata.are_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+}
+
+static void
+are_intr(void *arg)
+{
+ struct are_softc *sc = arg;
+ uint32_t status;
+ struct ifnet *ifp = sc->are_ifp;
+//kdb_break();
+
+ ARE_LOCK(sc);
+
+ /* mask out interrupts */
+
+ status = CSR_READ_4(sc, CSR_STATUS);
+ if (status) {
+ CSR_WRITE_4(sc, CSR_STATUS, status);
+ }
+ if (status & sc->sc_rxint_mask) {
+ are_rx(sc);
+ }
+ if (status & sc->sc_txint_mask) {
+ are_tx(sc);
+ }
+
+ /* Try to get more packets going. */
+ are_start(ifp);
+
+ ARE_UNLOCK(sc);
+}
+
+static void
+are_tick(void *xsc)
+{
+#ifdef ARE_MII
+ struct are_softc *sc = xsc;
+ struct mii_data *mii;
+
+ ARE_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->are_miibus);
+ mii_tick(mii);
+ callout_reset(&sc->are_stat_callout, hz, are_tick, sc);
+#endif
+}
+
+static void
+are_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 ARE_MDIO
+static int
+aremdio_probe(device_t dev)
+{
+ device_set_desc(dev, "Atheros AR531x built-in ethernet interface, MDIO controller");
+ return(0);
+}
+
+static int
+aremdio_attach(device_t dev)
+{
+ struct are_softc *sc;
+ int error = 0;
+
+ sc = device_get_softc(dev);
+ sc->are_dev = dev;
+ sc->are_rid = 0;
+ sc->are_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->are_rid, RF_ACTIVE | RF_SHAREABLE);
+ if (sc->are_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->are_btag = rman_get_bustag(sc->are_res);
+ sc->are_bhandle = rman_get_bushandle(sc->are_res);
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ error = bus_generic_attach(dev);
+fail:
+ return (error);
+}
+
+static int
+aremdio_detach(device_t dev)
+{
+ return(0);
+}
+#endif
+
+#ifdef ARE_DEBUG
+void
+dump_txdesc(struct are_softc *sc, int pos)
+{
+ struct are_desc *desc;
+
+ desc = &sc->are_rdata.are_tx_ring[pos];
+ device_printf(sc->are_dev, "CSR_TXLIST %08x\n", CSR_READ_4(sc, CSR_TXLIST));
+ device_printf(sc->are_dev, "CSR_HTBA %08x\n", CSR_READ_4(sc, CSR_HTBA));
+ device_printf(sc->are_dev, "%d TDES0:%08x TDES1:%08x TDES2:%08x TDES3:%08x\n",
+ pos, desc->are_stat, desc->are_devcs, desc->are_addr, desc->are_link);
+}
+
+void
+dump_status_reg(struct are_softc *sc)
+{
+ uint32_t status;
+
+ /* mask out interrupts */
+
+ device_printf(sc->are_dev, "CSR_HTBA %08x\n", CSR_READ_4(sc, CSR_HTBA));
+ status = CSR_READ_4(sc, CSR_STATUS);
+ device_printf(sc->are_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: sys/mips/atheros/ar531x/if_arereg.h
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/if_arereg.h
@@ -0,0 +1,401 @@
+/*-
+ * 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 SOFTWARE 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 ARE 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 SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef __IF_AREREG_H__
+#define __IF_AREREG_H__
+
+struct are_desc {
+ uint32_t are_stat;
+ uint32_t are_devcs;
+ uint32_t are_addr;
+ uint32_t are_link;
+};
+
+#define ARE_DMASIZE(len) ((len) & ((1 << 11)-1))
+#define ARE_PKTSIZE(len) ((len & 0xffff0000) >> 16)
+
+#define ARE_RX_RING_CNT 128
+#define ARE_TX_RING_CNT 128
+#define ARE_TX_RING_SIZE sizeof(struct are_desc) * ARE_TX_RING_CNT
+#define ARE_RX_RING_SIZE sizeof(struct are_desc) * ARE_RX_RING_CNT
+#define ARE_RING_ALIGN sizeof(struct are_desc)
+#define ARE_RX_ALIGN sizeof(uint32_t)
+#define ARE_MAXFRAGS 8
+#define ARE_TX_INTR_THRESH 8
+
+#define ARE_TX_RING_ADDR(sc, i) \
+ ((sc)->are_rdata.are_tx_ring_paddr + sizeof(struct are_desc) * (i))
+#define ARE_RX_RING_ADDR(sc, i) \
+ ((sc)->are_rdata.are_rx_ring_paddr + sizeof(struct are_desc) * (i))
+#define ARE_INC(x,y) (x) = (((x) + 1) % y)
+
+struct are_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct are_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct are_desc *desc;
+ /* Use this values on error instead of allocating new mbuf */
+ uint32_t saved_ctl, saved_ca;
+};
+
+struct are_chain_data {
+ bus_dma_tag_t are_parent_tag;
+ bus_dma_tag_t are_tx_tag;
+ struct are_txdesc are_txdesc[ARE_TX_RING_CNT];
+ bus_dma_tag_t are_rx_tag;
+ struct are_rxdesc are_rxdesc[ARE_RX_RING_CNT];
+ bus_dma_tag_t are_tx_ring_tag;
+ bus_dma_tag_t are_rx_ring_tag;
+ bus_dmamap_t are_tx_ring_map;
+ bus_dmamap_t are_rx_ring_map;
+ bus_dmamap_t are_rx_sparemap;
+ int are_tx_pkts;
+ int are_tx_prod;
+ int are_tx_cons;
+ int are_tx_cnt;
+ int are_rx_cons;
+};
+
+struct are_ring_data {
+ struct are_desc *are_rx_ring;
+ struct are_desc *are_tx_ring;
+ bus_addr_t are_rx_ring_paddr;
+ bus_addr_t are_tx_ring_paddr;
+};
+
+struct are_softc {
+ struct ifnet *are_ifp; /* interface info */
+ bus_space_handle_t are_bhandle; /* bus space handle */
+ bus_space_tag_t are_btag; /* bus space tag */
+ device_t are_dev;
+ uint8_t are_eaddr[ETHER_ADDR_LEN];
+ struct resource *are_res;
+ int are_rid;
+ struct resource *are_irq;
+ void *are_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 ARE_MII
+ device_t are_miibus;
+#else
+ struct ifmedia are_ifmedia;
+#endif
+#ifdef ARE_MDIO
+ device_t are_miiproxy;
+#endif
+ bus_dma_tag_t are_parent_tag;
+ bus_dma_tag_t are_tag;
+ struct mtx are_mtx;
+ struct callout are_stat_callout;
+ struct task are_link_task;
+ struct are_chain_data are_cdata;
+ struct are_ring_data are_rdata;
+ int are_link_status;
+ int are_detach;
+};
+
+#define ARE_LOCK(_sc) mtx_lock(&(_sc)->are_mtx)
+#define ARE_UNLOCK(_sc) mtx_unlock(&(_sc)->are_mtx)
+#define ARE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->are_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->are_btag, sc->are_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->are_btag, sc->are_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 SOFTWARE 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 ARE 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 SOFTWARE, 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_AC 0x04000000 /* Add CRC Disable */
+#define ADCTL_Tx_DPD 0x00800000 /* Disabled Padding */
+
+/*
+ * Control registers.
+ */
+
+/* tese are registers only found on this part */
+#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 */
+
+/* these are more or less normal Tulip registers */
+#define CSR_BUSMODE 0x1000 /* bus mode */
+#define CSR_TXPOLL 0x1004 /* tx poll demand */
+#define CSR_RXPOLL 0x1008 /* rx poll demand */
+#define CSR_RXLIST 0x100C /* rx base descriptor address */
+#define CSR_TXLIST 0x1010 /* tx base descriptor address */
+#define CSR_STATUS 0x1014 /* (interrupt) status */
+#define CSR_OPMODE 0x1018 /* operation mode */
+#define CSR_INTEN 0x101C /* interrupt enable */
+#define CSR_MISSED 0x1020 /* missed frame counter */
+#define CSR_HTBA 0x1050 /* host tx buffer address (ro) */
+#define CSR_HRBA 0x1054 /* host rx buffer address (ro) */
+
+/* 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_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_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 */
+
+/* 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)
+
+#endif /* __IF_AREREG_H__ */
Index: sys/mips/atheros/ar531x/uart_bus_ar5315.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/uart_bus_ar5315.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2009, 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 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
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+
+#include "uart_if.h"
+
+static int uart_ar5315_probe(device_t dev);
+extern struct uart_class uart_ar5315_uart_class;
+
+static device_method_t uart_ar5315_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_ar5315_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ DEVMETHOD_END
+};
+
+static driver_t uart_ar5315_driver = {
+ uart_driver_name,
+ uart_ar5315_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_ar5315_probe(device_t dev)
+{
+ struct uart_softc *sc;
+ uint64_t freq;
+
+ freq = ar531x_ahb_freq();
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_ns8250_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ sc->sc_sysdev->bas.regshft = 2;
+ sc->sc_sysdev->bas.bst = mips_bus_space_generic;
+ sc->sc_sysdev->bas.bsh = ar531x_uart_addr() + 3;
+ sc->sc_bas.regshft = 2;
+ sc->sc_bas.bst = mips_bus_space_generic;
+ sc->sc_bas.bsh = ar531x_uart_addr() + 3;
+
+ return (uart_bus_probe(dev, 2, freq, 0, 0));
+}
+
+DRIVER_MODULE(uart, apb, uart_ar5315_driver, uart_devclass, 0, 0);
Index: sys/mips/atheros/ar531x/uart_cpu_ar5315.c
===================================================================
--- /dev/null
+++ sys/mips/atheros/ar531x/uart_cpu_ar5315.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2009 Oleksandr Tymoshenko
+ * 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 "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/atheros/ar531x/ar5315reg.h>
+#include <mips/atheros/ar531x/ar5315_cpudef.h>
+#include <mips/atheros/ar71xx_bus_space_reversed.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ uint64_t freq;
+
+ freq = ar531x_ahb_freq();
+
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = ar71xx_bus_space_reversed;
+ di->bas.regshft = 2;
+ di->bas.rclk = freq;
+ di->baudrate = 9600; // RedBoot default is 9600
+ di->databits = 8;
+ di->stopbits = 1;
+
+ di->parity = UART_PARITY_NONE;
+
+ uart_bus_space_io = NULL;
+ uart_bus_space_mem = ar71xx_bus_space_reversed;
+ di->bas.bsh = ar531x_uart_addr();
+ return (0);
+}
Index: sys/mips/conf/AR5312_BASE
===================================================================
--- /dev/null
+++ sys/mips/conf/AR5312_BASE
@@ -0,0 +1,78 @@
+#
+# AR5312 -- Kernel configuration file for FreeBSD/MIPS for Atheros 5312 systems
+#
+# This includes all the common drivers for the AR5312 boards
+#
+# $FreeBSD$
+#
+
+machine mips mips
+ident AR5312_BASE
+cpu CPU_MIPS4K
+makeoptions KERNLOADADDR=0x80050000
+options HZ=1000
+
+files "../atheros/ar531x/files.ar5315"
+
+options INTRNG
+options AR531X_1ST_GENERATION
+
+# For now, hints are per-board.
+
+hints "AR5312_BASE.hints"
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+
+# For small memory footprints
+options VM_KMEM_SIZE_SCALE=1
+
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options INET6 # IPv6
+
+# options NFSCL #Network Filesystem Client
+
+options PSEUDOFS #Pseudo-filesystem framework
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+
+# options NFS_LEGACYRPC
+# Debugging for use in -current
+options INVARIANTS
+options INVARIANT_SUPPORT
+options WITNESS
+options WITNESS_SKIPSPIN
+options DEBUG_REDZONE
+options DEBUG_MEMGUARD
+
+options FFS #Berkeley Fast Filesystem
+# options SOFTUPDATES #Enable FFS soft updates support
+# options UFS_ACL #Support for access control lists
+# options UFS_DIRHASH #Improve performance on big directories
+# options MSDOSFS # Read MSDOS filesystems; useful for USB/CF
+
+device mii
+device are
+
+device cfi
+options CFI_HARDWAREBYTESWAP
+device geom_redboot
+
+device ar5315_wdog
+
+device uart
+device uart_ar5315
+
+device loop
+device ether
+device md
+device bpf
+device random
+
+options ARGE_DEBUG # Enable if_arge debugging for now
+
+# Enable GPIO
+device gpio
+device gpioled
Index: sys/mips/conf/AR5312_BASE.hints
===================================================================
--- /dev/null
+++ sys/mips/conf/AR5312_BASE.hints
@@ -0,0 +1,29 @@
+# $FreeBSD$
+hint.apb.0.at="nexus0"
+hint.apb.0.irq=4
+
+# uart0
+hint.uart.0.at="apb0"
+# see atheros/uart_cpu_ar71xx.c why +3
+hint.uart.0.maddr=0x1C000003
+hint.uart.0.msize=0x20
+#hint.uart.0.irq=4
+#hint.uart.0.flags="0x30"
+
+# Watchdog
+hint.ar5315_wdog.0.at="apb0"
+hint.ar5315_wdog.0.irq=6
+
+# Ethernet
+hint.are.0.at="nexus0"
+hint.are.0.maddr=0x18100000
+hint.are.0.msize=0x00100000
+hint.are.0.irq=1
+
+hint.are.1.at="nexus0"
+hint.are.1.maddr=0x18200000
+hint.are.1.msize=0x00100000
+hint.are.1.irq=2
+
+# GEOM redboot FIS directory offset
+#hint.redboot.0.fisoffset="0x007e0000"
Index: sys/mips/conf/AR5315_BASE
===================================================================
--- /dev/null
+++ sys/mips/conf/AR5315_BASE
@@ -0,0 +1,78 @@
+#
+# AR5315 -- Kernel configuration file for FreeBSD/MIPS for Atheros 5315 systems
+#
+# This includes all the common drivers for the AR5315 boards
+#
+# $FreeBSD$
+#
+
+machine mips mips
+ident AR5315_BASE
+cpu CPU_MIPS4K
+makeoptions KERNLOADADDR=0x80050000
+options HZ=1000
+
+files "../atheros/ar531x/files.ar5315"
+
+options INTRNG
+
+# For now, hints are per-board.
+
+hints "AR5315_BASE.hints"
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+
+# For small memory footprints
+options VM_KMEM_SIZE_SCALE=1
+
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options INET6 # IPv6
+
+# options NFSCL #Network Filesystem Client
+
+options PSEUDOFS #Pseudo-filesystem framework
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+
+# options NFS_LEGACYRPC
+# Debugging for use in -current
+options INVARIANTS
+options INVARIANT_SUPPORT
+options WITNESS
+options WITNESS_SKIPSPIN
+options DEBUG_REDZONE
+options DEBUG_MEMGUARD
+
+options FFS #Berkeley Fast Filesystem
+# options SOFTUPDATES #Enable FFS soft updates support
+# options UFS_ACL #Support for access control lists
+# options UFS_DIRHASH #Improve performance on big directories
+# options MSDOSFS # Read MSDOS filesystems; useful for USB/CF
+
+device mii
+device are
+
+device ar5315_spi
+device spibus
+device mx25l
+device geom_redboot
+
+device ar5315_wdog
+
+device uart
+device uart_ar5315
+
+device loop
+device ether
+device md
+device bpf
+device random
+
+options ARGE_DEBUG # Enable if_arge debugging for now
+
+# Enable GPIO
+device gpio
+device gpioled
Index: sys/mips/conf/AR5315_BASE.hints
===================================================================
--- /dev/null
+++ sys/mips/conf/AR5315_BASE.hints
@@ -0,0 +1,34 @@
+# $FreeBSD$
+hint.apb.0.at="nexus0"
+hint.apb.0.irq=0
+
+# uart0
+hint.uart.0.at="apb0"
+hint.uart.0.maddr=0x11100003
+hint.uart.0.msize=0x20
+#hint.uart.0.irq=0
+#hint.uart.0.flags="0x30"
+
+# Watchdog
+hint.ar5315_wdog.0.at="apb0"
+hint.ar5315_wdog.0.irq=7
+
+# SPI
+hint.spi.0.at="nexus0"
+hint.spi.0.maddr=0x11300000
+hint.spi.0.msize=0x0000000c
+#hint.spi.0.irq=2
+
+# Ethernet
+hint.are.0.at="nexus0"
+hint.are.0.maddr=0x10500000
+hint.are.0.msize=0x500000
+hint.are.0.irq=2
+
+# Flash
+hint.mx25l.0.at="spibus0"
+hint.mx25l.0.cs=0
+
+# GEOM redboot FIS directory offset
+#hint.redboot.0.fisoffset="0x007e0000"
+

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 7, 11:37 AM (8 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29365166
Default Alt Text
D7237.id19435.diff (182 KB)

Event Timeline