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_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 */
 23static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base);
 24
 25static 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
 84put_node:
 85	of_node_put(np);
 86
 87	return ret;
 88}
 89
 90static 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
105static 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
119static const struct platform_suspend_ops socfpga_pm_ops = {
120	.valid	= suspend_valid_only_mem,
121	.enter	= socfpga_pm_enter,
122};
123
124static 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}
137arch_initcall(socfpga_pm_init);