xref: /OK3568_Linux_fs/kernel/arch/arm/mach-tegra/sleep-tegra30.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun#include <linux/linkage.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun#include <soc/tegra/flowctrl.h>
9*4882a593Smuzhiyun#include <soc/tegra/fuse.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun#include <asm/asm-offsets.h>
12*4882a593Smuzhiyun#include <asm/assembler.h>
13*4882a593Smuzhiyun#include <asm/cache.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun#include "irammap.h"
16*4882a593Smuzhiyun#include "sleep.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun#define EMC_CFG				0xc
19*4882a593Smuzhiyun#define EMC_ADR_CFG			0x10
20*4882a593Smuzhiyun#define EMC_TIMING_CONTROL		0x28
21*4882a593Smuzhiyun#define EMC_NOP				0xdc
22*4882a593Smuzhiyun#define EMC_SELF_REF			0xe0
23*4882a593Smuzhiyun#define EMC_MRW				0xe8
24*4882a593Smuzhiyun#define EMC_FBIO_CFG5			0x104
25*4882a593Smuzhiyun#define EMC_AUTO_CAL_CONFIG		0x2a4
26*4882a593Smuzhiyun#define EMC_AUTO_CAL_INTERVAL		0x2a8
27*4882a593Smuzhiyun#define EMC_AUTO_CAL_STATUS		0x2ac
28*4882a593Smuzhiyun#define EMC_REQ_CTRL			0x2b0
29*4882a593Smuzhiyun#define EMC_CFG_DIG_DLL			0x2bc
30*4882a593Smuzhiyun#define EMC_EMC_STATUS			0x2b4
31*4882a593Smuzhiyun#define EMC_ZCAL_INTERVAL		0x2e0
32*4882a593Smuzhiyun#define EMC_ZQ_CAL			0x2ec
33*4882a593Smuzhiyun#define EMC_XM2VTTGENPADCTRL		0x310
34*4882a593Smuzhiyun#define EMC_XM2VTTGENPADCTRL2		0x314
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun#define PMC_CTRL			0x0
37*4882a593Smuzhiyun#define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun#define PMC_PLLP_WB0_OVERRIDE		0xf8
40*4882a593Smuzhiyun#define PMC_IO_DPD_REQ			0x1b8
41*4882a593Smuzhiyun#define PMC_IO_DPD_STATUS		0x1bc
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun#define CLK_RESET_CCLK_BURST		0x20
44*4882a593Smuzhiyun#define CLK_RESET_CCLK_DIVIDER		0x24
45*4882a593Smuzhiyun#define CLK_RESET_SCLK_BURST		0x28
46*4882a593Smuzhiyun#define CLK_RESET_SCLK_DIVIDER		0x2c
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun#define CLK_RESET_PLLC_BASE		0x80
49*4882a593Smuzhiyun#define CLK_RESET_PLLC_MISC		0x8c
50*4882a593Smuzhiyun#define CLK_RESET_PLLM_BASE		0x90
51*4882a593Smuzhiyun#define CLK_RESET_PLLM_MISC		0x9c
52*4882a593Smuzhiyun#define CLK_RESET_PLLP_BASE		0xa0
53*4882a593Smuzhiyun#define CLK_RESET_PLLP_MISC		0xac
54*4882a593Smuzhiyun#define CLK_RESET_PLLA_BASE		0xb0
55*4882a593Smuzhiyun#define CLK_RESET_PLLA_MISC		0xbc
56*4882a593Smuzhiyun#define CLK_RESET_PLLX_BASE		0xe0
57*4882a593Smuzhiyun#define CLK_RESET_PLLX_MISC		0xe4
58*4882a593Smuzhiyun#define CLK_RESET_PLLX_MISC3		0x518
59*4882a593Smuzhiyun#define CLK_RESET_PLLX_MISC3_IDDQ	3
60*4882a593Smuzhiyun#define CLK_RESET_PLLM_MISC_IDDQ	5
61*4882a593Smuzhiyun#define CLK_RESET_PLLC_MISC_IDDQ	26
62*4882a593Smuzhiyun#define CLK_RESET_PLLP_RESHIFT		0x528
63*4882a593Smuzhiyun#define CLK_RESET_PLLP_RESHIFT_DEFAULT	0x3b
64*4882a593Smuzhiyun#define CLK_RESET_PLLP_RESHIFT_ENABLE	0x3
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun#define CLK_RESET_CLK_SOURCE_MSELECT	0x3b4
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun#define MSELECT_CLKM			(0x3 << 30)
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun#define LOCK_DELAY 50 /* safety delay after lock is detected */
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun#define TEGRA30_POWER_HOTPLUG_SHUTDOWN	(1 << 27) /* Hotplug shutdown */
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun.macro emc_device_mask, rd, base
75*4882a593Smuzhiyun	ldr	\rd, [\base, #EMC_ADR_CFG]
76*4882a593Smuzhiyun	tst	\rd, #0x1
77*4882a593Smuzhiyun	moveq	\rd, #(0x1 << 8)		@ just 1 device
78*4882a593Smuzhiyun	movne	\rd, #(0x3 << 8)		@ 2 devices
79*4882a593Smuzhiyun.endm
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun.macro emc_timing_update, rd, base
82*4882a593Smuzhiyun	mov	\rd, #1
83*4882a593Smuzhiyun	str	\rd, [\base, #EMC_TIMING_CONTROL]
84*4882a593Smuzhiyun1001:
85*4882a593Smuzhiyun	ldr	\rd, [\base, #EMC_EMC_STATUS]
86*4882a593Smuzhiyun	tst	\rd, #(0x1<<23)	@ wait EMC_STATUS_TIMING_UPDATE_STALLED is clear
87*4882a593Smuzhiyun	bne	1001b
88*4882a593Smuzhiyun.endm
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun.macro pll_enable, rd, r_car_base, pll_base, pll_misc
91*4882a593Smuzhiyun	ldr	\rd, [\r_car_base, #\pll_base]
92*4882a593Smuzhiyun	tst	\rd, #(1 << 30)
93*4882a593Smuzhiyun	orreq	\rd, \rd, #(1 << 30)
94*4882a593Smuzhiyun	streq	\rd, [\r_car_base, #\pll_base]
95*4882a593Smuzhiyun	/* Enable lock detector */
96*4882a593Smuzhiyun	.if	\pll_misc
97*4882a593Smuzhiyun	ldr	\rd, [\r_car_base, #\pll_misc]
98*4882a593Smuzhiyun	bic	\rd, \rd, #(1 << 18)
99*4882a593Smuzhiyun	str	\rd, [\r_car_base, #\pll_misc]
100*4882a593Smuzhiyun	ldr	\rd, [\r_car_base, #\pll_misc]
101*4882a593Smuzhiyun	ldr	\rd, [\r_car_base, #\pll_misc]
102*4882a593Smuzhiyun	orr	\rd, \rd, #(1 << 18)
103*4882a593Smuzhiyun	str	\rd, [\r_car_base, #\pll_misc]
104*4882a593Smuzhiyun	.endif
105*4882a593Smuzhiyun.endm
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun.macro pll_locked, rd, r_car_base, pll_base
108*4882a593Smuzhiyun1:
109*4882a593Smuzhiyun	ldr	\rd, [\r_car_base, #\pll_base]
110*4882a593Smuzhiyun	tst	\rd, #(1 << 27)
111*4882a593Smuzhiyun	beq	1b
112*4882a593Smuzhiyun.endm
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun.macro pll_iddq_exit, rd, car, iddq, iddq_bit
115*4882a593Smuzhiyun	ldr	\rd, [\car, #\iddq]
116*4882a593Smuzhiyun	bic	\rd, \rd, #(1<<\iddq_bit)
117*4882a593Smuzhiyun	str	\rd, [\car, #\iddq]
118*4882a593Smuzhiyun.endm
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun.macro pll_iddq_entry, rd, car, iddq, iddq_bit
121*4882a593Smuzhiyun	ldr	\rd, [\car, #\iddq]
122*4882a593Smuzhiyun	orr	\rd, \rd, #(1<<\iddq_bit)
123*4882a593Smuzhiyun	str	\rd, [\car, #\iddq]
124*4882a593Smuzhiyun.endm
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
127*4882a593Smuzhiyun/*
128*4882a593Smuzhiyun * tegra30_hotplug_shutdown(void)
129*4882a593Smuzhiyun *
130*4882a593Smuzhiyun * Powergates the current CPU.
131*4882a593Smuzhiyun * Should never return.
132*4882a593Smuzhiyun */
133*4882a593SmuzhiyunENTRY(tegra30_hotplug_shutdown)
134*4882a593Smuzhiyun	/* Powergate this CPU */
135*4882a593Smuzhiyun	mov	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
136*4882a593Smuzhiyun	bl	tegra30_cpu_shutdown
137*4882a593Smuzhiyun	ret	lr			@ should never get here
138*4882a593SmuzhiyunENDPROC(tegra30_hotplug_shutdown)
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun/*
141*4882a593Smuzhiyun * tegra30_cpu_shutdown(unsigned long flags)
142*4882a593Smuzhiyun *
143*4882a593Smuzhiyun * Puts the current CPU in wait-for-event mode on the flow controller
144*4882a593Smuzhiyun * and powergates it -- flags (in R0) indicate the request type.
145*4882a593Smuzhiyun *
146*4882a593Smuzhiyun * r10 = SoC ID
147*4882a593Smuzhiyun * corrupts r0-r4, r10-r12
148*4882a593Smuzhiyun */
149*4882a593SmuzhiyunENTRY(tegra30_cpu_shutdown)
150*4882a593Smuzhiyun	cpu_id	r3
151*4882a593Smuzhiyun	tegra_get_soc_id TEGRA_APB_MISC_VIRT, r10
152*4882a593Smuzhiyun	cmp	r10, #TEGRA30
153*4882a593Smuzhiyun	bne	_no_cpu0_chk	@ It's not Tegra30
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun	cmp	r3, #0
156*4882a593Smuzhiyun	reteq	lr		@ Must never be called for CPU 0
157*4882a593Smuzhiyun_no_cpu0_chk:
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun	ldr	r12, =TEGRA_FLOW_CTRL_VIRT
160*4882a593Smuzhiyun	cpu_to_csr_reg r1, r3
161*4882a593Smuzhiyun	add	r1, r1, r12	@ virtual CSR address for this CPU
162*4882a593Smuzhiyun	cpu_to_halt_reg r2, r3
163*4882a593Smuzhiyun	add	r2, r2, r12	@ virtual HALT_EVENTS address for this CPU
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun	/*
166*4882a593Smuzhiyun	 * Clear this CPU's "event" and "interrupt" flags and power gate
167*4882a593Smuzhiyun	 * it when halting but not before it is in the "WFE" state.
168*4882a593Smuzhiyun	 */
169*4882a593Smuzhiyun	movw	r12, \
170*4882a593Smuzhiyun		FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
171*4882a593Smuzhiyun		FLOW_CTRL_CSR_ENABLE
172*4882a593Smuzhiyun	cmp	r10, #TEGRA30
173*4882a593Smuzhiyun	moveq	r4, #(1 << 4)			@ wfe bitmap
174*4882a593Smuzhiyun	movne	r4, #(1 << 8)			@ wfi bitmap
175*4882a593Smuzhiyun ARM(	orr	r12, r12, r4, lsl r3	)
176*4882a593Smuzhiyun THUMB(	lsl	r4, r4, r3		)
177*4882a593Smuzhiyun THUMB(	orr	r12, r12, r4		)
178*4882a593Smuzhiyun	str	r12, [r1]
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun	/* Halt this CPU. */
181*4882a593Smuzhiyun	mov	r3, #0x400
182*4882a593Smuzhiyundelay_1:
183*4882a593Smuzhiyun	subs	r3, r3, #1			@ delay as a part of wfe war.
184*4882a593Smuzhiyun	bge	delay_1;
185*4882a593Smuzhiyun	cpsid	a				@ disable imprecise aborts.
186*4882a593Smuzhiyun	ldr	r3, [r1]			@ read CSR
187*4882a593Smuzhiyun	str	r3, [r1]			@ clear CSR
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun	tst	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
190*4882a593Smuzhiyun	beq	flow_ctrl_setting_for_lp2
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun	/* flow controller set up for hotplug */
193*4882a593Smuzhiyun	mov	r3, #FLOW_CTRL_WAITEVENT		@ For hotplug
194*4882a593Smuzhiyun	b	flow_ctrl_done
195*4882a593Smuzhiyunflow_ctrl_setting_for_lp2:
196*4882a593Smuzhiyun	/* flow controller set up for LP2 */
197*4882a593Smuzhiyun	cmp	r10, #TEGRA30
198*4882a593Smuzhiyun	moveq   r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT	@ For LP2
199*4882a593Smuzhiyun	movne	r3, #FLOW_CTRL_WAITEVENT
200*4882a593Smuzhiyun	orrne	r3, r3, #FLOW_CTRL_HALT_GIC_IRQ
201*4882a593Smuzhiyun	orrne	r3, r3, #FLOW_CTRL_HALT_GIC_FIQ
202*4882a593Smuzhiyunflow_ctrl_done:
203*4882a593Smuzhiyun	cmp	r10, #TEGRA30
204*4882a593Smuzhiyun	str	r3, [r2]
205*4882a593Smuzhiyun	ldr	r0, [r2]
206*4882a593Smuzhiyun	b	wfe_war
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun__cpu_reset_again:
209*4882a593Smuzhiyun	dsb
210*4882a593Smuzhiyun	.align 5
211*4882a593Smuzhiyun	wfeeq					@ CPU should be power gated here
212*4882a593Smuzhiyun	wfine
213*4882a593Smuzhiyunwfe_war:
214*4882a593Smuzhiyun	b	__cpu_reset_again
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun	/*
217*4882a593Smuzhiyun	 * 38 nop's, which fills rest of wfe cache line and
218*4882a593Smuzhiyun	 * 4 more cachelines with nop
219*4882a593Smuzhiyun	 */
220*4882a593Smuzhiyun	.rept 38
221*4882a593Smuzhiyun	nop
222*4882a593Smuzhiyun	.endr
223*4882a593Smuzhiyun	b	.				@ should never get here
224*4882a593Smuzhiyun
225*4882a593SmuzhiyunENDPROC(tegra30_cpu_shutdown)
226*4882a593Smuzhiyun#endif
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun#ifdef CONFIG_PM_SLEEP
229*4882a593Smuzhiyun/*
230*4882a593Smuzhiyun * tegra30_sleep_core_finish(unsigned long v2p)
231*4882a593Smuzhiyun *
232*4882a593Smuzhiyun * Enters suspend in LP0 or LP1 by turning off the MMU and jumping to
233*4882a593Smuzhiyun * tegra30_tear_down_core in IRAM
234*4882a593Smuzhiyun */
235*4882a593SmuzhiyunENTRY(tegra30_sleep_core_finish)
236*4882a593Smuzhiyun	mov	r4, r0
237*4882a593Smuzhiyun	/* Flush, disable the L1 data cache and exit SMP */
238*4882a593Smuzhiyun	mov	r0, #TEGRA_FLUSH_CACHE_ALL
239*4882a593Smuzhiyun	bl	tegra_disable_clean_inv_dcache
240*4882a593Smuzhiyun	mov	r0, r4
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun	/*
243*4882a593Smuzhiyun	 * Preload all the address literals that are needed for the
244*4882a593Smuzhiyun	 * CPU power-gating process, to avoid loading from SDRAM which
245*4882a593Smuzhiyun	 * are not supported once SDRAM is put into self-refresh.
246*4882a593Smuzhiyun	 * LP0 / LP1 use physical address, since the MMU needs to be
247*4882a593Smuzhiyun	 * disabled before putting SDRAM into self-refresh to avoid
248*4882a593Smuzhiyun	 * memory access due to page table walks.
249*4882a593Smuzhiyun	 */
250*4882a593Smuzhiyun	mov32	r4, TEGRA_PMC_BASE
251*4882a593Smuzhiyun	mov32	r5, TEGRA_CLK_RESET_BASE
252*4882a593Smuzhiyun	mov32	r6, TEGRA_FLOW_CTRL_BASE
253*4882a593Smuzhiyun	mov32	r7, TEGRA_TMRUS_BASE
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun	mov32	r3, tegra_shut_off_mmu
256*4882a593Smuzhiyun	add	r3, r3, r0
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun	mov32	r0, tegra30_tear_down_core
259*4882a593Smuzhiyun	mov32	r1, tegra30_iram_start
260*4882a593Smuzhiyun	sub	r0, r0, r1
261*4882a593Smuzhiyun	mov32	r1, TEGRA_IRAM_LPx_RESUME_AREA
262*4882a593Smuzhiyun	add	r0, r0, r1
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun	ret	r3
265*4882a593SmuzhiyunENDPROC(tegra30_sleep_core_finish)
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun/*
268*4882a593Smuzhiyun * tegra30_pm_secondary_cpu_suspend(unsigned long unused_arg)
269*4882a593Smuzhiyun *
270*4882a593Smuzhiyun * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU.
271*4882a593Smuzhiyun */
272*4882a593SmuzhiyunENTRY(tegra30_pm_secondary_cpu_suspend)
273*4882a593Smuzhiyun	mov	r7, lr
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun	/* Flush and disable the L1 data cache */
276*4882a593Smuzhiyun	mov 	r0, #TEGRA_FLUSH_CACHE_LOUIS
277*4882a593Smuzhiyun	bl	tegra_disable_clean_inv_dcache
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun	/* Powergate this CPU. */
280*4882a593Smuzhiyun	mov	r0, #0                          @ power mode flags (!hotplug)
281*4882a593Smuzhiyun	bl	tegra30_cpu_shutdown
282*4882a593Smuzhiyun	mov	r0, #1                          @ never return here
283*4882a593Smuzhiyun	ret	r7
284*4882a593SmuzhiyunENDPROC(tegra30_pm_secondary_cpu_suspend)
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun/*
287*4882a593Smuzhiyun * tegra30_tear_down_cpu
288*4882a593Smuzhiyun *
289*4882a593Smuzhiyun * Switches the CPU to enter sleep.
290*4882a593Smuzhiyun */
291*4882a593SmuzhiyunENTRY(tegra30_tear_down_cpu)
292*4882a593Smuzhiyun	mov32	r6, TEGRA_FLOW_CTRL_BASE
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun	b	tegra30_enter_sleep
295*4882a593SmuzhiyunENDPROC(tegra30_tear_down_cpu)
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun/* START OF ROUTINES COPIED TO IRAM */
298*4882a593Smuzhiyun	.align L1_CACHE_SHIFT
299*4882a593Smuzhiyun	.globl tegra30_iram_start
300*4882a593Smuzhiyuntegra30_iram_start:
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun/*
303*4882a593Smuzhiyun * tegra30_lp1_reset
304*4882a593Smuzhiyun *
305*4882a593Smuzhiyun * reset vector for LP1 restore; copied into IRAM during suspend.
306*4882a593Smuzhiyun * Brings the system back up to a safe staring point (SDRAM out of
307*4882a593Smuzhiyun * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLX,
308*4882a593Smuzhiyun * system clock running on the same PLL that it suspended at), and
309*4882a593Smuzhiyun * jumps to tegra_resume to restore virtual addressing.
310*4882a593Smuzhiyun * The physical address of tegra_resume expected to be stored in
311*4882a593Smuzhiyun * PMC_SCRATCH41.
312*4882a593Smuzhiyun *
313*4882a593Smuzhiyun * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_LPx_RESUME_AREA.
314*4882a593Smuzhiyun */
315*4882a593SmuzhiyunENTRY(tegra30_lp1_reset)
316*4882a593Smuzhiyun	/*
317*4882a593Smuzhiyun	 * The CPU and system bus are running at 32KHz and executing from
318*4882a593Smuzhiyun	 * IRAM when this code is executed; immediately switch to CLKM and
319*4882a593Smuzhiyun	 * enable PLLP, PLLM, PLLC, PLLA and PLLX.
320*4882a593Smuzhiyun	 */
321*4882a593Smuzhiyun	mov32	r0, TEGRA_CLK_RESET_BASE
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun	mov	r1, #(1 << 28)
324*4882a593Smuzhiyun	str	r1, [r0, #CLK_RESET_SCLK_BURST]
325*4882a593Smuzhiyun	str	r1, [r0, #CLK_RESET_CCLK_BURST]
326*4882a593Smuzhiyun	mov	r1, #0
327*4882a593Smuzhiyun	str	r1, [r0, #CLK_RESET_CCLK_DIVIDER]
328*4882a593Smuzhiyun	str	r1, [r0, #CLK_RESET_SCLK_DIVIDER]
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun	tegra_get_soc_id TEGRA_APB_MISC_BASE, r10
331*4882a593Smuzhiyun	cmp	r10, #TEGRA30
332*4882a593Smuzhiyun	beq	_no_pll_iddq_exit
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun	pll_iddq_exit r1, r0, CLK_RESET_PLLM_MISC, CLK_RESET_PLLM_MISC_IDDQ
335*4882a593Smuzhiyun	pll_iddq_exit r1, r0, CLK_RESET_PLLC_MISC, CLK_RESET_PLLC_MISC_IDDQ
336*4882a593Smuzhiyun	pll_iddq_exit r1, r0, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun	mov32	r7, TEGRA_TMRUS_BASE
339*4882a593Smuzhiyun	ldr	r1, [r7]
340*4882a593Smuzhiyun	add	r1, r1, #2
341*4882a593Smuzhiyun	wait_until r1, r7, r3
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun	/* enable PLLM via PMC */
344*4882a593Smuzhiyun	mov32	r2, TEGRA_PMC_BASE
345*4882a593Smuzhiyun	ldr	r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
346*4882a593Smuzhiyun	orr	r1, r1, #(1 << 12)
347*4882a593Smuzhiyun	str	r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLM_BASE, 0
350*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLC_BASE, 0
351*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLX_BASE, 0
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun	b	_pll_m_c_x_done
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun_no_pll_iddq_exit:
356*4882a593Smuzhiyun	/* enable PLLM via PMC */
357*4882a593Smuzhiyun	mov32	r2, TEGRA_PMC_BASE
358*4882a593Smuzhiyun	ldr	r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
359*4882a593Smuzhiyun	orr	r1, r1, #(1 << 12)
360*4882a593Smuzhiyun	str	r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC
363*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun_pll_m_c_x_done:
366*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC
367*4882a593Smuzhiyun	pll_enable r1, r0, CLK_RESET_PLLA_BASE, CLK_RESET_PLLA_MISC
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun	pll_locked r1, r0, CLK_RESET_PLLM_BASE
370*4882a593Smuzhiyun	pll_locked r1, r0, CLK_RESET_PLLP_BASE
371*4882a593Smuzhiyun	pll_locked r1, r0, CLK_RESET_PLLA_BASE
372*4882a593Smuzhiyun	pll_locked r1, r0, CLK_RESET_PLLC_BASE
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun	/*
375*4882a593Smuzhiyun	 * CPUFreq driver could select other PLL for CPU. PLLX will be
376*4882a593Smuzhiyun	 * enabled by the Tegra30 CLK driver on an as-needed basis, see
377*4882a593Smuzhiyun	 * tegra30_cpu_clock_resume().
378*4882a593Smuzhiyun	 */
379*4882a593Smuzhiyun	tegra_get_soc_id TEGRA_APB_MISC_BASE, r1
380*4882a593Smuzhiyun	cmp	r1, #TEGRA30
381*4882a593Smuzhiyun	beq	1f
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun	pll_locked r1, r0, CLK_RESET_PLLX_BASE
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun	ldr	r1, [r0, #CLK_RESET_PLLP_BASE]
386*4882a593Smuzhiyun	bic	r1, r1, #(1<<31)	@ disable PllP bypass
387*4882a593Smuzhiyun	str	r1, [r0, #CLK_RESET_PLLP_BASE]
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun	mov	r1, #CLK_RESET_PLLP_RESHIFT_DEFAULT
390*4882a593Smuzhiyun	str	r1, [r0, #CLK_RESET_PLLP_RESHIFT]
391*4882a593Smuzhiyun1:
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun	mov32	r7, TEGRA_TMRUS_BASE
394*4882a593Smuzhiyun	ldr	r1, [r7]
395*4882a593Smuzhiyun	add	r1, r1, #LOCK_DELAY
396*4882a593Smuzhiyun	wait_until r1, r7, r3
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun	adr	r5, tegra_sdram_pad_save
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun	ldr	r4, [r5, #0x18]		@ restore CLK_SOURCE_MSELECT
401*4882a593Smuzhiyun	str	r4, [r0, #CLK_RESET_CLK_SOURCE_MSELECT]
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun	ldr	r4, [r5, #0x1C]		@ restore SCLK_BURST
404*4882a593Smuzhiyun	str	r4, [r0, #CLK_RESET_SCLK_BURST]
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun	movw	r4, #:lower16:((1 << 28) | (0x4))	@ burst policy is PLLP
407*4882a593Smuzhiyun	movt	r4, #:upper16:((1 << 28) | (0x4))
408*4882a593Smuzhiyun	str	r4, [r0, #CLK_RESET_CCLK_BURST]
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun	/* Restore pad power state to normal */
411*4882a593Smuzhiyun	ldr	r1, [r5, #0x14]		@ PMC_IO_DPD_STATUS
412*4882a593Smuzhiyun	mvn	r1, r1
413*4882a593Smuzhiyun	bic	r1, r1, #(1 << 31)
414*4882a593Smuzhiyun	orr	r1, r1, #(1 << 30)
415*4882a593Smuzhiyun	str	r1, [r2, #PMC_IO_DPD_REQ]	@ DPD_OFF
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun	cmp	r10, #TEGRA30
418*4882a593Smuzhiyun	movweq	r0, #:lower16:TEGRA_EMC_BASE	@ r0 reserved for emc base
419*4882a593Smuzhiyun	movteq	r0, #:upper16:TEGRA_EMC_BASE
420*4882a593Smuzhiyun	cmp	r10, #TEGRA114
421*4882a593Smuzhiyun	movweq	r0, #:lower16:TEGRA_EMC0_BASE
422*4882a593Smuzhiyun	movteq	r0, #:upper16:TEGRA_EMC0_BASE
423*4882a593Smuzhiyun	cmp	r10, #TEGRA124
424*4882a593Smuzhiyun	movweq	r0, #:lower16:TEGRA124_EMC_BASE
425*4882a593Smuzhiyun	movteq	r0, #:upper16:TEGRA124_EMC_BASE
426*4882a593Smuzhiyun
427*4882a593Smuzhiyunexit_self_refresh:
428*4882a593Smuzhiyun	ldr	r1, [r5, #0xC]		@ restore EMC_XM2VTTGENPADCTRL
429*4882a593Smuzhiyun	str	r1, [r0, #EMC_XM2VTTGENPADCTRL]
430*4882a593Smuzhiyun	ldr	r1, [r5, #0x10]		@ restore EMC_XM2VTTGENPADCTRL2
431*4882a593Smuzhiyun	str	r1, [r0, #EMC_XM2VTTGENPADCTRL2]
432*4882a593Smuzhiyun	ldr	r1, [r5, #0x8]		@ restore EMC_AUTO_CAL_INTERVAL
433*4882a593Smuzhiyun	str	r1, [r0, #EMC_AUTO_CAL_INTERVAL]
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun	/* Relock DLL */
436*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_CFG_DIG_DLL]
437*4882a593Smuzhiyun	orr	r1, r1, #(1 << 30)	@ set DLL_RESET
438*4882a593Smuzhiyun	str	r1, [r0, #EMC_CFG_DIG_DLL]
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun	emc_timing_update r1, r0
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun	cmp	r10, #TEGRA114
443*4882a593Smuzhiyun	movweq	r1, #:lower16:TEGRA_EMC1_BASE
444*4882a593Smuzhiyun	movteq	r1, #:upper16:TEGRA_EMC1_BASE
445*4882a593Smuzhiyun	cmpeq	r0, r1
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_AUTO_CAL_CONFIG]
448*4882a593Smuzhiyun	orr	r1, r1, #(1 << 31)	@ set AUTO_CAL_ACTIVE
449*4882a593Smuzhiyun	orreq	r1, r1, #(1 << 27)	@ set slave mode for channel 1
450*4882a593Smuzhiyun	str	r1, [r0, #EMC_AUTO_CAL_CONFIG]
451*4882a593Smuzhiyun
452*4882a593Smuzhiyunemc_wait_auto_cal_onetime:
453*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_AUTO_CAL_STATUS]
454*4882a593Smuzhiyun	tst	r1, #(1 << 31)		@ wait until AUTO_CAL_ACTIVE is cleared
455*4882a593Smuzhiyun	bne	emc_wait_auto_cal_onetime
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_CFG]
458*4882a593Smuzhiyun	bic	r1, r1, #(1 << 31)	@ disable DRAM_CLK_STOP_PD
459*4882a593Smuzhiyun	str	r1, [r0, #EMC_CFG]
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun	mov	r1, #0
462*4882a593Smuzhiyun	str	r1, [r0, #EMC_SELF_REF]	@ take DRAM out of self refresh
463*4882a593Smuzhiyun	mov	r1, #1
464*4882a593Smuzhiyun	cmp	r10, #TEGRA30
465*4882a593Smuzhiyun	streq	r1, [r0, #EMC_NOP]
466*4882a593Smuzhiyun	streq	r1, [r0, #EMC_NOP]
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun	emc_device_mask r1, r0
469*4882a593Smuzhiyun
470*4882a593Smuzhiyunexit_selfrefresh_loop:
471*4882a593Smuzhiyun	ldr	r2, [r0, #EMC_EMC_STATUS]
472*4882a593Smuzhiyun	ands	r2, r2, r1
473*4882a593Smuzhiyun	bne	exit_selfrefresh_loop
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun	lsr	r1, r1, #8		@ devSel, bit0:dev0, bit1:dev1
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun	mov32	r7, TEGRA_TMRUS_BASE
478*4882a593Smuzhiyun	ldr	r2, [r0, #EMC_FBIO_CFG5]
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun	and	r2, r2,	#3		@ check DRAM_TYPE
481*4882a593Smuzhiyun	cmp	r2, #2
482*4882a593Smuzhiyun	beq	emc_lpddr2
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun	/* Issue a ZQ_CAL for dev0 - DDR3 */
485*4882a593Smuzhiyun	mov32	r2, 0x80000011		@ DEV_SELECTION=2, LENGTH=LONG, CMD=1
486*4882a593Smuzhiyun	str	r2, [r0, #EMC_ZQ_CAL]
487*4882a593Smuzhiyun	ldr	r2, [r7]
488*4882a593Smuzhiyun	add	r2, r2, #10
489*4882a593Smuzhiyun	wait_until r2, r7, r3
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun	tst	r1, #2
492*4882a593Smuzhiyun	beq	zcal_done
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun	/* Issue a ZQ_CAL for dev1 - DDR3 */
495*4882a593Smuzhiyun	mov32	r2, 0x40000011		@ DEV_SELECTION=1, LENGTH=LONG, CMD=1
496*4882a593Smuzhiyun	str	r2, [r0, #EMC_ZQ_CAL]
497*4882a593Smuzhiyun	ldr	r2, [r7]
498*4882a593Smuzhiyun	add	r2, r2, #10
499*4882a593Smuzhiyun	wait_until r2, r7, r3
500*4882a593Smuzhiyun	b	zcal_done
501*4882a593Smuzhiyun
502*4882a593Smuzhiyunemc_lpddr2:
503*4882a593Smuzhiyun	/* Issue a ZQ_CAL for dev0 - LPDDR2 */
504*4882a593Smuzhiyun	mov32	r2, 0x800A00AB		@ DEV_SELECTION=2, MA=10, OP=0xAB
505*4882a593Smuzhiyun	str	r2, [r0, #EMC_MRW]
506*4882a593Smuzhiyun	ldr	r2, [r7]
507*4882a593Smuzhiyun	add	r2, r2, #1
508*4882a593Smuzhiyun	wait_until r2, r7, r3
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun	tst	r1, #2
511*4882a593Smuzhiyun	beq	zcal_done
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun	/* Issue a ZQ_CAL for dev0 - LPDDR2 */
514*4882a593Smuzhiyun	mov32	r2, 0x400A00AB		@ DEV_SELECTION=1, MA=10, OP=0xAB
515*4882a593Smuzhiyun	str	r2, [r0, #EMC_MRW]
516*4882a593Smuzhiyun	ldr	r2, [r7]
517*4882a593Smuzhiyun	add	r2, r2, #1
518*4882a593Smuzhiyun	wait_until r2, r7, r3
519*4882a593Smuzhiyun
520*4882a593Smuzhiyunzcal_done:
521*4882a593Smuzhiyun	mov	r1, #0			@ unstall all transactions
522*4882a593Smuzhiyun	str	r1, [r0, #EMC_REQ_CTRL]
523*4882a593Smuzhiyun	ldr	r1, [r5, #0x4]		@ restore EMC_ZCAL_INTERVAL
524*4882a593Smuzhiyun	str	r1, [r0, #EMC_ZCAL_INTERVAL]
525*4882a593Smuzhiyun	ldr	r1, [r5, #0x0]		@ restore EMC_CFG
526*4882a593Smuzhiyun	str	r1, [r0, #EMC_CFG]
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun	emc_timing_update r1, r0
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun	/* Tegra114 had dual EMC channel, now config the other one */
531*4882a593Smuzhiyun	cmp	r10, #TEGRA114
532*4882a593Smuzhiyun	bne	__no_dual_emc_chanl
533*4882a593Smuzhiyun	mov32	r1, TEGRA_EMC1_BASE
534*4882a593Smuzhiyun	cmp	r0, r1
535*4882a593Smuzhiyun	movne	r0, r1
536*4882a593Smuzhiyun	addne	r5, r5, #0x20
537*4882a593Smuzhiyun	bne	exit_self_refresh
538*4882a593Smuzhiyun__no_dual_emc_chanl:
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun	mov32	r0, TEGRA_PMC_BASE
541*4882a593Smuzhiyun	ldr	r0, [r0, #PMC_SCRATCH41]
542*4882a593Smuzhiyun	ret	r0			@ jump to tegra_resume
543*4882a593SmuzhiyunENDPROC(tegra30_lp1_reset)
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun	.align	L1_CACHE_SHIFT
546*4882a593Smuzhiyuntegra30_sdram_pad_address:
547*4882a593Smuzhiyun	.word	TEGRA_EMC_BASE + EMC_CFG				@0x0
548*4882a593Smuzhiyun	.word	TEGRA_EMC_BASE + EMC_ZCAL_INTERVAL			@0x4
549*4882a593Smuzhiyun	.word	TEGRA_EMC_BASE + EMC_AUTO_CAL_INTERVAL			@0x8
550*4882a593Smuzhiyun	.word	TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL			@0xc
551*4882a593Smuzhiyun	.word	TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL2			@0x10
552*4882a593Smuzhiyun	.word	TEGRA_PMC_BASE + PMC_IO_DPD_STATUS			@0x14
553*4882a593Smuzhiyun	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT	@0x18
554*4882a593Smuzhiyun	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST		@0x1c
555*4882a593Smuzhiyuntegra30_sdram_pad_address_end:
556*4882a593Smuzhiyun
557*4882a593Smuzhiyuntegra114_sdram_pad_address:
558*4882a593Smuzhiyun	.word	TEGRA_EMC0_BASE + EMC_CFG				@0x0
559*4882a593Smuzhiyun	.word	TEGRA_EMC0_BASE + EMC_ZCAL_INTERVAL			@0x4
560*4882a593Smuzhiyun	.word	TEGRA_EMC0_BASE + EMC_AUTO_CAL_INTERVAL			@0x8
561*4882a593Smuzhiyun	.word	TEGRA_EMC0_BASE + EMC_XM2VTTGENPADCTRL			@0xc
562*4882a593Smuzhiyun	.word	TEGRA_EMC0_BASE + EMC_XM2VTTGENPADCTRL2			@0x10
563*4882a593Smuzhiyun	.word	TEGRA_PMC_BASE + PMC_IO_DPD_STATUS			@0x14
564*4882a593Smuzhiyun	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT	@0x18
565*4882a593Smuzhiyun	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST		@0x1c
566*4882a593Smuzhiyun	.word	TEGRA_EMC1_BASE + EMC_CFG				@0x20
567*4882a593Smuzhiyun	.word	TEGRA_EMC1_BASE + EMC_ZCAL_INTERVAL			@0x24
568*4882a593Smuzhiyun	.word	TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL			@0x28
569*4882a593Smuzhiyun	.word	TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL			@0x2c
570*4882a593Smuzhiyun	.word	TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2			@0x30
571*4882a593Smuzhiyuntegra114_sdram_pad_adress_end:
572*4882a593Smuzhiyun
573*4882a593Smuzhiyuntegra124_sdram_pad_address:
574*4882a593Smuzhiyun	.word	TEGRA124_EMC_BASE + EMC_CFG				@0x0
575*4882a593Smuzhiyun	.word	TEGRA124_EMC_BASE + EMC_ZCAL_INTERVAL			@0x4
576*4882a593Smuzhiyun	.word	TEGRA124_EMC_BASE + EMC_AUTO_CAL_INTERVAL		@0x8
577*4882a593Smuzhiyun	.word	TEGRA124_EMC_BASE + EMC_XM2VTTGENPADCTRL		@0xc
578*4882a593Smuzhiyun	.word	TEGRA124_EMC_BASE + EMC_XM2VTTGENPADCTRL2		@0x10
579*4882a593Smuzhiyun	.word	TEGRA_PMC_BASE + PMC_IO_DPD_STATUS			@0x14
580*4882a593Smuzhiyun	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT	@0x18
581*4882a593Smuzhiyun	.word	TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST		@0x1c
582*4882a593Smuzhiyuntegra124_sdram_pad_address_end:
583*4882a593Smuzhiyun
584*4882a593Smuzhiyuntegra30_sdram_pad_size:
585*4882a593Smuzhiyun	.word	tegra30_sdram_pad_address_end - tegra30_sdram_pad_address
586*4882a593Smuzhiyun
587*4882a593Smuzhiyuntegra114_sdram_pad_size:
588*4882a593Smuzhiyun	.word	tegra114_sdram_pad_adress_end - tegra114_sdram_pad_address
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun	.type	tegra_sdram_pad_save, %object
591*4882a593Smuzhiyuntegra_sdram_pad_save:
592*4882a593Smuzhiyun	.rept (tegra114_sdram_pad_adress_end - tegra114_sdram_pad_address) / 4
593*4882a593Smuzhiyun	.long	0
594*4882a593Smuzhiyun	.endr
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun/*
597*4882a593Smuzhiyun * tegra30_tear_down_core
598*4882a593Smuzhiyun *
599*4882a593Smuzhiyun * copied into and executed from IRAM
600*4882a593Smuzhiyun * puts memory in self-refresh for LP0 and LP1
601*4882a593Smuzhiyun */
602*4882a593Smuzhiyuntegra30_tear_down_core:
603*4882a593Smuzhiyun	bl	tegra30_sdram_self_refresh
604*4882a593Smuzhiyun	bl	tegra30_switch_cpu_to_clk32k
605*4882a593Smuzhiyun	b	tegra30_enter_sleep
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun/*
608*4882a593Smuzhiyun * tegra30_switch_cpu_to_clk32k
609*4882a593Smuzhiyun *
610*4882a593Smuzhiyun * In LP0 and LP1 all PLLs will be turned off. Switching the CPU and System CLK
611*4882a593Smuzhiyun * to the 32KHz clock.
612*4882a593Smuzhiyun * r4 = TEGRA_PMC_BASE
613*4882a593Smuzhiyun * r5 = TEGRA_CLK_RESET_BASE
614*4882a593Smuzhiyun * r6 = TEGRA_FLOW_CTRL_BASE
615*4882a593Smuzhiyun * r7 = TEGRA_TMRUS_BASE
616*4882a593Smuzhiyun * r10= SoC ID
617*4882a593Smuzhiyun */
618*4882a593Smuzhiyuntegra30_switch_cpu_to_clk32k:
619*4882a593Smuzhiyun	/*
620*4882a593Smuzhiyun	 * start by jumping to CLKM to safely disable PLLs, then jump to
621*4882a593Smuzhiyun	 * CLKS.
622*4882a593Smuzhiyun	 */
623*4882a593Smuzhiyun	mov	r0, #(1 << 28)
624*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_SCLK_BURST]
625*4882a593Smuzhiyun	/* 2uS delay delay between changing SCLK and CCLK */
626*4882a593Smuzhiyun	ldr	r1, [r7]
627*4882a593Smuzhiyun	add	r1, r1, #2
628*4882a593Smuzhiyun	wait_until r1, r7, r9
629*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_CCLK_BURST]
630*4882a593Smuzhiyun	mov	r0, #0
631*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_CCLK_DIVIDER]
632*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_SCLK_DIVIDER]
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun	/* switch the clock source of mselect to be CLK_M */
635*4882a593Smuzhiyun	ldr	r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT]
636*4882a593Smuzhiyun	orr	r0, r0, #MSELECT_CLKM
637*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT]
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun	/* 2uS delay delay between changing SCLK and disabling PLLs */
640*4882a593Smuzhiyun	ldr	r1, [r7]
641*4882a593Smuzhiyun	add	r1, r1, #2
642*4882a593Smuzhiyun	wait_until r1, r7, r9
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun	/* disable PLLM via PMC in LP1 */
645*4882a593Smuzhiyun	ldr	r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
646*4882a593Smuzhiyun	bic	r0, r0, #(1 << 12)
647*4882a593Smuzhiyun	str	r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun	/* disable PLLP, PLLA, PLLC and PLLX */
650*4882a593Smuzhiyun	tegra_get_soc_id TEGRA_APB_MISC_BASE, r1
651*4882a593Smuzhiyun	cmp	r1, #TEGRA30
652*4882a593Smuzhiyun	ldr	r0, [r5, #CLK_RESET_PLLP_BASE]
653*4882a593Smuzhiyun	orrne	r0, r0, #(1 << 31)	@ enable PllP bypass on fast cluster
654*4882a593Smuzhiyun	bic	r0, r0, #(1 << 30)
655*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_PLLP_BASE]
656*4882a593Smuzhiyun	beq	1f
657*4882a593Smuzhiyun	mov	r0, #CLK_RESET_PLLP_RESHIFT_ENABLE
658*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_PLLP_RESHIFT]
659*4882a593Smuzhiyun1:
660*4882a593Smuzhiyun	ldr	r0, [r5, #CLK_RESET_PLLA_BASE]
661*4882a593Smuzhiyun	bic	r0, r0, #(1 << 30)
662*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_PLLA_BASE]
663*4882a593Smuzhiyun	ldr	r0, [r5, #CLK_RESET_PLLC_BASE]
664*4882a593Smuzhiyun	bic	r0, r0, #(1 << 30)
665*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_PLLC_BASE]
666*4882a593Smuzhiyun	ldr	r0, [r5, #CLK_RESET_PLLX_BASE]
667*4882a593Smuzhiyun	bic	r0, r0, #(1 << 30)
668*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_PLLX_BASE]
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun	cmp	r10, #TEGRA30
671*4882a593Smuzhiyun	beq	_no_pll_in_iddq
672*4882a593Smuzhiyun	pll_iddq_entry r1, r5, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ
673*4882a593Smuzhiyun_no_pll_in_iddq:
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun	/*
676*4882a593Smuzhiyun	 * Switch to clk_s (32KHz); bits 28:31=0
677*4882a593Smuzhiyun	 * Enable burst on CPU IRQ; bit 24=1
678*4882a593Smuzhiyun	 * Set IRQ burst clock source to clk_m; bits 10:8=0
679*4882a593Smuzhiyun	 */
680*4882a593Smuzhiyun	mov	r0, #(1 << 24)
681*4882a593Smuzhiyun	str	r0, [r5, #CLK_RESET_SCLK_BURST]
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun	ret	lr
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun/*
686*4882a593Smuzhiyun * tegra30_enter_sleep
687*4882a593Smuzhiyun *
688*4882a593Smuzhiyun * uses flow controller to enter sleep state
689*4882a593Smuzhiyun * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
690*4882a593Smuzhiyun * executes from SDRAM with target state is LP2
691*4882a593Smuzhiyun * r6 = TEGRA_FLOW_CTRL_BASE
692*4882a593Smuzhiyun */
693*4882a593Smuzhiyuntegra30_enter_sleep:
694*4882a593Smuzhiyun	cpu_id	r1
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun	cpu_to_csr_reg	r2, r1
697*4882a593Smuzhiyun	ldr	r0, [r6, r2]
698*4882a593Smuzhiyun	orr	r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
699*4882a593Smuzhiyun	orr	r0, r0, #FLOW_CTRL_CSR_ENABLE
700*4882a593Smuzhiyun	str	r0, [r6, r2]
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun	tegra_get_soc_id TEGRA_APB_MISC_BASE, r10
703*4882a593Smuzhiyun	cmp	r10, #TEGRA30
704*4882a593Smuzhiyun	mov	r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
705*4882a593Smuzhiyun	orreq	r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
706*4882a593Smuzhiyun	orrne   r0, r0, #FLOW_CTRL_HALT_LIC_IRQ | FLOW_CTRL_HALT_LIC_FIQ
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun	cpu_to_halt_reg r2, r1
709*4882a593Smuzhiyun	str	r0, [r6, r2]
710*4882a593Smuzhiyun	dsb
711*4882a593Smuzhiyun	ldr	r0, [r6, r2] /* memory barrier */
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun	cmp	r10, #TEGRA30
714*4882a593Smuzhiyunhalted:
715*4882a593Smuzhiyun	isb
716*4882a593Smuzhiyun	dsb
717*4882a593Smuzhiyun	wfine	/* CPU should be power gated here */
718*4882a593Smuzhiyun	wfeeq
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun	/* !!!FIXME!!! Implement halt failure handler */
721*4882a593Smuzhiyun	b	halted
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun/*
724*4882a593Smuzhiyun * tegra30_sdram_self_refresh
725*4882a593Smuzhiyun *
726*4882a593Smuzhiyun * called with MMU off and caches disabled
727*4882a593Smuzhiyun * must be executed from IRAM
728*4882a593Smuzhiyun * r4 = TEGRA_PMC_BASE
729*4882a593Smuzhiyun * r5 = TEGRA_CLK_RESET_BASE
730*4882a593Smuzhiyun * r6 = TEGRA_FLOW_CTRL_BASE
731*4882a593Smuzhiyun * r7 = TEGRA_TMRUS_BASE
732*4882a593Smuzhiyun * r10= SoC ID
733*4882a593Smuzhiyun */
734*4882a593Smuzhiyuntegra30_sdram_self_refresh:
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun	adr	r8, tegra_sdram_pad_save
737*4882a593Smuzhiyun	tegra_get_soc_id TEGRA_APB_MISC_BASE, r10
738*4882a593Smuzhiyun	cmp	r10, #TEGRA30
739*4882a593Smuzhiyun	adreq	r2, tegra30_sdram_pad_address
740*4882a593Smuzhiyun	ldreq	r3, tegra30_sdram_pad_size
741*4882a593Smuzhiyun	cmp	r10, #TEGRA114
742*4882a593Smuzhiyun	adreq	r2, tegra114_sdram_pad_address
743*4882a593Smuzhiyun	ldreq	r3, tegra114_sdram_pad_size
744*4882a593Smuzhiyun	cmp	r10, #TEGRA124
745*4882a593Smuzhiyun	adreq	r2, tegra124_sdram_pad_address
746*4882a593Smuzhiyun	ldreq	r3, tegra30_sdram_pad_size
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun	mov	r9, #0
749*4882a593Smuzhiyun
750*4882a593Smuzhiyunpadsave:
751*4882a593Smuzhiyun	ldr	r0, [r2, r9]		@ r0 is the addr in the pad_address
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun	ldr	r1, [r0]
754*4882a593Smuzhiyun	str	r1, [r8, r9]		@ save the content of the addr
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun	add	r9, r9, #4
757*4882a593Smuzhiyun	cmp	r3, r9
758*4882a593Smuzhiyun	bne	padsave
759*4882a593Smuzhiyunpadsave_done:
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun	dsb
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun	cmp	r10, #TEGRA30
764*4882a593Smuzhiyun	ldreq	r0, =TEGRA_EMC_BASE	@ r0 reserved for emc base addr
765*4882a593Smuzhiyun	cmp	r10, #TEGRA114
766*4882a593Smuzhiyun	ldreq	r0, =TEGRA_EMC0_BASE
767*4882a593Smuzhiyun	cmp	r10, #TEGRA124
768*4882a593Smuzhiyun	ldreq	r0, =TEGRA124_EMC_BASE
769*4882a593Smuzhiyun
770*4882a593Smuzhiyunenter_self_refresh:
771*4882a593Smuzhiyun	cmp	r10, #TEGRA30
772*4882a593Smuzhiyun	mov	r1, #0
773*4882a593Smuzhiyun	str	r1, [r0, #EMC_ZCAL_INTERVAL]
774*4882a593Smuzhiyun	str	r1, [r0, #EMC_AUTO_CAL_INTERVAL]
775*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_CFG]
776*4882a593Smuzhiyun	bic	r1, r1, #(1 << 28)
777*4882a593Smuzhiyun	bicne	r1, r1, #(1 << 29)
778*4882a593Smuzhiyun	str	r1, [r0, #EMC_CFG]	@ disable DYN_SELF_REF
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun	emc_timing_update r1, r0
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun	ldr	r1, [r7]
783*4882a593Smuzhiyun	add	r1, r1, #5
784*4882a593Smuzhiyun	wait_until r1, r7, r2
785*4882a593Smuzhiyun
786*4882a593Smuzhiyunemc_wait_auto_cal:
787*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_AUTO_CAL_STATUS]
788*4882a593Smuzhiyun	tst	r1, #(1 << 31)		@ wait until AUTO_CAL_ACTIVE is cleared
789*4882a593Smuzhiyun	bne	emc_wait_auto_cal
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun	mov	r1, #3
792*4882a593Smuzhiyun	str	r1, [r0, #EMC_REQ_CTRL]	@ stall incoming DRAM requests
793*4882a593Smuzhiyun
794*4882a593Smuzhiyunemcidle:
795*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_EMC_STATUS]
796*4882a593Smuzhiyun	tst	r1, #4
797*4882a593Smuzhiyun	beq	emcidle
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun	mov	r1, #1
800*4882a593Smuzhiyun	str	r1, [r0, #EMC_SELF_REF]
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun	emc_device_mask r1, r0
803*4882a593Smuzhiyun
804*4882a593Smuzhiyunemcself:
805*4882a593Smuzhiyun	ldr	r2, [r0, #EMC_EMC_STATUS]
806*4882a593Smuzhiyun	and	r2, r2, r1
807*4882a593Smuzhiyun	cmp	r2, r1
808*4882a593Smuzhiyun	bne	emcself			@ loop until DDR in self-refresh
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun	/* Put VTTGEN in the lowest power mode */
811*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_XM2VTTGENPADCTRL]
812*4882a593Smuzhiyun	mov32	r2, 0xF8F8FFFF	@ clear XM2VTTGEN_DRVUP and XM2VTTGEN_DRVDN
813*4882a593Smuzhiyun	and	r1, r1, r2
814*4882a593Smuzhiyun	str	r1, [r0, #EMC_XM2VTTGENPADCTRL]
815*4882a593Smuzhiyun	ldr	r1, [r0, #EMC_XM2VTTGENPADCTRL2]
816*4882a593Smuzhiyun	cmp	r10, #TEGRA30
817*4882a593Smuzhiyun	orreq	r1, r1, #7		@ set E_NO_VTTGEN
818*4882a593Smuzhiyun	orrne	r1, r1, #0x3f
819*4882a593Smuzhiyun	str	r1, [r0, #EMC_XM2VTTGENPADCTRL2]
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun	emc_timing_update r1, r0
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun	/* Tegra114 had dual EMC channel, now config the other one */
824*4882a593Smuzhiyun	cmp	r10, #TEGRA114
825*4882a593Smuzhiyun	bne	no_dual_emc_chanl
826*4882a593Smuzhiyun	mov32	r1, TEGRA_EMC1_BASE
827*4882a593Smuzhiyun	cmp	r0, r1
828*4882a593Smuzhiyun	movne	r0, r1
829*4882a593Smuzhiyun	bne	enter_self_refresh
830*4882a593Smuzhiyunno_dual_emc_chanl:
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun	ldr	r1, [r4, #PMC_CTRL]
833*4882a593Smuzhiyun	tst	r1, #PMC_CTRL_SIDE_EFFECT_LP0
834*4882a593Smuzhiyun	bne	pmc_io_dpd_skip
835*4882a593Smuzhiyun	/*
836*4882a593Smuzhiyun	 * Put DDR_DATA, DISC_ADDR_CMD, DDR_ADDR_CMD, POP_ADDR_CMD, POP_CLK
837*4882a593Smuzhiyun	 * and COMP in the lowest power mode when LP1.
838*4882a593Smuzhiyun	 */
839*4882a593Smuzhiyun	mov32	r1, 0x8EC00000
840*4882a593Smuzhiyun	str	r1, [r4, #PMC_IO_DPD_REQ]
841*4882a593Smuzhiyunpmc_io_dpd_skip:
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun	dsb
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun	ret	lr
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun	.ltorg
848*4882a593Smuzhiyun/* dummy symbol for end of IRAM */
849*4882a593Smuzhiyun	.align L1_CACHE_SHIFT
850*4882a593Smuzhiyun	.global tegra30_iram_end
851*4882a593Smuzhiyuntegra30_iram_end:
852*4882a593Smuzhiyun	b	.
853*4882a593Smuzhiyun#endif
854