Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/blackfin/mach-common/pm.c
10817 views
1
/*
2
* Blackfin power management
3
*
4
* Copyright 2006-2009 Analog Devices Inc.
5
*
6
* Licensed under the GPL-2
7
* based on arm/mach-omap/pm.c
8
* Copyright 2001, Cliff Brake <[email protected]> and others
9
*/
10
11
#include <linux/suspend.h>
12
#include <linux/sched.h>
13
#include <linux/proc_fs.h>
14
#include <linux/slab.h>
15
#include <linux/io.h>
16
#include <linux/irq.h>
17
18
#include <asm/cplb.h>
19
#include <asm/gpio.h>
20
#include <asm/dma.h>
21
#include <asm/dpmc.h>
22
23
24
void bfin_pm_suspend_standby_enter(void)
25
{
26
bfin_pm_standby_setup();
27
28
#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
29
sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
30
#else
31
sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
32
#endif
33
34
bfin_pm_standby_restore();
35
36
#ifdef SIC_IWR0
37
bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
38
# ifdef SIC_IWR1
39
/* BF52x system reset does not properly reset SIC_IWR1 which
40
* will screw up the bootrom as it relies on MDMA0/1 waking it
41
* up from IDLE instructions. See this report for more info:
42
* http://blackfin.uclinux.org/gf/tracker/4323
43
*/
44
if (ANOMALY_05000435)
45
bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
46
else
47
bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
48
# endif
49
# ifdef SIC_IWR2
50
bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
51
# endif
52
#else
53
bfin_write_SIC_IWR(IWR_DISABLE_ALL);
54
#endif
55
}
56
57
int bf53x_suspend_l1_mem(unsigned char *memptr)
58
{
59
dma_memcpy_nocache(memptr, (const void *) L1_CODE_START,
60
L1_CODE_LENGTH);
61
dma_memcpy_nocache(memptr + L1_CODE_LENGTH,
62
(const void *) L1_DATA_A_START, L1_DATA_A_LENGTH);
63
dma_memcpy_nocache(memptr + L1_CODE_LENGTH + L1_DATA_A_LENGTH,
64
(const void *) L1_DATA_B_START, L1_DATA_B_LENGTH);
65
memcpy(memptr + L1_CODE_LENGTH + L1_DATA_A_LENGTH +
66
L1_DATA_B_LENGTH, (const void *) L1_SCRATCH_START,
67
L1_SCRATCH_LENGTH);
68
69
return 0;
70
}
71
72
int bf53x_resume_l1_mem(unsigned char *memptr)
73
{
74
dma_memcpy_nocache((void *) L1_CODE_START, memptr, L1_CODE_LENGTH);
75
dma_memcpy_nocache((void *) L1_DATA_A_START, memptr + L1_CODE_LENGTH,
76
L1_DATA_A_LENGTH);
77
dma_memcpy_nocache((void *) L1_DATA_B_START, memptr + L1_CODE_LENGTH +
78
L1_DATA_A_LENGTH, L1_DATA_B_LENGTH);
79
memcpy((void *) L1_SCRATCH_START, memptr + L1_CODE_LENGTH +
80
L1_DATA_A_LENGTH + L1_DATA_B_LENGTH, L1_SCRATCH_LENGTH);
81
82
return 0;
83
}
84
85
#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
86
static void flushinv_all_dcache(void)
87
{
88
u32 way, bank, subbank, set;
89
u32 status, addr;
90
u32 dmem_ctl = bfin_read_DMEM_CONTROL();
91
92
for (bank = 0; bank < 2; ++bank) {
93
if (!(dmem_ctl & (1 << (DMC1_P - bank))))
94
continue;
95
96
for (way = 0; way < 2; ++way)
97
for (subbank = 0; subbank < 4; ++subbank)
98
for (set = 0; set < 64; ++set) {
99
100
bfin_write_DTEST_COMMAND(
101
way << 26 |
102
bank << 23 |
103
subbank << 16 |
104
set << 5
105
);
106
CSYNC();
107
status = bfin_read_DTEST_DATA0();
108
109
/* only worry about valid/dirty entries */
110
if ((status & 0x3) != 0x3)
111
continue;
112
113
/* construct the address using the tag */
114
addr = (status & 0xFFFFC800) | (subbank << 12) | (set << 5);
115
116
/* flush it */
117
__asm__ __volatile__("FLUSHINV[%0];" : : "a"(addr));
118
}
119
}
120
}
121
#endif
122
123
int bfin_pm_suspend_mem_enter(void)
124
{
125
int wakeup, ret;
126
127
unsigned char *memptr = kmalloc(L1_CODE_LENGTH + L1_DATA_A_LENGTH
128
+ L1_DATA_B_LENGTH + L1_SCRATCH_LENGTH,
129
GFP_KERNEL);
130
131
if (memptr == NULL) {
132
panic("bf53x_suspend_l1_mem malloc failed");
133
return -ENOMEM;
134
}
135
136
wakeup = bfin_read_VR_CTL() & ~FREQ;
137
wakeup |= SCKELOW;
138
139
#ifdef CONFIG_PM_BFIN_WAKE_PH6
140
wakeup |= PHYWE;
141
#endif
142
#ifdef CONFIG_PM_BFIN_WAKE_GP
143
wakeup |= GPWE;
144
#endif
145
146
ret = blackfin_dma_suspend();
147
148
if (ret) {
149
kfree(memptr);
150
return ret;
151
}
152
153
bfin_gpio_pm_hibernate_suspend();
154
155
#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
156
flushinv_all_dcache();
157
#endif
158
_disable_dcplb();
159
_disable_icplb();
160
bf53x_suspend_l1_mem(memptr);
161
162
do_hibernate(wakeup | vr_wakeup); /* See you later! */
163
164
bf53x_resume_l1_mem(memptr);
165
166
_enable_icplb();
167
_enable_dcplb();
168
169
bfin_gpio_pm_hibernate_restore();
170
blackfin_dma_resume();
171
172
kfree(memptr);
173
174
return 0;
175
}
176
177
/*
178
* bfin_pm_valid - Tell the PM core that we only support the standby sleep
179
* state
180
* @state: suspend state we're checking.
181
*
182
*/
183
static int bfin_pm_valid(suspend_state_t state)
184
{
185
return (state == PM_SUSPEND_STANDBY
186
#if !(defined(BF533_FAMILY) || defined(CONFIG_BF561))
187
/*
188
* On BF533/2/1:
189
* If we enter Hibernate the SCKE Pin is driven Low,
190
* so that the SDRAM enters Self Refresh Mode.
191
* However when the reset sequence that follows hibernate
192
* state is executed, SCKE is driven High, taking the
193
* SDRAM out of Self Refresh.
194
*
195
* If you reconfigure and access the SDRAM "very quickly",
196
* you are likely to avoid errors, otherwise the SDRAM
197
* start losing its contents.
198
* An external HW workaround is possible using logic gates.
199
*/
200
|| state == PM_SUSPEND_MEM
201
#endif
202
);
203
}
204
205
/*
206
* bfin_pm_enter - Actually enter a sleep state.
207
* @state: State we're entering.
208
*
209
*/
210
static int bfin_pm_enter(suspend_state_t state)
211
{
212
switch (state) {
213
case PM_SUSPEND_STANDBY:
214
bfin_pm_suspend_standby_enter();
215
break;
216
case PM_SUSPEND_MEM:
217
bfin_pm_suspend_mem_enter();
218
break;
219
default:
220
return -EINVAL;
221
}
222
223
return 0;
224
}
225
226
static const struct platform_suspend_ops bfin_pm_ops = {
227
.enter = bfin_pm_enter,
228
.valid = bfin_pm_valid,
229
};
230
231
static int __init bfin_pm_init(void)
232
{
233
suspend_set_ops(&bfin_pm_ops);
234
return 0;
235
}
236
237
__initcall(bfin_pm_init);
238
239