Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  arch/arm/mach-socfpga/pm.c
0004  *
0005  * Copyright (C) 2014-2015 Altera Corporation. All rights reserved.
0006  *
0007  * with code from pm-imx6.c
0008  * Copyright 2011-2014 Freescale Semiconductor, Inc.
0009  * Copyright 2011 Linaro Ltd.
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 /* Pointer to function copied to ocram */
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     /* Copy the code that puts DDR in self refresh to ocram */
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);