1 #include <linux/init.h>
2 #include <linux/suspend.h>
5 #include <asm/mpc52xx.h>
6 #include "mpc52xx_pic.h"
8 /* defined in lite5200_sleep.S and only used here */
9 extern void lite5200_low_power(void __iomem
*sram
, void __iomem
*mbar
);
11 static struct mpc52xx_cdm __iomem
*cdm
;
12 static struct mpc52xx_intr __iomem
*pic
;
13 static struct mpc52xx_sdma __iomem
*bes
;
14 static struct mpc52xx_xlb __iomem
*xlb
;
15 static struct mpc52xx_gpio __iomem
*gps
;
16 static struct mpc52xx_gpio_wkup __iomem
*gpw
;
17 static void __iomem
*sram
;
18 static const int sram_size
= 0x4000; /* 16 kBytes */
19 static void __iomem
*mbar
;
21 static suspend_state_t lite5200_pm_target_state
;
23 static int lite5200_pm_valid(suspend_state_t state
)
26 case PM_SUSPEND_STANDBY
:
34 static int lite5200_pm_set_target(suspend_state_t state
)
36 if (lite5200_pm_valid(state
)) {
37 lite5200_pm_target_state
= state
;
43 static int lite5200_pm_prepare(void)
45 /* deep sleep? let mpc52xx code handle that */
46 if (lite5200_pm_target_state
== PM_SUSPEND_STANDBY
)
47 return mpc52xx_pm_prepare();
49 if (lite5200_pm_target_state
!= PM_SUSPEND_MEM
)
53 mbar
= mpc52xx_find_and_map("mpc5200");
55 printk(KERN_ERR
"%s:%i Error mapping registers\n", __func__
, __LINE__
);
70 /* save and restore registers not bound to any real devices */
71 static struct mpc52xx_cdm scdm
;
72 static struct mpc52xx_intr spic
;
73 static struct mpc52xx_sdma sbes
;
74 static struct mpc52xx_xlb sxlb
;
75 static struct mpc52xx_gpio sgps
;
76 static struct mpc52xx_gpio_wkup sgpw
;
78 static void lite5200_save_regs(void)
80 _memcpy_fromio(&spic
, pic
, sizeof(*pic
));
81 _memcpy_fromio(&sbes
, bes
, sizeof(*bes
));
82 _memcpy_fromio(&scdm
, cdm
, sizeof(*cdm
));
83 _memcpy_fromio(&sxlb
, xlb
, sizeof(*xlb
));
84 _memcpy_fromio(&sgps
, gps
, sizeof(*gps
));
85 _memcpy_fromio(&sgpw
, gpw
, sizeof(*gpw
));
87 _memcpy_fromio(saved_sram
, sram
, sram_size
);
90 static void lite5200_restore_regs(void)
93 _memcpy_toio(sram
, saved_sram
, sram_size
);
97 * GPIOs. Interrupt Master Enable has higher address then other
98 * registers, so just memcpy is ok.
100 _memcpy_toio(gpw
, &sgpw
, sizeof(*gpw
));
101 _memcpy_toio(gps
, &sgps
, sizeof(*gps
));
105 out_be32(&xlb
->snoop_window
, sxlb
.snoop_window
);
106 out_be32(&xlb
->master_priority
, sxlb
.master_priority
);
107 out_be32(&xlb
->master_pri_enable
, sxlb
.master_pri_enable
);
110 out_be32(&xlb
->int_enable
, sxlb
.int_enable
);
111 out_be32(&xlb
->config
, sxlb
.config
);
114 /* CDM - Clock Distribution Module */
115 out_8(&cdm
->ipb_clk_sel
, scdm
.ipb_clk_sel
);
116 out_8(&cdm
->pci_clk_sel
, scdm
.pci_clk_sel
);
118 out_8(&cdm
->ext_48mhz_en
, scdm
.ext_48mhz_en
);
119 out_8(&cdm
->fd_enable
, scdm
.fd_enable
);
120 out_be16(&cdm
->fd_counters
, scdm
.fd_counters
);
122 out_be32(&cdm
->clk_enables
, scdm
.clk_enables
);
124 out_8(&cdm
->osc_disable
, scdm
.osc_disable
);
126 out_be16(&cdm
->mclken_div_psc1
, scdm
.mclken_div_psc1
);
127 out_be16(&cdm
->mclken_div_psc2
, scdm
.mclken_div_psc2
);
128 out_be16(&cdm
->mclken_div_psc3
, scdm
.mclken_div_psc3
);
129 out_be16(&cdm
->mclken_div_psc6
, scdm
.mclken_div_psc6
);
133 out_be32(&bes
->taskBar
, sbes
.taskBar
);
134 out_be32(&bes
->currentPointer
, sbes
.currentPointer
);
135 out_be32(&bes
->endPointer
, sbes
.endPointer
);
136 out_be32(&bes
->variablePointer
, sbes
.variablePointer
);
138 out_8(&bes
->IntVect1
, sbes
.IntVect1
);
139 out_8(&bes
->IntVect2
, sbes
.IntVect2
);
140 out_be16(&bes
->PtdCntrl
, sbes
.PtdCntrl
);
143 out_8(&bes
->ipr
[i
], sbes
.ipr
[i
]);
145 out_be32(&bes
->cReqSelect
, sbes
.cReqSelect
);
146 out_be32(&bes
->task_size0
, sbes
.task_size0
);
147 out_be32(&bes
->task_size1
, sbes
.task_size1
);
148 out_be32(&bes
->MDEDebug
, sbes
.MDEDebug
);
149 out_be32(&bes
->ADSDebug
, sbes
.ADSDebug
);
150 out_be32(&bes
->Value1
, sbes
.Value1
);
151 out_be32(&bes
->Value2
, sbes
.Value2
);
152 out_be32(&bes
->Control
, sbes
.Control
);
153 out_be32(&bes
->Status
, sbes
.Status
);
154 out_be32(&bes
->PTDDebug
, sbes
.PTDDebug
);
158 out_be16(&bes
->tcr
[i
], sbes
.tcr
[i
]);
160 /* enable interrupts */
161 out_be32(&bes
->IntPend
, sbes
.IntPend
);
162 out_be32(&bes
->IntMask
, sbes
.IntMask
);
166 out_be32(&pic
->per_pri1
, spic
.per_pri1
);
167 out_be32(&pic
->per_pri2
, spic
.per_pri2
);
168 out_be32(&pic
->per_pri3
, spic
.per_pri3
);
170 out_be32(&pic
->main_pri1
, spic
.main_pri1
);
171 out_be32(&pic
->main_pri2
, spic
.main_pri2
);
173 out_be32(&pic
->enc_status
, spic
.enc_status
);
175 /* unmask and enable interrupts */
176 out_be32(&pic
->per_mask
, spic
.per_mask
);
177 out_be32(&pic
->main_mask
, spic
.main_mask
);
178 out_be32(&pic
->ctrl
, spic
.ctrl
);
181 static int lite5200_pm_enter(suspend_state_t state
)
183 /* deep sleep? let mpc52xx code handle that */
184 if (state
== PM_SUSPEND_STANDBY
) {
185 return mpc52xx_pm_enter(state
);
188 lite5200_save_regs();
190 /* effectively save FP regs */
193 lite5200_low_power(sram
, mbar
);
195 lite5200_restore_regs();
197 /* restart jiffies */
198 wakeup_decrementer();
204 static void lite5200_pm_finish(void)
206 /* deep sleep? let mpc52xx code handle that */
207 if (lite5200_pm_target_state
== PM_SUSPEND_STANDBY
)
211 static struct platform_suspend_ops lite5200_pm_ops
= {
212 .valid
= lite5200_pm_valid
,
213 .set_target
= lite5200_pm_set_target
,
214 .prepare
= lite5200_pm_prepare
,
215 .enter
= lite5200_pm_enter
,
216 .finish
= lite5200_pm_finish
,
219 int __init
lite5200_pm_init(void)
221 suspend_set_ops(&lite5200_pm_ops
);