Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  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 */
 25static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base);
 26
 27static 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, "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(&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(ocram_pool, 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(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
 86put_device:
 87	put_device(&pdev->dev);
 88put_node:
 89	of_node_put(np);
 90
 91	return ret;
 92}
 93
 94static 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
109static 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
123static const struct platform_suspend_ops socfpga_pm_ops = {
124	.valid	= suspend_valid_only_mem,
125	.enter	= socfpga_pm_enter,
126};
127
128static 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(&socfpga_pm_ops);
137	pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n");
138
139	return 0;
140}
141arch_initcall(socfpga_pm_init);