bus: ti-sysc: Probe for l4_wkup and l4_cfg interconnect devices first
authorTony Lindgren <tony@atomide.com>
Mon, 8 Mar 2021 09:35:07 +0000 (11:35 +0200)
committerTony Lindgren <tony@atomide.com>
Mon, 8 Mar 2021 09:35:07 +0000 (11:35 +0200)
We want to probe l4_wkup and l4_cfg interconnect devices first to avoid
issues with missing resources. Otherwise we attempt to probe l4_per
devices first causing pointless deferred probe and also annoyingh
renumbering of the MMC devices for example.

Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/bus/ti-sysc.c

index f6491bc..68145e3 100644 (file)
@@ -635,6 +635,51 @@ static int sysc_parse_and_check_child_range(struct sysc *ddata)
        return 0;
 }
 
+/* Interconnect instances to probe before l4_per instances */
+static struct resource early_bus_ranges[] = {
+       /* am3/4 l4_wkup */
+       { .start = 0x44c00000, .end = 0x44c00000 + 0x300000, },
+       /* omap4/5 and dra7 l4_cfg */
+       { .start = 0x4a000000, .end = 0x4a000000 + 0x300000, },
+       /* omap4 l4_wkup */
+       { .start = 0x4a300000, .end = 0x4a300000 + 0x30000,  },
+       /* omap5 and dra7 l4_wkup without dra7 dcan segment */
+       { .start = 0x4ae00000, .end = 0x4ae00000 + 0x30000,  },
+};
+
+static atomic_t sysc_defer = ATOMIC_INIT(10);
+
+/**
+ * sysc_defer_non_critical - defer non_critical interconnect probing
+ * @ddata: device driver data
+ *
+ * We want to probe l4_cfg and l4_wkup interconnect instances before any
+ * l4_per instances as l4_per instances depend on resources on l4_cfg and
+ * l4_wkup interconnects.
+ */
+static int sysc_defer_non_critical(struct sysc *ddata)
+{
+       struct resource *res;
+       int i;
+
+       if (!atomic_read(&sysc_defer))
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(early_bus_ranges); i++) {
+               res = &early_bus_ranges[i];
+               if (ddata->module_pa >= res->start &&
+                   ddata->module_pa <= res->end) {
+                       atomic_set(&sysc_defer, 0);
+
+                       return 0;
+               }
+       }
+
+       atomic_dec_if_positive(&sysc_defer);
+
+       return -EPROBE_DEFER;
+}
+
 static struct device_node *stdout_path;
 
 static void sysc_init_stdout_path(struct sysc *ddata)
@@ -860,6 +905,10 @@ static int sysc_map_and_check_registers(struct sysc *ddata)
        if (error)
                return error;
 
+       error = sysc_defer_non_critical(ddata);
+       if (error)
+               return error;
+
        sysc_check_children(ddata);
 
        if (!of_get_property(np, "reg", NULL))