Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F146883666
D7237.id19435.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
182 KB
Referenced Files
None
Subscribers
None
D7237.id19435.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D7237: Add support Atheros AR531x soc.
Attached
Detach File
Event Timeline
Log In to Comment