diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 21:34:35 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 21:34:35 +0300 |
commit | 4aa705b18bf17c4ff33ff7bbcd3f0c596443fa81 (patch) | |
tree | 3b166bff290d123ccaa88598ad2d45be67f5b358 /arch/arm/mach-socfpga/pm.c | |
parent | c11d716218910c3aa2bac1bb641e6086ad649555 (diff) | |
parent | 2879e43f09122f8b3ef5456e3d7e48716b086e60 (diff) | |
download | linux-4aa705b18bf17c4ff33ff7bbcd3f0c596443fa81.tar.xz |
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform support updates from Kevin Hilman:
"Our SoC branch usually contains expanded support for new SoCs and
other core platform code. Some highlights from this round:
- sunxi: SMP support for A23 SoC
- socpga: big-endian support
- pxa: conversion to common clock framework
- bcm: SMP support for BCM63138
- imx: support new I.MX7D SoC
- zte: basic support for ZX296702 SoC"
* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (134 commits)
ARM: zx: Add basic defconfig support for ZX296702
ARM: dts: zx: add an initial zx296702 dts and doc
clk: zx: add clock support to zx296702
dt-bindings: Add #defines for ZTE ZX296702 clocks
ARM: socfpga: fix build error due to secondary_startup
MAINTAINERS: ARM64: EXYNOS: Extend entry for ARM64 DTS
ARM: ep93xx: simone: support for SPI-based MMC/SD cards
MAINTAINERS: update Shawn's email to use kernel.org one
ARM: socfpga: support suspend to ram
ARM: socfpga: add CPU_METHOD_OF_DECLARE for Arria 10
ARM: socfpga: use CPU_METHOD_OF_DECLARE for socfpga_cyclone5
ARM: EXYNOS: register power domain driver from core_initcall
ARM: EXYNOS: use PS_HOLD based poweroff for all supported SoCs
ARM: SAMSUNG: Constify platform_device_id
ARM: EXYNOS: Constify irq_domain_ops
ARM: EXYNOS: add coupled cpuidle support for Exynos3250
ARM: EXYNOS: add exynos_get_boot_addr() helper
ARM: EXYNOS: add exynos_set_boot_addr() helper
ARM: EXYNOS: make exynos_core_restart() less verbose
ARM: EXYNOS: fix exynos_boot_secondary() return value on timeout
...
Diffstat (limited to 'arch/arm/mach-socfpga/pm.c')
-rw-r--r-- | arch/arm/mach-socfpga/pm.c | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/arch/arm/mach-socfpga/pm.c b/arch/arm/mach-socfpga/pm.c new file mode 100644 index 000000000000..1ed89fc2b7a8 --- /dev/null +++ b/arch/arm/mach-socfpga/pm.c @@ -0,0 +1,149 @@ +/* + * arch/arm/mach-socfpga/pm.c + * + * Copyright (C) 2014-2015 Altera Corporation. All rights reserved. + * + * with code from pm-imx6.c + * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/bitops.h> +#include <linux/genalloc.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/of_platform.h> +#include <linux/suspend.h> +#include <asm/suspend.h> +#include <asm/fncpy.h> +#include "core.h" + +/* Pointer to function copied to ocram */ +static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base); + +static int socfpga_setup_ocram_self_refresh(void) +{ + struct platform_device *pdev; + phys_addr_t ocram_pbase; + struct device_node *np; + struct gen_pool *ocram_pool; + unsigned long ocram_base; + void __iomem *suspend_ocram_base; + int ret = 0; + + np = of_find_compatible_node(NULL, NULL, "mmio-sram"); + if (!np) { + pr_err("%s: Unable to find mmio-sram in dtb\n", __func__); + return -ENODEV; + } + + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_warn("%s: failed to find ocram device!\n", __func__); + ret = -ENODEV; + goto put_node; + } + + ocram_pool = dev_get_gen_pool(&pdev->dev); + if (!ocram_pool) { + pr_warn("%s: ocram pool unavailable!\n", __func__); + ret = -ENODEV; + goto put_node; + } + + ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz); + if (!ocram_base) { + pr_warn("%s: unable to alloc ocram!\n", __func__); + ret = -ENOMEM; + goto put_node; + } + + ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base); + + suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, + socfpga_sdram_self_refresh_sz, + false); + if (!suspend_ocram_base) { + pr_warn("%s: __arm_ioremap_exec failed!\n", __func__); + ret = -ENOMEM; + goto put_node; + } + + /* Copy the code that puts DDR in self refresh to ocram */ + socfpga_sdram_self_refresh_in_ocram = + (void *)fncpy(suspend_ocram_base, + &socfpga_sdram_self_refresh, + socfpga_sdram_self_refresh_sz); + + WARN(!socfpga_sdram_self_refresh_in_ocram, + "could not copy function to ocram"); + if (!socfpga_sdram_self_refresh_in_ocram) + ret = -EFAULT; + +put_node: + of_node_put(np); + + return ret; +} + +static int socfpga_pm_suspend(unsigned long arg) +{ + u32 ret; + + if (!sdr_ctl_base_addr) + return -EFAULT; + + ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr); + + pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__, + ret & 0xffff, (ret >> 16) & 0xffff); + + return 0; +} + +static int socfpga_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + outer_disable(); + cpu_suspend(0, socfpga_pm_suspend); + outer_resume(); + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct platform_suspend_ops socfpga_pm_ops = { + .valid = suspend_valid_only_mem, + .enter = socfpga_pm_enter, +}; + +static int __init socfpga_pm_init(void) +{ + int ret; + + ret = socfpga_setup_ocram_self_refresh(); + if (ret) + return ret; + + suspend_set_ops(&socfpga_pm_ops); + pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n"); + + return 0; +} +arch_initcall(socfpga_pm_init); |