ARM: OMAP2+: pm33xx-core: Add cpuidle_ops for am335x/am437x
authorDave Gerlach <d-gerlach@ti.com>
Fri, 2 Nov 2018 10:29:46 +0000 (15:59 +0530)
committerTero Kristo <t-kristo@ti.com>
Tue, 6 Nov 2018 13:25:29 +0000 (15:25 +0200)
am335x and am437x can now make use of the generic cpuidle-arm driver.
This requires that we define init and suspend ops to be passed set as
the cpuidle ops for the SoC. These ops are invoked directly at the last
stage of the cpuidle-arm driver in order to allow low level platform
code to run and bring the CPU the rest of the way into it's desired idle
state. It is required that the CPUIDLE_METHOD_OF_DECLARE be called from
code that is built in so define these ops in pm33xx-core where the
always built-in portion of the PM code for these SoCs lives.

The cpuidle_ops that we define are matched in the DT to the "enable-method"
defined for the SoC, so also define two new enable-method compatible
strings and document them, one for "ti,am3352" and one for "ti,am4372".

Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Documentation/devicetree/bindings/arm/cpus.txt
arch/arm/mach-omap2/pm33xx-core.c

index 96dfccc0faa8d9471d52900150b6dea9ad96ff62..81b6dde4586b2567c0fb93484101b602603a3220 100644 (file)
@@ -224,6 +224,8 @@ described below.
                            "rockchip,rk3036-smp"
                            "rockchip,rk3066-smp"
                            "ste,dbx500-smp"
+                           "ti,am3352"
+                           "ti,am4372"
 
        - cpu-release-addr
                Usage: required for systems that have an "enable-method"
index 3665ac6aca76441b5af1cfc7824aab9d4041a0a4..b16fed8911be696ef4609183c5e7512a4b12620b 100644 (file)
@@ -6,10 +6,12 @@
  *     Dave Gerlach
  */
 
+#include <linux/cpuidle.h>
+#include <linux/platform_data/pm33xx.h>
+#include <asm/cpuidle.h>
 #include <asm/smp_scu.h>
 #include <asm/suspend.h>
 #include <linux/errno.h>
-#include <linux/platform_data/pm33xx.h>
 #include <linux/clk.h>
 #include <linux/platform_data/gpio-omap.h>
 #include <linux/pinctrl/pinmux.h>
@@ -34,6 +36,14 @@ static struct clockdomain *gfx_l4ls_clkdm;
 static void __iomem *scu_base;
 static struct omap_hwmod *rtc_oh;
 
+static int (*idle_fn)(u32 wfi_flags);
+
+struct amx3_idle_state {
+       int wfi_flags;
+};
+
+static struct amx3_idle_state *idle_states;
+
 static int __init am43xx_map_scu(void)
 {
        scu_base = ioremap(scu_a9_get_base(), SZ_256);
@@ -275,3 +285,64 @@ int __init amx3_common_pm_init(void)
 
        return 0;
 }
+
+static int __init amx3_idle_init(struct device_node *cpu_node, int cpu)
+{
+       struct device_node *state_node;
+       struct amx3_idle_state states[CPUIDLE_STATE_MAX];
+       int i;
+       int state_count = 1;
+
+       for (i = 0; ; i++) {
+               state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+               if (!state_node)
+                       break;
+
+               if (!of_device_is_available(state_node))
+                       continue;
+
+               if (i == CPUIDLE_STATE_MAX) {
+                       pr_warn("%s: cpuidle states reached max possible\n",
+                               __func__);
+                       break;
+               }
+
+               states[state_count].wfi_flags = 0;
+
+               if (of_property_read_bool(state_node, "ti,idle-wkup-m3"))
+                       states[state_count].wfi_flags |= WFI_FLAG_WAKE_M3 |
+                                                        WFI_FLAG_FLUSH_CACHE;
+
+               state_count++;
+       }
+
+       idle_states = kcalloc(state_count, sizeof(*idle_states), GFP_KERNEL);
+       if (!idle_states)
+               return -ENOMEM;
+
+       for (i = 1; i < state_count; i++)
+               idle_states[i].wfi_flags = states[i].wfi_flags;
+
+       return 0;
+}
+
+static int amx3_idle_enter(unsigned long index)
+{
+       struct amx3_idle_state *idle_state = &idle_states[index];
+
+       if (!idle_state)
+               return -EINVAL;
+
+       if (idle_fn)
+               idle_fn(idle_state->wfi_flags);
+
+       return 0;
+}
+
+static struct cpuidle_ops amx3_cpuidle_ops __initdata = {
+       .init = amx3_idle_init,
+       .suspend = amx3_idle_enter,
+};
+
+CPUIDLE_METHOD_OF_DECLARE(pm33xx_idle, "ti,am3352", &amx3_cpuidle_ops);
+CPUIDLE_METHOD_OF_DECLARE(pm43xx_idle, "ti,am4372", &amx3_cpuidle_ops);