root/arch/arm/mach-socfpga/pm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. socfpga_setup_ocram_self_refresh
  2. socfpga_pm_suspend
  3. socfpga_pm_enter
  4. socfpga_pm_init

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

/* [<][>][^][v][top][bottom][index][help] */