0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/bitops.h>
0013 #include <linux/genalloc.h>
0014 #include <linux/init.h>
0015 #include <linux/io.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/suspend.h>
0018 #include <asm/suspend.h>
0019 #include <asm/fncpy.h>
0020 #include "core.h"
0021
0022
0023 static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base);
0024
0025 static int socfpga_setup_ocram_self_refresh(void)
0026 {
0027 struct platform_device *pdev;
0028 phys_addr_t ocram_pbase;
0029 struct device_node *np;
0030 struct gen_pool *ocram_pool;
0031 unsigned long ocram_base;
0032 void __iomem *suspend_ocram_base;
0033 int ret = 0;
0034
0035 np = of_find_compatible_node(NULL, NULL, "mmio-sram");
0036 if (!np) {
0037 pr_err("%s: Unable to find mmio-sram in dtb\n", __func__);
0038 return -ENODEV;
0039 }
0040
0041 pdev = of_find_device_by_node(np);
0042 if (!pdev) {
0043 pr_warn("%s: failed to find ocram device!\n", __func__);
0044 ret = -ENODEV;
0045 goto put_node;
0046 }
0047
0048 ocram_pool = gen_pool_get(&pdev->dev, NULL);
0049 if (!ocram_pool) {
0050 pr_warn("%s: ocram pool unavailable!\n", __func__);
0051 ret = -ENODEV;
0052 goto put_device;
0053 }
0054
0055 ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz);
0056 if (!ocram_base) {
0057 pr_warn("%s: unable to alloc ocram!\n", __func__);
0058 ret = -ENOMEM;
0059 goto put_device;
0060 }
0061
0062 ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);
0063
0064 suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
0065 socfpga_sdram_self_refresh_sz,
0066 false);
0067 if (!suspend_ocram_base) {
0068 pr_warn("%s: __arm_ioremap_exec failed!\n", __func__);
0069 ret = -ENOMEM;
0070 goto put_device;
0071 }
0072
0073
0074 socfpga_sdram_self_refresh_in_ocram =
0075 (void *)fncpy(suspend_ocram_base,
0076 &socfpga_sdram_self_refresh,
0077 socfpga_sdram_self_refresh_sz);
0078
0079 WARN(!socfpga_sdram_self_refresh_in_ocram,
0080 "could not copy function to ocram");
0081 if (!socfpga_sdram_self_refresh_in_ocram)
0082 ret = -EFAULT;
0083
0084 put_device:
0085 put_device(&pdev->dev);
0086 put_node:
0087 of_node_put(np);
0088
0089 return ret;
0090 }
0091
0092 static int socfpga_pm_suspend(unsigned long arg)
0093 {
0094 u32 ret;
0095
0096 if (!sdr_ctl_base_addr)
0097 return -EFAULT;
0098
0099 ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr);
0100
0101 pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__,
0102 ret & 0xffff, (ret >> 16) & 0xffff);
0103
0104 return 0;
0105 }
0106
0107 static int socfpga_pm_enter(suspend_state_t state)
0108 {
0109 switch (state) {
0110 case PM_SUSPEND_MEM:
0111 outer_disable();
0112 cpu_suspend(0, socfpga_pm_suspend);
0113 outer_resume();
0114 break;
0115 default:
0116 return -EINVAL;
0117 }
0118 return 0;
0119 }
0120
0121 static const struct platform_suspend_ops socfpga_pm_ops = {
0122 .valid = suspend_valid_only_mem,
0123 .enter = socfpga_pm_enter,
0124 };
0125
0126 static int __init socfpga_pm_init(void)
0127 {
0128 int ret;
0129
0130 ret = socfpga_setup_ocram_self_refresh();
0131 if (ret)
0132 return ret;
0133
0134 suspend_set_ops(&socfpga_pm_ops);
0135 pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n");
0136
0137 return 0;
0138 }
0139 arch_initcall(socfpga_pm_init);