1#include <linux/linkage.h>
2#include <asm/blackfin.h>
3#include <asm/dpmc.h>
4
5#include <asm/context.S>
6
7#define PM_STACK   (COREA_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
8
9.section .l1.text
10ENTRY(_enter_hibernate)
11	/* switch stack to L1 scratch, prepare for ddr srfr */
12	P0.H = HI(PM_STACK);
13	P0.L = LO(PM_STACK);
14	SP = P0;
15
16	call _bf609_ddr_sr;
17	call _bfin_hibernate_syscontrol;
18
19	P0.H = HI(DPM0_RESTORE4);
20	P0.L = LO(DPM0_RESTORE4);
21	P1.H = _bf609_pm_data;
22	P1.L = _bf609_pm_data;
23	[P0] = P1;
24
25	P0.H = HI(DPM0_CTL);
26	P0.L = LO(DPM0_CTL);
27	R3.H = HI(0x00000010);
28	R3.L = LO(0x00000010);
29
30	bfin_init_pm_bench_cycles;
31
32	[P0] = R3;
33
34	SSYNC;
35ENDPROC(_enter_hibernate)
36
37/* DPM wake up interrupt won't wake up core on bf60x if its core IMASK
38 * is disabled. This behavior differ from bf5xx serial processor.
39 */
40ENTRY(_dummy_deepsleep)
41	[--sp] = SYSCFG;
42	[--sp] = (R7:0,P5:0);
43	cli r0;
44
45	/* get wake up interrupt ID */
46	P0.l = LO(SEC_SCI_BASE + SEC_CSID);
47	P0.h = HI(SEC_SCI_BASE + SEC_CSID);
48	R0 = [P0];
49
50	/* ACK wake up interrupt in SEC */
51	P1.l = LO(SEC_END);
52	P1.h = HI(SEC_END);
53
54	[P1] = R0;
55	SSYNC;
56
57	/* restore EVT 11 entry */
58	p0.h = hi(EVT11);
59	p0.l = lo(EVT11);
60	p1.h = _evt_evt11;
61	p1.l = _evt_evt11;
62
63	[p0] = p1;
64	SSYNC;
65
66	(R7:0,P5:0) = [sp++];
67	SYSCFG = [sp++];
68	RTI;
69ENDPROC(_dummy_deepsleep)
70
71ENTRY(_enter_deepsleep)
72	LINK 0xC;
73	[--sp] = (R7:0,P5:0);
74
75	/* Change EVT 11 entry to dummy handler for wake up event */
76	p0.h = hi(EVT11);
77	p0.l = lo(EVT11);
78	p1.h = _dummy_deepsleep;
79	p1.l = _dummy_deepsleep;
80
81	[p0] = p1;
82
83	P0.H = HI(PM_STACK);
84	P0.L = LO(PM_STACK);
85
86	EX_SCRATCH_REG = SP;
87	SP = P0;
88
89	SSYNC;
90
91	/* should put ddr to self refresh mode before sleep */
92	call _bf609_ddr_sr;
93
94	/* Set DPM controller to deep sleep mode */
95	P0.H = HI(DPM0_CTL);
96	P0.L = LO(DPM0_CTL);
97	R3.H = HI(0x00000008);
98	R3.L = LO(0x00000008);
99	[P0] = R3;
100	CSYNC;
101
102	/* Enable evt 11 in IMASK before idle, otherwise core doesn't wake up. */
103	r0.l = 0x800;
104	r0.h = 0;
105	sti r0;
106	SSYNC;
107
108	bfin_init_pm_bench_cycles;
109
110	/* Fall into deep sleep in idle*/
111	idle;
112	SSYNC;
113
114	/* Restore PLL after wake up from deep sleep */
115	call _bf609_resume_ccbuf;
116
117	/* turn ddr out of self refresh mode */
118	call _bf609_ddr_sr_exit;
119
120	SP = EX_SCRATCH_REG;
121
122	(R7:0,P5:0) = [SP++];
123	UNLINK;
124	RTS;
125ENDPROC(_enter_deepsleep)
126
127.section .text
128ENTRY(_bf609_hibernate)
129	bfin_cpu_reg_save;
130	bfin_core_mmr_save;
131
132	P0.H = _bf609_pm_data;
133	P0.L = _bf609_pm_data;
134	R1.H = 0xDEAD;
135	R1.L = 0xBEEF;
136	R2.H = .Lpm_resume_here;
137	R2.L = .Lpm_resume_here;
138	[P0++] = R1;
139	[P0++] = R2;
140	[P0++] = SP;
141
142	P1.H = _enter_hibernate;
143	P1.L = _enter_hibernate;
144
145	call (P1);
146.Lpm_resume_here:
147
148	bfin_core_mmr_restore;
149	bfin_cpu_reg_restore;
150
151	[--sp] = RETI;  /* Clear Global Interrupt Disable */
152	SP += 4;
153
154	RTS;
155
156ENDPROC(_bf609_hibernate)
157
158