Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74655749 authored by Dave Gerlach's avatar Dave Gerlach Committed by Tony Lindgren
Browse files

ARM: OMAP2+: sleep33/43xx: Make sleep actions configurable



Add an argument to the sleep33xx and sleep43xx code to allow us to set
flags to determine which portions of the code get called in order to use
the same code for multiple power saving modes. This patch allows us to
decide whether or not we flush and disable caches, save EMIF context,
put the memory into self refresh and disable the EMIF, and/or invoke
the wkup_m3 when entering into WFI.

Signed-off-by: default avatarDave Gerlach <d-gerlach@ti.com>
Signed-off-by: default avatarTero Kristo <t-kristo@ti.com>
Signed-off-by: default avatarKeerthy <j-keerthy@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent eb07fe9f
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -106,12 +106,13 @@ static void amx3_post_suspend_common(void)
		pr_err("PM: GFX domain did not transition: %x\n", status);
}

static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long))
static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long),
			  unsigned long args)
{
	int ret = 0;

	amx3_pre_suspend_common();
	ret = cpu_suspend(0, fn);
	ret = cpu_suspend(args, fn);
	amx3_post_suspend_common();

	/*
@@ -128,13 +129,14 @@ static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long))
	return ret;
}

static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long))
static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
			  unsigned long args)
{
	int ret = 0;

	amx3_pre_suspend_common();
	scu_power_mode(scu_base, SCU_PM_POWEROFF);
	ret = cpu_suspend(0, fn);
	ret = cpu_suspend(args, fn);
	scu_power_mode(scu_base, SCU_PM_NORMAL);
	amx3_post_suspend_common();

+47 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include <generated/ti-pm-asm-offsets.h>
#include <linux/linkage.h>
#include <linux/platform_data/pm33xx.h>
#include <linux/ti-emif-sram.h>
#include <asm/assembler.h>
#include <asm/memory.h>
@@ -19,12 +20,25 @@
#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE			0x0003
#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE			0x0002

/* replicated define because linux/bitops.h cannot be included in assembly */
#define BIT(nr)			(1 << (nr))

	.arm
	.align 3

ENTRY(am33xx_do_wfi)
	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack

	/* Save wfi_flags arg to data space */
	mov	r4, r0
	adr	r3, am33xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	str	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

	/* Only flush cache is we know we are losing MPU context */
	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_flush

	/*
	 * Flush all data from the L1 and L2 data cache before disabling
	 * SCTLR.C bit.
@@ -48,14 +62,33 @@ ENTRY(am33xx_do_wfi)
	ldr	r1, kernel_flush
	blx	r1

	adr	r3, am33xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	ldr	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

cache_skip_flush:
	/* Check if we want self refresh */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_enter_sr

	adr	r9, am33xx_emif_sram_table

	ldr	r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
	blx	r3

emif_skip_enter_sr:
	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SAVE_EMIF
	beq	emif_skip_save

	ldr	r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
	blx	r3

emif_skip_save:
	/* Only can disable EMIF if we have entered self refresh */
	tst     r4, #WFI_FLAG_SELF_REFRESH
	beq     emif_skip_disable

	/* Disable EMIF */
	ldr     r1, virt_emif_clkctrl
	ldr     r2, [r1]
@@ -69,6 +102,10 @@ wait_emif_disable:
	cmp	r2, r3
	bne	wait_emif_disable

emif_skip_disable:
	tst	r4, #WFI_FLAG_WAKE_M3
	beq	wkup_m3_skip

	/*
	 * For the MPU WFI to be registered as an interrupt
	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
@@ -79,6 +116,7 @@ wait_emif_disable:
	bic	r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
	str	r2, [r1]

wkup_m3_skip:
	/*
	 * Execute an ISB instruction to ensure that all of the
	 * CP15 register changes have been committed.
@@ -132,10 +170,18 @@ wait_emif_enable:
	cmp	r2, r3
	bne	wait_emif_enable

	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_exit_sr_abt

	adr	r9, am33xx_emif_sram_table
	ldr	r1, [r9, #EMIF_PM_ABORT_SR_OFFSET]
	blx	r1

emif_skip_exit_sr_abt:
	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_restore

	/*
	 * Set SCTLR.C bit to allow data cache allocation
	 */
@@ -144,6 +190,7 @@ wait_emif_enable:
	mcr	p15, 0, r0, c1, c0, 0
	isb

cache_skip_restore:
	/* Let the suspend code know about the abort */
	mov	r0, #1
	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
+52 −4
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
#include <generated/ti-pm-asm-offsets.h>
#include <linux/linkage.h>
#include <linux/ti-emif-sram.h>

#include <linux/platform_data/pm33xx.h>
#include <asm/assembler.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/memory.h>
@@ -22,6 +22,9 @@
#include "prm33xx.h"
#include "prcm43xx.h"

/* replicated define because linux/bitops.h cannot be included in assembly */
#define BIT(nr)			(1 << (nr))

#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED		0x00030000
#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE		0x0003
#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE		0x0002
@@ -51,6 +54,12 @@
ENTRY(am43xx_do_wfi)
	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack

	/* Save wfi_flags arg to data space */
	mov	r4, r0
	adr	r3, am43xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	str	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

#ifdef CONFIG_CACHE_L2X0
	/* Retrieve l2 cache virt address BEFORE we shut off EMIF */
	ldr	r1, get_l2cache_base
@@ -58,6 +67,10 @@ ENTRY(am43xx_do_wfi)
	mov	r8, r0
#endif

	/* Only flush cache is we know we are losing MPU context */
	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_flush

	/*
	 * Flush all data from the L1 and L2 data cache before disabling
	 * SCTLR.C bit.
@@ -128,14 +141,34 @@ sync:
	bne	sync
#endif

	/* Restore wfi_flags */
	adr	r3, am43xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	ldr	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

cache_skip_flush:
	/* Check if we want self refresh */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_enter_sr

	adr     r9, am43xx_emif_sram_table

	ldr     r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
	blx     r3

emif_skip_enter_sr:
	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SAVE_EMIF
	beq	emif_skip_save

	ldr     r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
	blx	r3

emif_skip_save:
	/* Only can disable EMIF if we have entered self refresh */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_disable

	/* Disable EMIF */
	ldr	r1, am43xx_virt_emif_clkctrl
	ldr	r2, [r1]
@@ -148,6 +181,10 @@ wait_emif_disable:
	cmp	r2, r3
	bne	wait_emif_disable

emif_skip_disable:
	tst	r4, #WFI_FLAG_WAKE_M3
	beq	wkup_m3_skip

	/*
	 * For the MPU WFI to be registered as an interrupt
	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
@@ -165,6 +202,7 @@ wait_emif_disable:
	mov	r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP
	str	r2, [r1]

wkup_m3_skip:
	/*
	 * Execute a barrier instruction to ensure that all cache,
	 * TLB and branch predictor maintenance operations issued
@@ -218,6 +256,9 @@ wait_emif_enable:
	cmp	r2, r3
	bne	wait_emif_enable

	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_restore

	/*
	 * Set SCTLR.C bit to allow data cache allocation
	 */
@@ -226,9 +267,16 @@ wait_emif_enable:
	mcr	p15, 0, r0, c1, c0, 0
	isb

cache_skip_restore:
	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_exit_sr_abt

	adr	r9, am43xx_emif_sram_table
	ldr	r1, [r9, #EMIF_PM_ABORT_SR_OFFSET]
	blx	r1

emif_skip_exit_sr_abt:
	/* Let the suspend code know about the abort */
	mov	r0, #1
	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
+14 −1
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ static struct am33xx_pm_sram_addr *pm_sram;
static struct device *pm33xx_dev;
static struct wkup_m3_ipc *m3_ipc;

static unsigned long suspend_wfi_flags;

static u32 sram_suspend_address(unsigned long addr)
{
	return ((unsigned long)am33xx_do_wfi_sram +
@@ -53,7 +55,7 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state)
	int i, ret = 0;

	ret = pm_ops->soc_suspend((unsigned long)suspend_state,
				  am33xx_do_wfi_sram);
				  am33xx_do_wfi_sram, suspend_wfi_flags);

	if (ret) {
		dev_err(pm33xx_dev, "PM: Kernel suspend failure\n");
@@ -310,6 +312,17 @@ static int am33xx_pm_probe(struct platform_device *pdev)
	suspend_set_ops(&am33xx_pm_ops);
#endif /* CONFIG_SUSPEND */

	/*
	 * For a system suspend we must flush the caches, we want
	 * the DDR in self-refresh, we want to save the context
	 * of the EMIF, and we want the wkup_m3 to handle low-power
	 * transition.
	 */
	suspend_wfi_flags |= WFI_FLAG_FLUSH_CACHE;
	suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH;
	suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF;
	suspend_wfi_flags |= WFI_FLAG_WAKE_M3;

	ret = pm_ops->init();
	if (ret) {
		dev_err(dev, "Unable to call core pm init!\n");
+25 −1
Original line number Diff line number Diff line
@@ -12,6 +12,29 @@
#include <linux/kbuild.h>
#include <linux/types.h>

/*
 * WFI Flags for sleep code control
 *
 * These flags allow PM code to exclude certain operations from happening
 * in the low level ASM code found in sleep33xx.S and sleep43xx.S
 *
 * WFI_FLAG_FLUSH_CACHE: Flush the ARM caches and disable caching. Only
 *			 needed when MPU will lose context.
 * WFI_FLAG_SELF_REFRESH: Let EMIF place DDR memory into self-refresh and
 *			  disable EMIF.
 * WFI_FLAG_SAVE_EMIF: Save context of all EMIF registers and restore in
 *		       resume path. Only needed if PER domain loses context
 *		       and must also have WFI_FLAG_SELF_REFRESH set.
 * WFI_FLAG_WAKE_M3: Disable MPU clock or clockdomain to cause wkup_m3 to
 *		     execute when WFI instruction executes.
 * WFI_FLAG_RTC_ONLY: Configure the RTC to enter RTC+DDR mode.
 */
#define WFI_FLAG_FLUSH_CACHE		BIT(0)
#define WFI_FLAG_SELF_REFRESH		BIT(1)
#define WFI_FLAG_SAVE_EMIF		BIT(2)
#define WFI_FLAG_WAKE_M3		BIT(3)
#define WFI_FLAG_RTC_ONLY		BIT(4)

#ifndef __ASSEMBLER__
struct am33xx_pm_sram_addr {
	void (*do_wfi)(void);
@@ -23,7 +46,8 @@ struct am33xx_pm_sram_addr {

struct am33xx_pm_platform_data {
	int	(*init)(void);
	int	(*soc_suspend)(unsigned int state, int (*fn)(unsigned long));
	int	(*soc_suspend)(unsigned int state, int (*fn)(unsigned long),
			       unsigned long args);
	struct  am33xx_pm_sram_addr *(*get_sram_addrs)(void);
};