Hi,

this diff replaces the ARM mainbus with a new implementation.  This
implementation works like the old version if there's no device tree.

But if there is a device tree, this tree will be used to enumerate
and attach all device drivers.

Currently drivers kind of depend on each other.  This means one
driver might expect the GPIO driver to already be attached.  Until
there are proper ways to establish interrupts, establish and set GPIOs,
set pinmuxes and attach clocks, we need to keep this attachment order.

To cope with that this code goes through the list of drivers on mainbus,
and for every driver looks through the whole device tree and calls
the driver's match function per node.  So that we don't attach nodes
multiple times, we need to keep a list of nodes that we already
attached.

For now we need to manually attach the cpu and cortex bus.  Soon I hope
that the cortex bus will not be needed for FDT, so that the devices
can attach directly to mainbus and don't need this extra step.

Thoughts? ok?

Patrick

diff --git sys/arch/arm/conf/files.arm sys/arch/arm/conf/files.arm
index cb11960..3436e8e 100644
--- sys/arch/arm/conf/files.arm
+++ sys/arch/arm/conf/files.arm
@@ -21,6 +21,9 @@ device        mainbus {}
 attach mainbus at root
 file   arch/arm/mainbus/mainbus.c              mainbus
 
+# FDT support
+file   dev/ofw/fdt.c
+
 include "arch/arm/cortex/files.cortex"
 
 device cpu {}
diff --git sys/arch/arm/cortex/cortex.c sys/arch/arm/cortex/cortex.c
index 73aa315..db878b7 100644
--- sys/arch/arm/cortex/cortex.c
+++ sys/arch/arm/cortex/cortex.c
@@ -51,6 +51,7 @@
 #include <arm/cpufunc.h>
 #include <arm/armv7/armv7var.h>
 #include <arm/cortex/cortex.h>
+#include <arm/mainbus/mainbus.h>
 
 struct arm32_bus_dma_tag cortex_bus_dma_tag = {
        0,
@@ -94,10 +95,15 @@ struct cfdriver cortex_cd = {
  */
 
 int
-cortexmatch(struct device *parent, void *cf, void *aux)
+cortexmatch(struct device *parent, void *cfdata, void *aux)
 {
+       struct mainbus_attach_args *ma = aux;
+       struct cfdata *cf = (struct cfdata *)cfdata;
        int cputype = cpufunc_id();
 
+       if (strcmp(cf->cf_driver->cd_name, ma->ma_name) != 0)
+               return (0);
+
        if ((cputype & CPU_ID_CORTEX_A7_MASK) == CPU_ID_CORTEX_A7 ||
            (cputype & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9 ||
            (cputype & CPU_ID_CORTEX_A15_MASK) == CPU_ID_CORTEX_A15 ||
diff --git sys/arch/arm/mainbus/mainbus.c sys/arch/arm/mainbus/mainbus.c
index 6ad3e8f..02062a6 100644
--- sys/arch/arm/mainbus/mainbus.c
+++ sys/arch/arm/mainbus/mainbus.c
@@ -1,124 +1,255 @@
-/*     $OpenBSD: mainbus.c,v 1.7 2013/05/30 16:15:01 deraadt Exp $     */
-/* $NetBSD: mainbus.c,v 1.3 2001/06/13 17:52:43 nathanw Exp $ */
-
+/* $OpenBSD$ */
 /*
- * Copyright (c) 1994,1995 Mark Brinicombe.
- * Copyright (c) 1994 Brini.
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by Brini.
- * 4. The name of the company nor the name of the author may be used to
- *    endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * RiscBSD kernel project
+ * Copyright (c) 2014-2016 Patrick Wildt <patr...@blueri.se>
  *
- * mainbus.c
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * mainbus configuration
- *
- * Created      : 15/12/94
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+
+#include <dev/ofw/fdt.h>
 
 #include <arm/mainbus/mainbus.h>
 
-/* Prototypes for functions provided */
+int mainbus_match(struct device *, void *, void *);
+void mainbus_attach(struct device *, struct device *, void *);
+
+struct device *mainbus_is_attached(void *);
+void mainbus_dev_list_insert(void *, struct device *);
+
+void mainbus_find_match(struct device *, void *);
+void mainbus_iterate(struct device *, struct device *, void *);
+void mainbus_attach_node(struct device *, void *, void *);
+
+int mainbus_legacy_search(struct device *, void *, void *);
+void mainbus_legacy_found(struct device *, char *);
+
+struct mainbus_softc {
+       struct device            sc_dev;
+       bus_space_tag_t          sc_iot;
+       bus_dma_tag_t            sc_dmat;
+};
+
+/*
+ * We need to look through the tree at least twice.  To make sure we
+ * do not attach node multiple times, keep a list of nodes that are
+ * already handled by any kind of driver.
+ */
+SLIST_HEAD(, mainbus_entry) mainbus_dev_list = 
SLIST_HEAD_INITIALIZER(mainbus_dev_list);
+struct mainbus_entry {
+       SLIST_ENTRY(mainbus_entry)       me_list;
+       void                            *me_node;
+       struct device                   *me_dev;
+};
+
+struct device *
+mainbus_is_attached(void *node)
+{
+       struct mainbus_entry *me;
+
+       SLIST_FOREACH(me, &mainbus_dev_list, me_list)
+               if (me->me_node == node)
+                       return me->me_dev;
+
+       return NULL;
+}
+
+void
+mainbus_dev_list_insert(void *node, struct device *child)
+{
+       struct mainbus_entry *me;
+
+       if (child == NULL)
+               return;
 
-int  mainbusmatch(struct device *, void *, void *);
-void mainbusattach(struct device *, struct device *, void *);
-int  mainbusprint(void *aux, const char *mainbus);
-int mainbussearch(struct device *,  void *, void *);
+       me = malloc(sizeof(*me), M_DEVBUF, M_NOWAIT|M_ZERO);
+       if (me == NULL)
+               panic("%s: cannot allocate memory", __func__);
 
-/* attach and device structures for the device */
+       me->me_node = node;
+       me->me_dev = child;
+       SLIST_INSERT_HEAD(&mainbus_dev_list, me, me_list);
+}
 
 struct cfattach mainbus_ca = {
-       sizeof(struct device), mainbusmatch, mainbusattach
+       sizeof(struct mainbus_softc), mainbus_match, mainbus_attach, NULL,
+       config_activate_children
 };
 
 struct cfdriver mainbus_cd = {
        NULL, "mainbus", DV_DULL
 };
 
+struct arm32_bus_dma_tag mainbus_dma_tag = {
+       0,
+       0,
+       NULL,
+       _bus_dmamap_create,
+       _bus_dmamap_destroy,
+       _bus_dmamap_load,
+       _bus_dmamap_load_mbuf,
+       _bus_dmamap_load_uio,
+       _bus_dmamap_load_raw,
+       _bus_dmamap_unload,
+       _bus_dmamap_sync,
+       _bus_dmamem_alloc,
+       _bus_dmamem_free,
+       _bus_dmamem_map,
+       _bus_dmamem_unmap,
+       _bus_dmamem_mmap,
+};
+
 /*
- * int mainbusmatch(struct device *parent, struct cfdata *cf, void *aux)
+ * Mainbus takes care of FDT and non-FDT machines, so we
+ * always attach.
  */
-
 int
-mainbusmatch(struct device *parent, void *cf, void *aux)
+mainbus_match(struct device *parent, void *cfdata, void *aux)
 {
        return (1);
 }
 
+void
+mainbus_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct mainbus_softc *sc = (struct mainbus_softc *)self;
+       char *compatible;
+       void *node;
+
+       if ((node = fdt_next_node(0)) == NULL) {
+               printf(": running without device tree\n");
+               config_search(mainbus_legacy_search, self, aux);
+               return;
+       }
+
+#ifdef CPU_ARMv7
+       extern struct bus_space armv7_bs_tag;
+       sc->sc_iot = &armv7_bs_tag;
+#endif
+       sc->sc_dmat = &mainbus_dma_tag;
+
+       if (fdt_node_property(node, "compatible", &compatible))
+               printf(": %s compatible\n", compatible);
+       else
+               printf(": unknown\n");
+
+       /* Attach CPU first. */
+       mainbus_legacy_found(self, "cpu");
+
+       /* TODO: Cortex clients should connect to FDT. */
+       mainbus_legacy_found(self, "cortex");
+
+       /* TODO: Scan for interrupt controllers and attach them first? */
+
+       /* Scan the whole tree. */
+       config_scan(mainbus_find_match, self);
+}
+
 /*
- * void mainbusattach(struct device *parent, struct device *self, void *aux)
+ * Usually you should be able to attach devices in the order
+ * specified in the device tree.  Due to how a few drivers
+ * are written we need to make sure we attach them in the
+ * order stated in files.xxx.
  *
- * probe and attach all children
+ * This means for every driver enabled, we go through the
+ * FDT and look for compatible nodes.
  */
+void
+mainbus_find_match(struct device *self, void *match)
+{
+       mainbus_iterate(self, match, fdt_next_node(0));
+}
+
+void
+mainbus_iterate(struct device *self, struct device *match, void *node)
+{
+       for (;
+           node != NULL;
+           node = fdt_next_node(node))
+       {
+               /* skip nodes that are already handled by some driver */
+               if (!mainbus_is_attached(node))
+                       mainbus_attach_node(self, match, node);
+
+               mainbus_iterate(self, match, fdt_child_node(node));
+       }
+}
 
+/*
+ * Try to attach a node to a known driver.
+ */
 void
-mainbusattach(struct device *parent, struct device *self, void *aux)
+mainbus_attach_node(struct device *self, void *match, void *node)
 {
-       printf("\n");
+       struct mainbus_softc    *sc = (struct mainbus_softc *)self;
+       struct mainbus_attach_args ma;
+       struct cfdata           *cf = match;
+       struct device           *child;
+       char                    *status;
+
+       if (!fdt_node_property(node, "compatible", NULL))
+               return;
+
+       if (fdt_node_property(node, "status", &status))
+               if (!strcmp(status, "disabled"))
+                       return;
+
+       memset(&ma, 0, sizeof(ma));
+       ma.ma_name = "";
+       ma.ma_node = node;
+       ma.ma_iot = sc->sc_iot;
+       ma.ma_dmat = sc->sc_dmat;
 
-       config_search(mainbussearch, self, aux);
+       /* allow for devices to be disabled in UKC */
+       if ((*cf->cf_attach->ca_match)(self, cf, &ma) == 0)
+               return;
+
+       /* TODO: attach the device's clocks first? */
+
+       child = config_attach(self, cf, &ma, NULL);
+       mainbus_dev_list_insert(node, child);
 }
 
+/*
+ * Legacy support for SoCs that do not use FDT.
+ */
 int
-mainbussearch(struct device *parent, void *vcf, void *aux)
+mainbus_legacy_search(struct device *parent, void *match, void *aux)
 {
        struct mainbus_attach_args ma;
-       struct cfdata *cf = vcf;
+       struct cfdata           *cf = match;
 
+       memset(&ma, 0, sizeof(ma));
        ma.ma_name = cf->cf_driver->cd_name;
 
        /* allow for devices to be disabled in UKC */
        if ((*cf->cf_attach->ca_match)(parent, cf, &ma) == 0)
                return 0;
 
-       config_attach(parent, cf, &ma, mainbusprint);
+       config_attach(parent, cf, &ma, NULL);
        return 1;
 }
 
-/*
- * int mainbusprint(void *aux, const char *mainbus)
- *
- * print routine used during config of children
- */
-
-int
-mainbusprint(void *aux, const char *mainbus)
+void
+mainbus_legacy_found(struct device *self, char *name)
 {
-       struct mainbus_attach_args *ma = aux;
+       struct mainbus_attach_args ma;
 
-       if (mainbus != NULL)
-               printf("%s at %s", ma->ma_name, mainbus);
+       memset(&ma, 0, sizeof(ma));
+       ma.ma_name = name;
 
-       return (UNCONF);
+       config_found(self, &ma, NULL);
 }
diff --git sys/arch/arm/mainbus/mainbus.h sys/arch/arm/mainbus/mainbus.h
index 3e17996..188bc5a 100644
--- sys/arch/arm/mainbus/mainbus.h
+++ sys/arch/arm/mainbus/mainbus.h
@@ -1,51 +1,32 @@
-/*     $OpenBSD: mainbus.h,v 1.2 2011/09/22 17:45:59 miod Exp $        */
-/* $NetBSD: mainbus.h,v 1.1 2001/02/24 19:38:02 reinoud Exp $ */
-
+/* $OpenBSD$ */
 /*
- * Copyright (c) 1994,1995 Mark Brinicombe.
- * Copyright (c) 1994 Brini.
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by Brini.
- * 4. The name of the company nor the name of the author may be used to
- *    endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * RiscBSD kernel project
- *
- * mainbus.h
+ * Copyright (c) 2016 Patrick Wildt <patr...@blueri.se>
  *
- * mainbus configuration
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * Created      : 15/12/94
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/*
- * mainbus driver attach arguments
- */
+#ifndef __MAINBUS_H__
+#define __MAINBUS_H__
 
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
+/* Passed as third arg to attach functions. */
 struct mainbus_attach_args {
-       const char      *ma_name;
+       const char              *ma_name;
+       void                    *ma_node;
+       bus_space_tag_t          ma_iot;
+       bus_dma_tag_t            ma_dmat;
 };
+
+#endif /* __MAINBUS_H__ */
diff --git sys/arch/armv7/conf/files.armv7 sys/arch/armv7/conf/files.armv7
index c5d022c..ae40f36 100644
--- sys/arch/armv7/conf/files.armv7
+++ sys/arch/armv7/conf/files.armv7
@@ -10,7 +10,6 @@ major {rd = 18}
 
 define fdt {}
 file   arch/armv7/fdt/fdt_machdep.c    fdt     needs-flag
-file   dev/ofw/fdt.c
 
 file   arch/arm/arm/conf.c
 
diff --git sys/dev/ofw/fdt.c sys/dev/ofw/fdt.c
index cdb588b..4cf7248 100644
--- sys/dev/ofw/fdt.c
+++ sys/dev/ofw/fdt.c
@@ -160,6 +160,7 @@ skip_node_name(u_int32_t *ptr)
 /*
  * Retrieves node property, the returned pointer is inside the fdt tree,
  * so we should not modify content pointed by it directly.
+ * A NULL out parameter will cause this function to only return the size.
  */
 int
 fdt_node_property(void *node, char *name, char **out)
@@ -182,7 +183,8 @@ fdt_node_property(void *node, char *name, char **out)
                nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
                tmp = fdt_get_str(nameid);
                if (!strcmp(name, tmp)) {
-                       *out = (char *)(ptr + 3); /* beginning of the value */
+                       if (out != NULL)
+                               *out = (char *)(ptr + 3); /* beginning of the 
value */
                        return betoh32(*(ptr + 1)); /* size of value */
                }
                ptr = skip_property(ptr);

Reply via email to