1 // SPDX-License-Identifier: GPL-2.0
3 * AM33XX Power Management Routines
5 * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/
6 * Vaibhav Bedia, Dave Gerlach
10 #include <linux/err.h>
11 #include <linux/genalloc.h>
12 #include <linux/kernel.h>
13 #include <linux/init.h>
15 #include <linux/module.h>
17 #include <linux/platform_data/pm33xx.h>
18 #include <linux/platform_device.h>
19 #include <linux/sizes.h>
20 #include <linux/sram.h>
21 #include <linux/suspend.h>
22 #include <linux/ti-emif-sram.h>
23 #include <linux/wkup_m3_ipc.h>
25 #include <asm/proc-fns.h>
26 #include <asm/suspend.h>
27 #include <asm/system_misc.h>
29 #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
30 (unsigned long)pm_sram->do_wfi)
32 static int (*am33xx_do_wfi_sram
)(unsigned long unused
);
33 static phys_addr_t am33xx_do_wfi_sram_phys
;
35 static struct gen_pool
*sram_pool
, *sram_pool_data
;
36 static unsigned long ocmcram_location
, ocmcram_location_data
;
38 static struct am33xx_pm_platform_data
*pm_ops
;
39 static struct am33xx_pm_sram_addr
*pm_sram
;
41 static struct device
*pm33xx_dev
;
42 static struct wkup_m3_ipc
*m3_ipc
;
44 static u32
sram_suspend_address(unsigned long addr
)
46 return ((unsigned long)am33xx_do_wfi_sram
+
47 AMX3_PM_SRAM_SYMBOL_OFFSET(addr
));
51 static int am33xx_pm_suspend(suspend_state_t suspend_state
)
55 ret
= pm_ops
->soc_suspend((unsigned long)suspend_state
,
59 dev_err(pm33xx_dev
, "PM: Kernel suspend failure\n");
61 i
= m3_ipc
->ops
->request_pm_status(m3_ipc
);
66 "PM: Successfully put all powerdomains to target state\n");
70 "PM: Could not transition all powerdomains to target state\n");
75 "PM: CM3 returned unknown result = %d\n", i
);
83 static int am33xx_pm_enter(suspend_state_t suspend_state
)
87 switch (suspend_state
) {
89 case PM_SUSPEND_STANDBY
:
90 ret
= am33xx_pm_suspend(suspend_state
);
99 static int am33xx_pm_begin(suspend_state_t state
)
105 ret
= m3_ipc
->ops
->prepare_low_power(m3_ipc
, WKUP_M3_DEEPSLEEP
);
107 case PM_SUSPEND_STANDBY
:
108 ret
= m3_ipc
->ops
->prepare_low_power(m3_ipc
, WKUP_M3_STANDBY
);
115 static void am33xx_pm_end(void)
117 m3_ipc
->ops
->finish_low_power(m3_ipc
);
120 static int am33xx_pm_valid(suspend_state_t state
)
123 case PM_SUSPEND_STANDBY
:
131 static const struct platform_suspend_ops am33xx_pm_ops
= {
132 .begin
= am33xx_pm_begin
,
133 .end
= am33xx_pm_end
,
134 .enter
= am33xx_pm_enter
,
135 .valid
= am33xx_pm_valid
,
137 #endif /* CONFIG_SUSPEND */
139 static void am33xx_pm_set_ipc_ops(void)
144 temp
= ti_emif_get_mem_type();
146 dev_err(pm33xx_dev
, "PM: Cannot determine memory type, no PM available\n");
149 m3_ipc
->ops
->set_mem_type(m3_ipc
, temp
);
151 /* Physical resume address to be used by ROM code */
152 resume_address
= am33xx_do_wfi_sram_phys
+
153 *pm_sram
->resume_offset
+ 0x4;
155 m3_ipc
->ops
->set_resume_address(m3_ipc
, (void *)resume_address
);
158 static void am33xx_pm_free_sram(void)
160 gen_pool_free(sram_pool
, ocmcram_location
, *pm_sram
->do_wfi_sz
);
161 gen_pool_free(sram_pool_data
, ocmcram_location_data
,
162 sizeof(struct am33xx_pm_ro_sram_data
));
166 * Push the minimal suspend-resume code to SRAM
168 static int am33xx_pm_alloc_sram(void)
170 struct device_node
*np
;
173 np
= of_find_compatible_node(NULL
, NULL
, "ti,omap3-mpu");
175 np
= of_find_compatible_node(NULL
, NULL
, "ti,omap4-mpu");
177 dev_err(pm33xx_dev
, "PM: %s: Unable to find device node for mpu\n",
183 sram_pool
= of_gen_pool_get(np
, "pm-sram", 0);
185 dev_err(pm33xx_dev
, "PM: %s: Unable to get sram pool for ocmcram\n",
191 sram_pool_data
= of_gen_pool_get(np
, "pm-sram", 1);
192 if (!sram_pool_data
) {
193 dev_err(pm33xx_dev
, "PM: %s: Unable to get sram data pool for ocmcram\n",
199 ocmcram_location
= gen_pool_alloc(sram_pool
, *pm_sram
->do_wfi_sz
);
200 if (!ocmcram_location
) {
201 dev_err(pm33xx_dev
, "PM: %s: Unable to allocate memory from ocmcram\n",
207 ocmcram_location_data
= gen_pool_alloc(sram_pool_data
,
208 sizeof(struct emif_regs_amx3
));
209 if (!ocmcram_location_data
) {
210 dev_err(pm33xx_dev
, "PM: Unable to allocate memory from ocmcram\n");
211 gen_pool_free(sram_pool
, ocmcram_location
, *pm_sram
->do_wfi_sz
);
220 static int am33xx_push_sram_idle(void)
222 struct am33xx_pm_ro_sram_data ro_sram_data
;
224 u32 table_addr
, ro_data_addr
;
227 ro_sram_data
.amx3_pm_sram_data_virt
= ocmcram_location_data
;
228 ro_sram_data
.amx3_pm_sram_data_phys
=
229 gen_pool_virt_to_phys(sram_pool_data
, ocmcram_location_data
);
231 /* Save physical address to calculate resume offset during pm init */
232 am33xx_do_wfi_sram_phys
= gen_pool_virt_to_phys(sram_pool
,
235 am33xx_do_wfi_sram
= sram_exec_copy(sram_pool
, (void *)ocmcram_location
,
237 *pm_sram
->do_wfi_sz
);
238 if (!am33xx_do_wfi_sram
) {
240 "PM: %s: am33xx_do_wfi copy to sram failed\n",
246 sram_suspend_address((unsigned long)pm_sram
->emif_sram_table
);
247 ret
= ti_emif_copy_pm_function_table(sram_pool
, (void *)table_addr
);
250 "PM: %s: EMIF function copy failed\n", __func__
);
251 return -EPROBE_DEFER
;
255 sram_suspend_address((unsigned long)pm_sram
->ro_sram_data
);
256 copy_addr
= sram_exec_copy(sram_pool
, (void *)ro_data_addr
,
258 sizeof(ro_sram_data
));
261 "PM: %s: ro_sram_data copy to sram failed\n",
269 static int am33xx_pm_probe(struct platform_device
*pdev
)
271 struct device
*dev
= &pdev
->dev
;
274 if (!of_machine_is_compatible("ti,am33xx") &&
275 !of_machine_is_compatible("ti,am43"))
278 pm_ops
= dev
->platform_data
;
280 dev_err(dev
, "PM: Cannot get core PM ops!\n");
284 pm_sram
= pm_ops
->get_sram_addrs();
286 dev_err(dev
, "PM: Cannot get PM asm function addresses!!\n");
292 ret
= am33xx_pm_alloc_sram();
296 ret
= am33xx_push_sram_idle();
300 m3_ipc
= wkup_m3_ipc_get();
302 dev_dbg(dev
, "PM: Cannot get wkup_m3_ipc handle\n");
307 am33xx_pm_set_ipc_ops();
309 #ifdef CONFIG_SUSPEND
310 suspend_set_ops(&am33xx_pm_ops
);
311 #endif /* CONFIG_SUSPEND */
313 ret
= pm_ops
->init();
315 dev_err(dev
, "Unable to call core pm init!\n");
317 goto err_put_wkup_m3_ipc
;
323 wkup_m3_ipc_put(m3_ipc
);
325 am33xx_pm_free_sram();
330 static int am33xx_pm_remove(struct platform_device
*pdev
)
332 suspend_set_ops(NULL
);
333 wkup_m3_ipc_put(m3_ipc
);
334 am33xx_pm_free_sram();
338 static struct platform_driver am33xx_pm_driver
= {
342 .probe
= am33xx_pm_probe
,
343 .remove
= am33xx_pm_remove
,
345 module_platform_driver(am33xx_pm_driver
);
347 MODULE_ALIAS("platform:pm33xx");
348 MODULE_LICENSE("GPL v2");
349 MODULE_DESCRIPTION("am33xx power management driver");