1 #include <linux/init.h>
2 #include <linux/suspend.h>
5 #include <asm/mpc52xx.h>
6 #include <asm/switch_to.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
*pci
;
18 static void __iomem
*sram
;
19 static const int sram_size
= 0x4000; /* 16 kBytes */
20 static void __iomem
*mbar
;
22 static suspend_state_t lite5200_pm_target_state
;
24 static int lite5200_pm_valid(suspend_state_t state
)
27 case PM_SUSPEND_STANDBY
:
35 static int lite5200_pm_begin(suspend_state_t state
)
37 if (lite5200_pm_valid(state
)) {
38 lite5200_pm_target_state
= state
;
44 static int lite5200_pm_prepare(void)
46 struct device_node
*np
;
47 const struct of_device_id immr_ids
[] = {
48 { .compatible
= "fsl,mpc5200-immr", },
49 { .compatible
= "fsl,mpc5200b-immr", },
50 { .type
= "soc", .compatible
= "mpc5200", }, /* lite5200 */
51 { .type
= "builtin", .compatible
= "mpc5200", }, /* efika */
57 /* deep sleep? let mpc52xx code handle that */
58 if (lite5200_pm_target_state
== PM_SUSPEND_STANDBY
)
59 return mpc52xx_pm_prepare();
61 if (lite5200_pm_target_state
!= PM_SUSPEND_MEM
)
65 np
= of_find_matching_node(NULL
, immr_ids
);
66 regaddr_p
= of_get_address(np
, 0, NULL
, NULL
);
68 regaddr64
= of_translate_address(np
, regaddr_p
);
71 mbar
= ioremap((u32
) regaddr64
, 0xC000);
73 printk(KERN_ERR
"%s:%i Error mapping registers\n", __func__
, __LINE__
);
89 /* save and restore registers not bound to any real devices */
90 static struct mpc52xx_cdm scdm
;
91 static struct mpc52xx_intr spic
;
92 static struct mpc52xx_sdma sbes
;
93 static struct mpc52xx_xlb sxlb
;
94 static struct mpc52xx_gpio sgps
;
95 static struct mpc52xx_gpio_wkup sgpw
;
96 static char spci
[0x200];
98 static void lite5200_save_regs(void)
100 _memcpy_fromio(&spic
, pic
, sizeof(*pic
));
101 _memcpy_fromio(&sbes
, bes
, sizeof(*bes
));
102 _memcpy_fromio(&scdm
, cdm
, sizeof(*cdm
));
103 _memcpy_fromio(&sxlb
, xlb
, sizeof(*xlb
));
104 _memcpy_fromio(&sgps
, gps
, sizeof(*gps
));
105 _memcpy_fromio(&sgpw
, gpw
, sizeof(*gpw
));
106 _memcpy_fromio(spci
, pci
, 0x200);
108 _memcpy_fromio(saved_sram
, sram
, sram_size
);
111 static void lite5200_restore_regs(void)
114 _memcpy_toio(sram
, saved_sram
, sram_size
);
116 /* PCI Configuration */
117 _memcpy_toio(pci
, spci
, 0x200);
120 * GPIOs. Interrupt Master Enable has higher address then other
121 * registers, so just memcpy is ok.
123 _memcpy_toio(gpw
, &sgpw
, sizeof(*gpw
));
124 _memcpy_toio(gps
, &sgps
, sizeof(*gps
));
128 out_be32(&xlb
->snoop_window
, sxlb
.snoop_window
);
129 out_be32(&xlb
->master_priority
, sxlb
.master_priority
);
130 out_be32(&xlb
->master_pri_enable
, sxlb
.master_pri_enable
);
133 out_be32(&xlb
->int_enable
, sxlb
.int_enable
);
134 out_be32(&xlb
->config
, sxlb
.config
);
137 /* CDM - Clock Distribution Module */
138 out_8(&cdm
->ipb_clk_sel
, scdm
.ipb_clk_sel
);
139 out_8(&cdm
->pci_clk_sel
, scdm
.pci_clk_sel
);
141 out_8(&cdm
->ext_48mhz_en
, scdm
.ext_48mhz_en
);
142 out_8(&cdm
->fd_enable
, scdm
.fd_enable
);
143 out_be16(&cdm
->fd_counters
, scdm
.fd_counters
);
145 out_be32(&cdm
->clk_enables
, scdm
.clk_enables
);
147 out_8(&cdm
->osc_disable
, scdm
.osc_disable
);
149 out_be16(&cdm
->mclken_div_psc1
, scdm
.mclken_div_psc1
);
150 out_be16(&cdm
->mclken_div_psc2
, scdm
.mclken_div_psc2
);
151 out_be16(&cdm
->mclken_div_psc3
, scdm
.mclken_div_psc3
);
152 out_be16(&cdm
->mclken_div_psc6
, scdm
.mclken_div_psc6
);
156 out_be32(&bes
->taskBar
, sbes
.taskBar
);
157 out_be32(&bes
->currentPointer
, sbes
.currentPointer
);
158 out_be32(&bes
->endPointer
, sbes
.endPointer
);
159 out_be32(&bes
->variablePointer
, sbes
.variablePointer
);
161 out_8(&bes
->IntVect1
, sbes
.IntVect1
);
162 out_8(&bes
->IntVect2
, sbes
.IntVect2
);
163 out_be16(&bes
->PtdCntrl
, sbes
.PtdCntrl
);
166 out_8(&bes
->ipr
[i
], sbes
.ipr
[i
]);
168 out_be32(&bes
->cReqSelect
, sbes
.cReqSelect
);
169 out_be32(&bes
->task_size0
, sbes
.task_size0
);
170 out_be32(&bes
->task_size1
, sbes
.task_size1
);
171 out_be32(&bes
->MDEDebug
, sbes
.MDEDebug
);
172 out_be32(&bes
->ADSDebug
, sbes
.ADSDebug
);
173 out_be32(&bes
->Value1
, sbes
.Value1
);
174 out_be32(&bes
->Value2
, sbes
.Value2
);
175 out_be32(&bes
->Control
, sbes
.Control
);
176 out_be32(&bes
->Status
, sbes
.Status
);
177 out_be32(&bes
->PTDDebug
, sbes
.PTDDebug
);
181 out_be16(&bes
->tcr
[i
], sbes
.tcr
[i
]);
183 /* enable interrupts */
184 out_be32(&bes
->IntPend
, sbes
.IntPend
);
185 out_be32(&bes
->IntMask
, sbes
.IntMask
);
189 out_be32(&pic
->per_pri1
, spic
.per_pri1
);
190 out_be32(&pic
->per_pri2
, spic
.per_pri2
);
191 out_be32(&pic
->per_pri3
, spic
.per_pri3
);
193 out_be32(&pic
->main_pri1
, spic
.main_pri1
);
194 out_be32(&pic
->main_pri2
, spic
.main_pri2
);
196 out_be32(&pic
->enc_status
, spic
.enc_status
);
198 /* unmask and enable interrupts */
199 out_be32(&pic
->per_mask
, spic
.per_mask
);
200 out_be32(&pic
->main_mask
, spic
.main_mask
);
201 out_be32(&pic
->ctrl
, spic
.ctrl
);
204 static int lite5200_pm_enter(suspend_state_t state
)
206 /* deep sleep? let mpc52xx code handle that */
207 if (state
== PM_SUSPEND_STANDBY
) {
208 return mpc52xx_pm_enter(state
);
211 lite5200_save_regs();
213 /* effectively save FP regs */
216 lite5200_low_power(sram
, mbar
);
218 lite5200_restore_regs();
224 static void lite5200_pm_finish(void)
226 /* deep sleep? let mpc52xx code handle that */
227 if (lite5200_pm_target_state
== PM_SUSPEND_STANDBY
)
231 static void lite5200_pm_end(void)
233 lite5200_pm_target_state
= PM_SUSPEND_ON
;
236 static const struct platform_suspend_ops lite5200_pm_ops
= {
237 .valid
= lite5200_pm_valid
,
238 .begin
= lite5200_pm_begin
,
239 .prepare
= lite5200_pm_prepare
,
240 .enter
= lite5200_pm_enter
,
241 .finish
= lite5200_pm_finish
,
242 .end
= lite5200_pm_end
,
245 int __init
lite5200_pm_init(void)
247 suspend_set_ops(&lite5200_pm_ops
);