1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/init.h>
3 #include <linux/suspend.h>
6 #include <asm/mpc52xx.h>
7 #include <asm/switch_to.h>
9 /* defined in lite5200_sleep.S and only used here */
10 extern void lite5200_low_power(void __iomem
*sram
, void __iomem
*mbar
);
12 static struct mpc52xx_cdm __iomem
*cdm
;
13 static struct mpc52xx_intr __iomem
*pic
;
14 static struct mpc52xx_sdma __iomem
*bes
;
15 static struct mpc52xx_xlb __iomem
*xlb
;
16 static struct mpc52xx_gpio __iomem
*gps
;
17 static struct mpc52xx_gpio_wkup __iomem
*gpw
;
18 static void __iomem
*pci
;
19 static void __iomem
*sram
;
20 static const int sram_size
= 0x4000; /* 16 kBytes */
21 static void __iomem
*mbar
;
23 static suspend_state_t lite5200_pm_target_state
;
25 static int lite5200_pm_valid(suspend_state_t state
)
28 case PM_SUSPEND_STANDBY
:
36 static int lite5200_pm_begin(suspend_state_t state
)
38 if (lite5200_pm_valid(state
)) {
39 lite5200_pm_target_state
= state
;
45 static int lite5200_pm_prepare(void)
47 struct device_node
*np
;
48 const struct of_device_id immr_ids
[] = {
49 { .compatible
= "fsl,mpc5200-immr", },
50 { .compatible
= "fsl,mpc5200b-immr", },
51 { .type
= "soc", .compatible
= "mpc5200", }, /* lite5200 */
52 { .type
= "builtin", .compatible
= "mpc5200", }, /* efika */
58 /* deep sleep? let mpc52xx code handle that */
59 if (lite5200_pm_target_state
== PM_SUSPEND_STANDBY
)
60 return mpc52xx_pm_prepare();
62 if (lite5200_pm_target_state
!= PM_SUSPEND_MEM
)
66 np
= of_find_matching_node(NULL
, immr_ids
);
67 regaddr_p
= of_get_address(np
, 0, NULL
, NULL
);
69 regaddr64
= of_translate_address(np
, regaddr_p
);
72 mbar
= ioremap((u32
) regaddr64
, 0xC000);
74 printk(KERN_ERR
"%s:%i Error mapping registers\n", __func__
, __LINE__
);
90 /* save and restore registers not bound to any real devices */
91 static struct mpc52xx_cdm scdm
;
92 static struct mpc52xx_intr spic
;
93 static struct mpc52xx_sdma sbes
;
94 static struct mpc52xx_xlb sxlb
;
95 static struct mpc52xx_gpio sgps
;
96 static struct mpc52xx_gpio_wkup sgpw
;
97 static char spci
[0x200];
99 static void lite5200_save_regs(void)
101 _memcpy_fromio(&spic
, pic
, sizeof(*pic
));
102 _memcpy_fromio(&sbes
, bes
, sizeof(*bes
));
103 _memcpy_fromio(&scdm
, cdm
, sizeof(*cdm
));
104 _memcpy_fromio(&sxlb
, xlb
, sizeof(*xlb
));
105 _memcpy_fromio(&sgps
, gps
, sizeof(*gps
));
106 _memcpy_fromio(&sgpw
, gpw
, sizeof(*gpw
));
107 _memcpy_fromio(spci
, pci
, 0x200);
109 _memcpy_fromio(saved_sram
, sram
, sram_size
);
112 static void lite5200_restore_regs(void)
115 _memcpy_toio(sram
, saved_sram
, sram_size
);
117 /* PCI Configuration */
118 _memcpy_toio(pci
, spci
, 0x200);
121 * GPIOs. Interrupt Master Enable has higher address then other
122 * registers, so just memcpy is ok.
124 _memcpy_toio(gpw
, &sgpw
, sizeof(*gpw
));
125 _memcpy_toio(gps
, &sgps
, sizeof(*gps
));
129 out_be32(&xlb
->snoop_window
, sxlb
.snoop_window
);
130 out_be32(&xlb
->master_priority
, sxlb
.master_priority
);
131 out_be32(&xlb
->master_pri_enable
, sxlb
.master_pri_enable
);
134 out_be32(&xlb
->int_enable
, sxlb
.int_enable
);
135 out_be32(&xlb
->config
, sxlb
.config
);
138 /* CDM - Clock Distribution Module */
139 out_8(&cdm
->ipb_clk_sel
, scdm
.ipb_clk_sel
);
140 out_8(&cdm
->pci_clk_sel
, scdm
.pci_clk_sel
);
142 out_8(&cdm
->ext_48mhz_en
, scdm
.ext_48mhz_en
);
143 out_8(&cdm
->fd_enable
, scdm
.fd_enable
);
144 out_be16(&cdm
->fd_counters
, scdm
.fd_counters
);
146 out_be32(&cdm
->clk_enables
, scdm
.clk_enables
);
148 out_8(&cdm
->osc_disable
, scdm
.osc_disable
);
150 out_be16(&cdm
->mclken_div_psc1
, scdm
.mclken_div_psc1
);
151 out_be16(&cdm
->mclken_div_psc2
, scdm
.mclken_div_psc2
);
152 out_be16(&cdm
->mclken_div_psc3
, scdm
.mclken_div_psc3
);
153 out_be16(&cdm
->mclken_div_psc6
, scdm
.mclken_div_psc6
);
157 out_be32(&bes
->taskBar
, sbes
.taskBar
);
158 out_be32(&bes
->currentPointer
, sbes
.currentPointer
);
159 out_be32(&bes
->endPointer
, sbes
.endPointer
);
160 out_be32(&bes
->variablePointer
, sbes
.variablePointer
);
162 out_8(&bes
->IntVect1
, sbes
.IntVect1
);
163 out_8(&bes
->IntVect2
, sbes
.IntVect2
);
164 out_be16(&bes
->PtdCntrl
, sbes
.PtdCntrl
);
167 out_8(&bes
->ipr
[i
], sbes
.ipr
[i
]);
169 out_be32(&bes
->cReqSelect
, sbes
.cReqSelect
);
170 out_be32(&bes
->task_size0
, sbes
.task_size0
);
171 out_be32(&bes
->task_size1
, sbes
.task_size1
);
172 out_be32(&bes
->MDEDebug
, sbes
.MDEDebug
);
173 out_be32(&bes
->ADSDebug
, sbes
.ADSDebug
);
174 out_be32(&bes
->Value1
, sbes
.Value1
);
175 out_be32(&bes
->Value2
, sbes
.Value2
);
176 out_be32(&bes
->Control
, sbes
.Control
);
177 out_be32(&bes
->Status
, sbes
.Status
);
178 out_be32(&bes
->PTDDebug
, sbes
.PTDDebug
);
182 out_be16(&bes
->tcr
[i
], sbes
.tcr
[i
]);
184 /* enable interrupts */
185 out_be32(&bes
->IntPend
, sbes
.IntPend
);
186 out_be32(&bes
->IntMask
, sbes
.IntMask
);
190 out_be32(&pic
->per_pri1
, spic
.per_pri1
);
191 out_be32(&pic
->per_pri2
, spic
.per_pri2
);
192 out_be32(&pic
->per_pri3
, spic
.per_pri3
);
194 out_be32(&pic
->main_pri1
, spic
.main_pri1
);
195 out_be32(&pic
->main_pri2
, spic
.main_pri2
);
197 out_be32(&pic
->enc_status
, spic
.enc_status
);
199 /* unmask and enable interrupts */
200 out_be32(&pic
->per_mask
, spic
.per_mask
);
201 out_be32(&pic
->main_mask
, spic
.main_mask
);
202 out_be32(&pic
->ctrl
, spic
.ctrl
);
205 static int lite5200_pm_enter(suspend_state_t state
)
207 /* deep sleep? let mpc52xx code handle that */
208 if (state
== PM_SUSPEND_STANDBY
) {
209 return mpc52xx_pm_enter(state
);
212 lite5200_save_regs();
214 /* effectively save FP regs */
217 lite5200_low_power(sram
, mbar
);
219 lite5200_restore_regs();
225 static void lite5200_pm_finish(void)
227 /* deep sleep? let mpc52xx code handle that */
228 if (lite5200_pm_target_state
== PM_SUSPEND_STANDBY
)
232 static void lite5200_pm_end(void)
234 lite5200_pm_target_state
= PM_SUSPEND_ON
;
237 static const struct platform_suspend_ops lite5200_pm_ops
= {
238 .valid
= lite5200_pm_valid
,
239 .begin
= lite5200_pm_begin
,
240 .prepare
= lite5200_pm_prepare
,
241 .enter
= lite5200_pm_enter
,
242 .finish
= lite5200_pm_finish
,
243 .end
= lite5200_pm_end
,
246 int __init
lite5200_pm_init(void)
248 suspend_set_ops(&lite5200_pm_ops
);