alistair23-linux/arch/arm/mach-tegra/sleep.S
Joseph Lo 1d328606c6 ARM: tegra20: cpuidle: apply coupled cpuidle for powered-down mode
The "powered-down" cpuidle mode of Tegra20 needs the CPU0 be the last one
core to go into this mode before other core. The coupled cpuidle framework
can help to sync the MPCore to coupled state then go into "powered-down"
idle mode together. The driver can just assume the MPCore come into
"powered-down" mode at the same time. No need to take care if the CPU_0
goes into this mode along and only can put it into safe idle mode (WFI).

The powered-down state of Tegra20 requires power gating both CPU cores.
When the secondary CPU requests to enter powered-down state, it saves
its own contexts and then enters WFI for waiting CPU0 in the same state.
When the CPU0 requests powered-down state, it attempts to put the secondary
CPU into reset to prevent it from waking up. Then power down both CPUs
together and power off the cpu rail.

Be aware of that, you may see the legacy power state "LP2" in the code
which is exactly the same meaning of "CPU power down".

Based on the work by:
Colin Cross <ccross@android.com>
Gary King <gking@nvidia.com>

Signed-off-by: Joseph Lo <josephl@nvidia.com>
Acked-by: Colin Cross <ccross@android.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-28 11:20:38 -07:00

133 lines
3.2 KiB
ArmAsm

/*
* arch/arm/mach-tegra/sleep.S
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
* Copyright (c) 2011, Google, Inc.
*
* Author: Colin Cross <ccross@android.com>
* Gary King <gking@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/cache.h>
#include <asm/cp15.h>
#include <asm/hardware/cache-l2x0.h>
#include "iomap.h"
#include "flowctrl.h"
#include "sleep.h"
#define CLK_RESET_CCLK_BURST 0x20
#define CLK_RESET_CCLK_DIVIDER 0x24
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
/*
* tegra_disable_clean_inv_dcache
*
* disable, clean & invalidate the D-cache
*
* Corrupted registers: r1-r3, r6, r8, r9-r11
*/
ENTRY(tegra_disable_clean_inv_dcache)
stmfd sp!, {r0, r4-r5, r7, r9-r11, lr}
dmb @ ensure ordering
/* Disable the D-cache */
mrc p15, 0, r2, c1, c0, 0
bic r2, r2, #CR_C
mcr p15, 0, r2, c1, c0, 0
isb
/* Flush the D-cache */
bl v7_flush_dcache_louis
/* Trun off coherency */
exit_smp r4, r5
ldmfd sp!, {r0, r4-r5, r7, r9-r11, pc}
ENDPROC(tegra_disable_clean_inv_dcache)
#endif
#ifdef CONFIG_PM_SLEEP
/*
* tegra_sleep_cpu_finish(unsigned long v2p)
*
* enters suspend in LP2 by turning off the mmu and jumping to
* tegra?_tear_down_cpu
*/
ENTRY(tegra_sleep_cpu_finish)
/* Flush and disable the L1 data cache */
bl tegra_disable_clean_inv_dcache
mov32 r6, tegra_tear_down_cpu
ldr r1, [r6]
add r1, r1, r0
mov32 r3, tegra_shut_off_mmu
add r3, r3, r0
mov r0, r1
mov pc, r3
ENDPROC(tegra_sleep_cpu_finish)
/*
* tegra_shut_off_mmu
*
* r0 = physical address to jump to with mmu off
*
* called with VA=PA mapping
* turns off MMU, icache, dcache and branch prediction
*/
.align L1_CACHE_SHIFT
.pushsection .idmap.text, "ax"
ENTRY(tegra_shut_off_mmu)
mrc p15, 0, r3, c1, c0, 0
movw r2, #CR_I | CR_Z | CR_C | CR_M
bic r3, r3, r2
dsb
mcr p15, 0, r3, c1, c0, 0
isb
#ifdef CONFIG_CACHE_L2X0
/* Disable L2 cache */
mov32 r4, TEGRA_ARM_PERIF_BASE + 0x3000
mov r5, #0
str r5, [r4, #L2X0_CTRL]
#endif
mov pc, r0
ENDPROC(tegra_shut_off_mmu)
.popsection
/*
* tegra_switch_cpu_to_pllp
*
* In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp
*/
ENTRY(tegra_switch_cpu_to_pllp)
/* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */
mov32 r5, TEGRA_CLK_RESET_BASE
mov r0, #(2 << 28) @ burst policy = run mode
orr r0, r0, #(4 << 4) @ use PLLP in run mode burst
str r0, [r5, #CLK_RESET_CCLK_BURST]
mov r0, #0
str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
mov pc, lr
ENDPROC(tegra_switch_cpu_to_pllp)
#endif