summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/headsmp.S
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-04-16 14:36:45 -0700
committerColin Cross <ccross@android.com>2010-10-06 16:26:25 -0700
commit75a8c9a0082c0a957b32616da54a20314c3efbe0 (patch)
tree87115c3b6fda499c361f8b6fd23981eb7a6182c7 /arch/arm/mach-tegra/headsmp.S
parent6fe5b81eb261cd6b606af37be721e4779803f4df (diff)
[ARM] tegra: Add suspend and hotplug support
LP2 idle mode power-gates the main CPU complex, requiring a full processor state save and restore from a reset vector processor context area is allocated during platform initialization from the kernel, and mapped into the hotplug page tables (which also serve as the initial page tables for the LP2 main processor reset) restoring the processor from LP2 requires calculation of a system- and APB-clock-dependent CPU power good timer value. on Harmony, 2ms is a good baseline value for this, and the APB clock is running at 13.5MHz. these values need to be un-hardcoded for other platforms. platform-specific data (power good times, PMU capabilities, etc.) must be specified when registering the suspend operations to ensure that platform power sequencing restrictions are maintained since all device interrupts (except timers) are disabled in the suspend path, the wakeup interrupts need to be manually unmasked before entering into a suspend state or the processor will never wake up; these forced-unmask interrupts are re-masked immediately in the resume path to prevent the kernel from live-locking prior to driver resume. in both LP0 and LP1, SDRAM is placed into self-refresh. in order to safely perform this transition, the final shutdown procedure responsible for * turning off the MMU and L1 data cache * putting memory into self-refresh * setting the DDR pads to the lowest power state * and turning off PLLs is copied into IRAM (at the address TEGRA_IRAM_BASE + SZ_4K) at the start of the suspend process. in LP1 mode (like LP2), the CPU is reset and executes the code specified at the EVP reset vector. since SDRAM is in self-refresh, this code must also be located in IRAM, and it must re-enable DRAM before restoring the full context. in this implementation, it enables the CPU on PLLP, enables PLLC and PLLM, restores the SCLK burst policy, and jumps to the LP2 reset vector to restore the rest of the system (MMU, PLLX, coresite, etc.). the LP2 reset vector is expected to be found in PMC_SCRATCH1, and is initialized during system-bootup in LP0 mode, the core voltage domain is also shutoff. as a result, all of the volatile state in the core voltage domain (e.g., pinmux registers, clock registers, etc.) must be saved to memory so that it can be restored after the system resumes. a limited set of wakeups are available from LP0, and the correct levels for the wakeups must be programmed into the PMC wakepad configuration register prior to system shutdown. on resume, the system resets into the boot ROM, and the boot ROM restores SDRAM and other system state using values saved during kernel initialization in the PMC scratch registers. resuming from LP0 requires the boot ROM to supply a signed recovery codeblob to the kernel; the kernel expects that the length and address of this blob is supplied with the lp0_vec= command line argument; if not present, suspend- to-LP0 will be disabled for simplicity, the outer cache is shutdown for both LP0 and LP1; it is possible to optimize the LP1 routine to bypass outer cache shutdown and restart to save power, SMP tegra SoCs place non-boot CPUs in reset when they are removed from the scheduling cluster using CPU hotplug. slave CPUs save their contexts (incl. CP15 and VFP state) out to a reserved memory region, cancel SMP operation, and write to the SoC reset controller to disable themselves. this is done with caches and MMU enabled, so care is taken to ensure that all the dirty context cache lines are cleaned out to the PoC before shutting down. when re-enabled, slave CPUs execute a hotplug boot routine which mirrors the initial configuration performed by secondary_startup, but after enabling the MMU "return" to __cortex_a9_restore which restores the saved state from the context area, and returns to platform_cpu_die. a local page directory is maintained (initially a copy of init_mm) by the tegra hotplug code, to ensure that all necessary context data and text is properly mapped (including 1:1 virtual->physical mappings for the code which re-enables the MMU); this page table will also be used for the idle and suspend save and resume routines for the master CPU. in pseudo-code, the hotplug startup routine is basically: * invalidate i-cache, BTAC, TLB, exclusive monitor * enable i-cache, branch prediction * invalidate d-cache * invalidate SCU tags * enable SMP * setup page tables to tegra_pgd * enable MMU & d-cache * restore CP15 from context area * change page table pointer to context from shutdown * restore stack registers * return to platform_cpu_die Includes fixes from: Scott Williams <scwilliams@nvidia.com> Aleksandr Frid <afrid@nvidia.com> Vik Kasivajhula <tkasivajhula@nvidia.com> Bharat Nihalani (bnihalani@nvidia.com) Change-Id: I50e6a524696342f946b6117a2d7f019f401c3bbd Signed-off-by: Gary King <gking@nvidia.com> Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/headsmp.S')
-rw-r--r--arch/arm/mach-tegra/headsmp.S61
1 files changed, 0 insertions, 61 deletions
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
deleted file mode 100644
index b5349b2f13d2..000000000000
--- a/arch/arm/mach-tegra/headsmp.S
+++ /dev/null
@@ -1,61 +0,0 @@
-#include <linux/linkage.h>
-#include <linux/init.h>
-
- .section ".text.head", "ax"
- __CPUINIT
-
-/*
- * Tegra specific entry point for secondary CPUs.
- * The secondary kernel init calls v7_flush_dcache_all before it enables
- * the L1; however, the L1 comes out of reset in an undefined state, so
- * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
- * of cache lines with uninitialized data and uninitialized tags to get
- * written out to memory, which does really unpleasant things to the main
- * processor. We fix this by performing an invalidate, rather than a
- * clean + invalidate, before jumping into the kernel.
- */
-ENTRY(v7_invalidate_l1)
- mov r0, #0
- mcr p15, 2, r0, c0, c0, 0
- mrc p15, 1, r0, c0, c0, 0
-
- ldr r1, =0x7fff
- and r2, r1, r0, lsr #13
-
- ldr r1, =0x3ff
-
- and r3, r1, r0, lsr #3 @ NumWays - 1
- add r2, r2, #1 @ NumSets
-
- and r0, r0, #0x7
- add r0, r0, #4 @ SetShift
-
- clz r1, r3 @ WayShift
- add r4, r3, #1 @ NumWays
-1: sub r2, r2, #1 @ NumSets--
- mov r3, r4 @ Temp = NumWays
-2: subs r3, r3, #1 @ Temp--
- mov r5, r3, lsl r1
- mov r6, r2, lsl r0
- orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
- mcr p15, 0, r5, c7, c6, 2
- bgt 2b
- cmp r2, #0
- bgt 1b
- dsb
- isb
- mov pc, lr
-ENDPROC(v7_invalidate_l1)
-
-ENTRY(tegra_secondary_startup)
- msr cpsr_fsxc, #0xd3
- bl v7_invalidate_l1
- mrc p15, 0, r0, c0, c0, 5
- and r0, r0, #15
- ldr r1, =0x6000f100
- str r0, [r1]
-1: ldr r2, [r1]
- cmp r0, r2
- beq 1b
- b secondary_startup
-ENDPROC(tegra_secondary_startup)