History

ARM: OMAP2+: pm33xx-core: Add cpuidle_ops for am335x/am437x

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. Additionally, although an soc_suspend function is already exposed by the pm33xx platform code, it contains additional operations needed for full SoC suspend beyond what is needed for a relatively simple CPU suspend needed during cpuidle. To get around this introduce cpu_suspend ops to be used by the am335x and am437x PM driver for the last stage of cpuidle path.

Dave Gerlach committed 6 years ago

Commit 06ee7a91 parent b749ebe2 files · +119 −1Browse files

Unified · Split

2 files
  1. arch/arm/mach-omap2/pm33xx-core.c +116 −1
  2. include/linux/platform_data/pm33xx.h +3 −0
arch/arm/mach-omap2/pm33xx-core.c+116−1
@@ -6,11 +6,14 @@ · 5 unmodified lines
66 * Dave Gerlach
77 */
88
9+#include <linux/cpuidle.h>
10+#include <linux/platform_data/pm33xx.h>
11+#include <asm/cpuidle.h>
912 #include <asm/smp_scu.h>
1013 #include <asm/suspend.h>
1114 #include <linux/errno.h>
12−#include <linux/platform_data/pm33xx.h>
1315 #include <linux/clk.h>
16+#include <linux/cpu.h>
1417 #include <linux/platform_data/gpio-omap.h>
1518 #include <linux/pinctrl/pinmux.h>
1619 #include <linux/wkup_m3_ipc.h>
@@ -35,6 +38,14 @@ static struct clockdomain *gfx_l4ls_clkdm; · 18 unmodified lines
3538 static void __iomem *scu_base;
3639 static struct omap_hwmod *rtc_oh;
3740
41+static int (*idle_fn)(u32 wfi_flags);
42+
43+struct amx3_idle_state {
44+ int wfi_flags;
45+};
46+
47+static struct amx3_idle_state *idle_states;
48+
3849 static int am43xx_map_scu(void)
3950 {
4051 scu_base = ioremap(scu_a9_get_base(), SZ_256);
@@ -201,6 +212,43 @@ static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long), · 160 unmodified lines
201212 return ret;
202213 }
203214
215+static int am33xx_cpu_suspend(int (*fn)(unsigned long), unsigned long args)
216+{
217+ int ret = 0;
218+
219+ if (omap_irq_pending() || need_resched())
220+ return ret;
221+
222+ ret = cpu_suspend(args, fn);
223+
224+ return ret;
225+}
226+
227+static int am43xx_cpu_suspend(int (*fn)(unsigned long), unsigned long args)
228+{
229+ int ret = 0;
230+
231+ if (!scu_base)
232+ return 0;
233+
234+ scu_power_mode(scu_base, SCU_PM_DORMANT);
235+ ret = cpu_suspend(args, fn);
236+ scu_power_mode(scu_base, SCU_PM_NORMAL);
237+
238+ return ret;
239+}
240+
241+static void amx3_begin_suspend(void)
242+{
243+ cpu_idle_poll_ctrl(true);
244+}
245+
246+static void amx3_finish_suspend(void)
247+{
248+ cpu_idle_poll_ctrl(false);
249+}
250+
251+
204252 static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
205253 {
206254 if (soc_is_am33xx())
@@ -254,6 +302,9 @@ static void am43xx_prepare_rtc_resume(void) · 47 unmodified lines
254302 static struct am33xx_pm_platform_data am33xx_ops = {
255303 .init = am33xx_suspend_init,
256304 .soc_suspend = am33xx_suspend,
305+ .cpu_suspend = am33xx_cpu_suspend,
306+ .begin_suspend = amx3_begin_suspend,
307+ .finish_suspend = amx3_finish_suspend,
257308 .get_sram_addrs = amx3_get_sram_addrs,
258309 .save_context = am33xx_save_context,
259310 .restore_context = am33xx_restore_context,
@@ -266,6 +317,9 @@ static struct am33xx_pm_platform_data am33xx_ops = { · 6 unmodified lines
266317 static struct am33xx_pm_platform_data am43xx_ops = {
267318 .init = am43xx_suspend_init,
268319 .soc_suspend = am43xx_suspend,
320+ .cpu_suspend = am43xx_cpu_suspend,
321+ .begin_suspend = amx3_begin_suspend,
322+ .finish_suspend = amx3_finish_suspend,
269323 .get_sram_addrs = amx3_get_sram_addrs,
270324 .save_context = am43xx_save_context,
271325 .restore_context = am43xx_restore_context,
@@ -301,3 +355,64 @@ int __init amx3_common_pm_init(void) · 29 unmodified lines
301355
302356 return 0;
303357 }
358+
359+static int __init amx3_idle_init(struct device_node *cpu_node, int cpu)
360+{
361+ struct device_node *state_node;
362+ struct amx3_idle_state states[CPUIDLE_STATE_MAX];
363+ int i;
364+ int state_count = 1;
365+
366+ for (i = 0; ; i++) {
367+ state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
368+ if (!state_node)
369+ break;
370+
371+ if (!of_device_is_available(state_node))
372+ continue;
373+
374+ if (i == CPUIDLE_STATE_MAX) {
375+ pr_warn("%s: cpuidle states reached max possible\n",
376+ __func__);
377+ break;
378+ }
379+
380+ states[state_count].wfi_flags = 0;
381+
382+ if (of_property_read_bool(state_node, "ti,idle-wkup-m3"))
383+ states[state_count].wfi_flags |= WFI_FLAG_WAKE_M3 |
384+ WFI_FLAG_FLUSH_CACHE;
385+
386+ state_count++;
387+ }
388+
389+ idle_states = kcalloc(state_count, sizeof(*idle_states), GFP_KERNEL);
390+ if (!idle_states)
391+ return -ENOMEM;
392+
393+ for (i = 1; i < state_count; i++)
394+ idle_states[i].wfi_flags = states[i].wfi_flags;
395+
396+ return 0;
397+}
398+
399+static int amx3_idle_enter(unsigned long index)
400+{
401+ struct amx3_idle_state *idle_state = &idle_states[index];
402+
403+ if (!idle_state)
404+ return -EINVAL;
405+
406+ if (idle_fn)
407+ idle_fn(idle_state->wfi_flags);
408+
409+ return 0;
410+}
411+
412+static struct cpuidle_ops amx3_cpuidle_ops __initdata = {
413+ .init = amx3_idle_init,
414+ .suspend = amx3_idle_enter,
415+};
416+
417+CPUIDLE_METHOD_OF_DECLARE(pm33xx_idle, "ti,am3352", &amx3_cpuidle_ops);
418+CPUIDLE_METHOD_OF_DECLARE(pm43xx_idle, "ti,am4372", &amx3_cpuidle_ops);
include/linux/platform_data/pm33xx.h+3−0
@@ -49,6 +49,9 @@ struct am33xx_pm_platform_data { · 48 unmodified lines
4949 int (*init)(void);
5050 int (*soc_suspend)(unsigned int state, int (*fn)(unsigned long),
5151 unsigned long args);
52+ int (*cpu_suspend)(int (*fn)(unsigned long), unsigned long args);
53+ void (*begin_suspend)(void);
54+ void (*finish_suspend)(void);
5255 struct am33xx_pm_sram_addr *(*get_sram_addrs)(void);
5356 void __iomem *(*get_rtc_base_addr)(void);
5457 void (*save_context)(void);