summaryrefslogtreecommitdiffstats
path: root/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch')
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch1529
1 files changed, 1529 insertions, 0 deletions
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch
new file mode 100755
index 000000000..4db90e4e0
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch
@@ -0,0 +1,1529 @@
+From 34a419b3fd88a2275ca681c99a5787b937e0f39d Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 16:47:29 +0900
+Subject: [PATCH 02/15] Add Hibernation arch code(Only R-CAR M2W)
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ arch/arm/Kconfig | 5 +
+ arch/arm/include/asm/memory.h | 1 +
+ arch/arm/include/asm/smp.h | 4 +
+ arch/arm/include/asm/suspend.h | 3 +
+ arch/arm/kernel/Makefile | 1 +
+ arch/arm/kernel/hibernate.c | 139 ++++++++++++++
+ arch/arm/kernel/process.c | 7 +-
+ arch/arm/kernel/sleep.S | 8 +
+ arch/arm/kernel/smp.c | 6 +
+ arch/arm/kernel/suspend.c | 64 ++++---
+ arch/arm/mach-shmobile/Kconfig | 65 +++++++
+ arch/arm/mach-shmobile/Makefile | 1 +
+ arch/arm/mach-shmobile/common.h | 8 +
+ arch/arm/mach-shmobile/crc32_word4.c | 299 +++++++++++++++++++++++++++++++
+ arch/arm/mach-shmobile/crc32_word4.h | 23 +++
+ arch/arm/mach-shmobile/headsmp.S | 2 -
+ arch/arm/mach-shmobile/hibernation.c | 243 +++++++++++++++++++++++++
+ arch/arm/mach-shmobile/platsmp-apmu.c | 13 +-
+ arch/arm/mach-shmobile/platsmp-rst.c | 3 +-
+ arch/arm/mach-shmobile/pm-r8a7791.c | 27 +--
+ arch/arm/mach-shmobile/rcar-gen2.h | 39 ++++
+ arch/arm/mach-shmobile/setup-r8a7791.c | 10 +-
+ arch/arm/mach-shmobile/setup-rcar-gen2.c | 14 +-
+ arch/arm/mach-shmobile/smp-r8a7791.c | 8 +-
+ arch/arm/mm/proc-v7.S | 31 ++--
+ 25 files changed, 947 insertions(+), 77 deletions(-)
+ create mode 100644 arch/arm/kernel/hibernate.c
+ create mode 100644 arch/arm/mach-shmobile/crc32_word4.c
+ create mode 100644 arch/arm/mach-shmobile/crc32_word4.h
+ create mode 100644 arch/arm/mach-shmobile/hibernation.c
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 4dd95dd..eb76182 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -2232,6 +2232,11 @@ config ARCH_SUSPEND_POSSIBLE
+ config ARM_CPU_SUSPEND
+ def_bool PM_SLEEP
+
++config ARCH_HIBERNATION_POSSIBLE
++ bool
++ depends on MMU
++ default y if ARCH_SUSPEND_POSSIBLE
++
+ endmenu
+
+ source "net/Kconfig"
+diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
+index 48cb2b3..01158e7 100644
+--- a/arch/arm/include/asm/memory.h
++++ b/arch/arm/include/asm/memory.h
+@@ -241,6 +241,7 @@ static inline void *phys_to_virt(phys_addr_t x)
+ #define __pa(x) __virt_to_phys((unsigned long)(x))
+ #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
+ #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
++#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
+
+ /*
+ * Virtual <-> DMA view memory address translations
+diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
+index d3a22be..b718040 100644
+--- a/arch/arm/include/asm/smp.h
++++ b/arch/arm/include/asm/smp.h
+@@ -42,6 +42,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs);
+ */
+ extern void smp_init_cpus(void);
+
++/*
++ * Provide a function to call machine specific cpu initialization sequence
++ */
++extern void arch_smp_prepare_cpus(unsigned int max_cpus);
+
+ /*
+ * Provide a function to raise an IPI cross call on CPUs in callmap.
+diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
+index 1c0a551..709afa4 100644
+--- a/arch/arm/include/asm/suspend.h
++++ b/arch/arm/include/asm/suspend.h
+@@ -3,5 +3,8 @@
+
+ extern void cpu_resume(void);
+ extern int cpu_suspend(unsigned long, int (*)(unsigned long));
++extern const void __nosave_begin, __nosave_end;
++extern void cpu_resume_restore_nosave(u32, u32, u32);
++extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
+
+ #endif
+diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
+index 5f3338e..70f439f 100644
+--- a/arch/arm/kernel/Makefile
++++ b/arch/arm/kernel/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o
+ obj-$(CONFIG_ISA_DMA) += dma-isa.o
+ obj-$(CONFIG_PCI) += bios32.o isa.o
+ obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o
++obj-$(CONFIG_HIBERNATION) += hibernate.o
+ obj-$(CONFIG_SMP) += smp.o smp_tlb.o
+ obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
+ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
+diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c
+new file mode 100644
+index 0000000..9380fe2
+--- /dev/null
++++ b/arch/arm/kernel/hibernate.c
+@@ -0,0 +1,139 @@
++/*
++ * Hibernation support specific for ARM
++ *
++ * Derived from work on ARM hibernation support by:
++ *
++ * Ubuntu project, hibernation support for mach-dove
++ * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu)
++ * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.)
++ * https://lkml.org/lkml/2010/6/18/4
++ * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html
++ * https://patchwork.kernel.org/patch/96442/
++ *
++ * Copyright (C) 2006 Rafael J. Wysocki <rjw at sisk.pl>
++ *
++ * License terms: GNU General Public License (GPL) version 2
++ */
++
++#include <linux/mm.h>
++#include <linux/suspend.h>
++#include <asm/system_misc.h>
++#include <asm/idmap.h>
++#include <asm/suspend.h>
++#include <asm/memory.h>
++
++struct swsusp_archdata {
++ u32 nosave_backup_phys;
++ u32 nosave_begin_phys;
++ u32 nosave_end_phys;
++ /* Function pointer */
++ u32 cpu_resume_restore_nosave;
++};
++
++static struct swsusp_archdata __archdata;
++
++void swsusp_arch_add_info(char *archdata)
++{
++ memcpy((void *)archdata, (void *)&__archdata,
++ sizeof(struct swsusp_archdata));
++}
++
++int pfn_is_nosave(unsigned long pfn)
++{
++ unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin);
++ unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1);
++
++ return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn);
++}
++
++void notrace save_processor_state(void)
++{
++ WARN_ON(num_online_cpus() != 1);
++ local_fiq_disable();
++}
++
++void notrace restore_processor_state(void)
++{
++ local_fiq_enable();
++}
++
++/*
++ * Snapshot kernel memory and reset the system.
++ *
++ * swsusp_save() is executed in the suspend finisher so that the CPU
++ * context pointer and memory are part of the saved image, which is
++ * required by the resume kernel image to restart execution from
++ * swsusp_arch_suspend().
++ *
++ * soft_restart is not technically needed, but is used to get success
++ * returned from cpu_suspend.
++ *
++ * When soft reboot completes, the hibernation snapshot is written out.
++ */
++static int notrace arch_save_image(unsigned long unused)
++{
++ int ret;
++ ret = swsusp_save();
++ if (ret == 0)
++ soft_restart(virt_to_phys(cpu_resume));
++ return ret;
++}
++
++/*
++ * Save the current CPU state before suspend / poweroff.
++ */
++int notrace swsusp_arch_suspend(void)
++{
++ return cpu_suspend(0, arch_save_image);
++}
++
++/*
++ * Restore page contents for physical pages that were in use during loading
++ * hibernation image. Switch to idmap_pgd so the physical page tables
++ * are overwritten with the same contents.
++ */
++static void notrace arch_restore_image(void *unused)
++{
++ struct pbe *pbe;
++
++
++ cpu_switch_mm(idmap_pgd, &init_mm);
++ for (pbe = restore_pblist; pbe; pbe = pbe->next)
++ copy_page(pbe->orig_address, pbe->address);
++
++ soft_restart(virt_to_phys(cpu_resume));
++}
++static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata;
++
++/*
++ * Resume from the hibernation image.
++ * Due to the kernel heap / data restore, stack contents change underneath
++ * and that would make function calls impossible; switch to a temporary
++ * stack within the nosave region to avoid that problem.
++ */
++int swsusp_arch_resume(void)
++{
++ call_with_stack(arch_restore_image, 0,
++ resume_stack + ARRAY_SIZE(resume_stack));
++ return 0;
++}
++
++static int __init swsusp_arch_init(void)
++{
++ char *backup;
++ size_t len;
++
++ len = &__nosave_end - &__nosave_begin;
++ backup = kmalloc(len, GFP_KERNEL);
++ if (backup)
++ memcpy(backup, &__nosave_begin, len);
++
++ __archdata.nosave_backup_phys = virt_to_phys(backup);
++ __archdata.nosave_begin_phys = virt_to_phys(&__nosave_begin);
++ __archdata.nosave_end_phys = virt_to_phys(&__nosave_end);
++ __archdata.cpu_resume_restore_nosave =
++ virt_to_phys(cpu_resume_restore_nosave);
++
++ return 0;
++}
++late_initcall(swsusp_arch_init);
+diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
+index 7927629..ae56f0b 100644
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -98,7 +98,7 @@ void soft_restart(unsigned long addr)
+ u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack);
+
+ /* Disable interrupts first */
+- local_irq_disable();
++ raw_local_irq_disable();
+ local_fiq_disable();
+
+ /* Disable the L2 if we're the last man standing. */
+@@ -284,12 +284,17 @@ void __show_regs(struct pt_regs *regs)
+ buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
+ buf[4] = '\0';
+
++#ifndef CONFIG_CPU_V7M
+ printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n",
+ buf, interrupts_enabled(regs) ? "n" : "ff",
+ fast_interrupts_enabled(regs) ? "n" : "ff",
+ processor_modes[processor_mode(regs)],
+ isa_modes[isa_mode(regs)],
+ get_fs() == get_ds() ? "kernel" : "user");
++#else
++ printk("xPSR: %08lx\n", regs->ARM_cpsr);
++#endif
++
+ #ifdef CONFIG_CPU_CP15
+ {
+ unsigned int ctrl;
+diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
+index 987dcf3..e4d092f 100644
+--- a/arch/arm/kernel/sleep.S
++++ b/arch/arm/kernel/sleep.S
+@@ -98,6 +98,14 @@ THUMB( mov sp, r2 )
+ THUMB( bx r3 )
+ ENDPROC(cpu_resume)
+
++ .align
++ENTRY(cpu_resume_restore_nosave)
++1: ldmia r0!, {r3-r10}
++ stmia r1!, {r3-r10}
++ cmp r1, r2
++ bne 1b
++ b cpu_resume
++
+ sleep_save_sp:
+ .rept CONFIG_NR_CPUS
+ .long 0 @ preserve stack phys ptr here
+diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
+index 5919eb4..c9a2991 100644
+--- a/arch/arm/kernel/smp.c
++++ b/arch/arm/kernel/smp.c
+@@ -125,6 +125,12 @@ void __init smp_init_cpus(void)
+ smp_ops.smp_init_cpus();
+ }
+
++void arch_smp_prepare_cpus(unsigned int max_cpus)
++{
++ if (smp_ops.smp_prepare_cpus)
++ smp_ops.smp_prepare_cpus(max_cpus);
++}
++
+ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+ {
+ if (smp_ops.smp_boot_secondary)
+diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
+index c59c97e..38a5067 100644
+--- a/arch/arm/kernel/suspend.c
++++ b/arch/arm/kernel/suspend.c
+@@ -10,6 +10,42 @@
+ extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
+ extern void cpu_resume_mmu(void);
+
++#ifdef CONFIG_MMU
++/*
++ * Hide the first two arguments to __cpu_suspend - these are an implementation
++ * detail which platform code shouldn't have to know about.
++ */
++int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
++{
++ struct mm_struct *mm = current->active_mm;
++ int ret;
++
++ if (!idmap_pgd)
++ return -EINVAL;
++
++ /*
++ * Provide a temporary page table with an identity mapping for
++ * the MMU-enable code, required for resuming. On successful
++ * resume (indicated by a zero return code), we need to switch
++ * back to the correct page tables.
++ */
++ ret = __cpu_suspend(arg, fn);
++ if (ret == 0) {
++ cpu_switch_mm(mm->pgd, mm);
++ local_flush_bp_all();
++ local_flush_tlb_all();
++ }
++
++ return ret;
++}
++#else
++int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
++{
++ return __cpu_suspend(arg, fn);
++}
++#define idmap_pgd NULL
++#endif
++
+ /*
+ * This is called by __cpu_suspend() to save the state, and do whatever
+ * flushing is required to ensure that when the CPU goes to sleep we have
+@@ -46,31 +82,3 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
+ outer_clean_range(virt_to_phys(save_ptr),
+ virt_to_phys(save_ptr) + sizeof(*save_ptr));
+ }
+-
+-/*
+- * Hide the first two arguments to __cpu_suspend - these are an implementation
+- * detail which platform code shouldn't have to know about.
+- */
+-int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+-{
+- struct mm_struct *mm = current->active_mm;
+- int ret;
+-
+- if (!idmap_pgd)
+- return -EINVAL;
+-
+- /*
+- * Provide a temporary page table with an identity mapping for
+- * the MMU-enable code, required for resuming. On successful
+- * resume (indicated by a zero return code), we need to switch
+- * back to the correct page tables.
+- */
+- ret = __cpu_suspend(arg, fn);
+- if (ret == 0) {
+- cpu_switch_mm(mm->pgd, mm);
+- local_flush_bp_all();
+- local_flush_tlb_all();
+- }
+-
+- return ret;
+-}
+diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
+index 7c15245..73371de 100644
+--- a/arch/arm/mach-shmobile/Kconfig
++++ b/arch/arm/mach-shmobile/Kconfig
+@@ -64,6 +64,25 @@ config MACH_KOELSCH
+ select MICREL_PHY if SH_ETH
+ select SND_SOC_AK4642 if SND_SIMPLE_CARD
+
++config MACH_KOELSCH_FTEN
++ bool "FTEN spf development environment"
++ depends on MACH_KOELSCH
++
++config MACH_FTEN
++ bool
++
++config MACH_FTEN_DT
++ bool
++
++config MACH_FTEN_M2W
++ bool "FTEN R-Car M2W board"
++ depends on ARCH_R8A7791
++ select MACH_FTEN
++ select MACH_FTEN_DT
++ select HAVE_IDE
++ select FIQ
++ select SND_SOC_DIRANA3 if SND_SIMPLE_CARD
++
+ config MACH_LAGER
+ bool "Lager board"
+ depends on ARCH_R8A7790
+@@ -76,6 +95,15 @@ config MACH_GOSE
+ select MICREL_PHY if SH_ETH
+ select SND_SOC_AK4642 if SND_SIMPLE_CARD
+
++config MACH_FTEN_M2N
++ bool "FTEN R-Car M2N board"
++ depends on ARCH_R8A7793
++ select MACH_FTEN
++ select MACH_FTEN_DT
++ select HAVE_IDE
++ select FIQ
++ select SND_SOC_DIRANA3 if SND_SIMPLE_CARD
++
+ config MACH_ALT
+ bool "Alt board"
+ depends on ARCH_R8A7794
+@@ -287,6 +315,19 @@ config MACH_KOELSCH
+ select USE_OF
+ select MICREL_PHY if SH_ETH
+
++config MACH_FTEN
++ bool "FTEN strawberry board"
++ depends on ARCH_R8A7791
++ select USE_OF
++ select HAVE_IDE
++
++config MACH_FTEN_DT
++ bool "FTEN strawberry board - Device Tree Implementation"
++ depends on ARCH_R8A7791
++ select USE_OF
++ select HAVE_IDE
++ select SND_SOC_DIRANA3 if SND_SIMPLE_CARD
++
+ config MACH_KZM9G
+ bool "KZM-A9-GT board"
+ depends on ARCH_SH73A0
+@@ -360,4 +401,28 @@ config EM_TIMER_STI
+
+ endmenu
+
++if HIBERNATION
++
++menu "Hibernation area parameters"
++
++config SWSUSP_AREA
++ hex "RAM hibernation area address"
++ default "0x44000000"
++ depends on HIBERNATION
++ ---help---
++ RAM hibernation area address, this is required for CRC
++ calculation of final compressed hibernation image
++
++config SWSUSP_AREA_SIZE
++ hex "RAM hibernation area size"
++ default "0x4000000"
++ depends on HIBERNATION
++ ---help---
++ RAM hibernation area size, this is required for CRC
++ calculation of final compressed hibernation image
++
++endmenu
++
++endif
++
+ endif
+diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
+index 43b4025..71cfcfa 100644
+--- a/arch/arm/mach-shmobile/Makefile
++++ b/arch/arm/mach-shmobile/Makefile
+@@ -55,6 +55,7 @@ smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o
+
+ # PM objects
+ obj-$(CONFIG_SUSPEND) += suspend.o
++obj-$(CONFIG_HIBERNATION) += hibernation.o
+ obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+ obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+ obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o pm-rmobile.o
+diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h
+index 95a77a0..37c7f87 100644
+--- a/arch/arm/mach-shmobile/common.h
++++ b/arch/arm/mach-shmobile/common.h
+@@ -25,6 +25,7 @@ struct clk;
+ extern int shmobile_clk_init(void);
+ extern void shmobile_handle_irq_intc(struct pt_regs *);
+ extern struct platform_suspend_ops shmobile_suspend_ops;
++extern const struct platform_hibernation_ops shmobile_hibernation_ops;
+ struct cpuidle_driver;
+ extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv);
+ extern void shmobile_smp_apmu_enter_cpuidle(void);
+@@ -37,6 +38,12 @@ static inline int shmobile_suspend_init(void) { return 0; }
+ static inline void shmobile_smp_apmu_suspend_init(void) { }
+ #endif
+
++#ifdef CONFIG_HIBERNATION
++int shmobile_hibernation_init(void);
++#else
++static inline int shmobile_hibernation_init(void) { return 0; }
++#endif
++
+ #ifdef CONFIG_CPU_IDLE
+ int shmobile_cpuidle_init(void);
+ #else
+@@ -59,6 +66,7 @@ extern unsigned int l2actlr_value;
+ static inline void __init shmobile_init_late(void)
+ {
+ shmobile_suspend_init();
++ shmobile_hibernation_init();
+ shmobile_cpuidle_init();
+ shmobile_cpufreq_init();
+ }
+diff --git a/arch/arm/mach-shmobile/crc32_word4.c b/arch/arm/mach-shmobile/crc32_word4.c
+new file mode 100644
+index 0000000..8aaefc6
+--- /dev/null
++++ b/arch/arm/mach-shmobile/crc32_word4.c
+@@ -0,0 +1,299 @@
++/*************************************************************************
++ * crc32_word4.c: rapid CRC32
++ * Coptright (C) FUJITSUTEN Limited, 2015 All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that 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, write to the Free Software Foundation,
++ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++ *************************************************************************/
++#ifdef OWNTEST
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <asm/types.h>
++typedef unsigned int u_int32_t;
++#else
++#endif
++
++#include "crc32_word4.h"
++
++#define CRC_INIT_VALUE (-1)
++#define CRC_FIX(_crc32) (~(_crc32))
++
++/* #define HWDPLS_ENABLE */
++#define __HWDTPLS_OUT()
++#define MEASURE(msg)
++
++/**** calc_crc32.c *****/
++
++/*
++ * CRC32は、ISO 3309 で規程され
++ * そのサンプルは
++ * RFC 2083 :PNG(Poratble Network Graphics
++ * で公になっています。本プログラムは、RFC2083 で掲示された
++ * CRC32を独自に最適化したプログラムです。
++ */
++const static u_int32_t CRC_Table[256] = {
++ 0x00000000 , 0x77073096 , 0xee0e612c , 0x990951ba , 0x076dc419 , 0x706af48f , 0xe963a535 , 0x9e6495a3 ,
++ 0x0edb8832 , 0x79dcb8a4 , 0xe0d5e91e , 0x97d2d988 , 0x09b64c2b , 0x7eb17cbd , 0xe7b82d07 , 0x90bf1d91 ,
++ 0x1db71064 , 0x6ab020f2 , 0xf3b97148 , 0x84be41de , 0x1adad47d , 0x6ddde4eb , 0xf4d4b551 , 0x83d385c7 ,
++ 0x136c9856 , 0x646ba8c0 , 0xfd62f97a , 0x8a65c9ec , 0x14015c4f , 0x63066cd9 , 0xfa0f3d63 , 0x8d080df5 ,
++ 0x3b6e20c8 , 0x4c69105e , 0xd56041e4 , 0xa2677172 , 0x3c03e4d1 , 0x4b04d447 , 0xd20d85fd , 0xa50ab56b ,
++ 0x35b5a8fa , 0x42b2986c , 0xdbbbc9d6 , 0xacbcf940 , 0x32d86ce3 , 0x45df5c75 , 0xdcd60dcf , 0xabd13d59 ,
++ 0x26d930ac , 0x51de003a , 0xc8d75180 , 0xbfd06116 , 0x21b4f4b5 , 0x56b3c423 , 0xcfba9599 , 0xb8bda50f ,
++ 0x2802b89e , 0x5f058808 , 0xc60cd9b2 , 0xb10be924 , 0x2f6f7c87 , 0x58684c11 , 0xc1611dab , 0xb6662d3d ,
++ 0x76dc4190 , 0x01db7106 , 0x98d220bc , 0xefd5102a , 0x71b18589 , 0x06b6b51f , 0x9fbfe4a5 , 0xe8b8d433 ,
++ 0x7807c9a2 , 0x0f00f934 , 0x9609a88e , 0xe10e9818 , 0x7f6a0dbb , 0x086d3d2d , 0x91646c97 , 0xe6635c01 ,
++ 0x6b6b51f4 , 0x1c6c6162 , 0x856530d8 , 0xf262004e , 0x6c0695ed , 0x1b01a57b , 0x8208f4c1 , 0xf50fc457 ,
++ 0x65b0d9c6 , 0x12b7e950 , 0x8bbeb8ea , 0xfcb9887c , 0x62dd1ddf , 0x15da2d49 , 0x8cd37cf3 , 0xfbd44c65 ,
++ 0x4db26158 , 0x3ab551ce , 0xa3bc0074 , 0xd4bb30e2 , 0x4adfa541 , 0x3dd895d7 , 0xa4d1c46d , 0xd3d6f4fb ,
++ 0x4369e96a , 0x346ed9fc , 0xad678846 , 0xda60b8d0 , 0x44042d73 , 0x33031de5 , 0xaa0a4c5f , 0xdd0d7cc9 ,
++ 0x5005713c , 0x270241aa , 0xbe0b1010 , 0xc90c2086 , 0x5768b525 , 0x206f85b3 , 0xb966d409 , 0xce61e49f ,
++ 0x5edef90e , 0x29d9c998 , 0xb0d09822 , 0xc7d7a8b4 , 0x59b33d17 , 0x2eb40d81 , 0xb7bd5c3b , 0xc0ba6cad ,
++ 0xedb88320 , 0x9abfb3b6 , 0x03b6e20c , 0x74b1d29a , 0xead54739 , 0x9dd277af , 0x04db2615 , 0x73dc1683 ,
++ 0xe3630b12 , 0x94643b84 , 0x0d6d6a3e , 0x7a6a5aa8 , 0xe40ecf0b , 0x9309ff9d , 0x0a00ae27 , 0x7d079eb1 ,
++ 0xf00f9344 , 0x8708a3d2 , 0x1e01f268 , 0x6906c2fe , 0xf762575d , 0x806567cb , 0x196c3671 , 0x6e6b06e7 ,
++ 0xfed41b76 , 0x89d32be0 , 0x10da7a5a , 0x67dd4acc , 0xf9b9df6f , 0x8ebeeff9 , 0x17b7be43 , 0x60b08ed5 ,
++ 0xd6d6a3e8 , 0xa1d1937e , 0x38d8c2c4 , 0x4fdff252 , 0xd1bb67f1 , 0xa6bc5767 , 0x3fb506dd , 0x48b2364b ,
++ 0xd80d2bda , 0xaf0a1b4c , 0x36034af6 , 0x41047a60 , 0xdf60efc3 , 0xa867df55 , 0x316e8eef , 0x4669be79 ,
++ 0xcb61b38c , 0xbc66831a , 0x256fd2a0 , 0x5268e236 , 0xcc0c7795 , 0xbb0b4703 , 0x220216b9 , 0x5505262f ,
++ 0xc5ba3bbe , 0xb2bd0b28 , 0x2bb45a92 , 0x5cb36a04 , 0xc2d7ffa7 , 0xb5d0cf31 , 0x2cd99e8b , 0x5bdeae1d ,
++ 0x9b64c2b0 , 0xec63f226 , 0x756aa39c , 0x026d930a , 0x9c0906a9 , 0xeb0e363f , 0x72076785 , 0x05005713 ,
++ 0x95bf4a82 , 0xe2b87a14 , 0x7bb12bae , 0x0cb61b38 , 0x92d28e9b , 0xe5d5be0d , 0x7cdcefb7 , 0x0bdbdf21 ,
++ 0x86d3d2d4 , 0xf1d4e242 , 0x68ddb3f8 , 0x1fda836e , 0x81be16cd , 0xf6b9265b , 0x6fb077e1 , 0x18b74777 ,
++ 0x88085ae6 , 0xff0f6a70 , 0x66063bca , 0x11010b5c , 0x8f659eff , 0xf862ae69 , 0x616bffd3 , 0x166ccf45 ,
++ 0xa00ae278 , 0xd70dd2ee , 0x4e048354 , 0x3903b3c2 , 0xa7672661 , 0xd06016f7 , 0x4969474d , 0x3e6e77db ,
++ 0xaed16a4a , 0xd9d65adc , 0x40df0b66 , 0x37d83bf0 , 0xa9bcae53 , 0xdebb9ec5 , 0x47b2cf7f , 0x30b5ffe9 ,
++ 0xbdbdf21c , 0xcabac28a , 0x53b39330 , 0x24b4a3a6 , 0xbad03605 , 0xcdd70693 , 0x54de5729 , 0x23d967bf ,
++ 0xb3667a2e , 0xc4614ab8 , 0x5d681b02 , 0x2a6f2b94 , 0xb40bbe37 , 0xc30c8ea1 , 0x5a05df1b , 0x2d02ef8d ,
++};
++
++/***
++ * CRC Table creater.
++ *
++void make_crc_table(void) {
++ u_int32_t c;
++ u_int32_t n, k;
++ for (n = 0; n < 256; n++)
++ {
++ c = (u_int32_t) n;
++ for (k = 0; k < 8; k++)
++ {
++ if (c & 1)
++ c = 0xedb88320L ^ (c >> 1);
++ else
++ c = c >> 1;
++ }
++ CRC_Table[n] = c;
++ }
++}
++***/
++#define NEXT_PTR (4)
++
++static __inline__
++u_int32_t _update_crc(u_int32_t crc, unsigned char *buf, size_t len)
++{
++ u_int32_t c = crc;
++ size_t n;
++ for (n = 0; n < len; n++)
++ c = CRC_Table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
++ return c;
++}
++/*********************************************************************
++ * update_crc4x4()()
++ * calc_crc32() をベースに、4 ワード毎に個別に CRC32 を計算する方法
++ *
++ * +0 +1 +2 +3
++ * +0x00 AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
++ * +0x04 EEEEEEEE FFFFFFFF 00000000 11111111
++ * : : : :
++ * CRC32 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
++ *
++ *********************************************************************/
++
++static __inline__
++void update_crc4x4(u_int32_t crc[4], unsigned char *buf)
++{
++ u_int32_t c1, c2, c3, c4;
++ u_int32_t *p = (void *)buf;
++
++ c1 = crc[0] ^ p[0];
++ c2 = crc[1] ^ p[1];
++ c3 = crc[2] ^ p[2];
++ c4 = crc[3] ^ p[3];
++
++ c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8);
++ c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8);
++ c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8);
++ c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8);
++
++ c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8);
++ c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8);
++ c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8);
++ c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8);
++
++ c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8);
++ c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8);
++ c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8);
++ c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8);
++
++ c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8);
++ c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8);
++ c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8);
++ c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8);
++
++ crc[0] = c1;
++ crc[1] = c2;
++ crc[2] = c3;
++ crc[3] = c4;
++}
++
++
++void calc_crc32x4(unsigned char *buf, size_t len, CRC32_WORD4_t *result)
++{
++ unsigned int crc_tmp[4] = {CRC_INIT_VALUE, CRC_INIT_VALUE, CRC_INIT_VALUE, CRC_INIT_VALUE};
++ u_int32_t i;
++ int res;
++ u_int32_t n4;
++ int xlen = len;
++#ifdef HWDPLS_ENABLE
++ unsigned long plstout = 60;
++ unsigned long plsstart = 0;
++ if ((unsigned long)CONFIG_SYS_HZ > 100000)
++ plstout *= (unsigned long)CONFIG_SYS_HZ / 1000;
++ else
++ plstout = DIV_ROUND_UP(plstout * (unsigned long)CONFIG_SYS_HZ, 1000);
++#endif
++
++ /**
++ * 4バイト境界に合わない開始アドレスの場合
++ * 境界までのCRCを crc_tmp[0] に求める。
++ */
++ if ((unsigned long)buf & 3) {
++ crc_tmp[0] = _update_crc(crc_tmp[0], buf, (unsigned long)buf & 3);
++ buf = (unsigned char *)((unsigned long)buf & ~3);
++ xlen -= (unsigned long)buf & 3;
++ }
++
++ n4 = xlen/(NEXT_PTR*4);
++ /**
++ * 4バイト境界に合わない開始アドレスの場合
++ * 境界までのCRCを crc_tmp[0] に求める。
++ */
++#ifdef HWDPLS_ENABLE
++ reset_timer();
++ plsstart = get_timer(0);
++#endif
++ for (i = 0; i < n4; i++) {
++ update_crc4x4(crc_tmp, buf);
++ buf += NEXT_PTR * 4;
++#ifdef HWDPLS_ENABLE
++ /**
++ * WDを考慮
++ */
++ if (__builtin_expect((int)((i & 0x1f) == 0), 0)) {
++ if ((get_timer(plsstart)) > plstout) {
++ __HWDTPLS_OUT();
++ MEASURE("crc plsout")
++ plsstart += plstout;
++ }
++ }
++#endif /*HWPLS_ENABLE*/
++ }
++
++ res = xlen % (NEXT_PTR * 4);
++ if (res > 0)
++ crc_tmp[3] = _update_crc(crc_tmp[3], buf, res);
++
++ result->crc_w[0] = CRC_FIX(crc_tmp[0]);
++ result->crc_w[1] = CRC_FIX(crc_tmp[1]);
++ result->crc_w[2] = CRC_FIX(crc_tmp[2]);
++ result->crc_w[3] = CRC_FIX(crc_tmp[3]);
++
++ MEASURE("calc_crc32x4 finish")
++}
++
++#if defined(OWNTEST)
++#define BUFSIZE (2 * 1024 * 1024)
++#include <sys/time.h>
++#include <malloc.h>
++
++int main()
++{
++ unsigned char *buf, *buf2;
++ struct timeval start, end;
++ unsigned long long diff;
++ int i;
++
++ CRC32_WORD4_t result = { .crc_w = {0, 0, 0, 0 } };
++ CRC32_WORD4_t result2 = { .crc_w = {0, 0, 0, 0 } };
++
++ buf = malloc(BUFSIZE);
++ if (!buf) {
++ perror("malloc");
++ return 1;
++ }
++ printf("Generate %dMB random data..\n", BUFSIZE / 1024 / 1024);
++ srand(0);
++ for (i = 0; i < BUFSIZE / 4; i++)
++ ((int *)buf)[i] = rand();
++
++ /* Memory dup */
++ buf2 = memalign(NEXT_PTR, BUFSIZE);
++ if (!buf2) {
++ perror("malloc");
++ return 1;
++ }
++ memcpy(buf2, buf, BUFSIZE);
++
++
++ gettimeofday(&start, NULL);
++ calc_crc32x4(buf, BUFSIZE, &result);
++ gettimeofday(&end, NULL);
++
++ diff = (end.tv_sec - start.tv_sec) * 1000000;
++ diff += end.tv_usec - start.tv_usec;
++
++ printf("time=%lluus\n", diff);
++ printf(" result.word[0] = %x\n", result.crc_w[0]);
++ printf(" result.word[1] = %x\n", result.crc_w[1]);
++ printf(" result.word[2] = %x\n", result.crc_w[2]);
++ printf(" result.word[3] = %x\n", result.crc_w[3]);
++
++ /* Broken test */
++#if 0 /* Destory test */
++ buf[rand() % BUFSIZE] ^= 1 << (rand()%7);
++#endif
++ for (i = 0; i < BUFSIZE; i++) {
++ if (buf[i] != buf2[i])
++ printf("buf[%d] %02x : %02x\n", i, buf[i], buf2[i]);
++ }
++
++ gettimeofday(&start, NULL);
++ calc_crc32x4(buf, BUFSIZE, &result2);
++ gettimeofday(&end, NULL);
++
++ diff = (end.tv_sec - start.tv_sec) * 1000000;
++ diff += end.tv_usec - start.tv_usec;
++
++ printf("time=%lluus\n", diff);
++ printf(" result.word[0] = %x:%s\n", result2.crc_w[0] ,
++ result.crc_w[0] == result2.crc_w[0] ? "OK" : "NG");
++ printf(" result.word[1] = %x:%s\n", result2.crc_w[1] ,
++ result.crc_w[1] == result2.crc_w[1] ? "OK" : "NG");
++ printf(" result.word[2] = %x:%s\n", result2.crc_w[2] ,
++ result.crc_w[2] == result2.crc_w[2] ? "OK" : "NG");
++ printf(" result.word[3] = %x:%s\n", result2.crc_w[3] ,
++ result.crc_w[3] == result2.crc_w[3] ? "OK" : "NG");
++ return 0;
++}
++#endif /* TEST */
+diff --git a/arch/arm/mach-shmobile/crc32_word4.h b/arch/arm/mach-shmobile/crc32_word4.h
+new file mode 100644
+index 0000000..6c04878
+--- /dev/null
++++ b/arch/arm/mach-shmobile/crc32_word4.h
+@@ -0,0 +1,23 @@
++/*************************************************************************
++ * Coptright (C) FUJITSUTEN Limited, 2012 All Rights Reserved.
++ *
++ *************************************************************************/
++#ifndef __CRC32_WORD4_H__
++#define __CRC32_WORD4_H__
++
++typedef struct {
++ unsigned int crc_w[4];
++} CRC32_WORD4_t;
++
++void calc_crc32x4(unsigned char *buf, size_t len, CRC32_WORD4_t *result);
++
++typedef struct {
++ unsigned int size;
++ CRC32_WORD4_t chksum;
++ unsigned int dummy[3];
++} CRC32_WORD4_TICKET_t;
++
++#define IS_CRC_WORD4_OK(_res1, _res2) (!memcmp(_res1, _res2, sizeof(CRC32_WORD4_t)))
++#define IS_CRC_WORD4_ZERO(_w4) (((_w4)->crc_w[0] == 0) && ((_w4)->crc_w[1] == 0) && ((_w4)->crc_w[2] == 0) && ((_w4)->crc_w[3] == 0))
++#define IS_CRC_WORD4_ALL_F(_w4) (((_w4)->crc_w[0] == 0xffffffff) && ((_w4)->crc_w[1] == 0xffffffff) && ((_w4)->crc_w[2] == 0xffffffff) && ((_w4)->crc_w[3] == 0xffffffff))
++#endif
+diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S
+index debf271..f99f8b2 100644
+--- a/arch/arm/mach-shmobile/headsmp.S
++++ b/arch/arm/mach-shmobile/headsmp.S
+@@ -16,8 +16,6 @@
+ #include <linux/threads.h>
+ #include <asm/memory.h>
+
+- __CPUINIT
+-
+ #ifdef CONFIG_SMP
+ ENTRY(shmobile_invalidate_start)
+ bl v7_invalidate_l1
+diff --git a/arch/arm/mach-shmobile/hibernation.c b/arch/arm/mach-shmobile/hibernation.c
+new file mode 100644
+index 0000000..94fa78b
+--- /dev/null
++++ b/arch/arm/mach-shmobile/hibernation.c
+@@ -0,0 +1,243 @@
++/*
++ * Suspend-to-RAM support code for SH-Mobile ARM
++ *
++ * Copyright (C) 2011 Magnus Damm
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#include <linux/pm.h>
++#include <linux/suspend.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/cpu.h>
++#include <linux/smp.h>
++
++#include <linux/io.h>
++#include <asm/system_misc.h>
++#include <asm/page.h>
++#include <asm/smp_plat.h>
++
++#include "common.h"
++#include "rcar-gen2.h"
++
++#include <linux/clk.h>
++
++#include "crc32_word4.c"
++#include "pm-rcar.h"
++
++
++struct swsusp_header {
++ char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) -
++ sizeof(u32) - sizeof(CRC32_WORD4_t) - sizeof(u32)];
++ CRC32_WORD4_t comp_crc32;
++ u32 img_size; /* add. see. kernel/power/swap.c */
++ u32 crc32;
++ sector_t image;
++ unsigned int flags; /* Flags to pass to the "boot" kernel */
++ char orig_sig[10];
++ char sig[10];
++} __packed;
++static unsigned long swsusp_area = CONFIG_SWSUSP_AREA;
++static unsigned long swsusp_area_size = CONFIG_SWSUSP_AREA_SIZE;
++
++enum {
++ MSTP00, MSTP01, MSTP02, MSTP03, MSTP04, MSTP05,
++ MSTP07, MSTP08, MSTP09, MSTP10, MSTP11,
++ MSTP_NR,
++};
++
++static struct {
++ u32 s_offset;
++ u32 s_val;
++ u32 r_offset;
++ u32 r_val;
++} mstp_regs[] = {
++ [MSTP00] = { SMSTPCR0, 0,
++ RMSTPCR0, 0},
++ [MSTP01] = { SMSTPCR1, 0,
++ RMSTPCR1, 0},
++ [MSTP02] = { SMSTPCR2, 0,
++ RMSTPCR2, 0},
++ [MSTP03] = { SMSTPCR3, 0,
++ RMSTPCR3, 0},
++ [MSTP04] = { SMSTPCR4, 0,
++ RMSTPCR4, 0},
++ [MSTP05] = { SMSTPCR5, 0,
++ RMSTPCR5, 0},
++ [MSTP07] = { SMSTPCR7, 0,
++ RMSTPCR7, 0},
++ [MSTP08] = { SMSTPCR8, 0,
++ RMSTPCR8, 0},
++ [MSTP09] = { SMSTPCR9, 0,
++ RMSTPCR9, 0},
++ [MSTP10] = { SMSTPCR10, 0,
++ RMSTPCR10, 0},
++ [MSTP11] = { SMSTPCR11, 0,
++ RMSTPCR11, 0},
++};
++
++static void save_mstp_regs(void)
++{
++ int i;
++ void *m = ioremap(CPG_BASE, CPG_LEN);
++ for (i = MSTP00; i < MSTP_NR; i++) {
++ mstp_regs[i].s_val = ioread32(m +mstp_regs[i].s_offset);
++ mstp_regs[i].r_val = ioread32(m +mstp_regs[i].r_offset);
++ }
++ iounmap(m);
++}
++
++static void restore_mstp_regs(void)
++{
++ int i;
++ void *m = ioremap(CPG_BASE, CPG_LEN);
++ for (i = MSTP00; i < MSTP_NR; i++) {
++ iowrite32(mstp_regs[i].s_val, m +mstp_regs[i].s_offset);
++ iowrite32(mstp_regs[i].r_val, m +mstp_regs[i].r_offset);
++ }
++ iounmap(m);
++}
++
++static int shmobile_hibernation_begin(void)
++{
++ save_mstp_regs();
++ return 0;
++}
++
++static void shmobile_hibernation_end(void)
++{
++}
++
++static int shmobile_hibernation_pre_snapshot(void)
++{
++ return 0;
++}
++
++
++static void shmobile_hibernation_finish(void)
++{
++}
++
++static int shmobile_hibernation_prepare(void)
++{
++ return 0;
++}
++
++static int shmobile_hibernation_enter(void)
++{
++ void *m, *l;
++ struct swsusp_header *h;
++ unsigned int calc_sz;
++ if (swsusp_area_size > 0) {
++ h = m = ioremap(swsusp_area, swsusp_area_size);
++ if (h) {
++ if ((h->img_size > PAGE_SIZE)
++ && (h->img_size < (swsusp_area_size - PAGE_SIZE)))
++ calc_sz = h->img_size;
++ else
++ calc_sz = swsusp_area_size - PAGE_SIZE;
++ memset(&h->comp_crc32, 0, sizeof(h->comp_crc32));
++ calc_crc32x4(m + PAGE_SIZE, calc_sz, &h->comp_crc32);
++ mb();
++ iounmap(m);
++ }
++ }
++ /* Resetting FDP0 */
++ l = ioremap(0xfe940000, 0x4000);
++ writel(1, l + 0x1c);
++ mb();
++ iounmap(l);
++ /* Resetting FDP1 */
++ l = ioremap(0xfe944000, 0x4000);
++ writel(1, l + 0x1c);
++ mb();
++ iounmap(l);
++ /* Doing board reset */
++ l = ioremap(0xe6300200, 4);
++ writel(0xa1b20001, l);
++ mb();
++ iounmap(l);
++
++ return 0;
++}
++
++char *clks[] = {
++ "ehci", "hsusb", "dmal", "dmah", "sys-dmac1",
++ "sys-dmac0", "ssp", "ssp_dev", "ipmmu_gp",
++ "audmac0", "audmac1",
++};
++
++static int shmobile_hibernation_pre_restore(void)
++{
++ return 0;
++}
++
++
++static void shmobile_hibernation_restore_cleanup(void)
++{
++}
++
++extern int in_suspend;
++
++static void shmobile_hibernation_leave(void)
++{
++ int restore_highmem(void);
++ struct clk *clk;
++ unsigned int i;
++
++ if (!in_suspend) {
++#ifdef CONFIG_SMP
++ if (is_smp())
++ arch_smp_prepare_cpus(setup_max_cpus);
++#endif
++
++#ifdef CONFIG_HIGHMEM
++ restore_highmem();
++#endif
++ restore_mstp_regs();
++ }
++
++ for (i = 0; i < ARRAY_SIZE(clks); ++i) {
++ clk = clk_get(NULL, clks[i]);
++ if (!IS_ERR(clk)) {
++ clk_prepare_enable(clk);
++ clk_put(clk);
++ }
++ }
++}
++
++const struct platform_hibernation_ops shmobile_hibernation_ops = {
++ .leave = shmobile_hibernation_leave,
++ .begin = shmobile_hibernation_begin,
++ .end = shmobile_hibernation_end,
++ .pre_snapshot = shmobile_hibernation_pre_snapshot,
++ .finish = shmobile_hibernation_finish,
++ .prepare = shmobile_hibernation_prepare,
++ .enter = shmobile_hibernation_enter,
++ .pre_restore = shmobile_hibernation_pre_restore,
++ .restore_cleanup = shmobile_hibernation_restore_cleanup,
++};
++
++int __init shmobile_hibernation_init(void)
++{
++ hibernation_set_ops(&shmobile_hibernation_ops);
++ return 0;
++}
++static int setup_swsusp_area(char *s)
++{
++ long tmp = 0;
++ char *p;
++ if (!kstrtol(s, 0, &tmp) && tmp > 0)
++ swsusp_area = tmp;
++ p = strchr(s, ',');
++ if (!p)
++ goto out;
++ if (!kstrtol(p, 0, &tmp) && tmp > 0)
++ swsusp_area_size = tmp;
++out:
++ return 1;
++}
++__setup("swsusp_area=", setup_swsusp_area);
++
+diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c
+index cff7a25..e382e26 100644
+--- a/arch/arm/mach-shmobile/platsmp-apmu.c
++++ b/arch/arm/mach-shmobile/platsmp-apmu.c
+@@ -33,7 +33,10 @@
+
+ /* only enable the cluster that includes the boot CPU by default */
+ static bool enable_multicluster = false;
++#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) || \
++defined(CONFIG_CPU_IDLE)
+ static bool is_last_cpu;
++#endif
+
+ static __init int apmu_setup(char *opt)
+ {
+@@ -71,12 +74,15 @@ static int __maybe_unused apmu_power_on(void __iomem *p, int bit)
+ return 0;
+ }
+
++#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) || \
++defined(CONFIG_CPU_IDLE)
+ static int apmu_power_off(void __iomem *p, int bit)
+ {
+ /* request Core Standby for next WFI */
+ writel_relaxed(3, p + CPUNCR_OFFS(bit));
+ return 0;
+ }
++#endif
+
+ static int __maybe_unused apmu_power_off_poll(void __iomem *p, int bit)
+ {
+@@ -92,12 +98,15 @@ static int __maybe_unused apmu_power_off_poll(void __iomem *p, int bit)
+ return 0;
+ }
+
++#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) || \
++defined(CONFIG_CPU_IDLE) || defined(CONFIG_SMP)
+ static int apmu_wrap(int cpu, int (*fn)(void __iomem *p, int cpu))
+ {
+ void __iomem *p = apmu_cpus[cpu].iomem;
+
+ return p ? fn(p, apmu_cpus[cpu].bit) : -EINVAL;
+ }
++#endif
+
+ static void apmu_init_cpu(struct resource *res, int cpu, int bit)
+ {
+@@ -141,7 +150,7 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit),
+ }
+ }
+
+-void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
++void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
+ struct rcar_apmu_config *apmu_config,
+ int num)
+ {
+@@ -328,7 +337,7 @@ static int __cpuinit shmobile_smp_apmu_enter_suspend(suspend_state_t state)
+ return 0;
+ }
+
+-void __init shmobile_smp_apmu_suspend_init(void)
++void shmobile_smp_apmu_suspend_init(void)
+ {
+ cpucmcr_ca7 = ioremap_nocache(CPUCMCR_CA7, 0x4);
+ cpucmcr_ca15 = ioremap_nocache(CPUCMCR_CA15, 0x4);
+diff --git a/arch/arm/mach-shmobile/platsmp-rst.c b/arch/arm/mach-shmobile/platsmp-rst.c
+index 70a2b6c..7ba9eeb 100644
+--- a/arch/arm/mach-shmobile/platsmp-rst.c
++++ b/arch/arm/mach-shmobile/platsmp-rst.c
+@@ -11,8 +11,7 @@
+ #include <linux/io.h>
+ #include <asm/smp_plat.h>
+ #include <mach/platsmp-rst.h>
+-
+-#define RST 0xe6160000
++#include "rcar-gen2.h"
+
+ #define r8a779x_clst_id(cpu) (cpu_logical_map((cpu)) >> 8)
+ #define r8a779x_cpu_id(cpu) (cpu_logical_map((cpu)) & 0xff)
+diff --git a/arch/arm/mach-shmobile/pm-r8a7791.c b/arch/arm/mach-shmobile/pm-r8a7791.c
+index f0ed98c..a13da84 100644
+--- a/arch/arm/mach-shmobile/pm-r8a7791.c
++++ b/arch/arm/mach-shmobile/pm-r8a7791.c
+@@ -21,16 +21,9 @@
+ #include <asm/io.h>
+ #include "common.h"
+ #include "pm-rcar.h"
++#include "rcar-gen2.h"
+ #include "r8a7791.h"
+
+-#define RST 0xe6160000
+-#define CA15BAR 0x0020
+-#define RAM 0xe63c0000
+-
+-/* SYSC */
+-#define SYSCIER 0x0c
+-#define SYSCIMR 0x10
+-
+ struct r8a7791_pm_domain {
+ struct generic_pm_domain genpd;
+ struct rcar_sysc_ch ch;
+@@ -43,13 +36,14 @@ static inline struct rcar_sysc_ch *to_r8a7791_ch(struct generic_pm_domain *d)
+
+ #if defined(CONFIG_PM) || defined(CONFIG_SMP)
+
+-static void __init r8a7791_sysc_init(void)
++static void r8a7791_sysc_init(void)
+ {
+- void __iomem *base = rcar_sysc_init(0xe6180000);
++ void __iomem *base = rcar_sysc_init(SYSC_BASE);
+
+ /* enable all interrupt sources, but do not use interrupt handler */
+ iowrite32(0x0131000e, base + SYSCIER);
+- iowrite32(0, base + SYSCIMR);
++ /* keep reserved bits as they are in TRM */
++ iowrite32(0x012001ec, base + SYSCIMR);
+ }
+
+ #else /* CONFIG_PM || CONFIG_SMP */
+@@ -60,9 +54,6 @@ static inline void r8a7791_sysc_init(void) {}
+
+ #ifdef CONFIG_PM
+
+-#define CPG_BASE 0xe6150000
+-#define CPG_LEN 0x1000
+-
+ /* Software Reset */
+ #define SRCR0 0x00a0
+ #define SRCR1 0x00a8
+@@ -243,14 +234,10 @@ static struct notifier_block platform_nb = {
+
+ #endif /* CONFIG_PM */
+
+-void __init r8a7791_pm_init(void)
++void r8a7791_pm_init(void)
+ {
+ void __iomem *p;
+ u32 bar;
+- static int once;
+-
+- if (once++)
+- return;
+
+ /* RAM for jump stub, because BAR requires 256KB aligned address */
+ p = ioremap_nocache(RAM, shmobile_boot_size);
+@@ -258,7 +245,7 @@ void __init r8a7791_pm_init(void)
+ iounmap(p);
+
+ /* setup reset vectors */
+- p = ioremap_nocache(RST, 0x63);
++ p = ioremap_nocache(RST, RST_LEN);
+ bar = (RAM >> 8) & 0xfffffc00;
+ writel_relaxed(bar, p + CA15BAR);
+ writel_relaxed(bar | 0x10, p + CA15BAR);
+diff --git a/arch/arm/mach-shmobile/rcar-gen2.h b/arch/arm/mach-shmobile/rcar-gen2.h
+index ce53cb5..df7201a 100644
+--- a/arch/arm/mach-shmobile/rcar-gen2.h
++++ b/arch/arm/mach-shmobile/rcar-gen2.h
+@@ -1,6 +1,45 @@
+ #ifndef __ASM_RCAR_GEN2_H__
+ #define __ASM_RCAR_GEN2_H__
+
++#define CPG_BASE 0xe6150000
++#define CPG_LEN 0x1000
++#define RMSTPCR0 0x110
++#define RMSTPCR1 0x114
++#define RMSTPCR2 0x118
++#define RMSTPCR3 0x11c
++#define RMSTPCR4 0x120
++#define RMSTPCR5 0x124
++#define RMSTPCR7 0x12c
++#define RMSTPCR8 0x980
++#define RMSTPCR9 0x984
++#define RMSTPCR10 0x988
++#define RMSTPCR11 0x98c
++#define SMSTPCR0 0x130
++#define SMSTPCR1 0x134
++#define SMSTPCR2 0x138
++#define SMSTPCR3 0x13c
++#define SMSTPCR4 0x140
++#define SMSTPCR5 0x144
++#define SMSTPCR7 0x14c
++#define SMSTPCR8 0x990
++#define SMSTPCR9 0x994
++#define SMSTPCR10 0x998
++#define SMSTPCR11 0x99c
++
++#define SYSC_BASE 0xe6180000
++#define SYSCIER 0x0c
++#define SYSCIMR 0x10
++
++#define RST 0xe6160000
++#define RST_LEN 0x64
++
++#define CA15BAR 0x0020
++#define CA7BAR 0x0030
++#define RAM 0xe63c0000
++
++#define CNTCR 0
++#define CNTFID0 0x20
++
+ void rcar_gen2_timer_init(void);
+ #define MD(nr) BIT(nr)
+ u32 rcar_gen2_read_mode_pins(void);
+diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c
+index 2aa431a..c48c6a9 100644
+--- a/arch/arm/mach-shmobile/setup-r8a7791.c
++++ b/arch/arm/mach-shmobile/setup-r8a7791.c
+@@ -29,6 +29,7 @@
+ #include <linux/sh_timer.h>
+ #include <linux/spi/sh_msiof.h>
+ #include <asm/mach/arch.h>
++#include <asm/smp_plat.h>
+
+ #include "common.h"
+ #include "dma-register.h"
+@@ -243,8 +244,6 @@ static const struct resource powervr_resources[] __initconst = {
+ powervr_resources, \
+ ARRAY_SIZE(powervr_resources))
+
+-#define CPG_BASE 0xe6150000
+-#define CPG_LEN 0x1000
+ #define RGXCR 0x0B4
+
+ void __init r8a7791_register_pvrsrvkm(void)
+@@ -271,7 +270,12 @@ void __init r8a7791_register_ssp(void)
+
+ void __init r8a7791_add_dt_devices(void)
+ {
+- r8a7791_pm_init();
++#ifdef CONFIG_SMP
++ /* In case of SMP config pm_init already called from smp_prepare_cpus.
++ * It is still needed to call pm_init if 'nosmp' was given */
++ if (!setup_max_cpus)
++#endif
++ r8a7791_pm_init();
+ r8a7791_init_pm_domains();
+ r8a7791_register_cmt(00);
+ r8a7791_register_pvrsrvkm();
+diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c
+index da16ebd..641ee1d 100644
+--- a/arch/arm/mach-shmobile/setup-rcar-gen2.c
++++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c
+@@ -47,9 +47,6 @@ u32 rcar_gen2_read_mode_pins(void)
+ return mode;
+ }
+
+-#define CNTCR 0
+-#define CNTFID0 0x20
+-
+ void __init rcar_gen2_timer_init(void)
+ {
+ #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK)
+@@ -58,7 +55,7 @@ void __init rcar_gen2_timer_init(void)
+ #ifdef CONFIG_ARM_ARCH_TIMER
+ void __iomem *base;
+ int extal_mhz = 0;
+- u32 freq;
++ u32 rcar_gen2_archtimer_freq;
+
+ /* At Linux boot time the r8a7790 arch timer comes up
+ * with the counter disabled. Moreover, it may also report
+@@ -83,7 +80,7 @@ void __init rcar_gen2_timer_init(void)
+ }
+
+ /* The arch timer frequency equals EXTAL / 2 */
+- freq = extal_mhz * (1000000 / 2);
++ rcar_gen2_archtimer_freq = extal_mhz * (1000000 / 2);
+
+ /* Remap "armgcnt address map" space */
+ base = ioremap(0xe6080000, PAGE_SIZE);
+@@ -96,10 +93,11 @@ void __init rcar_gen2_timer_init(void)
+ */
+
+ if ((ioread32(base + CNTCR) & 1) == 0 ||
+- ioread32(base + CNTFID0) != freq) {
++ ioread32(base + CNTFID0) != rcar_gen2_archtimer_freq) {
+ /* Update registers with correct frequency */
+- iowrite32(freq, base + CNTFID0);
+- asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq));
++ iowrite32(rcar_gen2_archtimer_freq, base + CNTFID0);
++ asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r"
++ (rcar_gen2_archtimer_freq));
+
+ /* make sure arch timer is started by setting bit 0 of CNTCR */
+ iowrite32(1, base + CNTCR);
+diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c
+index 24cad9f..4583cb6 100644
+--- a/arch/arm/mach-shmobile/smp-r8a7791.c
++++ b/arch/arm/mach-shmobile/smp-r8a7791.c
+@@ -33,6 +33,11 @@
+
+ #define CA15RESCNT 0x0040
+
++static struct rcar_sysc_ch r8a7791_ca15_scu = {
++ .chan_offs = 0x180, /* PWRSR5 .. PWRER5 */
++ .isr_bit = 12, /* CA15-SCU */
++};
++
+ static struct rcar_apmu_config r8a7791_apmu_config[] = {
+ {
+ .iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
+@@ -47,7 +52,7 @@ static struct rcar_rst_config r8a7791_rst_config[] = {
+ }
+ };
+
+-static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus)
++static void r8a7791_smp_prepare_cpus(unsigned int max_cpus)
+ {
+ void __iomem *p;
+ u32 val;
+@@ -67,6 +72,7 @@ static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus)
+ }
+
+ r8a7791_pm_init();
++ rcar_sysc_power_up(&r8a7791_ca15_scu);
+
+ /* keep secondary CPU cores in reset */
+ r8a779x_init_reset(r8a7791_rst_config);
+diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
+index 19da841..35c9048 100644
+--- a/arch/arm/mm/proc-v7.S
++++ b/arch/arm/mm/proc-v7.S
+@@ -92,48 +92,59 @@ ENDPROC(cpu_v7_dcache_clean_area)
+
+ /* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
+ .globl cpu_v7_suspend_size
+-.equ cpu_v7_suspend_size, 4 * 8
++.equ cpu_v7_suspend_size, 4 * 9
+ #ifdef CONFIG_ARM_CPU_SUSPEND
+ ENTRY(cpu_v7_do_suspend)
+ stmfd sp!, {r4 - r10, lr}
+ mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
+ mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID
+ stmia r0!, {r4 - r5}
++#ifdef CONFIG_MMU
+ mrc p15, 0, r6, c3, c0, 0 @ Domain ID
++#ifdef CONFIG_ARM_LPAE
++ mrrc p15, 1, r5, r7, c2 @ TTB 1
++#else
+ mrc p15, 0, r7, c2, c0, 1 @ TTB 1
++#endif
+ mrc p15, 0, r11, c2, c0, 2 @ TTB control register
++#endif
+ mrc p15, 0, r8, c1, c0, 0 @ Control register
+ mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register
+ mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control
+- stmia r0, {r6 - r11}
++ stmia r0, {r5 - r11}
+ ldmfd sp!, {r4 - r10, pc}
+ ENDPROC(cpu_v7_do_suspend)
+
+ ENTRY(cpu_v7_do_resume)
+ mov ip, #0
+- mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs
+ mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
+ mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
+ ldmia r0!, {r4 - r5}
+ mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
+ mcr p15, 0, r5, c13, c0, 3 @ User r/o thread ID
+- ldmia r0, {r6 - r11}
++ ldmia r0, {r5 - r11}
++#ifdef CONFIG_MMU
++ mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs
+ mcr p15, 0, r6, c3, c0, 0 @ Domain ID
+-#ifndef CONFIG_ARM_LPAE
++#ifdef CONFIG_ARM_LPAE
++ mcrr p15, 0, r1, ip, c2 @ TTB 0
++ mcrr p15, 1, r5, r7, c2 @ TTB 1
++#else
+ ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
+ ALT_UP(orr r1, r1, #TTB_FLAGS_UP)
+-#endif
+ mcr p15, 0, r1, c2, c0, 0 @ TTB 0
+ mcr p15, 0, r7, c2, c0, 1 @ TTB 1
++#endif
+ mcr p15, 0, r11, c2, c0, 2 @ TTB control register
+- mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
+- teq r4, r9 @ Is it already set?
+- mcrne p15, 0, r9, c1, c0, 1 @ No, so write it
+- mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control
+ ldr r4, =PRRR @ PRRR
+ ldr r5, =NMRR @ NMRR
+ mcr p15, 0, r4, c10, c2, 0 @ write PRRR
+ mcr p15, 0, r5, c10, c2, 1 @ write NMRR
++#endif /* CONFIG_MMU */
++ mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
++ teq r4, r9 @ Is it already set?
++ mcrne p15, 0, r9, c1, c0, 1 @ No, so write it
++ mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control
+ isb
+ dsb
+ mov r0, r8 @ control register
+--
+1.8.3.1
+