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_device;
 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_device;
 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_device;
 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_device:
 85	put_device(&pdev->dev);
 86put_node:
 87	of_node_put(np);
 88
 89	return ret;
 90}
 91
 92static int socfpga_pm_suspend(unsigned long arg)
 93{
 94	u32 ret;
 95
 96	if (!sdr_ctl_base_addr)
 97		return -EFAULT;
 98
 99	ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr);
100
101	pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__,
102		 ret & 0xffff, (ret >> 16) & 0xffff);
103
104	return 0;
105}
106
107static int socfpga_pm_enter(suspend_state_t state)
108{
109	switch (state) {
110	case PM_SUSPEND_MEM:
111		outer_disable();
112		cpu_suspend(0, socfpga_pm_suspend);
113		outer_resume();
114		break;
115	default:
116		return -EINVAL;
117	}
118	return 0;
119}
120
121static const struct platform_suspend_ops socfpga_pm_ops = {
122	.valid	= suspend_valid_only_mem,
123	.enter	= socfpga_pm_enter,
124};
125
126static int __init socfpga_pm_init(void)
127{
128	int ret;
129
130	ret = socfpga_setup_ocram_self_refresh();
131	if (ret)
132		return ret;
133
134	suspend_set_ops(&socfpga_pm_ops);
135	pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n");
136
137	return 0;
138}
139arch_initcall(socfpga_pm_init);