GNU Linux-libre 4.9.306-gnu1
[releases.git] / arch / blackfin / mach-bf609 / dpm.S
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
10 ENTRY(_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;
35 ENDPROC(_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  */
40 ENTRY(_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;
69 ENDPROC(_dummy_deepsleep)
70
71 ENTRY(_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;
125 ENDPROC(_enter_deepsleep)
126
127 .section .text
128 ENTRY(_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
156 ENDPROC(_bf609_hibernate)
157