1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * arch/arm/mach-socfpga/pm.c |
4 | * |
5 | * Copyright (C) 2014-2015 Altera Corporation. All rights reserved. |
6 | * |
7 | * with code from pm-imx6.c |
8 | * Copyright 2011-2014 Freescale Semiconductor, Inc. |
9 | * Copyright 2011 Linaro Ltd. |
10 | */ |
11 | |
12 | #include <linux/bitops.h> |
13 | #include <linux/genalloc.h> |
14 | #include <linux/init.h> |
15 | #include <linux/io.h> |
16 | #include <linux/of.h> |
17 | #include <linux/of_platform.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/suspend.h> |
20 | #include <asm/suspend.h> |
21 | #include <asm/fncpy.h> |
22 | #include "core.h" |
23 | |
24 | /* Pointer to function copied to ocram */ |
25 | static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base); |
26 | |
27 | static int socfpga_setup_ocram_self_refresh(void) |
28 | { |
29 | struct platform_device *pdev; |
30 | phys_addr_t ocram_pbase; |
31 | struct device_node *np; |
32 | struct gen_pool *ocram_pool; |
33 | unsigned long ocram_base; |
34 | void __iomem *suspend_ocram_base; |
35 | int ret = 0; |
36 | |
37 | np = of_find_compatible_node(NULL, NULL, compat: "mmio-sram" ); |
38 | if (!np) { |
39 | pr_err("%s: Unable to find mmio-sram in dtb\n" , __func__); |
40 | return -ENODEV; |
41 | } |
42 | |
43 | pdev = of_find_device_by_node(np); |
44 | if (!pdev) { |
45 | pr_warn("%s: failed to find ocram device!\n" , __func__); |
46 | ret = -ENODEV; |
47 | goto put_node; |
48 | } |
49 | |
50 | ocram_pool = gen_pool_get(dev: &pdev->dev, NULL); |
51 | if (!ocram_pool) { |
52 | pr_warn("%s: ocram pool unavailable!\n" , __func__); |
53 | ret = -ENODEV; |
54 | goto put_device; |
55 | } |
56 | |
57 | ocram_base = gen_pool_alloc(pool: ocram_pool, size: socfpga_sdram_self_refresh_sz); |
58 | if (!ocram_base) { |
59 | pr_warn("%s: unable to alloc ocram!\n" , __func__); |
60 | ret = -ENOMEM; |
61 | goto put_device; |
62 | } |
63 | |
64 | ocram_pbase = gen_pool_virt_to_phys(pool: ocram_pool, ocram_base); |
65 | |
66 | suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, |
67 | socfpga_sdram_self_refresh_sz, |
68 | false); |
69 | if (!suspend_ocram_base) { |
70 | pr_warn("%s: __arm_ioremap_exec failed!\n" , __func__); |
71 | ret = -ENOMEM; |
72 | goto put_device; |
73 | } |
74 | |
75 | /* Copy the code that puts DDR in self refresh to ocram */ |
76 | socfpga_sdram_self_refresh_in_ocram = |
77 | (void *)fncpy(suspend_ocram_base, |
78 | &socfpga_sdram_self_refresh, |
79 | socfpga_sdram_self_refresh_sz); |
80 | |
81 | WARN(!socfpga_sdram_self_refresh_in_ocram, |
82 | "could not copy function to ocram" ); |
83 | if (!socfpga_sdram_self_refresh_in_ocram) |
84 | ret = -EFAULT; |
85 | |
86 | put_device: |
87 | put_device(dev: &pdev->dev); |
88 | put_node: |
89 | of_node_put(node: np); |
90 | |
91 | return ret; |
92 | } |
93 | |
94 | static int socfpga_pm_suspend(unsigned long arg) |
95 | { |
96 | u32 ret; |
97 | |
98 | if (!sdr_ctl_base_addr) |
99 | return -EFAULT; |
100 | |
101 | ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr); |
102 | |
103 | pr_debug("%s self-refresh loops request=%d exit=%d\n" , __func__, |
104 | ret & 0xffff, (ret >> 16) & 0xffff); |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | static int socfpga_pm_enter(suspend_state_t state) |
110 | { |
111 | switch (state) { |
112 | case PM_SUSPEND_MEM: |
113 | outer_disable(); |
114 | cpu_suspend(0, socfpga_pm_suspend); |
115 | outer_resume(); |
116 | break; |
117 | default: |
118 | return -EINVAL; |
119 | } |
120 | return 0; |
121 | } |
122 | |
123 | static const struct platform_suspend_ops socfpga_pm_ops = { |
124 | .valid = suspend_valid_only_mem, |
125 | .enter = socfpga_pm_enter, |
126 | }; |
127 | |
128 | static int __init socfpga_pm_init(void) |
129 | { |
130 | int ret; |
131 | |
132 | ret = socfpga_setup_ocram_self_refresh(); |
133 | if (ret) |
134 | return ret; |
135 | |
136 | suspend_set_ops(ops: &socfpga_pm_ops); |
137 | pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n" ); |
138 | |
139 | return 0; |
140 | } |
141 | arch_initcall(socfpga_pm_init); |
142 | |