Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
arm
mach-mmp
pm-mmp2.c
Go to the documentation of this file.
1
/*
2
* MMP2 Power Management Routines
3
*
4
* This software program is licensed subject to the GNU General Public License
5
* (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
6
*
7
* (C) Copyright 2012 Marvell International Ltd.
8
* All Rights Reserved
9
*/
10
11
#include <linux/kernel.h>
12
#include <linux/errno.h>
13
#include <
linux/err.h
>
14
#include <linux/time.h>
15
#include <
linux/delay.h
>
16
#include <
linux/suspend.h
>
17
#include <
linux/irq.h
>
18
#include <
linux/io.h
>
19
#include <
linux/interrupt.h
>
20
#include <
asm/mach-types.h
>
21
#include <mach/hardware.h>
22
#include <mach/cputype.h>
23
#include <mach/addr-map.h>
24
#include <
mach/pm-mmp2.h
>
25
#include <
mach/regs-icu.h
>
26
#include <mach/irqs.h>
27
28
int
mmp2_set_wake
(
struct
irq_data
*
d
,
unsigned
int
on)
29
{
30
int
irq
= d->
irq
;
31
struct
irq_desc
*
desc
=
irq_to_desc
(irq);
32
unsigned
long
data
= 0;
33
34
if
(
unlikely
(irq >=
nr_irqs
)) {
35
pr_err
(
"IRQ nubmers are out of boundary!\n"
);
36
return
-
EINVAL
;
37
}
38
39
if
(on) {
40
if
(desc->
action
)
41
desc->
action
->flags |=
IRQF_NO_SUSPEND
;
42
}
else
{
43
if
(desc->
action
)
44
desc->
action
->flags &= ~
IRQF_NO_SUSPEND
;
45
}
46
47
/* enable wakeup sources */
48
switch
(irq) {
49
case
IRQ_MMP2_RTC
:
50
case
IRQ_MMP2_RTC_ALARM
:
51
data =
MPMU_WUCRM_PJ_WAKEUP
(4) |
MPMU_WUCRM_PJ_RTC_ALARM
;
52
break
;
53
case
IRQ_MMP2_PMIC
:
54
data =
MPMU_WUCRM_PJ_WAKEUP
(7);
55
break
;
56
case
IRQ_MMP2_MMC2
:
57
/* mmc use WAKEUP2, same as GPIO wakeup source */
58
data =
MPMU_WUCRM_PJ_WAKEUP
(2);
59
break
;
60
}
61
if
(on) {
62
if
(data) {
63
data |=
__raw_readl
(
MPMU_WUCRM_PJ
);
64
__raw_writel
(data,
MPMU_WUCRM_PJ
);
65
}
66
}
else
{
67
if
(data) {
68
data = ~data &
__raw_readl
(
MPMU_WUCRM_PJ
);
69
__raw_writel
(data,
MPMU_WUCRM_PJ
);
70
}
71
}
72
return
0;
73
}
74
75
static
void
pm_scu_clk_disable(
void
)
76
{
77
unsigned
int
val
;
78
79
/* close AXI fabric clock gate */
80
__raw_writel
(0x0,
CIU_REG
(0x64));
81
__raw_writel
(0x0,
CIU_REG
(0x68));
82
83
/* close MCB master clock gate */
84
val =
__raw_readl
(
CIU_REG
(0x1c));
85
val |= 0xf0;
86
__raw_writel
(val,
CIU_REG
(0x1c));
87
88
return
;
89
}
90
91
static
void
pm_scu_clk_enable(
void
)
92
{
93
unsigned
int
val
;
94
95
/* open AXI fabric clock gate */
96
__raw_writel
(0x03003003,
CIU_REG
(0x64));
97
__raw_writel
(0x00303030,
CIU_REG
(0x68));
98
99
/* open MCB master clock gate */
100
val =
__raw_readl
(
CIU_REG
(0x1c));
101
val &= ~(0xf0);
102
__raw_writel
(val,
CIU_REG
(0x1c));
103
104
return
;
105
}
106
107
static
void
pm_mpmu_clk_disable(
void
)
108
{
109
/*
110
* disable clocks in MPMU_CGR_PJ register
111
* except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
112
*/
113
__raw_writel
(0x0000a010,
MPMU_CGR_PJ
);
114
}
115
116
static
void
pm_mpmu_clk_enable(
void
)
117
{
118
unsigned
int
val
;
119
120
__raw_writel
(0xdffefffe,
MPMU_CGR_PJ
);
121
val =
__raw_readl
(
MPMU_PLL2_CTRL1
);
122
val |= (1 << 29);
123
__raw_writel
(val,
MPMU_PLL2_CTRL1
);
124
125
return
;
126
}
127
128
void
mmp2_pm_enter_lowpower_mode
(
int
state
)
129
{
130
uint32_t
idle_cfg, apcr;
131
132
idle_cfg =
__raw_readl
(
APMU_PJ_IDLE_CFG
);
133
apcr =
__raw_readl
(
MPMU_PCR_PJ
);
134
apcr &= ~(
MPMU_PCR_PJ_SLPEN
|
MPMU_PCR_PJ_DDRCORSD
|
MPMU_PCR_PJ_APBSD
135
|
MPMU_PCR_PJ_AXISD
|
MPMU_PCR_PJ_VCTCXOSD
| (1 << 13));
136
idle_cfg &= ~
APMU_PJ_IDLE_CFG_PJ_IDLE
;
137
138
switch
(state) {
139
case
POWER_MODE_SYS_SLEEP
:
140
apcr |=
MPMU_PCR_PJ_SLPEN
;
/* set the SLPEN bit */
141
apcr |=
MPMU_PCR_PJ_VCTCXOSD
;
/* set VCTCXOSD */
142
/* fall through */
143
case
POWER_MODE_CHIP_SLEEP
:
144
apcr |=
MPMU_PCR_PJ_SLPEN
;
145
/* fall through */
146
case
POWER_MODE_APPS_SLEEP
:
147
apcr |=
MPMU_PCR_PJ_APBSD
;
/* set APBSD */
148
/* fall through */
149
case
POWER_MODE_APPS_IDLE
:
150
apcr |=
MPMU_PCR_PJ_AXISD
;
/* set AXISDD bit */
151
apcr |=
MPMU_PCR_PJ_DDRCORSD
;
/* set DDRCORSD bit */
152
idle_cfg |=
APMU_PJ_IDLE_CFG_PJ_PWRDWN
;
/* PJ power down */
153
apcr |=
MPMU_PCR_PJ_SPSD
;
154
/* fall through */
155
case
POWER_MODE_CORE_EXTIDLE
:
156
idle_cfg |=
APMU_PJ_IDLE_CFG_PJ_IDLE
;
/* set the IDLE bit */
157
idle_cfg &= ~
APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK
;
158
idle_cfg |=
APMU_PJ_IDLE_CFG_PWR_SW
(3)
159
|
APMU_PJ_IDLE_CFG_L2_PWR_SW
;
160
break
;
161
case
POWER_MODE_CORE_INTIDLE
:
162
apcr &= ~
MPMU_PCR_PJ_SPSD
;
163
break
;
164
}
165
166
/* set reserve bits */
167
apcr |= (1 << 30) | (1 << 25);
168
169
/* finally write the registers back */
170
__raw_writel
(idle_cfg,
APMU_PJ_IDLE_CFG
);
171
__raw_writel
(apcr,
MPMU_PCR_PJ
);
/* 0xfe086000 */
172
}
173
174
static
int
mmp2_pm_enter(
suspend_state_t
state
)
175
{
176
int
temp
;
177
178
temp =
__raw_readl
(
MMP2_ICU_INT4_MASK
);
179
if
(temp & (1 << 1)) {
180
printk
(
KERN_ERR
"%s: PMIC interrupt is handling\n"
, __func__);
181
return
-
EAGAIN
;
182
}
183
184
temp =
__raw_readl
(
APMU_SRAM_PWR_DWN
);
185
temp |= ((1 << 19) | (1 << 18));
186
__raw_writel
(temp,
APMU_SRAM_PWR_DWN
);
187
pm_mpmu_clk_disable();
188
pm_scu_clk_disable();
189
190
printk
(
KERN_INFO
"%s: before suspend\n"
, __func__);
191
cpu_do_idle
();
192
printk
(
KERN_INFO
"%s: after suspend\n"
, __func__);
193
194
pm_mpmu_clk_enable();
/* enable clocks in MPMU */
195
pm_scu_clk_enable();
/* enable clocks in SCU */
196
197
return
0;
198
}
199
200
/*
201
* Called after processes are frozen, but before we shut down devices.
202
*/
203
static
int
mmp2_pm_prepare(
void
)
204
{
205
mmp2_pm_enter_lowpower_mode
(
POWER_MODE_SYS_SLEEP
);
206
207
return
0;
208
}
209
210
/*
211
* Called after devices are re-setup, but before processes are thawed.
212
*/
213
static
void
mmp2_pm_finish(
void
)
214
{
215
mmp2_pm_enter_lowpower_mode
(
POWER_MODE_CORE_INTIDLE
);
216
}
217
218
static
int
mmp2_pm_valid(
suspend_state_t
state)
219
{
220
return
((state ==
PM_SUSPEND_STANDBY
) || (state ==
PM_SUSPEND_MEM
));
221
}
222
223
/*
224
* Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
225
*/
226
static
const
struct
platform_suspend_ops
mmp2_pm_ops = {
227
.valid = mmp2_pm_valid,
228
.prepare = mmp2_pm_prepare,
229
.enter = mmp2_pm_enter,
230
.finish = mmp2_pm_finish,
231
};
232
233
static
int
__init
mmp2_pm_init(
void
)
234
{
235
uint32_t
apcr;
236
237
if
(!
cpu_is_mmp2
())
238
return
-
EIO
;
239
240
suspend_set_ops
(&mmp2_pm_ops);
241
242
/*
243
* Set bit 0, Slow clock Select 32K clock input instead of VCXO
244
* VCXO is chosen by default, which would be disabled in suspend
245
*/
246
__raw_writel
(0x5,
MPMU_SCCR
);
247
248
/*
249
* Clear bit 23 of CIU_CPU_CONF
250
* direct PJ4 to DDR access through Memory Controller slow queue
251
* fast queue has issue and cause lcd will flick
252
*/
253
__raw_writel
(
__raw_readl
(
CIU_REG
(0x8)) & ~(0x1 << 23),
CIU_REG
(0x8));
254
255
/* Clear default low power control bit */
256
apcr =
__raw_readl
(
MPMU_PCR_PJ
);
257
apcr &= ~(
MPMU_PCR_PJ_SLPEN
|
MPMU_PCR_PJ_DDRCORSD
258
|
MPMU_PCR_PJ_APBSD
|
MPMU_PCR_PJ_AXISD
| 1 << 13);
259
__raw_writel
(apcr,
MPMU_PCR_PJ
);
260
261
return
0;
262
}
263
264
late_initcall
(mmp2_pm_init);
Generated on Thu Jan 10 2013 12:59:47 for Linux Kernel by
1.8.2