drivers: move the early platform device support to arch/sh
authorBartosz Golaszewski <bgolaszewski@baylibre.com>
Thu, 3 Oct 2019 09:29:12 +0000 (11:29 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 7 Oct 2019 11:50:47 +0000 (13:50 +0200)
SuperH is the only user of the current implementation of early platform
device support. We want to introduce a more robust approach to early
probing. As the first step - move all the current early platform code
to arch/sh.

In order not to export internal drivers/base functions to arch code for
this temporary solution - copy the two needed routines for driver
matching from drivers/base/platform.c to arch/sh/drivers/platform_early.c.

Also: call early_platform_cleanup() from subsys_initcall() so that it's
called after all early devices are probed.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Cc: Rich Felker <dalias@libc.org>
Link: https://lore.kernel.org/r/20191003092913.10731-2-brgl@bgdev.pl
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
40 files changed:
arch/sh/drivers/Makefile
arch/sh/drivers/platform_early.c [new file with mode: 0644]
arch/sh/include/asm/platform_early.h [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh2a/setup-sh7264.c
arch/sh/kernel/cpu/sh2a/setup-sh7269.c
arch/sh/kernel/cpu/sh3/setup-sh3.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7734.c
arch/sh/kernel/cpu/sh4a/setup-sh7757.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/setup-sh5.c
arch/sh/kernel/setup.c
arch/sh/kernel/time.c
drivers/base/platform.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/tty/serial/sh-sci.c
include/linux/platform_device.h

index 3e93b434e6048edea4e27c3c2577ffeb30c22667..56b0acace6e7c81092ba615d24d60ba50b95f162 100644 (file)
@@ -3,7 +3,7 @@
 # Makefile for the Linux SuperH-specific device drivers.
 #
 
-obj-y          += dma/
+obj-y          += dma/ platform_early.o
 
 obj-$(CONFIG_PCI)              += pci/
 obj-$(CONFIG_SUPERHYWAY)       += superhyway/
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
new file mode 100644 (file)
index 0000000..3dfe9f3
--- /dev/null
@@ -0,0 +1,347 @@
+// SPDX--License-Identifier: GPL-2.0
+
+#include <asm/platform_early.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+
+static __initdata LIST_HEAD(early_platform_driver_list);
+static __initdata LIST_HEAD(early_platform_device_list);
+
+static const struct platform_device_id *
+platform_match_id(const struct platform_device_id *id,
+                 struct platform_device *pdev)
+{
+       while (id->name[0]) {
+               if (strcmp(pdev->name, id->name) == 0) {
+                       pdev->id_entry = id;
+                       return id;
+               }
+               id++;
+       }
+       return NULL;
+}
+
+static int platform_match(struct device *dev, struct device_driver *drv)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct platform_driver *pdrv = to_platform_driver(drv);
+
+       /* When driver_override is set, only bind to the matching driver */
+       if (pdev->driver_override)
+               return !strcmp(pdev->driver_override, drv->name);
+
+       /* Then try to match against the id table */
+       if (pdrv->id_table)
+               return platform_match_id(pdrv->id_table, pdev) != NULL;
+
+       /* fall-back to driver name match */
+       return (strcmp(pdev->name, drv->name) == 0);
+}
+
+#ifdef CONFIG_PM
+static void device_pm_init_common(struct device *dev)
+{
+       if (!dev->power.early_init) {
+               spin_lock_init(&dev->power.lock);
+               dev->power.qos = NULL;
+               dev->power.early_init = true;
+       }
+}
+
+static void pm_runtime_early_init(struct device *dev)
+{
+       dev->power.disable_depth = 1;
+       device_pm_init_common(dev);
+}
+#else
+static void pm_runtime_early_init(struct device *dev) {}
+#endif
+
+/**
+ * early_platform_driver_register - register early platform driver
+ * @epdrv: early_platform driver structure
+ * @buf: string passed from early_param()
+ *
+ * Helper function for early_platform_init() / early_platform_init_buffer()
+ */
+int __init early_platform_driver_register(struct early_platform_driver *epdrv,
+                                         char *buf)
+{
+       char *tmp;
+       int n;
+
+       /* Simply add the driver to the end of the global list.
+        * Drivers will by default be put on the list in compiled-in order.
+        */
+       if (!epdrv->list.next) {
+               INIT_LIST_HEAD(&epdrv->list);
+               list_add_tail(&epdrv->list, &early_platform_driver_list);
+       }
+
+       /* If the user has specified device then make sure the driver
+        * gets prioritized. The driver of the last device specified on
+        * command line will be put first on the list.
+        */
+       n = strlen(epdrv->pdrv->driver.name);
+       if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
+               list_move(&epdrv->list, &early_platform_driver_list);
+
+               /* Allow passing parameters after device name */
+               if (buf[n] == '\0' || buf[n] == ',')
+                       epdrv->requested_id = -1;
+               else {
+                       epdrv->requested_id = simple_strtoul(&buf[n + 1],
+                                                            &tmp, 10);
+
+                       if (buf[n] != '.' || (tmp == &buf[n + 1])) {
+                               epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
+                               n = 0;
+                       } else
+                               n += strcspn(&buf[n + 1], ",") + 1;
+               }
+
+               if (buf[n] == ',')
+                       n++;
+
+               if (epdrv->bufsize) {
+                       memcpy(epdrv->buffer, &buf[n],
+                              min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
+                       epdrv->buffer[epdrv->bufsize - 1] = '\0';
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * early_platform_add_devices - adds a number of early platform devices
+ * @devs: array of early platform devices to add
+ * @num: number of early platform devices in array
+ *
+ * Used by early architecture code to register early platform devices and
+ * their platform data.
+ */
+void __init early_platform_add_devices(struct platform_device **devs, int num)
+{
+       struct device *dev;
+       int i;
+
+       /* simply add the devices to list */
+       for (i = 0; i < num; i++) {
+               dev = &devs[i]->dev;
+
+               if (!dev->devres_head.next) {
+                       pm_runtime_early_init(dev);
+                       INIT_LIST_HEAD(&dev->devres_head);
+                       list_add_tail(&dev->devres_head,
+                                     &early_platform_device_list);
+               }
+       }
+}
+
+/**
+ * early_platform_driver_register_all - register early platform drivers
+ * @class_str: string to identify early platform driver class
+ *
+ * Used by architecture code to register all early platform drivers
+ * for a certain class. If omitted then only early platform drivers
+ * with matching kernel command line class parameters will be registered.
+ */
+void __init early_platform_driver_register_all(char *class_str)
+{
+       /* The "class_str" parameter may or may not be present on the kernel
+        * command line. If it is present then there may be more than one
+        * matching parameter.
+        *
+        * Since we register our early platform drivers using early_param()
+        * we need to make sure that they also get registered in the case
+        * when the parameter is missing from the kernel command line.
+        *
+        * We use parse_early_options() to make sure the early_param() gets
+        * called at least once. The early_param() may be called more than
+        * once since the name of the preferred device may be specified on
+        * the kernel command line. early_platform_driver_register() handles
+        * this case for us.
+        */
+       parse_early_options(class_str);
+}
+
+/**
+ * early_platform_match - find early platform device matching driver
+ * @epdrv: early platform driver structure
+ * @id: id to match against
+ */
+static struct platform_device * __init
+early_platform_match(struct early_platform_driver *epdrv, int id)
+{
+       struct platform_device *pd;
+
+       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+                       if (pd->id == id)
+                               return pd;
+
+       return NULL;
+}
+
+/**
+ * early_platform_left - check if early platform driver has matching devices
+ * @epdrv: early platform driver structure
+ * @id: return true if id or above exists
+ */
+static int __init early_platform_left(struct early_platform_driver *epdrv,
+                                      int id)
+{
+       struct platform_device *pd;
+
+       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
+               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+                       if (pd->id >= id)
+                               return 1;
+
+       return 0;
+}
+
+/**
+ * early_platform_driver_probe_id - probe drivers matching class_str and id
+ * @class_str: string to identify early platform driver class
+ * @id: id to match against
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ */
+static int __init early_platform_driver_probe_id(char *class_str,
+                                                int id,
+                                                int nr_probe)
+{
+       struct early_platform_driver *epdrv;
+       struct platform_device *match;
+       int match_id;
+       int n = 0;
+       int left = 0;
+
+       list_for_each_entry(epdrv, &early_platform_driver_list, list) {
+               /* only use drivers matching our class_str */
+               if (strcmp(class_str, epdrv->class_str))
+                       continue;
+
+               if (id == -2) {
+                       match_id = epdrv->requested_id;
+                       left = 1;
+
+               } else {
+                       match_id = id;
+                       left += early_platform_left(epdrv, id);
+
+                       /* skip requested id */
+                       switch (epdrv->requested_id) {
+                       case EARLY_PLATFORM_ID_ERROR:
+                       case EARLY_PLATFORM_ID_UNSET:
+                               break;
+                       default:
+                               if (epdrv->requested_id == id)
+                                       match_id = EARLY_PLATFORM_ID_UNSET;
+                       }
+               }
+
+               switch (match_id) {
+               case EARLY_PLATFORM_ID_ERROR:
+                       pr_warn("%s: unable to parse %s parameter\n",
+                               class_str, epdrv->pdrv->driver.name);
+                       /* fall-through */
+               case EARLY_PLATFORM_ID_UNSET:
+                       match = NULL;
+                       break;
+               default:
+                       match = early_platform_match(epdrv, match_id);
+               }
+
+               if (match) {
+                       /*
+                        * Set up a sensible init_name to enable
+                        * dev_name() and others to be used before the
+                        * rest of the driver core is initialized.
+                        */
+                       if (!match->dev.init_name && slab_is_available()) {
+                               if (match->id != -1)
+                                       match->dev.init_name =
+                                               kasprintf(GFP_KERNEL, "%s.%d",
+                                                         match->name,
+                                                         match->id);
+                               else
+                                       match->dev.init_name =
+                                               kasprintf(GFP_KERNEL, "%s",
+                                                         match->name);
+
+                               if (!match->dev.init_name)
+                                       return -ENOMEM;
+                       }
+
+                       if (epdrv->pdrv->probe(match))
+                               pr_warn("%s: unable to probe %s early.\n",
+                                       class_str, match->name);
+                       else
+                               n++;
+               }
+
+               if (n >= nr_probe)
+                       break;
+       }
+
+       if (left)
+               return n;
+       else
+               return -ENODEV;
+}
+
+/**
+ * early_platform_driver_probe - probe a class of registered drivers
+ * @class_str: string to identify early platform driver class
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ * @user_only: only probe user specified early platform devices
+ *
+ * Used by architecture code to probe registered early platform drivers
+ * within a certain class. For probe to happen a registered early platform
+ * device matching a registered early platform driver is needed.
+ */
+int __init early_platform_driver_probe(char *class_str,
+                                      int nr_probe,
+                                      int user_only)
+{
+       int k, n, i;
+
+       n = 0;
+       for (i = -2; n < nr_probe; i++) {
+               k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
+
+               if (k < 0)
+                       break;
+
+               n += k;
+
+               if (user_only)
+                       break;
+       }
+
+       return n;
+}
+
+/**
+ * early_platform_cleanup - clean up early platform code
+ */
+static int __init early_platform_cleanup(void)
+{
+       struct platform_device *pd, *pd2;
+
+       /* clean up the devres list used to chain devices */
+       list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
+                                dev.devres_head) {
+               list_del(&pd->dev.devres_head);
+               memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
+       }
+
+       return 0;
+}
+/*
+ * This must happen once after all early devices are probed but before probing
+ * real platform devices.
+ */
+subsys_initcall(early_platform_cleanup);
diff --git a/arch/sh/include/asm/platform_early.h b/arch/sh/include/asm/platform_early.h
new file mode 100644 (file)
index 0000000..4590ab7
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX--License-Identifier: GPL-2.0 */
+
+#ifndef __PLATFORM_EARLY__
+#define __PLATFORM_EARLY__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+struct early_platform_driver {
+       const char *class_str;
+       struct platform_driver *pdrv;
+       struct list_head list;
+       int requested_id;
+       char *buffer;
+       int bufsize;
+};
+
+#define EARLY_PLATFORM_ID_UNSET -2
+#define EARLY_PLATFORM_ID_ERROR -3
+
+extern int early_platform_driver_register(struct early_platform_driver *epdrv,
+                                         char *buf);
+extern void early_platform_add_devices(struct platform_device **devs, int num);
+
+static inline int is_early_platform_device(struct platform_device *pdev)
+{
+       return !pdev->dev.driver;
+}
+
+extern void early_platform_driver_register_all(char *class_str);
+extern int early_platform_driver_probe(char *class_str,
+                                      int nr_probe, int user_only);
+
+#define early_platform_init(class_string, platdrv)             \
+       early_platform_init_buffer(class_string, platdrv, NULL, 0)
+
+#ifndef MODULE
+#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static __initdata struct early_platform_driver early_driver = {                \
+       .class_str = class_string,                                      \
+       .buffer = buf,                                                  \
+       .bufsize = bufsiz,                                              \
+       .pdrv = platdrv,                                                \
+       .requested_id = EARLY_PLATFORM_ID_UNSET,                        \
+};                                                                     \
+static int __init early_platform_driver_setup_func(char *buffer)       \
+{                                                                      \
+       return early_platform_driver_register(&early_driver, buffer);   \
+}                                                                      \
+early_param(class_string, early_platform_driver_setup_func)
+#else /* MODULE */
+#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
+static inline char *early_platform_driver_setup_func(void)             \
+{                                                                      \
+       return bufsiz ? buf : NULL;                                     \
+}
+#endif /* MODULE */
+
+#endif /* __PLATFORM_EARLY__ */
index f5b6841ef7e1cd3783918e216b3c4b7471024157..27d459e8a59814536cd687f6e50a1184ba30b148 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sh_eth.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 52350ad0b0a26a23e7158485bc6b63f0f6d93da6..8a19c5754978e1e33207458d42e4ee7a6785a2b1 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index b51ed761ae087977e4bb4d3721636d830f67542f..d975e4d404bda25c5f3ad48f13d5a97ddb00d4d1 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 89b3e49fc2503673e5d5cf81ca82c4c6a1a9dcd2..318b8cd8d5b711fbceadeb7265b76e7b82ba7b0d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 36ff3a3139dabe1e98be6d60e32b0e56a1623d14..8e6fae60074a3d8b60609e3b83ecdfcb8cdfb927 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index d199618d877c070b2a4176d32027ea96a12f330a..2d95c9b38330cc97d0f1586869e9144945d2101c 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 9095c960b4558d90c9037c1a5849412d531c9519..ef4ff76cbe9e1e640292738e914c73c6f2d86cb9 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 8058c01cf09dfd187d8b29ed48eb241cd6739836..cf2a3f09fee44348a09795239af82707757792f7 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 /* All SH3 devices are equipped with IRQ0->5 (except sh7708) */
 
index e19d1ce7b6ad1f09730f0a676b55c9c8c6e76ba6..9b34d1f4e797aa4caa90e230006a75bf4c6c0b22 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sh_intc.h>
 #include <asm/rtc.h>
 #include <cpu/serial.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 5c5144bee6bcc7ced870ccd785042b7c534eb224..39f09504bd968edadc7a47e6cc920f7f4c5a717a 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <cpu/serial.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 4776e2495738fde54720a9cbd5508672f727f7fa..c006c8fcfa0feb5ff574851ab321157d6b077111 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <asm/rtc.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index 1d4c34e7b7db98ced3eafe368c3ff87dc1689ede..cf2eec9f6abd97cbe1305d10490a4c6ffdb43851 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sh_intc.h>
 #include <linux/usb/ohci_pdriver.h>
 #include <asm/rtc.h>
+#include <asm/platform_early.h>
 #include <cpu/serial.h>
 
 static struct resource rtc_resources[] = {
index a40ef35d101a9cb232ef69990aa1a1a329371e3b..2480ce4a3b1e9afefd2491d65d7692c18191d308 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE,
index b37bda66a532e8ddff486941114793db29bb62fa..4592d660b942637cf10d365192209c90001d5585 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <generated/machtypes.h>
+#include <asm/platform_early.h>
 
 static struct resource rtc_resources[] = {
        [0] = {
index 86845da859979da93e64c6e3da51b43f91fd7390..e64eb96e358925b0e3593ae9c746679312a76163 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
index a15e25690b5f96a3a78e3dead849228e5eafac77..0fa56128bdca0aad600a60f05e79f4db0e1402a3 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <asm/clock.h>
+#include <asm/platform_early.h>
 
 /* Serial */
 static struct plat_sci_port scif0_platform_data = {
index 7bd2776441ba0981701dbb2b97122fa9ed32ff93..9f2f75285ec357a8a9aa54aedbe18414db16cedb 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sh_intc.h>
 #include <linux/usb/r8a66597.h>
 #include <asm/clock.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE,
index 1ce65f88f060e7350041dba893388a3d8eef05e2..8e5eaac789a73876c881e7e405256094be4100c4 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 #include <asm/siu.h>
+#include <asm/platform_early.h>
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7722.h>
index edb6499506625a74e2b52b7efc233653d08047d6..b4b54aa0c26772644bb1297e821339101c6a6202 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 #include <cpu/sh7723.h>
 
 /* Serial */
index 3e9825031d3d76801a73f26b7675740743f2561d..ec237ab112cf7d25b54a9e12ed0984da6468979e 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/suspend.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7724.h>
index 06a91569697a7c697a2a6f4d92b6bf749690efb9..7ea9a8b4395591cb99efe9654927017d81b94e79 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/irq.h>
+#include <asm/platform_early.h>
 #include <cpu/sh7734.h>
 
 /* SCIF */
index 2501ce656511b061bbe843831e31a7d77a955641..922d9886be181c32087224879f68d322ec25a96d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/usb/ohci_pdriver.h>
 #include <cpu/dma-register.h>
 #include <cpu/sh7757.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_REIE,
index 419c5efe4a17fee24308ff77df5707bedeff6fe3..8725d4751bafe5e11859fb3feb7c849918db5738 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 #include <linux/usb/ohci_pdriver.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE,
index 5fb4cf9b58c691110ad41bff5dcc55f53e6e00e1..035a0d4f2a2eca010465c40bbeea55ca3f4bfa31 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE | SCSCR_TOIE,
index ab7d6b715865b54c07052660dfb960b4455bf832..983be87cb7be4b0af54fa34743aeeaa870539d1f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE | SCSCR_CKE1,
index a438da47285d6ceea28a5ff3c6609e2c93eb3e98..bb0cb710c16e05672201b99a10f1a6f538a7a242 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
index d894165a0ef6fb8ed16a94bd437501381e4b5ae9..b5d94366eed3271471ba60714cd955cd0f08246f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/usb/ohci_pdriver.h>
 #include <cpu/dma-register.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE | SCSCR_CKE1,
index 14aa4552bc45b5f75753f8aa2445f7795cd92467..e82398d80b74e1e1f3fca21eca25ed7b09c68db4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sh_intc.h>
 #include <cpu/shx3.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 
 /*
  * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
index 41c1673afc0b4301a6e4b56b4530c01411fe614d..584a6aeeca2613f5851557b693af7b09abfa8cce 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/sh_timer.h>
 #include <asm/addrspace.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .flags          = UPF_IOREMAP,
index 2c0e0f37a318d3ad6f2628df398bb5d1c54f5f72..e535507851e1be456f37c816f031f82b0dab5923 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/mmu_context.h>
 #include <asm/mmzone.h>
 #include <asm/sparsemem.h>
+#include <asm/platform_early.h>
 
 /*
  * Initialize loops_per_jiffy as 10000000 (1000MIPS).
index e16b2cd269a331f911a02a35de7170e67922a382..8ad9fd5c4ff60fde4e0d1329a9e64602a6955861 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/rtc.h>
 #include <asm/clock.h>
 #include <asm/rtc.h>
+#include <asm/platform_early.h>
 
 static void __init sh_late_time_init(void)
 {
index b6c6c7d97d5b2aa388baa153550ed7a4db3af022..be1e67ee3af67daa84f23260ce8a85ec30da858d 100644 (file)
@@ -1264,8 +1264,6 @@ int __init platform_bus_init(void)
 {
        int error;
 
-       early_platform_cleanup();
-
        error = device_register(&platform_bus);
        if (error) {
                put_device(&platform_bus);
@@ -1277,289 +1275,3 @@ int __init platform_bus_init(void)
        of_platform_register_reconfig_notifier();
        return error;
 }
-
-static __initdata LIST_HEAD(early_platform_driver_list);
-static __initdata LIST_HEAD(early_platform_device_list);
-
-/**
- * early_platform_driver_register - register early platform driver
- * @epdrv: early_platform driver structure
- * @buf: string passed from early_param()
- *
- * Helper function for early_platform_init() / early_platform_init_buffer()
- */
-int __init early_platform_driver_register(struct early_platform_driver *epdrv,
-                                         char *buf)
-{
-       char *tmp;
-       int n;
-
-       /* Simply add the driver to the end of the global list.
-        * Drivers will by default be put on the list in compiled-in order.
-        */
-       if (!epdrv->list.next) {
-               INIT_LIST_HEAD(&epdrv->list);
-               list_add_tail(&epdrv->list, &early_platform_driver_list);
-       }
-
-       /* If the user has specified device then make sure the driver
-        * gets prioritized. The driver of the last device specified on
-        * command line will be put first on the list.
-        */
-       n = strlen(epdrv->pdrv->driver.name);
-       if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
-               list_move(&epdrv->list, &early_platform_driver_list);
-
-               /* Allow passing parameters after device name */
-               if (buf[n] == '\0' || buf[n] == ',')
-                       epdrv->requested_id = -1;
-               else {
-                       epdrv->requested_id = simple_strtoul(&buf[n + 1],
-                                                            &tmp, 10);
-
-                       if (buf[n] != '.' || (tmp == &buf[n + 1])) {
-                               epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
-                               n = 0;
-                       } else
-                               n += strcspn(&buf[n + 1], ",") + 1;
-               }
-
-               if (buf[n] == ',')
-                       n++;
-
-               if (epdrv->bufsize) {
-                       memcpy(epdrv->buffer, &buf[n],
-                              min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
-                       epdrv->buffer[epdrv->bufsize - 1] = '\0';
-               }
-       }
-
-       return 0;
-}
-
-/**
- * early_platform_add_devices - adds a number of early platform devices
- * @devs: array of early platform devices to add
- * @num: number of early platform devices in array
- *
- * Used by early architecture code to register early platform devices and
- * their platform data.
- */
-void __init early_platform_add_devices(struct platform_device **devs, int num)
-{
-       struct device *dev;
-       int i;
-
-       /* simply add the devices to list */
-       for (i = 0; i < num; i++) {
-               dev = &devs[i]->dev;
-
-               if (!dev->devres_head.next) {
-                       pm_runtime_early_init(dev);
-                       INIT_LIST_HEAD(&dev->devres_head);
-                       list_add_tail(&dev->devres_head,
-                                     &early_platform_device_list);
-               }
-       }
-}
-
-/**
- * early_platform_driver_register_all - register early platform drivers
- * @class_str: string to identify early platform driver class
- *
- * Used by architecture code to register all early platform drivers
- * for a certain class. If omitted then only early platform drivers
- * with matching kernel command line class parameters will be registered.
- */
-void __init early_platform_driver_register_all(char *class_str)
-{
-       /* The "class_str" parameter may or may not be present on the kernel
-        * command line. If it is present then there may be more than one
-        * matching parameter.
-        *
-        * Since we register our early platform drivers using early_param()
-        * we need to make sure that they also get registered in the case
-        * when the parameter is missing from the kernel command line.
-        *
-        * We use parse_early_options() to make sure the early_param() gets
-        * called at least once. The early_param() may be called more than
-        * once since the name of the preferred device may be specified on
-        * the kernel command line. early_platform_driver_register() handles
-        * this case for us.
-        */
-       parse_early_options(class_str);
-}
-
-/**
- * early_platform_match - find early platform device matching driver
- * @epdrv: early platform driver structure
- * @id: id to match against
- */
-static struct platform_device * __init
-early_platform_match(struct early_platform_driver *epdrv, int id)
-{
-       struct platform_device *pd;
-
-       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
-               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
-                       if (pd->id == id)
-                               return pd;
-
-       return NULL;
-}
-
-/**
- * early_platform_left - check if early platform driver has matching devices
- * @epdrv: early platform driver structure
- * @id: return true if id or above exists
- */
-static int __init early_platform_left(struct early_platform_driver *epdrv,
-                                      int id)
-{
-       struct platform_device *pd;
-
-       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
-               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
-                       if (pd->id >= id)
-                               return 1;
-
-       return 0;
-}
-
-/**
- * early_platform_driver_probe_id - probe drivers matching class_str and id
- * @class_str: string to identify early platform driver class
- * @id: id to match against
- * @nr_probe: number of platform devices to successfully probe before exiting
- */
-static int __init early_platform_driver_probe_id(char *class_str,
-                                                int id,
-                                                int nr_probe)
-{
-       struct early_platform_driver *epdrv;
-       struct platform_device *match;
-       int match_id;
-       int n = 0;
-       int left = 0;
-
-       list_for_each_entry(epdrv, &early_platform_driver_list, list) {
-               /* only use drivers matching our class_str */
-               if (strcmp(class_str, epdrv->class_str))
-                       continue;
-
-               if (id == -2) {
-                       match_id = epdrv->requested_id;
-                       left = 1;
-
-               } else {
-                       match_id = id;
-                       left += early_platform_left(epdrv, id);
-
-                       /* skip requested id */
-                       switch (epdrv->requested_id) {
-                       case EARLY_PLATFORM_ID_ERROR:
-                       case EARLY_PLATFORM_ID_UNSET:
-                               break;
-                       default:
-                               if (epdrv->requested_id == id)
-                                       match_id = EARLY_PLATFORM_ID_UNSET;
-                       }
-               }
-
-               switch (match_id) {
-               case EARLY_PLATFORM_ID_ERROR:
-                       pr_warn("%s: unable to parse %s parameter\n",
-                               class_str, epdrv->pdrv->driver.name);
-                       /* fall-through */
-               case EARLY_PLATFORM_ID_UNSET:
-                       match = NULL;
-                       break;
-               default:
-                       match = early_platform_match(epdrv, match_id);
-               }
-
-               if (match) {
-                       /*
-                        * Set up a sensible init_name to enable
-                        * dev_name() and others to be used before the
-                        * rest of the driver core is initialized.
-                        */
-                       if (!match->dev.init_name && slab_is_available()) {
-                               if (match->id != -1)
-                                       match->dev.init_name =
-                                               kasprintf(GFP_KERNEL, "%s.%d",
-                                                         match->name,
-                                                         match->id);
-                               else
-                                       match->dev.init_name =
-                                               kasprintf(GFP_KERNEL, "%s",
-                                                         match->name);
-
-                               if (!match->dev.init_name)
-                                       return -ENOMEM;
-                       }
-
-                       if (epdrv->pdrv->probe(match))
-                               pr_warn("%s: unable to probe %s early.\n",
-                                       class_str, match->name);
-                       else
-                               n++;
-               }
-
-               if (n >= nr_probe)
-                       break;
-       }
-
-       if (left)
-               return n;
-       else
-               return -ENODEV;
-}
-
-/**
- * early_platform_driver_probe - probe a class of registered drivers
- * @class_str: string to identify early platform driver class
- * @nr_probe: number of platform devices to successfully probe before exiting
- * @user_only: only probe user specified early platform devices
- *
- * Used by architecture code to probe registered early platform drivers
- * within a certain class. For probe to happen a registered early platform
- * device matching a registered early platform driver is needed.
- */
-int __init early_platform_driver_probe(char *class_str,
-                                      int nr_probe,
-                                      int user_only)
-{
-       int k, n, i;
-
-       n = 0;
-       for (i = -2; n < nr_probe; i++) {
-               k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
-
-               if (k < 0)
-                       break;
-
-               n += k;
-
-               if (user_only)
-                       break;
-       }
-
-       return n;
-}
-
-/**
- * early_platform_cleanup - clean up early platform code
- */
-void __init early_platform_cleanup(void)
-{
-       struct platform_device *pd, *pd2;
-
-       /* clean up the devres list used to chain devices */
-       list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
-                                dev.devres_head) {
-               list_del(&pd->dev.devres_head);
-               memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
-       }
-}
-
index ef773db080e903002b693b41b961a2d48e0f5e53..3a185485300e4386d679a183a057f2a02d1b486a 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
 struct sh_cmt_device;
 
 /*
@@ -1109,7 +1113,10 @@ static void __exit sh_cmt_exit(void)
        platform_driver_unregister(&sh_cmt_device_driver);
 }
 
+#ifdef CONFIG_SUPERH
 early_platform_init("earlytimer", &sh_cmt_device_driver);
+#endif
+
 subsys_initcall(sh_cmt_init);
 module_exit(sh_cmt_exit);
 
index 354b27d14a19bfcef43656f3555e69a32b28da2d..d581060d33a26aaf4d1e9c34a9f18516b2477b60 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
 struct sh_mtu2_device;
 
 struct sh_mtu2_channel {
@@ -511,7 +515,10 @@ static void __exit sh_mtu2_exit(void)
        platform_driver_unregister(&sh_mtu2_device_driver);
 }
 
+#ifdef CONFIG_SUPERH
 early_platform_init("earlytimer", &sh_mtu2_device_driver);
+#endif
+
 subsys_initcall(sh_mtu2_init);
 module_exit(sh_mtu2_exit);
 
index 8c4f3753b36ecbec88cb4be5091264e44f6a1934..50e30ead050e3c31de95286c3ba84aa9afaae398 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
 enum sh_tmu_model {
        SH_TMU,
        SH_TMU_SH3,
@@ -615,6 +619,7 @@ static int sh_tmu_probe(struct platform_device *pdev)
                pm_runtime_idle(&pdev->dev);
                return ret;
        }
+
        if (is_early_platform_device(pdev))
                return 0;
 
@@ -665,7 +670,10 @@ static void __exit sh_tmu_exit(void)
        platform_driver_unregister(&sh_tmu_device_driver);
 }
 
+#ifdef CONFIG_SUPERH
 early_platform_init("earlytimer", &sh_tmu_device_driver);
+#endif
+
 subsys_initcall(sh_tmu_init);
 module_exit(sh_tmu_exit);
 
index 4e754a4850e6db63e1693edb04113b2e72e44a0e..2a645fd7f07b4910e597617473613c57839dfdcf 100644 (file)
@@ -54,6 +54,7 @@
 
 #ifdef CONFIG_SUPERH
 #include <asm/sh_bios.h>
+#include <asm/platform_early.h>
 #endif
 
 #include "serial_mctrl_gpio.h"
@@ -3086,6 +3087,7 @@ static struct console serial_console = {
        .data           = &sci_uart_driver,
 };
 
+#ifdef CONFIG_SUPERH
 static struct console early_serial_console = {
        .name           = "early_ttySC",
        .write          = serial_console_write,
@@ -3114,6 +3116,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
        register_console(&early_serial_console);
        return 0;
 }
+#endif
 
 #define SCI_CONSOLE    (&serial_console)
 
@@ -3314,8 +3317,10 @@ static int sci_probe(struct platform_device *dev)
         * the special early probe. We don't have sufficient device state
         * to make it beyond this yet.
         */
+#ifdef CONFIG_SUPERH
        if (is_early_platform_device(dev))
                return sci_probe_earlyprintk(dev);
+#endif
 
        if (dev->dev.of_node) {
                p = sci_parse_dt(dev, &dev_id);
@@ -3410,7 +3415,7 @@ static void __exit sci_exit(void)
                uart_unregister_driver(&sci_uart_driver);
 }
 
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SUPERH) && defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
 early_platform_init_buffer("earlyprintk", &sci_driver,
                           early_serial_buf, ARRAY_SIZE(early_serial_buf));
 #endif
index 1b5cec0675335d07cf5989fa9ffe38a1351226db..85aa28a041a9cfeaec504983d6738560695e0dda 100644 (file)
@@ -292,58 +292,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
 #define platform_register_drivers(drivers, count) \
        __platform_register_drivers(drivers, count, THIS_MODULE)
 
-/* early platform driver interface */
-struct early_platform_driver {
-       const char *class_str;
-       struct platform_driver *pdrv;
-       struct list_head list;
-       int requested_id;
-       char *buffer;
-       int bufsize;
-};
-
-#define EARLY_PLATFORM_ID_UNSET -2
-#define EARLY_PLATFORM_ID_ERROR -3
-
-extern int early_platform_driver_register(struct early_platform_driver *epdrv,
-                                         char *buf);
-extern void early_platform_add_devices(struct platform_device **devs, int num);
-
-static inline int is_early_platform_device(struct platform_device *pdev)
-{
-       return !pdev->dev.driver;
-}
-
-extern void early_platform_driver_register_all(char *class_str);
-extern int early_platform_driver_probe(char *class_str,
-                                      int nr_probe, int user_only);
-extern void early_platform_cleanup(void);
-
-#define early_platform_init(class_string, platdrv)             \
-       early_platform_init_buffer(class_string, platdrv, NULL, 0)
-
-#ifndef MODULE
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static __initdata struct early_platform_driver early_driver = {                \
-       .class_str = class_string,                                      \
-       .buffer = buf,                                                  \
-       .bufsize = bufsiz,                                              \
-       .pdrv = platdrv,                                                \
-       .requested_id = EARLY_PLATFORM_ID_UNSET,                        \
-};                                                                     \
-static int __init early_platform_driver_setup_func(char *buffer)       \
-{                                                                      \
-       return early_platform_driver_register(&early_driver, buffer);   \
-}                                                                      \
-early_param(class_string, early_platform_driver_setup_func)
-#else /* MODULE */
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static inline char *early_platform_driver_setup_func(void)             \
-{                                                                      \
-       return bufsiz ? buf : NULL;                                     \
-}
-#endif /* MODULE */
-
 #ifdef CONFIG_SUSPEND
 extern int platform_pm_suspend(struct device *dev);
 extern int platform_pm_resume(struct device *dev);
@@ -378,4 +326,16 @@ extern int platform_dma_configure(struct device *dev);
 #define USE_PLATFORM_PM_SLEEP_OPS
 #endif
 
+#ifndef CONFIG_SUPERH
+/*
+ * REVISIT: This stub is needed for all non-SuperH users of early platform
+ * drivers. It should go away once we introduce the new platform_device-based
+ * early driver framework.
+ */
+static inline int is_early_platform_device(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif /* CONFIG_SUPERH */
+
 #endif /* _PLATFORM_DEVICE_H_ */