Merge remote-tracking branch 'torvalds/master' into perf/core
[linux-2.6-microblaze.git] / drivers / bus / ti-sysc.c
index 3d74f23..38cb116 100644 (file)
@@ -288,7 +288,7 @@ static int sysc_add_named_clock_from_child(struct sysc *ddata,
         * limit for clk_get(). If cl ever needs to be freed, it should be done
         * with clkdev_drop().
         */
-       cl = kcalloc(1, sizeof(*cl), GFP_KERNEL);
+       cl = kzalloc(sizeof(*cl), GFP_KERNEL);
        if (!cl)
                return -ENOMEM;
 
@@ -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)
@@ -856,15 +901,19 @@ static int sysc_map_and_check_registers(struct sysc *ddata)
        struct device_node *np = ddata->dev->of_node;
        int error;
 
-       if (!of_get_property(np, "reg", NULL))
-               return 0;
-
        error = sysc_parse_and_check_child_range(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))
+               return 0;
+
        error = sysc_parse_registers(ddata);
        if (error)
                return error;
@@ -1285,6 +1334,34 @@ err_allow_idle:
        return error;
 }
 
+static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled)
+{
+       struct device *dev = ddata->dev;
+       int error;
+
+       /* Disable target module if it is enabled */
+       if (ddata->enabled) {
+               error = sysc_runtime_suspend(dev);
+               if (error)
+                       dev_warn(dev, "reinit suspend failed: %i\n", error);
+       }
+
+       /* Enable target module */
+       error = sysc_runtime_resume(dev);
+       if (error)
+               dev_warn(dev, "reinit resume failed: %i\n", error);
+
+       if (leave_enabled)
+               return error;
+
+       /* Disable target module if no leave_enabled was set */
+       error = sysc_runtime_suspend(dev);
+       if (error)
+               dev_warn(dev, "reinit suspend failed: %i\n", error);
+
+       return error;
+}
+
 static int __maybe_unused sysc_noirq_suspend(struct device *dev)
 {
        struct sysc *ddata;
@@ -1295,12 +1372,18 @@ static int __maybe_unused sysc_noirq_suspend(struct device *dev)
            (SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
                return 0;
 
-       return pm_runtime_force_suspend(dev);
+       if (!ddata->enabled)
+               return 0;
+
+       ddata->needs_resume = 1;
+
+       return sysc_runtime_suspend(dev);
 }
 
 static int __maybe_unused sysc_noirq_resume(struct device *dev)
 {
        struct sysc *ddata;
+       int error = 0;
 
        ddata = dev_get_drvdata(dev);
 
@@ -1308,7 +1391,19 @@ static int __maybe_unused sysc_noirq_resume(struct device *dev)
            (SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
                return 0;
 
-       return pm_runtime_force_resume(dev);
+       if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_RESUME) {
+               error = sysc_reinit_module(ddata, ddata->needs_resume);
+               if (error)
+                       dev_warn(dev, "noirq_resume failed: %i\n", error);
+       } else if (ddata->needs_resume) {
+               error = sysc_runtime_resume(dev);
+               if (error)
+                       dev_warn(dev, "noirq_resume failed: %i\n", error);
+       }
+
+       ddata->needs_resume = 0;
+
+       return error;
 }
 
 static const struct dev_pm_ops sysc_pm_ops = {
@@ -1359,9 +1454,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
        /* Uarts on omap4 and later */
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
-                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
        SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
 
        /* Quirks that need to be set based on the module address */
        SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff,
@@ -1410,6 +1505,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("tptc", 0, 0, -ENODEV, -ENODEV, 0x40007c00, 0xffffffff,
                   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+       SYSC_QUIRK("sata", 0, 0xfc, 0x1100, -ENODEV, 0x5e412000, 0xffffffff,
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff,
                   SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff,
@@ -1417,7 +1514,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
                   0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
-                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
+                  SYSC_QUIRK_REINIT_ON_RESUME),
        SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
                   SYSC_MODULE_QUIRK_WDT),
        /* PRUSS on am3, am4 and am5 */
@@ -1447,12 +1545,16 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("dwc3", 0, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 0),
        SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
        SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
+       SYSC_QUIRK("elm", 0x48080000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 0),
+       SYSC_QUIRK("emif", 0, 0, -ENODEV, -ENODEV, 0x40441403, 0xffff0fff, 0),
+       SYSC_QUIRK("emif", 0, 0, -ENODEV, -ENODEV, 0x50440500, 0xffffffff, 0),
        SYSC_QUIRK("epwmss", 0, 0, 0x4, -ENODEV, 0x47400001, 0xffffffff, 0),
        SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -ENODEV, 0, 0, 0),
        SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 0),
        SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50031d00, 0xffffffff, 0),
        SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
        SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0),
+       SYSC_QUIRK("keypad", 0x4a31c000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 0),
        SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0),
        SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0),
        SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0),
@@ -1464,6 +1566,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("ocp2scp", 0, 0, -ENODEV, -ENODEV, 0x50060007, 0xffffffff, 0),
        SYSC_QUIRK("padconf", 0, 0, 0x10, -ENODEV, 0x4fff0800, 0xffffffff, 0),
        SYSC_QUIRK("padconf", 0, 0, -ENODEV, -ENODEV, 0x40001100, 0xffffffff, 0),
+       SYSC_QUIRK("pcie", 0x51000000, -ENODEV, -ENODEV, -ENODEV, 0, 0, 0),
+       SYSC_QUIRK("pcie", 0x51800000, -ENODEV, -ENODEV, -ENODEV, 0, 0, 0),
        SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000100, 0xffffffff, 0),
        SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x00004102, 0xffffffff, 0),
        SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0),
@@ -1592,7 +1696,7 @@ static u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset,
        case SOC_UNKNOWN:
        default:
                return 0;
-       };
+       }
 
        /* Remap the whole module range to be able to reset dispc outputs */
        devm_iounmap(ddata->dev, ddata->module_va);
@@ -2802,6 +2906,7 @@ static int sysc_init_soc(struct sysc *ddata)
        const struct soc_device_attribute *match;
        struct ti_sysc_platform_data *pdata;
        unsigned long features = 0;
+       struct device_node *np;
 
        if (sysc_soc)
                return 0;
@@ -2822,6 +2927,24 @@ static int sysc_init_soc(struct sysc *ddata)
        if (match && match->data)
                sysc_soc->soc = (int)match->data;
 
+       /*
+        * Check and warn about possible old incomplete dtb. We now want to see
+        * simple-pm-bus instead of simple-bus in the dtb for genpd using SoCs.
+        */
+       switch (sysc_soc->soc) {
+       case SOC_AM3:
+       case SOC_AM4:
+       case SOC_4430 ... SOC_4470:
+       case SOC_5430:
+       case SOC_DRA7:
+               np = of_find_node_by_path("/ocp");
+               WARN_ONCE(np && of_device_is_compatible(np, "simple-bus"),
+                         "ti-sysc: Incomplete old dtb, please update\n");
+               break;
+       default:
+               break;
+       }
+
        /* Ignore devices that are not available on HS and EMU SoCs */
        if (!sysc_soc->general_purpose) {
                switch (sysc_soc->soc) {
@@ -2830,7 +2953,7 @@ static int sysc_init_soc(struct sysc *ddata)
                        break;
                default:
                        break;
-               };
+               }
        }
 
        match = soc_device_match(sysc_soc_feat_match);