]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap2/pm34xx.c
34XX: PM: Workaround to reset all wkdeps
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / pm34xx.c
1 /*
2  * linux/arch/arm/mach-omap2/pm34xx.c
3  *
4  * OMAP3 Power Management Routines
5  *
6  * Copyright (C) 2006-2008 Nokia Corporation
7  * Tony Lindgren <tony@atomide.com>
8  * Jouni Hogander
9  *
10  * Copyright (C) 2005 Texas Instruments, Inc.
11  * Richard Woodruff <r-woodruff2@ti.com>
12  *
13  * Based on pm.c for omap1
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License version 2 as
17  * published by the Free Software Foundation.
18  */
19
20 #include <linux/pm.h>
21 #include <linux/suspend.h>
22 #include <linux/interrupt.h>
23 #include <linux/module.h>
24 #include <linux/list.h>
25 #include <linux/err.h>
26
27 #include <asm/arch/gpio.h>
28 #include <asm/arch/sram.h>
29 #include <asm/arch/pm.h>
30 #include <asm/arch/clockdomain.h>
31 #include <asm/arch/powerdomain.h>
32
33 #include "cm.h"
34 #include "cm-regbits-34xx.h"
35 #include "prm-regbits-34xx.h"
36
37 #include "prm.h"
38 #include "pm.h"
39 #include "smartreflex.h"
40
41 struct power_state {
42         struct powerdomain *pwrdm;
43         u32 next_state;
44         u32 saved_state;
45         struct list_head node;
46 };
47
48 static LIST_HEAD(pwrst_list);
49
50 void (*_omap_sram_idle)(u32 *addr, int save_state);
51
52 static void (*saved_idle)(void);
53
54 static struct powerdomain *mpu_pwrdm;
55
56 /* PRCM Interrupt Handler for wakeups */
57 static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
58 {
59         u32 wkst, irqstatus_mpu;
60         u32 fclk, iclk;
61
62         /* WKUP */
63         wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
64         if (wkst) {
65                 iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
66                 fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
67                 cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
68                 cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
69                 prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
70                 while (prm_read_mod_reg(WKUP_MOD, PM_WKST));
71                 cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
72                 cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
73         }
74
75         /* CORE */
76         wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
77         if (wkst) {
78                 iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
79                 fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
80                 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
81                 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
82                 prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
83                 while (prm_read_mod_reg(CORE_MOD, PM_WKST1));
84                 cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
85                 cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
86         }
87         wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
88         if (wkst) {
89                 iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
90                 fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
91                 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
92                 cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
93                 prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
94                 while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3));
95                 cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
96                 cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
97         }
98
99         /* PER */
100         wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
101         if (wkst) {
102                 iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
103                 fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
104                 cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
105                 cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
106                 prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
107                 while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST));
108                 cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
109                 cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
110         }
111
112         if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) {
113                 /* USBHOST */
114                 wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
115                 if (wkst) {
116                         iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
117                                                CM_ICLKEN);
118                         fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
119                                                CM_FCLKEN);
120                         cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
121                                          CM_ICLKEN);
122                         cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
123                                          CM_FCLKEN);
124                         prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
125                                           PM_WKST);
126                         while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
127                                                 PM_WKST));
128                         cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
129                                          CM_ICLKEN);
130                         cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
131                                          CM_FCLKEN);
132                 }
133         }
134
135         irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
136                                         OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
137         prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
138                                         OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
139
140         while (prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET));
141
142         return IRQ_HANDLED;
143 }
144
145 static void omap_sram_idle(void)
146 {
147         /* Variable to tell what needs to be saved and restored
148          * in omap_sram_idle*/
149         /* save_state = 0 => Nothing to save and restored */
150         /* save_state = 1 => Only L1 and logic lost */
151         /* save_state = 2 => Only L2 lost */
152         /* save_state = 3 => L1, L2 and logic lost */
153         int save_state = 0, mpu_next_state;
154
155         if (!_omap_sram_idle)
156                 return;
157
158         mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
159         switch (mpu_next_state) {
160         case PWRDM_POWER_RET:
161                 /* No need to save context */
162                 save_state = 0;
163                 break;
164         default:
165                 /* Invalid state */
166                 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
167                 return;
168         }
169
170         omap2_gpio_prepare_for_retention();
171
172         _omap_sram_idle(NULL, save_state);
173
174         omap2_gpio_resume_after_retention();
175 }
176
177 static int omap3_can_sleep(void)
178 {
179         if (!enable_dyn_sleep)
180                 return 0;
181         if (atomic_read(&sleep_block) > 0)
182                 return 0;
183         return 1;
184 }
185
186 /* _clkdm_deny_idle - private callback function used by set_pwrdm_state() */
187 static int _clkdm_deny_idle(struct powerdomain *pwrdm,
188                             struct clockdomain *clkdm)
189 {
190         omap2_clkdm_deny_idle(clkdm);
191         return 0;
192 }
193
194 /* _clkdm_allow_idle - private callback function used by set_pwrdm_state() */
195 static int _clkdm_allow_idle(struct powerdomain *pwrdm,
196                              struct clockdomain *clkdm)
197 {
198         omap2_clkdm_allow_idle(clkdm);
199         return 0;
200 }
201
202 /* This sets pwrdm state (other than mpu & core. Currently only ON &
203  * RET are supported. Function is assuming that clkdm doesn't have
204  * hw_sup mode enabled. */
205 static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
206 {
207         u32 cur_state;
208         int ret = 0;
209
210         if (pwrdm == NULL || IS_ERR(pwrdm))
211                 return -EINVAL;
212
213         cur_state = pwrdm_read_next_pwrst(pwrdm);
214
215         if (cur_state == state)
216                 return ret;
217
218         pwrdm_for_each_clkdm(pwrdm, _clkdm_deny_idle);
219
220         ret = pwrdm_set_next_pwrst(pwrdm, state);
221         if (ret) {
222                 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
223                        pwrdm->name);
224                 goto err;
225         }
226
227         pwrdm_for_each_clkdm(pwrdm, _clkdm_allow_idle);
228
229 err:
230         return ret;
231 }
232
233 static void omap3_pm_idle(void)
234 {
235         local_irq_disable();
236         local_fiq_disable();
237
238         if (!omap3_can_sleep())
239                 goto out;
240
241         if (omap_irq_pending())
242                 goto out;
243
244         omap_sram_idle();
245
246 out:
247         local_fiq_enable();
248         local_irq_enable();
249 }
250
251 static int omap3_pm_prepare(void)
252 {
253         saved_idle = pm_idle;
254         pm_idle = NULL;
255         return 0;
256 }
257
258 static int omap3_pm_suspend(void)
259 {
260         struct power_state *pwrst;
261         int state, ret = 0;
262
263         /* XXX Disable smartreflex before entering suspend */
264         disable_smartreflex(SR1);
265         disable_smartreflex(SR2);
266
267         /* Read current next_pwrsts */
268         list_for_each_entry(pwrst, &pwrst_list, node)
269                 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
270         /* Set ones wanted by suspend */
271         list_for_each_entry(pwrst, &pwrst_list, node) {
272                 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
273                         goto restore;
274                 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
275                         goto restore;
276         }
277
278         omap_sram_idle();
279
280 restore:
281         /* Restore next_pwrsts */
282         list_for_each_entry(pwrst, &pwrst_list, node) {
283                 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
284                 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
285                 if (state != pwrst->next_state) {
286                         printk(KERN_INFO "Powerdomain (%s) didn't enter "
287                                "target state %d\n",
288                                pwrst->pwrdm->name, pwrst->next_state);
289                         ret = -1;
290                 }
291         }
292         if (ret)
293                 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
294         else
295                 printk(KERN_INFO "Successfully put all powerdomains "
296                        "to target state\n");
297
298         /* XXX Enable smartreflex after suspend */
299         enable_smartreflex(SR1);
300         enable_smartreflex(SR2);
301
302         return ret;
303 }
304
305 static int omap3_pm_enter(suspend_state_t state)
306 {
307         int ret = 0;
308
309         switch (state) {
310         case PM_SUSPEND_STANDBY:
311         case PM_SUSPEND_MEM:
312                 ret = omap3_pm_suspend();
313                 break;
314         default:
315                 ret = -EINVAL;
316         }
317
318         return ret;
319 }
320
321 static void omap3_pm_finish(void)
322 {
323         pm_idle = saved_idle;
324 }
325
326 static struct platform_suspend_ops omap_pm_ops = {
327         .prepare        = omap3_pm_prepare,
328         .enter          = omap3_pm_enter,
329         .finish         = omap3_pm_finish,
330         .valid          = suspend_valid_only_mem,
331 };
332
333 static void __init prcm_setup_regs(void)
334 {
335         /* XXX Reset all wkdeps. This should be done when initializing
336          * powerdomains */
337         prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
338         prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
339         prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
340         prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
341         prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
342         prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
343         if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) {
344                 prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
345                 prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
346         } else
347                 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
348
349         /* setup wakup source */
350         prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
351                           WKUP_MOD, PM_WKEN);
352         /* No need to write EN_IO, that is always enabled */
353         prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
354                           WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
355         /* For some reason IO doesn't generate wakeup event even if
356          * it is selected to mpu wakeup goup */
357         prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
358                         OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
359 }
360
361 static int __init pwrdms_setup(struct powerdomain *pwrdm)
362 {
363         struct power_state *pwrst;
364
365         if (!pwrdm->pwrsts)
366                 return 0;
367
368         pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
369         if (!pwrst)
370                 return -ENOMEM;
371         pwrst->pwrdm = pwrdm;
372         pwrst->next_state = PWRDM_POWER_RET;
373         list_add(&pwrst->node, &pwrst_list);
374
375         if (pwrdm_has_hdwr_sar(pwrdm))
376                 pwrdm_enable_hdwr_sar(pwrdm);
377
378         return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
379 }
380
381 int __init omap3_pm_init(void)
382 {
383         struct power_state *pwrst;
384         int ret;
385
386         printk(KERN_ERR "Power Management for TI OMAP3.\n");
387
388         /* XXX prcm_setup_regs needs to be before enabling hw
389          * supervised mode for powerdomains */
390         prcm_setup_regs();
391
392         ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
393                           (irq_handler_t)prcm_interrupt_handler,
394                           IRQF_DISABLED, "prcm", NULL);
395         if (ret) {
396                 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
397                        INT_34XX_PRCM_MPU_IRQ);
398                 goto err1;
399         }
400
401         ret = pwrdm_for_each(pwrdms_setup);
402         if (ret) {
403                 printk(KERN_ERR "Failed to setup powerdomains\n");
404                 goto err2;
405         }
406
407         mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
408         if (mpu_pwrdm == NULL) {
409                 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
410                 goto err2;
411         }
412
413         _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
414                                         omap34xx_cpu_suspend_sz);
415
416         suspend_set_ops(&omap_pm_ops);
417
418         pm_idle = omap3_pm_idle;
419
420 err1:
421         return ret;
422 err2:
423         free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
424         list_for_each_entry(pwrst, &pwrst_list, node) {
425                 list_del(&pwrst->node);
426                 kfree(pwrst);
427         }
428         return ret;
429 }