xref: /OK3568_Linux_fs/kernel/arch/arm/mach-davinci/sleep.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * (C) Copyright 2009, Texas Instruments, Inc. https://www.ti.com/
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun/* replicated define because linux/bitops.h cannot be included in assembly */
7*4882a593Smuzhiyun#define BIT(nr)			(1 << (nr))
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun#include <linux/linkage.h>
10*4882a593Smuzhiyun#include <asm/assembler.h>
11*4882a593Smuzhiyun#include "psc.h"
12*4882a593Smuzhiyun#include "ddr2.h"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun#include "clock.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun/* Arbitrary, hardware currently does not update PHYRDY correctly */
17*4882a593Smuzhiyun#define PHYRDY_CYCLES		0x1000
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
20*4882a593Smuzhiyun#define PLL_BYPASS_CYCLES	(PLL_BYPASS_TIME * 25)
21*4882a593Smuzhiyun#define PLL_RESET_CYCLES	(PLL_RESET_TIME	* 25)
22*4882a593Smuzhiyun#define PLL_LOCK_CYCLES		(PLL_LOCK_TIME * 25)
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun#define DEEPSLEEP_SLEEPENABLE_BIT	BIT(31)
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun	.text
27*4882a593Smuzhiyun	.arch	armv5te
28*4882a593Smuzhiyun/*
29*4882a593Smuzhiyun * Move DaVinci into deep sleep state
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * Note: This code is copied to internal SRAM by PM code. When the DaVinci
32*4882a593Smuzhiyun *	 wakes up it continues execution at the point it went to sleep.
33*4882a593Smuzhiyun * Register Usage:
34*4882a593Smuzhiyun * 	r0: contains virtual base for DDR2 controller
35*4882a593Smuzhiyun * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
36*4882a593Smuzhiyun * 	r2: contains PSC number for DDR2
37*4882a593Smuzhiyun * 	r3: contains virtual base DDR2 PLL controller
38*4882a593Smuzhiyun * 	r4: contains virtual address of the DEEPSLEEP register
39*4882a593Smuzhiyun */
40*4882a593SmuzhiyunENTRY(davinci_cpu_suspend)
41*4882a593Smuzhiyun	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun	ldr 	ip, CACHE_FLUSH
44*4882a593Smuzhiyun	blx	ip
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun	ldmia	r0, {r0-r4}
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun	/*
49*4882a593Smuzhiyun	 * Switch DDR to self-refresh mode.
50*4882a593Smuzhiyun	 */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun	/* calculate SDRCR address */
53*4882a593Smuzhiyun	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
54*4882a593Smuzhiyun	bic	ip, ip, #DDR2_SRPD_BIT
55*4882a593Smuzhiyun	orr	ip, ip, #DDR2_LPMODEN_BIT
56*4882a593Smuzhiyun	str	ip, [r0, #DDR2_SDRCR_OFFSET]
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
59*4882a593Smuzhiyun	orr	ip, ip, #DDR2_MCLKSTOPEN_BIT
60*4882a593Smuzhiyun	str	ip, [r0, #DDR2_SDRCR_OFFSET]
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun       mov	ip, #PHYRDY_CYCLES
63*4882a593Smuzhiyun1:     subs	ip, ip, #0x1
64*4882a593Smuzhiyun       bne	1b
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun       /* Disable DDR2 LPSC */
67*4882a593Smuzhiyun	mov	r7, r0
68*4882a593Smuzhiyun	mov	r0, #0x2
69*4882a593Smuzhiyun	bl davinci_ddr_psc_config
70*4882a593Smuzhiyun	mov	r0, r7
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun	/* Disable clock to DDR PHY */
73*4882a593Smuzhiyun	ldr	ip, [r3, #PLLDIV1]
74*4882a593Smuzhiyun	bic	ip, ip, #PLLDIV_EN
75*4882a593Smuzhiyun	str	ip, [r3, #PLLDIV1]
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun	/* Put the DDR PLL in bypass and power down */
78*4882a593Smuzhiyun	ldr	ip, [r3, #PLLCTL]
79*4882a593Smuzhiyun	bic	ip, ip, #PLLCTL_PLLENSRC
80*4882a593Smuzhiyun	bic	ip, ip, #PLLCTL_PLLEN
81*4882a593Smuzhiyun	str	ip, [r3, #PLLCTL]
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun	/* Wait for PLL to switch to bypass */
84*4882a593Smuzhiyun       mov	ip, #PLL_BYPASS_CYCLES
85*4882a593Smuzhiyun2:     subs	ip, ip, #0x1
86*4882a593Smuzhiyun       bne	2b
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun       /* Power down the PLL */
89*4882a593Smuzhiyun	ldr	ip, [r3, #PLLCTL]
90*4882a593Smuzhiyun	orr	ip, ip, #PLLCTL_PLLPWRDN
91*4882a593Smuzhiyun	str	ip, [r3, #PLLCTL]
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun	/* Go to deep sleep */
94*4882a593Smuzhiyun	ldr	ip, [r4]
95*4882a593Smuzhiyun	orr	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
96*4882a593Smuzhiyun	/* System goes to sleep beyond after this instruction */
97*4882a593Smuzhiyun	str	ip, [r4]
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun	/* Wake up from sleep */
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun	/* Clear sleep enable */
102*4882a593Smuzhiyun	ldr	ip, [r4]
103*4882a593Smuzhiyun	bic	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
104*4882a593Smuzhiyun	str	ip, [r4]
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun	/* initialize the DDR PLL controller */
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun	/* Put PLL in reset */
109*4882a593Smuzhiyun	ldr	ip, [r3, #PLLCTL]
110*4882a593Smuzhiyun	bic	ip, ip, #PLLCTL_PLLRST
111*4882a593Smuzhiyun	str	ip, [r3, #PLLCTL]
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun	/* Clear PLL power down */
114*4882a593Smuzhiyun	ldr	ip, [r3, #PLLCTL]
115*4882a593Smuzhiyun	bic	ip, ip, #PLLCTL_PLLPWRDN
116*4882a593Smuzhiyun	str	ip, [r3, #PLLCTL]
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun       mov	ip, #PLL_RESET_CYCLES
119*4882a593Smuzhiyun3:     subs	ip, ip, #0x1
120*4882a593Smuzhiyun       bne	3b
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun       /* Bring PLL out of reset */
123*4882a593Smuzhiyun	ldr	ip, [r3, #PLLCTL]
124*4882a593Smuzhiyun	orr	ip, ip, #PLLCTL_PLLRST
125*4882a593Smuzhiyun	str	ip, [r3, #PLLCTL]
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun	/* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
128*4882a593Smuzhiyun       mov	ip, #PLL_LOCK_CYCLES
129*4882a593Smuzhiyun4:     subs	ip, ip, #0x1
130*4882a593Smuzhiyun       bne	4b
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun       /* Remove PLL from bypass mode */
133*4882a593Smuzhiyun	ldr	ip, [r3, #PLLCTL]
134*4882a593Smuzhiyun	bic	ip, ip, #PLLCTL_PLLENSRC
135*4882a593Smuzhiyun	orr	ip, ip, #PLLCTL_PLLEN
136*4882a593Smuzhiyun	str	ip, [r3, #PLLCTL]
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun	/* Start 2x clock to DDR2 */
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun	ldr	ip, [r3, #PLLDIV1]
141*4882a593Smuzhiyun	orr	ip, ip, #PLLDIV_EN
142*4882a593Smuzhiyun	str	ip, [r3, #PLLDIV1]
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun	/* Enable VCLK */
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun       /* Enable DDR2 LPSC */
147*4882a593Smuzhiyun	mov	r7, r0
148*4882a593Smuzhiyun	mov	r0, #0x3
149*4882a593Smuzhiyun	bl davinci_ddr_psc_config
150*4882a593Smuzhiyun	mov	r0, r7
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun	/* clear  MCLKSTOPEN */
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
155*4882a593Smuzhiyun	bic	ip, ip, #DDR2_MCLKSTOPEN_BIT
156*4882a593Smuzhiyun	str	ip, [r0, #DDR2_SDRCR_OFFSET]
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
159*4882a593Smuzhiyun	bic	ip, ip, #DDR2_LPMODEN_BIT
160*4882a593Smuzhiyun	str	ip, [r0, #DDR2_SDRCR_OFFSET]
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun	/* Restore registers and return */
163*4882a593Smuzhiyun	ldmfd   sp!, {r0-r12, pc}
164*4882a593Smuzhiyun
165*4882a593SmuzhiyunENDPROC(davinci_cpu_suspend)
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun/*
168*4882a593Smuzhiyun * Disables or Enables DDR2 LPSC
169*4882a593Smuzhiyun * Register Usage:
170*4882a593Smuzhiyun * 	r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
171*4882a593Smuzhiyun * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
172*4882a593Smuzhiyun * 	r2: contains PSC number for DDR2
173*4882a593Smuzhiyun */
174*4882a593SmuzhiyunENTRY(davinci_ddr_psc_config)
175*4882a593Smuzhiyun	/* Set next state in mdctl for DDR2 */
176*4882a593Smuzhiyun	mov	r6, #MDCTL
177*4882a593Smuzhiyun	add	r6, r6, r2, lsl #2
178*4882a593Smuzhiyun	ldr	ip, [r1, r6]
179*4882a593Smuzhiyun	bic	ip, ip, #MDSTAT_STATE_MASK
180*4882a593Smuzhiyun	orr	ip, ip, r0
181*4882a593Smuzhiyun	str	ip, [r1, r6]
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun	/* Enable the Power Domain Transition Command */
184*4882a593Smuzhiyun	ldr	ip, [r1, #PTCMD]
185*4882a593Smuzhiyun	orr	ip, ip, #0x1
186*4882a593Smuzhiyun	str	ip, [r1, #PTCMD]
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun	/* Check for Transition Complete (PTSTAT) */
189*4882a593Smuzhiyunptstat_done:
190*4882a593Smuzhiyun	ldr	ip, [r1, #PTSTAT]
191*4882a593Smuzhiyun	and	ip, ip, #0x1
192*4882a593Smuzhiyun	cmp 	ip, #0x0
193*4882a593Smuzhiyun	bne	ptstat_done
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun	/* Check for DDR2 clock disable completion; */
196*4882a593Smuzhiyun	mov	r6, #MDSTAT
197*4882a593Smuzhiyun	add	r6, r6, r2, lsl #2
198*4882a593Smuzhiyunddr2clk_stop_done:
199*4882a593Smuzhiyun	ldr	ip, [r1, r6]
200*4882a593Smuzhiyun	and	ip, ip, #MDSTAT_STATE_MASK
201*4882a593Smuzhiyun	cmp	ip, r0
202*4882a593Smuzhiyun	bne	ddr2clk_stop_done
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun	ret	lr
205*4882a593SmuzhiyunENDPROC(davinci_ddr_psc_config)
206*4882a593Smuzhiyun
207*4882a593SmuzhiyunCACHE_FLUSH:
208*4882a593Smuzhiyun#ifdef CONFIG_CPU_V6
209*4882a593Smuzhiyun	.word	v6_flush_kern_cache_all
210*4882a593Smuzhiyun#else
211*4882a593Smuzhiyun	.word   arm926_flush_kern_cache_all
212*4882a593Smuzhiyun#endif
213*4882a593Smuzhiyun
214*4882a593SmuzhiyunENTRY(davinci_cpu_suspend_sz)
215*4882a593Smuzhiyun	.word	. - davinci_cpu_suspend
216*4882a593SmuzhiyunENDPROC(davinci_cpu_suspend_sz)
217