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
6 * Dave Gerlach6 * Dave Gerlach
7 */7 */
8 8
9#include <linux/cpuidle.h>
10#include <linux/platform_data/pm33xx.h>
11#include <asm/cpuidle.h>
9#include <asm/smp_scu.h>12#include <asm/smp_scu.h>
10#include <asm/suspend.h>13#include <asm/suspend.h>
11#include <linux/errno.h>14#include <linux/errno.h>
12#include <linux/platform_data/pm33xx.h>
13#include <linux/clk.h>15#include <linux/clk.h>
16#include <linux/cpu.h>
14#include <linux/platform_data/gpio-omap.h>17#include <linux/platform_data/gpio-omap.h>
15#include <linux/pinctrl/pinmux.h>18#include <linux/pinctrl/pinmux.h>
16#include <linux/wkup_m3_ipc.h>19#include <linux/wkup_m3_ipc.h>
@@ -35,6 +38,14 @@ static struct clockdomain *gfx_l4ls_clkdm; · 18 unmodified lines
35static void __iomem *scu_base;38static void __iomem *scu_base;
36static struct omap_hwmod *rtc_oh;39static struct omap_hwmod *rtc_oh;
37 40
41static int (*idle_fn)(u32 wfi_flags);
42
43struct amx3_idle_state {
44 int wfi_flags;
45};
46
47static struct amx3_idle_state *idle_states;
48
38static int am43xx_map_scu(void)49static int am43xx_map_scu(void)
39{50{
40 scu_base = ioremap(scu_a9_get_base(), SZ_256);51 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
201 return ret;212 return ret;
202}213}
203 214
215static 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
227static 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
241static void amx3_begin_suspend(void)
242{
243 cpu_idle_poll_ctrl(true);
244}
245
246static void amx3_finish_suspend(void)
247{
248 cpu_idle_poll_ctrl(false);
249}
250
251
204static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)252static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
205{253{
206 if (soc_is_am33xx())254 if (soc_is_am33xx())
@@ -254,6 +302,9 @@ static void am43xx_prepare_rtc_resume(void) · 47 unmodified lines
254static struct am33xx_pm_platform_data am33xx_ops = {302static struct am33xx_pm_platform_data am33xx_ops = {
255 .init = am33xx_suspend_init,303 .init = am33xx_suspend_init,
256 .soc_suspend = am33xx_suspend,304 .soc_suspend = am33xx_suspend,
305 .cpu_suspend = am33xx_cpu_suspend,
306 .begin_suspend = amx3_begin_suspend,
307 .finish_suspend = amx3_finish_suspend,
257 .get_sram_addrs = amx3_get_sram_addrs,308 .get_sram_addrs = amx3_get_sram_addrs,
258 .save_context = am33xx_save_context,309 .save_context = am33xx_save_context,
259 .restore_context = am33xx_restore_context,310 .restore_context = am33xx_restore_context,
@@ -266,6 +317,9 @@ static struct am33xx_pm_platform_data am33xx_ops = { · 6 unmodified lines
266static struct am33xx_pm_platform_data am43xx_ops = {317static struct am33xx_pm_platform_data am43xx_ops = {
267 .init = am43xx_suspend_init,318 .init = am43xx_suspend_init,
268 .soc_suspend = am43xx_suspend,319 .soc_suspend = am43xx_suspend,
320 .cpu_suspend = am43xx_cpu_suspend,
321 .begin_suspend = amx3_begin_suspend,
322 .finish_suspend = amx3_finish_suspend,
269 .get_sram_addrs = amx3_get_sram_addrs,323 .get_sram_addrs = amx3_get_sram_addrs,
270 .save_context = am43xx_save_context,324 .save_context = am43xx_save_context,
271 .restore_context = am43xx_restore_context,325 .restore_context = am43xx_restore_context,
@@ -301,3 +355,64 @@ int __init amx3_common_pm_init(void) · 29 unmodified lines
301 355
302 return 0;356 return 0;
303}357}
358
359static 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
399static 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
412static struct cpuidle_ops amx3_cpuidle_ops __initdata = {
413 .init = amx3_idle_init,
414 .suspend = amx3_idle_enter,
415};
416
417CPUIDLE_METHOD_OF_DECLARE(pm33xx_idle, "ti,am3352", &amx3_cpuidle_ops);
418CPUIDLE_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
49 int (*init)(void);49 int (*init)(void);
50 int (*soc_suspend)(unsigned int state, int (*fn)(unsigned long),50 int (*soc_suspend)(unsigned int state, int (*fn)(unsigned long),
51 unsigned long args);51 unsigned long args);
52 int (*cpu_suspend)(int (*fn)(unsigned long), unsigned long args);
53 void (*begin_suspend)(void);
54 void (*finish_suspend)(void);
52 struct am33xx_pm_sram_addr *(*get_sram_addrs)(void);55 struct am33xx_pm_sram_addr *(*get_sram_addrs)(void);
53 void __iomem *(*get_rtc_base_addr)(void);56 void __iomem *(*get_rtc_base_addr)(void);
54 void (*save_context)(void);57 void (*save_context)(void);