| /* | 
 |  * 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 "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 */ | 
 | 	cmp	r0, #TEGRA_FLUSH_CACHE_ALL | 
 | 	blne	v7_flush_dcache_louis | 
 | 	bleq	v7_flush_dcache_all | 
 |  | 
 | 	/* 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_init_l2_for_a15 | 
 |  * | 
 |  * set up the correct L2 cache data RAM latency | 
 |  */ | 
 | ENTRY(tegra_init_l2_for_a15) | 
 | 	mrc	p15, 0, r0, c0, c0, 5 | 
 | 	ubfx	r0, r0, #8, #4 | 
 | 	tst	r0, #1				@ only need for cluster 0 | 
 | 	bne	_exit_init_l2_a15 | 
 |  | 
 | 	mrc	p15, 0x1, r0, c9, c0, 2 | 
 | 	and	r0, r0, #7 | 
 | 	cmp	r0, #2 | 
 | 	bicne	r0, r0, #7 | 
 | 	orrne	r0, r0, #2 | 
 | 	mcrne	p15, 0x1, r0, c9, c0, 2 | 
 | _exit_init_l2_a15: | 
 |  | 
 | 	ret	lr | 
 | ENDPROC(tegra_init_l2_for_a15) | 
 |  | 
 | /* | 
 |  * 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) | 
 | 	mov	r4, r0 | 
 | 	/* Flush and disable the L1 data cache */ | 
 | 	mov	r0, #TEGRA_FLUSH_CACHE_ALL | 
 | 	bl	tegra_disable_clean_inv_dcache | 
 |  | 
 | 	mov	r0, r4 | 
 | 	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 | 
 |  | 
 | 	ret	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 */ | 
 | 	check_cpu_part_num 0xc09, r9, r10 | 
 | 	movweq	r2, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000) | 
 | 	movteq	r2, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000) | 
 | 	moveq	r3, #0 | 
 | 	streq	r3, [r2, #L2X0_CTRL] | 
 | #endif | 
 | 	ret	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] | 
 | 	ret	lr | 
 | ENDPROC(tegra_switch_cpu_to_pllp) | 
 | #endif |