All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Sekhar Nori <nsekhar@ti.com>, Kevin Hilman <khilman@kernel.org>,
	David Lechner <david@lechnology.com>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>, Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Yoshinori Sato <ysato@users.sourceforge.jp>,
	Rich Felker <dalias@libc.org>,
	Andy Shevchenko <andy.shevchenko@gmail.com>,
	Marc Zyngier <marc.zyngier@arm.com>,
	"Rafael J . Wysocki" <rafael.j.wysocki@intel.com>,
	Peter Rosin <peda@axentia.se>, Jiri Slaby <jslaby@suse.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	Geert Uytterhoeven <geert@linux-m68k.org>,
	Magnus Damm <magnus.damm@gmail.com>,
	Johan Hovold <johan@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	Frank Rowand <frowand.list@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arch@vger.kernel.org,
	Bartosz Golaszewski <bgolaszewski@baylibre.com>
Subject: [PATCH 10/12] platform/early: implement support for early platform drivers
Date: Fri, 11 May 2018 18:20:26 +0200	[thread overview]
Message-ID: <20180511162028.20616-11-brgl@bgdev.pl> (raw)
In-Reply-To: <20180511162028.20616-1-brgl@bgdev.pl>

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This introduces the core part of support for early platform drivers
and devices.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/base/Kconfig           |   3 +
 drivers/base/Makefile          |   1 +
 drivers/base/early.c           | 332 +++++++++++++++++++++++++++++++++
 drivers/misc/Makefile          |   1 +
 include/linux/early_platform.h |  75 ++++++++
 5 files changed, 412 insertions(+)
 create mode 100644 drivers/base/early.c
 create mode 100644 include/linux/early_platform.h

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 29b0eb452b3a..ea648daecec1 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -205,6 +205,9 @@ config DEBUG_TEST_DRIVER_REMOVE
 	  unusable. You should say N here unless you are explicitly looking to
 	  test this functionality.
 
+config EARLY_PLATFORM
+	def_bool n
+
 source "drivers/base/test/Kconfig"
 
 config SYS_HYPERVISOR
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 7845c95ee1b2..3998ad6719f1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -7,6 +7,7 @@ obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   attribute_container.o transport_class.o \
 			   topology.o container.o property.o cacheinfo.o \
 			   devcon.o
+obj-$(CONFIG_EARLY_PLATFORM) += early.o
 obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o
 obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y			+= power/
diff --git a/drivers/base/early.c b/drivers/base/early.c
new file mode 100644
index 000000000000..7d0b7fb85f58
--- /dev/null
+++ b/drivers/base/early.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#include <linux/early_platform.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include "base.h"
+
+extern struct early_platform_driver *__early_platform_drivers_table[];
+extern struct early_platform_driver *__early_platform_drivers_table_end[];
+
+static bool early_platform_done;
+
+static LIST_HEAD(early_platform_drivers);
+static LIST_HEAD(early_platform_devices);
+
+static int early_platform_device_set_name(struct early_platform_device *edev)
+{
+	switch (edev->pdev.id) {
+	case PLATFORM_DEVID_AUTO:
+		pr_warn("auto device ID not supported in early platform devices\n");
+		/* fallthrough */
+	case PLATFORM_DEVID_NONE:
+		edev->pdev.dev.init_name = kasprintf(GFP_KERNEL,
+						     "%s", edev->pdev.name);
+		break;
+	default:
+		edev->pdev.dev.init_name = kasprintf(GFP_KERNEL, "%s.%d",
+						     edev->pdev.name,
+						     edev->pdev.id);
+		break;
+	}
+
+	if (!edev->pdev.dev.init_name)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void early_platform_device_add(struct early_platform_device *edev)
+{
+	edev->pdev.dev.early = true;
+	INIT_LIST_HEAD(&edev->list);
+	list_add_tail(&edev->list, &early_platform_devices);
+}
+
+static void early_platform_probe_deferred(void)
+{
+	struct early_platform_device *edev;
+	int rv;
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (!edev->deferred || !edev->deferred_drv->early_probe)
+			continue;
+
+		rv = edev->deferred_drv->early_probe(&edev->pdev);
+		if (rv && rv != -EPROBE_DEFER) {
+			dev_err(&edev->pdev.dev,
+				"early platform driver probe failed: %d\n",
+				rv);
+		}
+	}
+}
+
+static void early_platform_try_probe(struct early_platform_driver *edrv,
+				     struct early_platform_device *edev)
+{
+	int rv;
+
+	rv = early_platform_device_set_name(edev);
+	if (rv)
+		pr_warn("unable to set the early platform device name\n");
+
+	if (edrv->early_probe) {
+		rv = edrv->early_probe(&edev->pdev);
+		if (rv && rv != -EPROBE_DEFER &&
+		    rv != -ENODEV && rv != -ENXIO) {
+			dev_err(&edev->pdev.dev,
+				"early platform driver probe failed: %d\n",
+				rv);
+			return;
+		} else if (rv == -EPROBE_DEFER) {
+			edev->deferred = true;
+			edev->deferred_drv = edrv;
+		} else {
+			early_platform_probe_deferred();
+		}
+	}
+}
+
+/**
+ * of_early_to_platform_device - return the platform device with which this
+ *                               device node is associated
+ * @np - device node to look up
+ *
+ * If a device node was populated early, the corresponding platform device
+ * already exists. Instead of allocating a new object, we need to retrieve
+ * the previous one. This routine enables it.
+ */
+struct platform_device *of_early_to_platform_device(struct device_node *np)
+{
+	struct early_platform_device *edev;
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (np == edev->pdev.dev.of_node)
+			return &edev->pdev;
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+
+static int of_early_platform_device_create(struct device_node *node,
+					   struct early_platform_driver *edrv)
+{
+	struct early_platform_device *edev;
+	int rc;
+
+	edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+	if (!edev)
+		return -ENOMEM;
+
+	platform_device_init(&edev->pdev, "", PLATFORM_DEVID_NONE);
+	/*
+	 * We can safely use platform_device_release since the platform_device
+	 * struct is the first member of early_platform_device.
+	 */
+	edev->pdev.dev.release = platform_device_release;
+
+	rc = of_device_init_resources(&edev->pdev, node);
+	if (rc) {
+		kfree(edev);
+		return rc;
+	}
+
+	of_node_set_flag(node, OF_POPULATED_EARLY);
+	edev->pdev.name = edrv->pdrv.driver.name;
+	edev->pdev.dev.of_node = of_node_get(node);
+	edev->pdev.dev.fwnode = &node->fwnode;
+	early_platform_device_add(edev);
+	early_platform_try_probe(edrv, edev);
+
+	return 0;
+}
+
+static int of_early_platform_populate(struct device_node *root)
+{
+	struct early_platform_driver *edrv;
+	const struct of_device_id *match;
+	struct device_node *child;
+	int rv;
+
+	if (!root)
+		return 0;
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		if (!edrv->pdrv.driver.of_match_table)
+			continue;
+
+		match = of_match_node(edrv->pdrv.driver.of_match_table, root);
+		if (!match)
+			continue;
+
+		rv = of_early_platform_device_create(root, edrv);
+		if (rv)
+			return rv;
+	}
+
+	for_each_child_of_node(root, child) {
+		rv = of_early_platform_populate(child);
+		if (rv) {
+			of_node_put(child);
+			return rv;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * early_platform_start - start handling early devices
+ *
+ * This should be called by the architecture code early in the boot sequence
+ * to register all early platform drivers, populate the early devices from DT
+ * and start matching platform devices specified in machine code.
+ */
+void early_platform_start(void)
+{
+	struct early_platform_driver **edrv;
+	struct device_node *root;
+	int rv;
+
+	WARN_ONCE(!slab_is_available(), "slab is required for early devices\n");
+
+	pr_debug("%s(): registering pending early platform drivers\n",
+		 __func__);
+
+	for (edrv = __early_platform_drivers_table;
+	     edrv < __early_platform_drivers_table_end; edrv++) {
+		rv = early_platform_driver_register(*edrv);
+		if (rv)
+			pr_warn("error registering early platform driver: %d\n",
+				rv);
+	}
+
+	if (of_have_populated_dt()) {
+		pr_debug("%s(): populating early_platform devices from DT\n",
+			 __func__);
+
+		root = of_find_node_by_path("/");
+
+		rv = of_early_platform_populate(root);
+		if (rv)
+			pr_warn("error populating early devices from DT: %d\n",
+				rv);
+
+		of_node_put(root);
+	}
+}
+EXPORT_SYMBOL_GPL(early_platform_start);
+
+/**
+ * early_platform_driver_register - register an early platform driver
+ * @edrv: early platform driver to register
+ *
+ * If we're past postcore initcall, this works exactly as
+ * platform_device_register().
+ */
+int early_platform_driver_register(struct early_platform_driver *edrv)
+{
+	struct early_platform_device *edev;
+
+	if (early_platform_done)
+		return platform_driver_register(&edrv->pdrv);
+
+	INIT_LIST_HEAD(&edrv->list);
+	list_add_tail(&edrv->list, &early_platform_drivers);
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (platform_match(&edev->pdev.dev, &edrv->pdrv.driver)) {
+			early_platform_try_probe(edrv, edev);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(early_platform_driver_register);
+
+/**
+ * early_platform_device_register - register an early platform device
+ * @edev: early platform device to register
+ *
+ * If we're past postcore initcall, this works exactly as
+ * platform_device_register().
+ */
+int early_platform_device_register(struct early_platform_device *edev)
+{
+	struct early_platform_driver *edrv;
+
+	if (early_platform_done)
+		return platform_device_register(&edev->pdev);
+
+	device_initialize(&edev->pdev.dev);
+	early_platform_device_add(edev);
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		if (platform_match(&edev->pdev.dev, &edrv->pdrv.driver)) {
+			early_platform_try_probe(edrv, edev);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(early_platform_device_register);
+
+/*
+ * This is called once the entire device model infrastructure is in place to
+ * seamlessly convert all early platform devices & drivers to regular ones.
+ *
+ * From this point forward all early platform devices work exactly like normal
+ * platform devices.
+ */
+static int early_platform_finalize(void)
+{
+	struct early_platform_driver *edrv;
+	struct early_platform_device *edev;
+	int rv;
+
+	early_platform_done = true;
+
+	pr_debug("%s(): converting early platform drivers to real platform drivers\n",
+		 __func__);
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		rv = platform_driver_register(&edrv->pdrv);
+		if (rv)
+			pr_warn("%s: error converting early platform driver to real platform driver\n",
+				edrv->pdrv.driver.name);
+	}
+
+	pr_debug("%s(): converting early platform devices to real platform devices\n",
+		 __func__);
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (edev->pdev.dev.of_node)
+			/* This will be handled by of_platform_populate(). */
+			continue;
+
+		kfree(edev->pdev.dev.init_name);
+
+		/*
+		 * We don't want to reinitialize the associated struct device
+		 * so we must not call platform_device_register().
+		 */
+		rv = platform_device_add(&edev->pdev);
+		if (rv)
+			pr_warn("%s: error converting early platform device to real platform device\n",
+				dev_name(&edev->pdev.dev));
+	}
+
+	return 0;
+}
+postcore_initcall(early_platform_finalize);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 20be70c3f118..d0a8788d5151 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_MISC_RTSX)		+= cardreader/
+CFLAGS_dummy-early.o := -DDEBUG
diff --git a/include/linux/early_platform.h b/include/linux/early_platform.h
new file mode 100644
index 000000000000..fd3fd4db8322
--- /dev/null
+++ b/include/linux/early_platform.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#ifndef __EARLY_PLATFORM_H__
+#define __EARLY_PLATFORM_H__
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/**
+ * struct early_platform_driver
+ *
+ * @pdrv: real platform driver associated with this early platform driver
+ * @list: list head for the list of early platform drivers
+ * @early_probe: early probe callback
+ */
+struct early_platform_driver {
+	struct platform_driver pdrv;
+	struct list_head list;
+	int (*early_probe)(struct platform_device *);
+};
+
+/**
+ * struct early_platform_device
+ *
+ * @pdev: real platform device associated with this early platform device
+ * @list: list head for the list of early platform devices
+ * @deferred: true if this device's early probe was deferred
+ * @deferred_drv: early platform driver with which this device was matched
+ */
+struct early_platform_device {
+	struct platform_device pdev;
+	struct list_head list;
+	bool deferred;
+	struct early_platform_driver *deferred_drv;
+};
+
+#ifdef CONFIG_EARLY_PLATFORM
+extern void early_platform_start(void);
+extern int early_platform_driver_register(struct early_platform_driver *edrv);
+extern int early_platform_device_register(struct early_platform_device *edev);
+#else /* CONFIG_EARLY_PLATFORM */
+static inline void early_platform_start(void) {}
+static int void
+early_platform_driver_register(struct early_platform_driver *edrv) {}
+static int void
+early_platform_device_register(struct early_platform_device *edev) {}
+#endif /* CONFIG_EARLY_PLATFORM */
+
+#if defined(CONFIG_EARLY_PLATFORM) && defined(CONFIG_OF)
+extern struct platform_device *
+of_early_to_platform_device(struct device_node *np);
+#else
+static inline struct platform_device *
+of_early_to_platform_device(struct device_node *np)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif /* defined(CONFIG_EARLY_PLATFORM) && defined(CONFIG_OF) */
+
+#ifdef CONFIG_EARLY_PLATFORM
+#define module_early_platform_driver(_edrv)				\
+	static const struct early_platform_driver *__##_edrv##_entry	\
+		__used __section(__early_platform_drivers_table)	\
+		= &(_edrv)
+#else /* CONFIG_EARLY_PLATFORM */
+#define module_early_platform_driver(_edrv)
+#endif /* CONFIG_EARLY_PLATFORM */
+
+#endif /* __EARLY_PLATFORM_H__ */
-- 
2.17.0

WARNING: multiple messages have this Message-ID (diff)
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Sekhar Nori <nsekhar@ti.com>, Kevin Hilman <khilman@kernel.org>,
	David Lechner <david@lechnology.com>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>, Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Yoshinori Sato <ysato@users.sourceforge.jp>,
	Rich Felker <dalias@libc.org>,
	Andy Shevchenko <andy.shevchenko@gmail.com>,
	Marc Zyngier <marc.zyngier@arm.com>,
	"Rafael J . Wysocki" <rafael.j.wysocki@intel.com>,
	Peter Rosin <peda@axentia.se>, Jiri Slaby <jslaby@suse.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	Geert Uytterhoeven <geert@linux-m68k.org>,
	Magnus Damm <magnus.damm@gmail.com>,
	Johan Hovold <johan@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-arch@vger.kernel.org,
	Bartosz Golaszewski <bgolaszewski@baylibre.com>
Subject: [PATCH 10/12] platform/early: implement support for early platform drivers
Date: Fri, 11 May 2018 18:20:26 +0200	[thread overview]
Message-ID: <20180511162028.20616-11-brgl@bgdev.pl> (raw)
In-Reply-To: <20180511162028.20616-1-brgl@bgdev.pl>

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This introduces the core part of support for early platform drivers
and devices.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/base/Kconfig           |   3 +
 drivers/base/Makefile          |   1 +
 drivers/base/early.c           | 332 +++++++++++++++++++++++++++++++++
 drivers/misc/Makefile          |   1 +
 include/linux/early_platform.h |  75 ++++++++
 5 files changed, 412 insertions(+)
 create mode 100644 drivers/base/early.c
 create mode 100644 include/linux/early_platform.h

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 29b0eb452b3a..ea648daecec1 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -205,6 +205,9 @@ config DEBUG_TEST_DRIVER_REMOVE
 	  unusable. You should say N here unless you are explicitly looking to
 	  test this functionality.
 
+config EARLY_PLATFORM
+	def_bool n
+
 source "drivers/base/test/Kconfig"
 
 config SYS_HYPERVISOR
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 7845c95ee1b2..3998ad6719f1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -7,6 +7,7 @@ obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   attribute_container.o transport_class.o \
 			   topology.o container.o property.o cacheinfo.o \
 			   devcon.o
+obj-$(CONFIG_EARLY_PLATFORM) += early.o
 obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o
 obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y			+= power/
diff --git a/drivers/base/early.c b/drivers/base/early.c
new file mode 100644
index 000000000000..7d0b7fb85f58
--- /dev/null
+++ b/drivers/base/early.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#include <linux/early_platform.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include "base.h"
+
+extern struct early_platform_driver *__early_platform_drivers_table[];
+extern struct early_platform_driver *__early_platform_drivers_table_end[];
+
+static bool early_platform_done;
+
+static LIST_HEAD(early_platform_drivers);
+static LIST_HEAD(early_platform_devices);
+
+static int early_platform_device_set_name(struct early_platform_device *edev)
+{
+	switch (edev->pdev.id) {
+	case PLATFORM_DEVID_AUTO:
+		pr_warn("auto device ID not supported in early platform devices\n");
+		/* fallthrough */
+	case PLATFORM_DEVID_NONE:
+		edev->pdev.dev.init_name = kasprintf(GFP_KERNEL,
+						     "%s", edev->pdev.name);
+		break;
+	default:
+		edev->pdev.dev.init_name = kasprintf(GFP_KERNEL, "%s.%d",
+						     edev->pdev.name,
+						     edev->pdev.id);
+		break;
+	}
+
+	if (!edev->pdev.dev.init_name)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void early_platform_device_add(struct early_platform_device *edev)
+{
+	edev->pdev.dev.early = true;
+	INIT_LIST_HEAD(&edev->list);
+	list_add_tail(&edev->list, &early_platform_devices);
+}
+
+static void early_platform_probe_deferred(void)
+{
+	struct early_platform_device *edev;
+	int rv;
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (!edev->deferred || !edev->deferred_drv->early_probe)
+			continue;
+
+		rv = edev->deferred_drv->early_probe(&edev->pdev);
+		if (rv && rv != -EPROBE_DEFER) {
+			dev_err(&edev->pdev.dev,
+				"early platform driver probe failed: %d\n",
+				rv);
+		}
+	}
+}
+
+static void early_platform_try_probe(struct early_platform_driver *edrv,
+				     struct early_platform_device *edev)
+{
+	int rv;
+
+	rv = early_platform_device_set_name(edev);
+	if (rv)
+		pr_warn("unable to set the early platform device name\n");
+
+	if (edrv->early_probe) {
+		rv = edrv->early_probe(&edev->pdev);
+		if (rv && rv != -EPROBE_DEFER &&
+		    rv != -ENODEV && rv != -ENXIO) {
+			dev_err(&edev->pdev.dev,
+				"early platform driver probe failed: %d\n",
+				rv);
+			return;
+		} else if (rv == -EPROBE_DEFER) {
+			edev->deferred = true;
+			edev->deferred_drv = edrv;
+		} else {
+			early_platform_probe_deferred();
+		}
+	}
+}
+
+/**
+ * of_early_to_platform_device - return the platform device with which this
+ *                               device node is associated
+ * @np - device node to look up
+ *
+ * If a device node was populated early, the corresponding platform device
+ * already exists. Instead of allocating a new object, we need to retrieve
+ * the previous one. This routine enables it.
+ */
+struct platform_device *of_early_to_platform_device(struct device_node *np)
+{
+	struct early_platform_device *edev;
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (np == edev->pdev.dev.of_node)
+			return &edev->pdev;
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+
+static int of_early_platform_device_create(struct device_node *node,
+					   struct early_platform_driver *edrv)
+{
+	struct early_platform_device *edev;
+	int rc;
+
+	edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+	if (!edev)
+		return -ENOMEM;
+
+	platform_device_init(&edev->pdev, "", PLATFORM_DEVID_NONE);
+	/*
+	 * We can safely use platform_device_release since the platform_device
+	 * struct is the first member of early_platform_device.
+	 */
+	edev->pdev.dev.release = platform_device_release;
+
+	rc = of_device_init_resources(&edev->pdev, node);
+	if (rc) {
+		kfree(edev);
+		return rc;
+	}
+
+	of_node_set_flag(node, OF_POPULATED_EARLY);
+	edev->pdev.name = edrv->pdrv.driver.name;
+	edev->pdev.dev.of_node = of_node_get(node);
+	edev->pdev.dev.fwnode = &node->fwnode;
+	early_platform_device_add(edev);
+	early_platform_try_probe(edrv, edev);
+
+	return 0;
+}
+
+static int of_early_platform_populate(struct device_node *root)
+{
+	struct early_platform_driver *edrv;
+	const struct of_device_id *match;
+	struct device_node *child;
+	int rv;
+
+	if (!root)
+		return 0;
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		if (!edrv->pdrv.driver.of_match_table)
+			continue;
+
+		match = of_match_node(edrv->pdrv.driver.of_match_table, root);
+		if (!match)
+			continue;
+
+		rv = of_early_platform_device_create(root, edrv);
+		if (rv)
+			return rv;
+	}
+
+	for_each_child_of_node(root, child) {
+		rv = of_early_platform_populate(child);
+		if (rv) {
+			of_node_put(child);
+			return rv;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * early_platform_start - start handling early devices
+ *
+ * This should be called by the architecture code early in the boot sequence
+ * to register all early platform drivers, populate the early devices from DT
+ * and start matching platform devices specified in machine code.
+ */
+void early_platform_start(void)
+{
+	struct early_platform_driver **edrv;
+	struct device_node *root;
+	int rv;
+
+	WARN_ONCE(!slab_is_available(), "slab is required for early devices\n");
+
+	pr_debug("%s(): registering pending early platform drivers\n",
+		 __func__);
+
+	for (edrv = __early_platform_drivers_table;
+	     edrv < __early_platform_drivers_table_end; edrv++) {
+		rv = early_platform_driver_register(*edrv);
+		if (rv)
+			pr_warn("error registering early platform driver: %d\n",
+				rv);
+	}
+
+	if (of_have_populated_dt()) {
+		pr_debug("%s(): populating early_platform devices from DT\n",
+			 __func__);
+
+		root = of_find_node_by_path("/");
+
+		rv = of_early_platform_populate(root);
+		if (rv)
+			pr_warn("error populating early devices from DT: %d\n",
+				rv);
+
+		of_node_put(root);
+	}
+}
+EXPORT_SYMBOL_GPL(early_platform_start);
+
+/**
+ * early_platform_driver_register - register an early platform driver
+ * @edrv: early platform driver to register
+ *
+ * If we're past postcore initcall, this works exactly as
+ * platform_device_register().
+ */
+int early_platform_driver_register(struct early_platform_driver *edrv)
+{
+	struct early_platform_device *edev;
+
+	if (early_platform_done)
+		return platform_driver_register(&edrv->pdrv);
+
+	INIT_LIST_HEAD(&edrv->list);
+	list_add_tail(&edrv->list, &early_platform_drivers);
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (platform_match(&edev->pdev.dev, &edrv->pdrv.driver)) {
+			early_platform_try_probe(edrv, edev);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(early_platform_driver_register);
+
+/**
+ * early_platform_device_register - register an early platform device
+ * @edev: early platform device to register
+ *
+ * If we're past postcore initcall, this works exactly as
+ * platform_device_register().
+ */
+int early_platform_device_register(struct early_platform_device *edev)
+{
+	struct early_platform_driver *edrv;
+
+	if (early_platform_done)
+		return platform_device_register(&edev->pdev);
+
+	device_initialize(&edev->pdev.dev);
+	early_platform_device_add(edev);
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		if (platform_match(&edev->pdev.dev, &edrv->pdrv.driver)) {
+			early_platform_try_probe(edrv, edev);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(early_platform_device_register);
+
+/*
+ * This is called once the entire device model infrastructure is in place to
+ * seamlessly convert all early platform devices & drivers to regular ones.
+ *
+ * From this point forward all early platform devices work exactly like normal
+ * platform devices.
+ */
+static int early_platform_finalize(void)
+{
+	struct early_platform_driver *edrv;
+	struct early_platform_device *edev;
+	int rv;
+
+	early_platform_done = true;
+
+	pr_debug("%s(): converting early platform drivers to real platform drivers\n",
+		 __func__);
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		rv = platform_driver_register(&edrv->pdrv);
+		if (rv)
+			pr_warn("%s: error converting early platform driver to real platform driver\n",
+				edrv->pdrv.driver.name);
+	}
+
+	pr_debug("%s(): converting early platform devices to real platform devices\n",
+		 __func__);
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (edev->pdev.dev.of_node)
+			/* This will be handled by of_platform_populate(). */
+			continue;
+
+		kfree(edev->pdev.dev.init_name);
+
+		/*
+		 * We don't want to reinitialize the associated struct device
+		 * so we must not call platform_device_register().
+		 */
+		rv = platform_device_add(&edev->pdev);
+		if (rv)
+			pr_warn("%s: error converting early platform device to real platform device\n",
+				dev_name(&edev->pdev.dev));
+	}
+
+	return 0;
+}
+postcore_initcall(early_platform_finalize);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 20be70c3f118..d0a8788d5151 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_MISC_RTSX)		+= cardreader/
+CFLAGS_dummy-early.o := -DDEBUG
diff --git a/include/linux/early_platform.h b/include/linux/early_platform.h
new file mode 100644
index 000000000000..fd3fd4db8322
--- /dev/null
+++ b/include/linux/early_platform.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#ifndef __EARLY_PLATFORM_H__
+#define __EARLY_PLATFORM_H__
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/**
+ * struct early_platform_driver
+ *
+ * @pdrv: real platform driver associated with this early platform driver
+ * @list: list head for the list of early platform drivers
+ * @early_probe: early probe callback
+ */
+struct early_platform_driver {
+	struct platform_driver pdrv;
+	struct list_head list;
+	int (*early_probe)(struct platform_device *);
+};
+
+/**
+ * struct early_platform_device
+ *
+ * @pdev: real platform device associated with this early platform device
+ * @list: list head for the list of early platform devices
+ * @deferred: true if this device's early probe was deferred
+ * @deferred_drv: early platform driver with which this device was matched
+ */
+struct early_platform_device {
+	struct platform_device pdev;
+	struct list_head list;
+	bool deferred;
+	struct early_platform_driver *deferred_drv;
+};
+
+#ifdef CONFIG_EARLY_PLATFORM
+extern void early_platform_start(void);
+extern int early_platform_driver_register(struct early_platform_driver *edrv);
+extern int early_platform_device_register(struct early_platform_device *edev);
+#else /* CONFIG_EARLY_PLATFORM */
+static inline void early_platform_start(void) {}
+static int void
+early_platform_driver_register(struct early_platform_driver *edrv) {}
+static int void
+early_platform_device_register(struct early_platform_device *edev) {}
+#endif /* CONFIG_EARLY_PLATFORM */
+
+#if defined(CONFIG_EARLY_PLATFORM) && defined(CONFIG_OF)
+extern struct platform_device *
+of_early_to_platform_device(struct device_node *np);
+#else
+static inline struct platform_device *
+of_early_to_platform_device(struct device_node *np)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif /* defined(CONFIG_EARLY_PLATFORM) && defined(CONFIG_OF) */
+
+#ifdef CONFIG_EARLY_PLATFORM
+#define module_early_platform_driver(_edrv)				\
+	static const struct early_platform_driver *__##_edrv##_entry	\
+		__used __section(__early_platform_drivers_table)	\
+		= &(_edrv)
+#else /* CONFIG_EARLY_PLATFORM */
+#define module_early_platform_driver(_edrv)
+#endif /* CONFIG_EARLY_PLATFORM */
+
+#endif /* __EARLY_PLATFORM_H__ */
-- 
2.17.0

WARNING: multiple messages have this Message-ID (diff)
From: brgl@bgdev.pl (Bartosz Golaszewski)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 10/12] platform/early: implement support for early platform drivers
Date: Fri, 11 May 2018 18:20:26 +0200	[thread overview]
Message-ID: <20180511162028.20616-11-brgl@bgdev.pl> (raw)
In-Reply-To: <20180511162028.20616-1-brgl@bgdev.pl>

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This introduces the core part of support for early platform drivers
and devices.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/base/Kconfig           |   3 +
 drivers/base/Makefile          |   1 +
 drivers/base/early.c           | 332 +++++++++++++++++++++++++++++++++
 drivers/misc/Makefile          |   1 +
 include/linux/early_platform.h |  75 ++++++++
 5 files changed, 412 insertions(+)
 create mode 100644 drivers/base/early.c
 create mode 100644 include/linux/early_platform.h

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 29b0eb452b3a..ea648daecec1 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -205,6 +205,9 @@ config DEBUG_TEST_DRIVER_REMOVE
 	  unusable. You should say N here unless you are explicitly looking to
 	  test this functionality.
 
+config EARLY_PLATFORM
+	def_bool n
+
 source "drivers/base/test/Kconfig"
 
 config SYS_HYPERVISOR
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 7845c95ee1b2..3998ad6719f1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -7,6 +7,7 @@ obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   attribute_container.o transport_class.o \
 			   topology.o container.o property.o cacheinfo.o \
 			   devcon.o
+obj-$(CONFIG_EARLY_PLATFORM) += early.o
 obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o
 obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y			+= power/
diff --git a/drivers/base/early.c b/drivers/base/early.c
new file mode 100644
index 000000000000..7d0b7fb85f58
--- /dev/null
+++ b/drivers/base/early.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#include <linux/early_platform.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include "base.h"
+
+extern struct early_platform_driver *__early_platform_drivers_table[];
+extern struct early_platform_driver *__early_platform_drivers_table_end[];
+
+static bool early_platform_done;
+
+static LIST_HEAD(early_platform_drivers);
+static LIST_HEAD(early_platform_devices);
+
+static int early_platform_device_set_name(struct early_platform_device *edev)
+{
+	switch (edev->pdev.id) {
+	case PLATFORM_DEVID_AUTO:
+		pr_warn("auto device ID not supported in early platform devices\n");
+		/* fallthrough */
+	case PLATFORM_DEVID_NONE:
+		edev->pdev.dev.init_name = kasprintf(GFP_KERNEL,
+						     "%s", edev->pdev.name);
+		break;
+	default:
+		edev->pdev.dev.init_name = kasprintf(GFP_KERNEL, "%s.%d",
+						     edev->pdev.name,
+						     edev->pdev.id);
+		break;
+	}
+
+	if (!edev->pdev.dev.init_name)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void early_platform_device_add(struct early_platform_device *edev)
+{
+	edev->pdev.dev.early = true;
+	INIT_LIST_HEAD(&edev->list);
+	list_add_tail(&edev->list, &early_platform_devices);
+}
+
+static void early_platform_probe_deferred(void)
+{
+	struct early_platform_device *edev;
+	int rv;
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (!edev->deferred || !edev->deferred_drv->early_probe)
+			continue;
+
+		rv = edev->deferred_drv->early_probe(&edev->pdev);
+		if (rv && rv != -EPROBE_DEFER) {
+			dev_err(&edev->pdev.dev,
+				"early platform driver probe failed: %d\n",
+				rv);
+		}
+	}
+}
+
+static void early_platform_try_probe(struct early_platform_driver *edrv,
+				     struct early_platform_device *edev)
+{
+	int rv;
+
+	rv = early_platform_device_set_name(edev);
+	if (rv)
+		pr_warn("unable to set the early platform device name\n");
+
+	if (edrv->early_probe) {
+		rv = edrv->early_probe(&edev->pdev);
+		if (rv && rv != -EPROBE_DEFER &&
+		    rv != -ENODEV && rv != -ENXIO) {
+			dev_err(&edev->pdev.dev,
+				"early platform driver probe failed: %d\n",
+				rv);
+			return;
+		} else if (rv == -EPROBE_DEFER) {
+			edev->deferred = true;
+			edev->deferred_drv = edrv;
+		} else {
+			early_platform_probe_deferred();
+		}
+	}
+}
+
+/**
+ * of_early_to_platform_device - return the platform device with which this
+ *                               device node is associated
+ * @np - device node to look up
+ *
+ * If a device node was populated early, the corresponding platform device
+ * already exists. Instead of allocating a new object, we need to retrieve
+ * the previous one. This routine enables it.
+ */
+struct platform_device *of_early_to_platform_device(struct device_node *np)
+{
+	struct early_platform_device *edev;
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (np == edev->pdev.dev.of_node)
+			return &edev->pdev;
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+
+static int of_early_platform_device_create(struct device_node *node,
+					   struct early_platform_driver *edrv)
+{
+	struct early_platform_device *edev;
+	int rc;
+
+	edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+	if (!edev)
+		return -ENOMEM;
+
+	platform_device_init(&edev->pdev, "", PLATFORM_DEVID_NONE);
+	/*
+	 * We can safely use platform_device_release since the platform_device
+	 * struct is the first member of early_platform_device.
+	 */
+	edev->pdev.dev.release = platform_device_release;
+
+	rc = of_device_init_resources(&edev->pdev, node);
+	if (rc) {
+		kfree(edev);
+		return rc;
+	}
+
+	of_node_set_flag(node, OF_POPULATED_EARLY);
+	edev->pdev.name = edrv->pdrv.driver.name;
+	edev->pdev.dev.of_node = of_node_get(node);
+	edev->pdev.dev.fwnode = &node->fwnode;
+	early_platform_device_add(edev);
+	early_platform_try_probe(edrv, edev);
+
+	return 0;
+}
+
+static int of_early_platform_populate(struct device_node *root)
+{
+	struct early_platform_driver *edrv;
+	const struct of_device_id *match;
+	struct device_node *child;
+	int rv;
+
+	if (!root)
+		return 0;
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		if (!edrv->pdrv.driver.of_match_table)
+			continue;
+
+		match = of_match_node(edrv->pdrv.driver.of_match_table, root);
+		if (!match)
+			continue;
+
+		rv = of_early_platform_device_create(root, edrv);
+		if (rv)
+			return rv;
+	}
+
+	for_each_child_of_node(root, child) {
+		rv = of_early_platform_populate(child);
+		if (rv) {
+			of_node_put(child);
+			return rv;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * early_platform_start - start handling early devices
+ *
+ * This should be called by the architecture code early in the boot sequence
+ * to register all early platform drivers, populate the early devices from DT
+ * and start matching platform devices specified in machine code.
+ */
+void early_platform_start(void)
+{
+	struct early_platform_driver **edrv;
+	struct device_node *root;
+	int rv;
+
+	WARN_ONCE(!slab_is_available(), "slab is required for early devices\n");
+
+	pr_debug("%s(): registering pending early platform drivers\n",
+		 __func__);
+
+	for (edrv = __early_platform_drivers_table;
+	     edrv < __early_platform_drivers_table_end; edrv++) {
+		rv = early_platform_driver_register(*edrv);
+		if (rv)
+			pr_warn("error registering early platform driver: %d\n",
+				rv);
+	}
+
+	if (of_have_populated_dt()) {
+		pr_debug("%s(): populating early_platform devices from DT\n",
+			 __func__);
+
+		root = of_find_node_by_path("/");
+
+		rv = of_early_platform_populate(root);
+		if (rv)
+			pr_warn("error populating early devices from DT: %d\n",
+				rv);
+
+		of_node_put(root);
+	}
+}
+EXPORT_SYMBOL_GPL(early_platform_start);
+
+/**
+ * early_platform_driver_register - register an early platform driver
+ * @edrv: early platform driver to register
+ *
+ * If we're past postcore initcall, this works exactly as
+ * platform_device_register().
+ */
+int early_platform_driver_register(struct early_platform_driver *edrv)
+{
+	struct early_platform_device *edev;
+
+	if (early_platform_done)
+		return platform_driver_register(&edrv->pdrv);
+
+	INIT_LIST_HEAD(&edrv->list);
+	list_add_tail(&edrv->list, &early_platform_drivers);
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (platform_match(&edev->pdev.dev, &edrv->pdrv.driver)) {
+			early_platform_try_probe(edrv, edev);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(early_platform_driver_register);
+
+/**
+ * early_platform_device_register - register an early platform device
+ * @edev: early platform device to register
+ *
+ * If we're past postcore initcall, this works exactly as
+ * platform_device_register().
+ */
+int early_platform_device_register(struct early_platform_device *edev)
+{
+	struct early_platform_driver *edrv;
+
+	if (early_platform_done)
+		return platform_device_register(&edev->pdev);
+
+	device_initialize(&edev->pdev.dev);
+	early_platform_device_add(edev);
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		if (platform_match(&edev->pdev.dev, &edrv->pdrv.driver)) {
+			early_platform_try_probe(edrv, edev);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(early_platform_device_register);
+
+/*
+ * This is called once the entire device model infrastructure is in place to
+ * seamlessly convert all early platform devices & drivers to regular ones.
+ *
+ * From this point forward all early platform devices work exactly like normal
+ * platform devices.
+ */
+static int early_platform_finalize(void)
+{
+	struct early_platform_driver *edrv;
+	struct early_platform_device *edev;
+	int rv;
+
+	early_platform_done = true;
+
+	pr_debug("%s(): converting early platform drivers to real platform drivers\n",
+		 __func__);
+
+	list_for_each_entry(edrv, &early_platform_drivers, list) {
+		rv = platform_driver_register(&edrv->pdrv);
+		if (rv)
+			pr_warn("%s: error converting early platform driver to real platform driver\n",
+				edrv->pdrv.driver.name);
+	}
+
+	pr_debug("%s(): converting early platform devices to real platform devices\n",
+		 __func__);
+
+	list_for_each_entry(edev, &early_platform_devices, list) {
+		if (edev->pdev.dev.of_node)
+			/* This will be handled by of_platform_populate(). */
+			continue;
+
+		kfree(edev->pdev.dev.init_name);
+
+		/*
+		 * We don't want to reinitialize the associated struct device
+		 * so we must not call platform_device_register().
+		 */
+		rv = platform_device_add(&edev->pdev);
+		if (rv)
+			pr_warn("%s: error converting early platform device to real platform device\n",
+				dev_name(&edev->pdev.dev));
+	}
+
+	return 0;
+}
+postcore_initcall(early_platform_finalize);
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 20be70c3f118..d0a8788d5151 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_MISC_RTSX)		+= cardreader/
+CFLAGS_dummy-early.o := -DDEBUG
diff --git a/include/linux/early_platform.h b/include/linux/early_platform.h
new file mode 100644
index 000000000000..fd3fd4db8322
--- /dev/null
+++ b/include/linux/early_platform.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments, Inc.
+ *
+ * Author:
+ *     Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#ifndef __EARLY_PLATFORM_H__
+#define __EARLY_PLATFORM_H__
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/**
+ * struct early_platform_driver
+ *
+ * @pdrv: real platform driver associated with this early platform driver
+ * @list: list head for the list of early platform drivers
+ * @early_probe: early probe callback
+ */
+struct early_platform_driver {
+	struct platform_driver pdrv;
+	struct list_head list;
+	int (*early_probe)(struct platform_device *);
+};
+
+/**
+ * struct early_platform_device
+ *
+ * @pdev: real platform device associated with this early platform device
+ * @list: list head for the list of early platform devices
+ * @deferred: true if this device's early probe was deferred
+ * @deferred_drv: early platform driver with which this device was matched
+ */
+struct early_platform_device {
+	struct platform_device pdev;
+	struct list_head list;
+	bool deferred;
+	struct early_platform_driver *deferred_drv;
+};
+
+#ifdef CONFIG_EARLY_PLATFORM
+extern void early_platform_start(void);
+extern int early_platform_driver_register(struct early_platform_driver *edrv);
+extern int early_platform_device_register(struct early_platform_device *edev);
+#else /* CONFIG_EARLY_PLATFORM */
+static inline void early_platform_start(void) {}
+static int void
+early_platform_driver_register(struct early_platform_driver *edrv) {}
+static int void
+early_platform_device_register(struct early_platform_device *edev) {}
+#endif /* CONFIG_EARLY_PLATFORM */
+
+#if defined(CONFIG_EARLY_PLATFORM) && defined(CONFIG_OF)
+extern struct platform_device *
+of_early_to_platform_device(struct device_node *np);
+#else
+static inline struct platform_device *
+of_early_to_platform_device(struct device_node *np)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif /* defined(CONFIG_EARLY_PLATFORM) && defined(CONFIG_OF) */
+
+#ifdef CONFIG_EARLY_PLATFORM
+#define module_early_platform_driver(_edrv)				\
+	static const struct early_platform_driver *__##_edrv##_entry	\
+		__used __section(__early_platform_drivers_table)	\
+		= &(_edrv)
+#else /* CONFIG_EARLY_PLATFORM */
+#define module_early_platform_driver(_edrv)
+#endif /* CONFIG_EARLY_PLATFORM */
+
+#endif /* __EARLY_PLATFORM_H__ */
-- 
2.17.0

  parent reply	other threads:[~2018-05-11 16:21 UTC|newest]

Thread overview: 106+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-11 16:20 [PATCH 00/12] introduce support for early platform drivers Bartosz Golaszewski
2018-05-11 16:20 ` Bartosz Golaszewski
2018-05-11 16:20 ` Bartosz Golaszewski
2018-05-11 16:20 ` [PATCH 01/12] platform/early: add a new field to struct device Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:24   ` Geert Uytterhoeven
2018-05-14 21:24     ` Geert Uytterhoeven
2018-05-14 21:24     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 02/12] platform/early: don't WARN() on non-empty devres list for early devices Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:24   ` Geert Uytterhoeven
2018-05-14 21:24     ` Geert Uytterhoeven
2018-05-14 21:24     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 03/12] platform/early: export platform_match() locally Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:25   ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 04/12] platform: provide a separate function for initializing platform devices Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:25   ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 05/12] platform: export platform_device_release() locally Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:25   ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 06/12] of: add a new flag for OF device nodes Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:25   ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-14 21:25     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 07/12] of/platform: provide a separate routine for setting up device resources Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:26   ` Geert Uytterhoeven
2018-05-14 21:26     ` Geert Uytterhoeven
2018-05-14 21:26     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 08/12] of/platform: provide a separate routine for device initialization Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:26   ` Geert Uytterhoeven
2018-05-14 21:26     ` Geert Uytterhoeven
2018-05-14 21:26     ` Geert Uytterhoeven
2018-05-11 16:20 ` [PATCH 09/12] platform/early: add an init section for early driver data Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:29   ` Geert Uytterhoeven
2018-05-14 21:29     ` Geert Uytterhoeven
2018-05-14 21:29     ` Geert Uytterhoeven
2018-05-15  8:41     ` Bartosz Golaszewski
2018-05-15  8:41       ` Bartosz Golaszewski
2018-05-15  8:41       ` Bartosz Golaszewski
2018-05-11 16:20 ` Bartosz Golaszewski [this message]
2018-05-11 16:20   ` [PATCH 10/12] platform/early: implement support for early platform drivers Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 13:37   ` Rob Herring
2018-05-14 13:37     ` Rob Herring
2018-05-14 13:37     ` Rob Herring
2018-05-15 14:06     ` Bartosz Golaszewski
2018-05-15 14:06       ` Bartosz Golaszewski
2018-05-15 14:06       ` Bartosz Golaszewski
2018-05-16  1:06       ` Rob Herring
2018-05-16  1:06         ` Rob Herring
2018-05-16  1:06         ` Rob Herring
2018-05-11 16:20 ` [PATCH 11/12] misc: implement a dummy early platform driver Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20 ` [PATCH 12/12] of/platform: make the OF code aware of early platform drivers Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-11 16:20   ` Bartosz Golaszewski
2018-05-14 21:32   ` Geert Uytterhoeven
2018-05-14 21:32     ` Geert Uytterhoeven
2018-05-14 21:32     ` Geert Uytterhoeven
2018-05-11 20:13 ` [PATCH 00/12] introduce support for " Rob Herring
2018-05-11 20:13   ` Rob Herring
2018-05-11 20:13   ` Rob Herring
2018-05-14 11:38   ` Bartosz Golaszewski
2018-05-14 11:38     ` Bartosz Golaszewski
2018-05-14 11:38     ` Bartosz Golaszewski
2018-05-14 13:20     ` Rob Herring
2018-05-14 13:20       ` Rob Herring
2018-05-14 13:20       ` Rob Herring
2018-05-30 19:40       ` Michael Turquette
2018-05-30 19:40         ` Michael Turquette
2018-05-30 19:40         ` Michael Turquette
2018-05-30 22:36         ` Rob Herring
2018-05-30 22:36           ` Rob Herring
2018-05-30 22:36           ` Rob Herring
2018-05-31  6:42           ` Geert Uytterhoeven
2018-05-31  6:42             ` Geert Uytterhoeven
2018-05-31  6:42             ` Geert Uytterhoeven
2018-05-31 14:16             ` Tony Lindgren
2018-05-31 14:16               ` Tony Lindgren
2018-05-31 14:16               ` Tony Lindgren
2018-10-19 12:08 ` Bartosz Golaszewski
2018-10-19 12:08   ` Bartosz Golaszewski
2018-10-19 12:08   ` Bartosz Golaszewski
2018-10-19 12:08   ` Bartosz Golaszewski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180511162028.20616-11-brgl@bgdev.pl \
    --to=brgl@bgdev.pl \
    --cc=andy.shevchenko@gmail.com \
    --cc=arnd@arndb.de \
    --cc=bgolaszewski@baylibre.com \
    --cc=dalias@libc.org \
    --cc=daniel.lezcano@linaro.org \
    --cc=david@lechnology.com \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=geert@linux-m68k.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=johan@kernel.org \
    --cc=jslaby@suse.com \
    --cc=khilman@kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=magnus.damm@gmail.com \
    --cc=marc.zyngier@arm.com \
    --cc=mark.rutland@arm.com \
    --cc=mturquette@baylibre.com \
    --cc=nsekhar@ti.com \
    --cc=peda@axentia.se \
    --cc=rafael.j.wysocki@intel.com \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=ysato@users.sourceforge.jp \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.