xref: /OK3568_Linux_fs/kernel/arch/arm/mach-tegra/sleep.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * arch/arm/mach-tegra/sleep.S
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2010-2011, NVIDIA Corporation.
6*4882a593Smuzhiyun * Copyright (c) 2011, Google, Inc.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Author: Colin Cross <ccross@android.com>
9*4882a593Smuzhiyun *         Gary King <gking@nvidia.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun#include <linux/linkage.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun#include <asm/assembler.h>
15*4882a593Smuzhiyun#include <asm/cache.h>
16*4882a593Smuzhiyun#include <asm/cp15.h>
17*4882a593Smuzhiyun#include <asm/hardware/cache-l2x0.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun#include "iomap.h"
20*4882a593Smuzhiyun#include "sleep.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun#define CLK_RESET_CCLK_BURST	0x20
23*4882a593Smuzhiyun#define CLK_RESET_CCLK_DIVIDER  0x24
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
26*4882a593Smuzhiyun/*
27*4882a593Smuzhiyun * tegra_disable_clean_inv_dcache
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * disable, clean & invalidate the D-cache
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * Corrupted registers: r1-r3, r6, r8, r9-r11
32*4882a593Smuzhiyun */
33*4882a593SmuzhiyunENTRY(tegra_disable_clean_inv_dcache)
34*4882a593Smuzhiyun	stmfd	sp!, {r0, r4-r5, r7, r9-r11, lr}
35*4882a593Smuzhiyun	dmb					@ ensure ordering
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun	/* Disable the D-cache */
38*4882a593Smuzhiyun	mrc	p15, 0, r2, c1, c0, 0
39*4882a593Smuzhiyun	tst	r2, #CR_C			@ see tegra_sleep_cpu()
40*4882a593Smuzhiyun	bic	r2, r2, #CR_C
41*4882a593Smuzhiyun	mcrne	p15, 0, r2, c1, c0, 0
42*4882a593Smuzhiyun	isb
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun	/* Flush the D-cache */
45*4882a593Smuzhiyun	cmp	r0, #TEGRA_FLUSH_CACHE_ALL
46*4882a593Smuzhiyun	blne	v7_flush_dcache_louis
47*4882a593Smuzhiyun	bleq	v7_flush_dcache_all
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun	/* Trun off coherency */
50*4882a593Smuzhiyun	exit_smp r4, r5
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun	ldmfd	sp!, {r0, r4-r5, r7, r9-r11, pc}
53*4882a593SmuzhiyunENDPROC(tegra_disable_clean_inv_dcache)
54*4882a593Smuzhiyun#endif
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun#ifdef CONFIG_PM_SLEEP
57*4882a593Smuzhiyun/*
58*4882a593Smuzhiyun * tegra_init_l2_for_a15
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * set up the correct L2 cache data RAM latency
61*4882a593Smuzhiyun */
62*4882a593SmuzhiyunENTRY(tegra_init_l2_for_a15)
63*4882a593Smuzhiyun	mrc	p15, 0, r0, c0, c0, 5
64*4882a593Smuzhiyun	ubfx	r0, r0, #8, #4
65*4882a593Smuzhiyun	tst	r0, #1				@ only need for cluster 0
66*4882a593Smuzhiyun	bne	_exit_init_l2_a15
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun	mrc	p15, 0x1, r0, c9, c0, 2
69*4882a593Smuzhiyun	and	r0, r0, #7
70*4882a593Smuzhiyun	cmp	r0, #2
71*4882a593Smuzhiyun	bicne	r0, r0, #7
72*4882a593Smuzhiyun	orrne	r0, r0, #2
73*4882a593Smuzhiyun	mcrne	p15, 0x1, r0, c9, c0, 2
74*4882a593Smuzhiyun_exit_init_l2_a15:
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun	ret	lr
77*4882a593SmuzhiyunENDPROC(tegra_init_l2_for_a15)
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun/*
80*4882a593Smuzhiyun * tegra_sleep_cpu_finish(unsigned long v2p)
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * enters suspend in LP2 by turning off the mmu and jumping to
83*4882a593Smuzhiyun * tegra?_tear_down_cpu
84*4882a593Smuzhiyun */
85*4882a593SmuzhiyunENTRY(tegra_sleep_cpu_finish)
86*4882a593Smuzhiyun	mov	r4, r0
87*4882a593Smuzhiyun	/* Flush and disable the L1 data cache */
88*4882a593Smuzhiyun	mov	r0, #TEGRA_FLUSH_CACHE_ALL
89*4882a593Smuzhiyun	bl	tegra_disable_clean_inv_dcache
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun	mov	r0, r4
92*4882a593Smuzhiyun	mov32	r6, tegra_tear_down_cpu
93*4882a593Smuzhiyun	ldr	r1, [r6]
94*4882a593Smuzhiyun	add	r1, r1, r0
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun	mov32	r3, tegra_shut_off_mmu
97*4882a593Smuzhiyun	add	r3, r3, r0
98*4882a593Smuzhiyun	mov	r0, r1
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun	ret	r3
101*4882a593SmuzhiyunENDPROC(tegra_sleep_cpu_finish)
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun/*
104*4882a593Smuzhiyun * tegra_shut_off_mmu
105*4882a593Smuzhiyun *
106*4882a593Smuzhiyun * r0 = physical address to jump to with mmu off
107*4882a593Smuzhiyun *
108*4882a593Smuzhiyun * called with VA=PA mapping
109*4882a593Smuzhiyun * turns off MMU, icache, dcache and branch prediction
110*4882a593Smuzhiyun */
111*4882a593Smuzhiyun	.align	L1_CACHE_SHIFT
112*4882a593Smuzhiyun	.pushsection	.idmap.text, "ax"
113*4882a593SmuzhiyunENTRY(tegra_shut_off_mmu)
114*4882a593Smuzhiyun	mrc	p15, 0, r3, c1, c0, 0
115*4882a593Smuzhiyun	movw	r2, #CR_I | CR_Z | CR_C | CR_M
116*4882a593Smuzhiyun	bic	r3, r3, r2
117*4882a593Smuzhiyun	dsb
118*4882a593Smuzhiyun	mcr	p15, 0, r3, c1, c0, 0
119*4882a593Smuzhiyun	isb
120*4882a593Smuzhiyun#ifdef CONFIG_CACHE_L2X0
121*4882a593Smuzhiyun	/* Disable L2 cache */
122*4882a593Smuzhiyun	check_cpu_part_num 0xc09, r9, r10
123*4882a593Smuzhiyun	retne	r0
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun	mov32	r2, TEGRA_ARM_PERIF_BASE + 0x3000
126*4882a593Smuzhiyun	ldr	r3, [r2, #L2X0_CTRL]
127*4882a593Smuzhiyun	tst	r3, #L2X0_CTRL_EN		@ see tegra_sleep_cpu()
128*4882a593Smuzhiyun	mov	r3, #0
129*4882a593Smuzhiyun	strne	r3, [r2, #L2X0_CTRL]
130*4882a593Smuzhiyun#endif
131*4882a593Smuzhiyun	ret	r0
132*4882a593SmuzhiyunENDPROC(tegra_shut_off_mmu)
133*4882a593Smuzhiyun	.popsection
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun/*
136*4882a593Smuzhiyun * tegra_switch_cpu_to_pllp
137*4882a593Smuzhiyun *
138*4882a593Smuzhiyun * In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp
139*4882a593Smuzhiyun */
140*4882a593SmuzhiyunENTRY(tegra_switch_cpu_to_pllp)
141*4882a593Smuzhiyun	/* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */
142*4882a593Smuzhiyun	mov32	r5, TEGRA_CLK_RESET_BASE
143*4882a593Smuzhiyun	mov	r0, #(2 << 28)			@ burst policy = run mode
144*4882a593Smuzhiyun	orr	r0, r0, #(4 << 4)		@ use PLLP in run mode burst
145*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_CCLK_BURST]
146*4882a593Smuzhiyun	mov	r0, #0
147*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_CCLK_DIVIDER]
148*4882a593Smuzhiyun	ret	lr
149*4882a593SmuzhiyunENDPROC(tegra_switch_cpu_to_pllp)
150*4882a593Smuzhiyun#endif
151