summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>2017-05-22 00:15:23 +0900
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2017-05-25 13:47:13 +0000
commita14e289caaae4c342c2bc686bd5d327ed612b0fc (patch)
tree87cc82526cadd31c77f72a208421e44ee97e7a3a
parent5b5a54b60f45e67d647cf6cc0fe2b879b2bb8229 (diff)
Add kernel Hibernation code for porter board.
This patch set is a support to Hibernation for a porter board. I've commit with Hibernation Off patch, because it depends strongly on user land. If you can use Hibernation, Please add local.conf agl-porter-hibernate. OVERRIDES .= ":agl-porter-hibernate" DISTRO_FEATURES_append = " agl-porter-hibernate" Change-Id: Ic64c9494a4bbd2518ef1aa334325b96eb7a9479e Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com> Reviewed-on: https://gerrit.automotivelinux.org/gerrit/9451 Tested-by: Jenkins Job builder account <agl-jobbuilder@automotivelinux.org> ci-image-build: Jenkins Job builder account <agl-jobbuilder@automotivelinux.org> Reviewed-by: Jan-Simon Moeller <jsmoeller@linuxfoundation.org>
-rwxr-xr-x[-rw-r--r--]meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux-renesas_%.bbappend20
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch853
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch1529
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0003-Add-sata-hibernation-code.patch56
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0004-Add-firmware-hibernation-code.patch25
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0005-Add-rcar-dma-hibernation-code.patch113
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0006-Add-rcar-du-hibernation-code.patch127
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0007-Add-rcar-i2c-hibernation-code.patch69
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0008-Add-rcar-mmc-hibernation-code.patch414
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0009-Add-hibernation-store-area.patch62
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0010-Add-rcar-eth-hibernation-code.patch238
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0011-Add-rcar-pci-hibernation-code.patch375
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0012-Add-rcar-gpio-hibernation-code.patch230
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0013-Add-rcar-spi-hibernation-code.patch168
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0014-Add-rcar-sci-hibernation-code.patch41
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0015-Add-rcar-usbphy-hibernation-code.patch83
-rwxr-xr-xmeta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/hibernation.cfg10
17 files changed, 4413 insertions, 0 deletions
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux-renesas_%.bbappend b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux-renesas_%.bbappend
index 29dcc75cb..35b225354 100644..100755
--- a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux-renesas_%.bbappend
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux-renesas_%.bbappend
@@ -16,3 +16,23 @@ SRC_URI += " file://disable_delay_printk.patch \
"
KERNEL_CONFIG_FRAGMENTS_append = " ${WORKDIR}/ath9k_htc.cfg ${WORKDIR}/rtl_sdr.cfg"
+
+SRC_URI_append_agl-porter-hibernate = " file://hibernation/0001-Add-Hibernation-kernel-base-code.patch \
+ file://hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch \
+ file://hibernation/0003-Add-sata-hibernation-code.patch \
+ file://hibernation/0004-Add-firmware-hibernation-code.patch \
+ file://hibernation/0005-Add-rcar-dma-hibernation-code.patch \
+ file://hibernation/0006-Add-rcar-du-hibernation-code.patch \
+ file://hibernation/0007-Add-rcar-i2c-hibernation-code.patch \
+ file://hibernation/0008-Add-rcar-mmc-hibernation-code.patch \
+ file://hibernation/0009-Add-hibernation-store-area.patch \
+ file://hibernation/0010-Add-rcar-eth-hibernation-code.patch \
+ file://hibernation/0011-Add-rcar-pci-hibernation-code.patch \
+ file://hibernation/0012-Add-rcar-gpio-hibernation-code.patch \
+ file://hibernation/0013-Add-rcar-spi-hibernation-code.patch \
+ file://hibernation/0014-Add-rcar-sci-hibernation-code.patch \
+ file://hibernation/0015-Add-rcar-usbphy-hibernation-code.patch \
+ file://hibernation/hibernation.cfg \
+ "
+
+KERNEL_CONFIG_FRAGMENTS_append_agl-porter-hibernate += " ${WORKDIR}/hibernation/hibernation.cfg"
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch
new file mode 100755
index 000000000..87cd2863a
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch
@@ -0,0 +1,853 @@
+From 60123966221b74199e4cf0c18d43396b4f00a94a Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 16:44:34 +0900
+Subject: [PATCH 01/15] Add Hibernation kernel base code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ include/linux/sched.h | 1 +
+ include/linux/suspend.h | 2 +
+ kernel/auditfilter.c | 2 +-
+ kernel/power/console.c | 2 +
+ kernel/power/hibernate.c | 146 +++++++++++++++++++++++++++++++----------------
+ kernel/power/main.c | 4 --
+ kernel/power/power.h | 8 ++-
+ kernel/power/process.c | 35 ++++++++----
+ kernel/power/snapshot.c | 33 +++++++----
+ kernel/power/suspend.c | 4 +-
+ kernel/power/swap.c | 50 ++++++++++++++--
+ 11 files changed, 201 insertions(+), 86 deletions(-)
+
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index f87e9a8..8e3270c 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -1644,6 +1644,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
+ #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */
+ #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
+ #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
++#define PF_SUSPEND_TASK 0x80000000 /* this thread called freeze_processes and should not be frozen */
+
+ /*
+ * Only the _current_ task can read/write to tsk->flags, but other
+diff --git a/include/linux/suspend.h b/include/linux/suspend.h
+index d4e3f16..243ff56 100644
+--- a/include/linux/suspend.h
++++ b/include/linux/suspend.h
+@@ -320,6 +320,8 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
+ extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
+ extern int hibernate(void);
+ extern bool system_entering_hibernation(void);
++asmlinkage int swsusp_save(void);
++extern struct pbe *restore_pblist;
+ #else /* CONFIG_HIBERNATION */
+ static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+ static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
+diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
+index 6bd4a90..ac08a9a 100644
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -423,7 +423,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
+ f->lsm_rule = NULL;
+
+ /* Support legacy tests for a valid loginuid */
+- if ((f->type == AUDIT_LOGINUID) && (f->val == 4294967295)) {
++ if ((f->type == AUDIT_LOGINUID) && (f->val == 0xFFFFFFFF)) {
+ f->type = AUDIT_LOGINUID_SET;
+ f->val = 0;
+ }
+diff --git a/kernel/power/console.c b/kernel/power/console.c
+index 463aa67..aba9c54 100644
+--- a/kernel/power/console.c
++++ b/kernel/power/console.c
+@@ -9,6 +9,7 @@
+ #include <linux/kbd_kern.h>
+ #include <linux/vt.h>
+ #include <linux/module.h>
++#include <linux/slab.h>
+ #include "power.h"
+
+ #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
+@@ -81,6 +82,7 @@ void pm_vt_switch_unregister(struct device *dev)
+ list_for_each_entry(tmp, &pm_vt_switch_list, head) {
+ if (tmp->dev == dev) {
+ list_del(&tmp->head);
++ kfree(tmp);
+ break;
+ }
+ }
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index b26f5f1..524dcf5 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -34,12 +34,13 @@
+
+ static int nocompress;
+ static int noresume;
++static int nohibernate;
+ static int resume_wait;
+-static int resume_delay;
++static unsigned int resume_delay;
+ static char resume_file[256] = CONFIG_PM_STD_PARTITION;
+ dev_t swsusp_resume_device;
+ sector_t swsusp_resume_block;
+-int in_suspend __nosavedata;
++__visible int in_suspend __nosavedata;
+
+ enum {
+ HIBERNATION_INVALID,
+@@ -61,6 +62,11 @@ bool freezer_test_done;
+
+ static const struct platform_hibernation_ops *hibernation_ops;
+
++bool hibernation_available(void)
++{
++ return (nohibernate == 0);
++}
++
+ /**
+ * hibernation_set_ops - Set the global hibernate operations.
+ * @ops: Hibernation operations to use in subsequent hibernation transitions.
+@@ -82,6 +88,7 @@ void hibernation_set_ops(const struct platform_hibernation_ops *ops)
+
+ unlock_system_sleep();
+ }
++EXPORT_SYMBOL_GPL(hibernation_set_ops);
+
+ static bool entering_platform_hibernation;
+
+@@ -227,19 +234,23 @@ static void platform_recover(int platform_mode)
+ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+ unsigned nr_pages, char *msg)
+ {
+- s64 elapsed_centisecs64;
+- int centisecs;
+- int k;
+- int kps;
++ u64 elapsed_centisecs64;
++ unsigned int centisecs;
++ unsigned int k;
++ unsigned int kps;
+
+ elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
++ /*
++ * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time,
++ * it is obvious enough for what went wrong.
++ */
+ do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
+ centisecs = elapsed_centisecs64;
+ if (centisecs == 0)
+ centisecs = 1; /* avoid div-by-zero */
+ k = nr_pages * (PAGE_SIZE / 1024);
+ kps = (k * 100) / centisecs;
+- printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
++ pr_info("PM: %s %u kbytes in %u.%02u seconds (%u.%02u MB/s)\n",
+ msg, k,
+ centisecs / 100, centisecs % 100,
+ kps / 1000, (kps % 1000) / 10);
+@@ -293,10 +304,10 @@ static int create_image(int platform_mode)
+ error);
+ /* Restore control flow magically appears here */
+ restore_processor_state();
+- if (!in_suspend) {
++ if (!in_suspend)
+ events_check_enabled = false;
+- platform_leave(platform_mode);
+- }
++
++ platform_leave(platform_mode);
+
+ Power_up:
+ syscore_resume();
+@@ -594,7 +605,8 @@ static void power_down(void)
+ case HIBERNATION_PLATFORM:
+ hibernation_platform_enter();
+ case HIBERNATION_SHUTDOWN:
+- kernel_power_off();
++ if (pm_power_off)
++ kernel_power_off();
+ break;
+ #ifdef CONFIG_SUSPEND
+ case HIBERNATION_SUSPEND:
+@@ -622,7 +634,8 @@ static void power_down(void)
+ * corruption after resume.
+ */
+ printk(KERN_CRIT "PM: Please power down manually\n");
+- while(1);
++ while (1)
++ cpu_relax();
+ }
+
+ /**
+@@ -632,6 +645,11 @@ int hibernate(void)
+ {
+ int error;
+
++ if (!hibernation_available()) {
++ pr_debug("PM: Hibernation not available.\n");
++ return -EPERM;
++ }
++
+ lock_system_sleep();
+ /* The snapshot device should not be opened while we're running */
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+@@ -644,22 +662,22 @@ int hibernate(void)
+ if (error)
+ goto Exit;
+
+- /* Allocate memory management structures */
+- error = create_basic_memory_bitmaps();
+- if (error)
+- goto Exit;
+-
+ printk(KERN_INFO "PM: Syncing filesystems ... ");
+ sys_sync();
+ printk("done.\n");
+
+ error = freeze_processes();
+ if (error)
+- goto Free_bitmaps;
++ goto Exit;
++
++ /* Allocate memory management structures */
++ error = create_basic_memory_bitmaps();
++ if (error)
++ goto Thaw;
+
+ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
+ if (error || freezer_test_done)
+- goto Thaw;
++ goto Free_bitmaps;
+
+ if (in_suspend) {
+ unsigned int flags = 0;
+@@ -682,14 +700,13 @@ int hibernate(void)
+ pr_debug("PM: Image restored successfully.\n");
+ }
+
++ Free_bitmaps:
++ free_basic_memory_bitmaps();
+ Thaw:
+ thaw_processes();
+
+ /* Don't bother checking whether freezer_test_done is true */
+ freezer_test_done = false;
+-
+- Free_bitmaps:
+- free_basic_memory_bitmaps();
+ Exit:
+ pm_notifier_call_chain(PM_POST_HIBERNATION);
+ pm_restore_console();
+@@ -723,7 +740,7 @@ static int software_resume(void)
+ /*
+ * If the user said "noresume".. bail out early.
+ */
+- if (noresume)
++ if (noresume || !hibernation_available())
+ return 0;
+
+ /*
+@@ -806,21 +823,19 @@ static int software_resume(void)
+ pm_prepare_console();
+ error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+ if (error)
+- goto close_finish;
+-
+- error = create_basic_memory_bitmaps();
+- if (error)
+- goto close_finish;
++ goto Close_Finish;
+
+ pr_debug("PM: Preparing processes for restore.\n");
+ error = freeze_processes();
+- if (error) {
+- swsusp_close(FMODE_READ);
+- goto Done;
+- }
++ if (error)
++ goto Close_Finish;
+
+ pr_debug("PM: Loading hibernation image.\n");
+
++ error = create_basic_memory_bitmaps();
++ if (error)
++ goto Thaw;
++
+ error = swsusp_read(&flags);
+ swsusp_close(FMODE_READ);
+ if (!error)
+@@ -828,9 +843,9 @@ static int software_resume(void)
+
+ printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
+ swsusp_free();
+- thaw_processes();
+- Done:
+ free_basic_memory_bitmaps();
++ Thaw:
++ thaw_processes();
+ Finish:
+ pm_notifier_call_chain(PM_POST_RESTORE);
+ pm_restore_console();
+@@ -840,12 +855,12 @@ static int software_resume(void)
+ mutex_unlock(&pm_mutex);
+ pr_debug("PM: Hibernation image not present or could not be loaded.\n");
+ return error;
+-close_finish:
++ Close_Finish:
+ swsusp_close(FMODE_READ);
+ goto Finish;
+ }
+
+-late_initcall(software_resume);
++late_initcall_sync(software_resume);
+
+
+ static const char * const hibernation_modes[] = {
+@@ -889,6 +904,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+ int i;
+ char *start = buf;
+
++ if (!hibernation_available())
++ return sprintf(buf, "[disabled]\n");
++
+ for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+ if (!hibernation_modes[i])
+ continue;
+@@ -923,6 +941,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+ char *p;
+ int mode = HIBERNATION_INVALID;
+
++ if (!hibernation_available())
++ return -EPERM;
++
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+
+@@ -971,16 +992,20 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
+ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+ {
+- unsigned int maj, min;
+ dev_t res;
+- int ret = -EINVAL;
++ int len = n;
++ char *name;
+
+- if (sscanf(buf, "%u:%u", &maj, &min) != 2)
+- goto out;
++ if (len && buf[len-1] == '\n')
++ len--;
++ name = kstrndup(buf, len, GFP_KERNEL);
++ if (!name)
++ return -ENOMEM;
+
+- res = MKDEV(maj,min);
+- if (maj != MAJOR(res) || min != MINOR(res))
+- goto out;
++ res = name_to_dev_t(name);
++ kfree(name);
++ if (!res)
++ return -EINVAL;
+
+ lock_system_sleep();
+ swsusp_resume_device = res;
+@@ -988,20 +1013,20 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
+ printk(KERN_INFO "PM: Starting manual resume from disk\n");
+ noresume = 0;
+ software_resume();
+- ret = n;
+- out:
+- return ret;
++ return n;
+ }
+
+ power_attr(resume);
+
+-static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
++static ssize_t image_size_show(struct kobject *kobj,
++ struct kobj_attribute *attr,
+ char *buf)
+ {
+ return sprintf(buf, "%lu\n", image_size);
+ }
+
+-static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
++static ssize_t image_size_store(struct kobject *kobj,
++ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+ {
+ unsigned long size;
+@@ -1065,7 +1090,7 @@ static int __init resume_setup(char *str)
+ if (noresume)
+ return 1;
+
+- strncpy( resume_file, str, 255 );
++ strncpy(resume_file, str, 255);
+ return 1;
+ }
+
+@@ -1088,6 +1113,10 @@ static int __init hibernate_setup(char *str)
+ noresume = 1;
+ else if (!strncmp(str, "nocompress", 10))
+ nocompress = 1;
++ else if (!strncmp(str, "no", 2)) {
++ noresume = 1;
++ nohibernate = 1;
++ }
+ return 1;
+ }
+
+@@ -1105,13 +1134,30 @@ static int __init resumewait_setup(char *str)
+
+ static int __init resumedelay_setup(char *str)
+ {
+- resume_delay = simple_strtoul(str, NULL, 0);
++ int rc = kstrtouint(str, 0, &resume_delay);
++
++ if (rc)
++ return rc;
++ return 1;
++}
++
++static int __init nohibernate_setup(char *str)
++{
++ noresume = 1;
++ nohibernate = 1;
+ return 1;
+ }
+
++static int __init kaslr_nohibernate_setup(char *str)
++{
++ return nohibernate_setup(str);
++}
++
+ __setup("noresume", noresume_setup);
+ __setup("resume_offset=", resume_offset_setup);
+ __setup("resume=", resume_setup);
+ __setup("hibernate=", hibernate_setup);
+ __setup("resumewait", resumewait_setup);
+ __setup("resumedelay=", resumedelay_setup);
++__setup("nohibernate", nohibernate_setup);
++__setup("kaslr", kaslr_nohibernate_setup);
+diff --git a/kernel/power/main.c b/kernel/power/main.c
+index d77663b..ac615e4 100644
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -610,7 +610,6 @@ static struct attribute_group attr_group = {
+ .attrs = g,
+ };
+
+-#ifdef CONFIG_PM_RUNTIME
+ struct workqueue_struct *pm_wq;
+ EXPORT_SYMBOL_GPL(pm_wq);
+
+@@ -620,9 +619,6 @@ static int __init pm_start_workqueue(void)
+
+ return pm_wq ? 0 : -ENOMEM;
+ }
+-#else
+-static inline int pm_start_workqueue(void) { return 0; }
+-#endif
+
+ static int __init pm_init(void)
+ {
+diff --git a/kernel/power/power.h b/kernel/power/power.h
+index 7d4b7ff..c5821ca 100644
+--- a/kernel/power/power.h
++++ b/kernel/power/power.h
+@@ -2,6 +2,7 @@
+ #include <linux/suspend_ioctls.h>
+ #include <linux/utsname.h>
+ #include <linux/freezer.h>
++#include <linux/compiler.h>
+
+ struct swsusp_info {
+ struct new_utsname uts;
+@@ -11,7 +12,8 @@ struct swsusp_info {
+ unsigned long image_pages;
+ unsigned long pages;
+ unsigned long size;
+-} __attribute__((aligned(PAGE_SIZE)));
++ char archdata[1024];
++} __aligned(PAGE_SIZE);
+
+ #ifdef CONFIG_HIBERNATION
+ /* kernel/power/snapshot.c */
+@@ -37,6 +39,8 @@ static inline char *check_image_kernel(struct swsusp_info *info)
+ }
+ #endif /* CONFIG_ARCH_HIBERNATION_HEADER */
+
++extern void __weak swsusp_arch_add_info(char *archdata);
++
+ /*
+ * Keep some memory free so that I/O operations can succeed without paging
+ * [Might this be more than 4 MB?]
+@@ -49,6 +53,8 @@ static inline char *check_image_kernel(struct swsusp_info *info)
+ */
+ #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
+
++asmlinkage int swsusp_save(void);
++
+ /* kernel/power/hibernate.c */
+ extern bool freezer_test_done;
+
+diff --git a/kernel/power/process.c b/kernel/power/process.c
+index 0695319..04559b4 100644
+--- a/kernel/power/process.c
++++ b/kernel/power/process.c
+@@ -30,9 +30,10 @@ static int try_to_freeze_tasks(bool user_only)
+ unsigned int todo;
+ bool wq_busy = false;
+ struct timeval start, end;
+- u64 elapsed_csecs64;
+- unsigned int elapsed_csecs;
++ u64 elapsed_msecs64;
++ unsigned int elapsed_msecs;
+ bool wakeup = false;
++ int sleep_usecs = USEC_PER_MSEC;
+
+ do_gettimeofday(&start);
+
+@@ -68,22 +69,25 @@ static int try_to_freeze_tasks(bool user_only)
+
+ /*
+ * We need to retry, but first give the freezing tasks some
+- * time to enter the refrigerator.
++ * time to enter the refrigerator. Start with an initial
++ * 1 ms sleep followed by exponential backoff until 8 ms.
+ */
+- msleep(10);
++ usleep_range(sleep_usecs / 2, sleep_usecs);
++ if (sleep_usecs < 8 * USEC_PER_MSEC)
++ sleep_usecs *= 2;
+ }
+
+ do_gettimeofday(&end);
+- elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
+- do_div(elapsed_csecs64, NSEC_PER_SEC / 100);
+- elapsed_csecs = elapsed_csecs64;
++ elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
++ do_div(elapsed_msecs64, NSEC_PER_MSEC);
++ elapsed_msecs = elapsed_msecs64;
+
+ if (todo) {
+ printk("\n");
+- printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
++ printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds "
+ "(%d tasks refusing to freeze, wq_busy=%d):\n",
+ wakeup ? "aborted" : "failed",
+- elapsed_csecs / 100, elapsed_csecs % 100,
++ elapsed_msecs / 1000, elapsed_msecs % 1000,
+ todo - wq_busy, wq_busy);
+
+ if (!wakeup) {
+@@ -96,8 +100,8 @@ static int try_to_freeze_tasks(bool user_only)
+ read_unlock(&tasklist_lock);
+ }
+ } else {
+- printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100,
+- elapsed_csecs % 100);
++ printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000,
++ elapsed_msecs % 1000);
+ }
+
+ return todo ? -EBUSY : 0;
+@@ -139,6 +143,9 @@ int freeze_processes(void)
+ if (error)
+ return error;
+
++ /* Make sure this task doesn't get frozen */
++ current->flags |= PF_SUSPEND_TASK;
++
+ if (!pm_freezing)
+ atomic_inc(&system_freezing_cnt);
+
+@@ -202,6 +209,7 @@ int freeze_kernel_threads(void)
+ void thaw_processes(void)
+ {
+ struct task_struct *g, *p;
++ struct task_struct *curr = current;
+
+ if (pm_freezing)
+ atomic_dec(&system_freezing_cnt);
+@@ -217,10 +225,15 @@ void thaw_processes(void)
+
+ read_lock(&tasklist_lock);
+ do_each_thread(g, p) {
++ /* No other threads should have PF_SUSPEND_TASK set */
++ WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));
+ __thaw_task(p);
+ } while_each_thread(g, p);
+ read_unlock(&tasklist_lock);
+
++ WARN_ON(!(curr->flags & PF_SUSPEND_TASK));
++ curr->flags &= ~PF_SUSPEND_TASK;
++
+ usermodehelper_enable();
+
+ schedule();
+diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
+index 91c04f1..a673f7b 100644
+--- a/kernel/power/snapshot.c
++++ b/kernel/power/snapshot.c
+@@ -27,6 +27,7 @@
+ #include <linux/highmem.h>
+ #include <linux/list.h>
+ #include <linux/slab.h>
++#include <linux/compiler.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/mmu_context.h>
+@@ -155,7 +156,7 @@ static inline void free_image_page(void *addr, int clear_nosave_free)
+ struct linked_page {
+ struct linked_page *next;
+ char data[LINKED_PAGE_DATA_SIZE];
+-} __attribute__((packed));
++} __packed;
+
+ static inline void
+ free_list_of_pages(struct linked_page *list, int clear_page_nosave)
+@@ -352,7 +353,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
+ struct mem_extent *ext, *cur, *aux;
+
+ zone_start = zone->zone_start_pfn;
+- zone_end = zone->zone_start_pfn + zone->spanned_pages;
++ zone_end = zone_end_pfn(zone);
+
+ list_for_each_entry(ext, list, hook)
+ if (zone_start <= ext->end)
+@@ -642,8 +643,9 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
+ region->end_pfn = end_pfn;
+ list_add_tail(&region->list, &nosave_regions);
+ Report:
+- printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n",
+- start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
++ printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n",
++ (unsigned long long) start_pfn << PAGE_SHIFT,
++ ((unsigned long long) end_pfn << PAGE_SHIFT) - 1);
+ }
+
+ /*
+@@ -742,7 +744,10 @@ int create_basic_memory_bitmaps(void)
+ struct memory_bitmap *bm1, *bm2;
+ int error = 0;
+
+- BUG_ON(forbidden_pages_map || free_pages_map);
++ if (forbidden_pages_map && free_pages_map)
++ return 0;
++ else
++ BUG_ON(forbidden_pages_map || free_pages_map);
+
+ bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
+ if (!bm1)
+@@ -788,7 +793,8 @@ void free_basic_memory_bitmaps(void)
+ {
+ struct memory_bitmap *bm1, *bm2;
+
+- BUG_ON(!(forbidden_pages_map && free_pages_map));
++ if (WARN_ON(!(forbidden_pages_map && free_pages_map)))
++ return;
+
+ bm1 = forbidden_pages_map;
+ bm2 = free_pages_map;
+@@ -883,7 +889,7 @@ static unsigned int count_highmem_pages(void)
+ continue;
+
+ mark_free_pages(zone);
+- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ max_zone_pfn = zone_end_pfn(zone);
+ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
+ if (saveable_highmem_page(zone, pfn))
+ n++;
+@@ -947,7 +953,7 @@ static unsigned int count_data_pages(void)
+ continue;
+
+ mark_free_pages(zone);
+- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ max_zone_pfn = zone_end_pfn(zone);
+ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
+ if (saveable_page(zone, pfn))
+ n++;
+@@ -1040,7 +1046,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
+ unsigned long max_zone_pfn;
+
+ mark_free_pages(zone);
+- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ max_zone_pfn = zone_end_pfn(zone);
+ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
+ if (page_is_saveable(zone, pfn))
+ memory_bm_set_bit(orig_bm, pfn);
+@@ -1092,7 +1098,7 @@ void swsusp_free(void)
+ unsigned long pfn, max_zone_pfn;
+
+ for_each_populated_zone(zone) {
+- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ max_zone_pfn = zone_end_pfn(zone);
+ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
+ if (pfn_valid(pfn)) {
+ struct page *page = pfn_to_page(pfn);
+@@ -1580,7 +1586,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
+ return -ENOMEM;
+ }
+
+-asmlinkage int swsusp_save(void)
++asmlinkage __visible int swsusp_save(void)
+ {
+ unsigned int nr_pages, nr_highmem;
+
+@@ -1628,6 +1634,7 @@ static int init_header_complete(struct swsusp_info *info)
+ {
+ memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));
+ info->version_code = LINUX_VERSION_CODE;
++ swsusp_arch_add_info(info->archdata);
+ return 0;
+ }
+
+@@ -1647,6 +1654,8 @@ static char *check_image_kernel(struct swsusp_info *info)
+ }
+ #endif /* CONFIG_ARCH_HIBERNATION_HEADER */
+
++void __weak swsusp_arch_add_info(char *archdata) {}
++
+ unsigned long snapshot_get_image_size(void)
+ {
+ return nr_copy_pages + nr_meta_pages + 1;
+@@ -1758,7 +1767,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm)
+
+ /* Clear page flags */
+ for_each_populated_zone(zone) {
+- max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
++ max_zone_pfn = zone_end_pfn(zone);
+ for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
+ if (pfn_valid(pfn))
+ swsusp_unset_page_free(pfn_to_page(pfn));
+diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
+index bef86d1..deec937 100644
+--- a/kernel/power/suspend.c
++++ b/kernel/power/suspend.c
+@@ -156,13 +156,13 @@ static int suspend_prepare(suspend_state_t state)
+ }
+
+ /* default implementation */
+-void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
++void __weak arch_suspend_disable_irqs(void)
+ {
+ local_irq_disable();
+ }
+
+ /* default implementation */
+-void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
++void __weak arch_suspend_enable_irqs(void)
+ {
+ local_irq_enable();
+ }
+diff --git a/kernel/power/swap.c b/kernel/power/swap.c
+index 7c33ed2..a6a1c55 100644
+--- a/kernel/power/swap.c
++++ b/kernel/power/swap.c
+@@ -91,17 +91,28 @@ struct swap_map_handle {
+ unsigned int k;
+ unsigned long reqd_free_pages;
+ u32 crc32;
++#ifdef CONFIG_ARCH_SHMOBILE
++ unsigned int img_size; /* add */
++#endif
+ };
+
+ struct swsusp_header {
++#ifdef CONFIG_ARCH_SHMOBILE
++ char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) -
++ sizeof(u32) - (sizeof(unsigned int)*4) - sizeof(u32)];
++ unsigned int comp_crc32[4];
++ u32 img_size;
++#else
+ char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) -
+- sizeof(u32)];
++ sizeof(u32) - sizeof(u32)];
++ u32 comp_crc32;
++#endif
+ u32 crc32;
+ sector_t image;
+ unsigned int flags; /* Flags to pass to the "boot" kernel */
+ char orig_sig[10];
+ char sig[10];
+-} __attribute__((packed));
++} __packed;
+
+ static struct swsusp_header *swsusp_header;
+
+@@ -230,6 +241,11 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+ swsusp_header->flags = flags;
+ if (flags & SF_CRC32_MODE)
+ swsusp_header->crc32 = handle->crc32;
++
++#ifdef CONFIG_ARCH_SHMOBILE
++ swsusp_header->img_size = handle->img_size;
++#endif
++
+ error = hib_bio_write_page(swsusp_resume_block,
+ swsusp_header, NULL);
+ } else {
+@@ -587,7 +603,11 @@ static int save_image_lzo(struct swap_map_handle *handle,
+ unsigned char *page = NULL;
+ struct cmp_data *data = NULL;
+ struct crc_data *crc = NULL;
++ int compr = 0;
+
++#ifdef CONFIG_ARCH_SHMOBILE
++ unsigned int comp_imgtotal = 0;
++#endif
+ /*
+ * We'll limit the number of threads for compression to limit memory
+ * footprint.
+@@ -733,7 +753,12 @@ static int save_image_lzo(struct swap_map_handle *handle,
+ }
+
+ *(size_t *)data[thr].cmp = data[thr].cmp_len;
+-
++ compr += data[thr].cmp_len;
++#ifdef CONFIG_ARCH_SHMOBILE
++ comp_imgtotal += (data[thr].cmp_len
++ + LZO_HEADER + (PAGE_SIZE - 1))
++ & ~(PAGE_SIZE - 1);
++#endif
+ /*
+ * Given we are writing one page at a time to disk, we
+ * copy that much from the buffer, although the last
+@@ -746,7 +771,6 @@ static int save_image_lzo(struct swap_map_handle *handle,
+ off < LZO_HEADER + data[thr].cmp_len;
+ off += PAGE_SIZE) {
+ memcpy(page, data[thr].cmp + off, PAGE_SIZE);
+-
+ ret = swap_write_page(handle, page, &bio);
+ if (ret)
+ goto out_finish;
+@@ -762,8 +786,24 @@ out_finish:
+ do_gettimeofday(&stop);
+ if (!ret)
+ ret = err2;
+- if (!ret)
++ if (!ret) {
++#ifdef CONFIG_ARCH_SHMOBILE
++ const unsigned int ds = comp_imgtotal +
++ ((comp_imgtotal
++ / ((2 * 1024 * 1024)
++ - PAGE_SIZE)) * PAGE_SIZE);
++ const unsigned int swaped =
++ (swp_offset(get_swap_page_of_type(root_swap))
++ - 2) * PAGE_SIZE;
++ if (ds < swaped)
++ handle->img_size = swaped;
++ else
++ handle->img_size = ds;
++#endif
+ printk(KERN_INFO "PM: Image saving done.\n");
++ printk(KERN_INFO "PM: Compressed output size: %d [%d] (imgsize=%d/swaped size=%d)\n",
++ compr, handle->img_size, ds, swaped);
++ }
+ swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+ out_clean:
+ if (crc) {
+--
+1.8.3.1
+
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
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0003-Add-sata-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0003-Add-sata-hibernation-code.patch
new file mode 100755
index 000000000..fd0dfb66f
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0003-Add-sata-hibernation-code.patch
@@ -0,0 +1,56 @@
+From 5d87144a96085d74b6002bd6d8c093c37bf128b7 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:04:33 +0900
+Subject: [PATCH 03/15] Add sata hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/ata/sata_rcar.c | 29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
+index 92abfdd..4c82b5e 100644
+--- a/drivers/ata/sata_rcar.c
++++ b/drivers/ata/sata_rcar.c
+@@ -1003,9 +1003,38 @@ static int sata_rcar_resume(struct device *dev)
+ return 0;
+ }
+
++static int sata_rcar_restore(struct device *dev)
++{
++ struct ata_host *host = dev_get_drvdata(dev);
++ struct sata_rcar_priv *priv = host->private_data;
++ int ret;
++
++ clk_prepare_enable(priv->clk);
++
++ ret = sata_rcar_setup_port(host);
++ if (ret)
++ goto cleanup;
++
++ /* initialize host controller */
++ sata_rcar_init_controller(host);
++
++ ata_host_resume(host);
++
++ return 0;
++
++cleanup:
++ clk_disable_unprepare(priv->clk);
++
++ return ret;
++}
++
+ static const struct dev_pm_ops sata_rcar_pm_ops = {
+ .suspend = sata_rcar_suspend,
+ .resume = sata_rcar_resume,
++ .freeze = sata_rcar_suspend,
++ .restore = sata_rcar_restore,
++ .thaw = sata_rcar_resume,
++ .poweroff = sata_rcar_suspend
+ };
+ #endif
+
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0004-Add-firmware-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0004-Add-firmware-hibernation-code.patch
new file mode 100755
index 000000000..d0250762e
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0004-Add-firmware-hibernation-code.patch
@@ -0,0 +1,25 @@
+From 33d4c0afe2a4e39c0afdc993f28a8d2d6228df01 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:31:24 +0900
+Subject: [PATCH 04/15] Add firmware hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/base/firmware_class.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
+index 01e2103..6123148 100644
+--- a/drivers/base/firmware_class.c
++++ b/drivers/base/firmware_class.c
+@@ -1464,6 +1464,7 @@ static int fw_pm_notify(struct notifier_block *notify_block,
+ switch (mode) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
++ case PM_RESTORE_PREPARE:
+ device_cache_fw_images();
+ break;
+
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0005-Add-rcar-dma-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0005-Add-rcar-dma-hibernation-code.patch
new file mode 100755
index 000000000..b446fa301
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0005-Add-rcar-dma-hibernation-code.patch
@@ -0,0 +1,113 @@
+From c094e905cb0f542acdeb5d7009ab9edc812897f7 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:32:30 +0900
+Subject: [PATCH 05/15] Add rcar-dma hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/dma/sh/rcar-dmac.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
+index e5e60ee..3b4a684 100644
+--- a/drivers/dma/sh/rcar-dmac.c
++++ b/drivers/dma/sh/rcar-dmac.c
+@@ -121,6 +121,7 @@ struct rcar_dmac_desc_page {
+ * struct rcar_dmac_chan - R-Car Gen2 DMA Controller Channel
+ * @chan: base DMA channel object
+ * @iomem: channel I/O memory base
++ * @backup: channel I/O memory backup base
+ * @index: index of this channel in the controller
+ * @src_xfer_size: size (in bytes) of hardware transfers on the source side
+ * @dst_xfer_size: size (in bytes) of hardware transfers on the destination side
+@@ -140,6 +141,7 @@ struct rcar_dmac_desc_page {
+ struct rcar_dmac_chan {
+ struct dma_chan chan;
+ void __iomem *iomem;
++ void *backup;
+ unsigned int index;
+
+ unsigned int src_xfer_size;
+@@ -171,6 +173,7 @@ struct rcar_dmac_chan {
+ * @engine: base DMA engine object
+ * @dev: the hardware device
+ * @iomem: remapped I/O memory base
++ * @backup: remapped I/O memory backup base
+ * @n_channels: number of available channels
+ * @channels: array of DMAC channels
+ * @modules: bitmask of client modules in use
+@@ -179,6 +182,7 @@ struct rcar_dmac {
+ struct dma_device engine;
+ struct device *dev;
+ void __iomem *iomem;
++ void *backup;
+
+ unsigned int n_channels;
+ struct rcar_dmac_chan *channels;
+@@ -277,6 +281,7 @@ static void rcar_dmac_write(struct rcar_dmac *dmac, u32 reg, u32 data)
+ writew(data, dmac->iomem + reg);
+ else
+ writel(data, dmac->iomem + reg);
++ writel(data, dmac->backup + reg);
+ }
+
+ static u32 rcar_dmac_read(struct rcar_dmac *dmac, u32 reg)
+@@ -301,6 +306,7 @@ static void rcar_dmac_chan_write(struct rcar_dmac_chan *chan, u32 reg, u32 data)
+ writew(data, chan->iomem + reg);
+ else
+ writel(data, chan->iomem + reg);
++ writel(data, chan->backup + reg);
+ }
+
+ /* -----------------------------------------------------------------------------
+@@ -1548,10 +1554,25 @@ static int rcar_dmac_runtime_resume(struct device *dev)
+ }
+ #endif
+
++static int rcar_dmac_freeze(struct device *dev)
++{
++ return 0;
++}
++
++static int rcar_dmac_restore(struct device *dev)
++{
++ int ret;
++ struct rcar_dmac *dmac = dev_get_drvdata(dev);
++ ret = rcar_dmac_init(dmac);
++ return ret;
++}
++
+ static const struct dev_pm_ops rcar_dmac_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rcar_dmac_sleep_suspend, rcar_dmac_sleep_resume)
+ SET_RUNTIME_PM_OPS(rcar_dmac_runtime_suspend, rcar_dmac_runtime_resume,
+ NULL)
++ .freeze = rcar_dmac_freeze,
++ .restore = rcar_dmac_restore,
+ };
+
+ /* -----------------------------------------------------------------------------
+@@ -1571,6 +1592,7 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
+
+ rchan->index = index;
+ rchan->iomem = dmac->iomem + RCAR_DMAC_CHAN_OFFSET(index);
++ rchan->backup = dmac->backup + RCAR_DMAC_CHAN_OFFSET(index);
+ rchan->mid_rid = -EINVAL;
+
+ spin_lock_init(&rchan->lock);
+@@ -1657,8 +1679,13 @@ static int rcar_dmac_probe(struct platform_device *pdev)
+ /* Request resources. */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dmac->iomem = devm_ioremap_resource(&pdev->dev, mem);
++ dmac->backup = devm_kzalloc(&pdev->dev, resource_size(mem), GFP_KERNEL);
+ if (IS_ERR(dmac->iomem))
+ return PTR_ERR(dmac->iomem);
++ dmac->backup = devm_kzalloc(&pdev->dev, resource_size(mem), GFP_KERNEL);
++ if (IS_ERR(dmac->backup)) {
++ return PTR_ERR(dmac->backup);
++ }
+
+ irq = platform_get_irq_byname(pdev, "error");
+ if (irq < 0) {
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0006-Add-rcar-du-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0006-Add-rcar-du-hibernation-code.patch
new file mode 100755
index 000000000..8942ed44e
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0006-Add-rcar-du-hibernation-code.patch
@@ -0,0 +1,127 @@
+From 4a9a11deb2e83549d2e77cac129f879a0000ef7e Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:33:54 +0900
+Subject: [PATCH 06/15] Add rcar-du hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/gpu/drm/rcar-du/rcar_du_drv.c | 68 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 67 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+index 53f1f6a..fbb212c 100644
+--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
++++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+@@ -442,6 +442,15 @@ static int rcar_du_pm_suspend(struct device *dev)
+
+ drm_kms_helper_poll_disable(rcdu->ddev);
+
++#ifdef CONFIG_MACH_FTEN
++ list_for_each_entry(encoder,
++ &rcdu->ddev->mode_config.encoder_list, head) {
++ if ((encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) &&
++ (get_rcar_slave_funcs(encoder)->dpms))
++ get_rcar_slave_funcs(encoder)->dpms(encoder,
++ DRM_MODE_DPMS_SUSPEND);
++ }
++#else
+ #if defined(CONFIG_DRM_ADV7511) || defined(CONFIG_DRM_ADV7511_MODULE)
+ list_for_each_entry(encoder,
+ &rcdu->ddev->mode_config.encoder_list, head) {
+@@ -451,6 +460,8 @@ static int rcar_du_pm_suspend(struct device *dev)
+ DRM_MODE_DPMS_OFF);
+ }
+ #endif
++#endif
++
+ #ifdef CONFIG_DRM_RCAR_LVDS
+ for (i = 0; i < rcdu->info->num_lvds; ++i) {
+ if (rcdu->lvds[i])
+@@ -483,6 +494,15 @@ static int rcar_du_pm_resume(struct device *dev)
+ }
+ #endif
+
++#ifdef CONFIG_MACH_FTEN
++ list_for_each_entry(encoder,
++ &rcdu->ddev->mode_config.encoder_list, head) {
++ if ((encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) &&
++ (get_rcar_slave_funcs(encoder)->dpms))
++ get_rcar_slave_funcs(encoder)->dpms(encoder,
++ DRM_MODE_DPMS_ON);
++ }
++#else
+ #if defined(CONFIG_DRM_ADV7511) || defined(CONFIG_DRM_ADV7511_MODULE)
+ list_for_each_entry(encoder,
+ &rcdu->ddev->mode_config.encoder_list, head) {
+@@ -492,14 +512,53 @@ static int rcar_du_pm_resume(struct device *dev)
+ DRM_MODE_DPMS_ON);
+ }
+ #endif
++#endif
+ drm_kms_helper_poll_enable(rcdu->ddev);
+
+ return 0;
+ }
+-#endif
++#ifdef CONFIG_MACH_FTEN
++static int rcar_du_pm_freeze(struct device *dev)
++{
++ int ret;
++
++ ret = rcar_du_pm_suspend(dev);
++ return ret;
++}
++
++static int rcar_du_pm_thaw(struct device *dev)
++{
++ int ret;
+
++ ret = rcar_du_pm_resume(dev);
++ return ret;
++}
++
++static int rcar_du_pm_restore(struct device *dev)
++{
++ int i, ret;
++ struct rcar_du_device *rcdu = dev_get_drvdata(dev);
++
++ ret = rcar_du_pm_resume(dev);
++ for (i = 0; i < rcdu->pdata->num_crtcs; ++i)
++ rcar_du_crtc_enable_vblank(&rcdu->crtcs[i],
++ rcdu->crtcs[i].vblank_enable);
++ return ret;
++}
++#endif
++#endif
+ static const struct dev_pm_ops rcar_du_pm_ops = {
++#if defined(CONFIG_MACH_FTEN) && defined(CONFIG_HIBERNATION) && \
++ defined(CONFIG_PM_SLEEP)
++ .suspend = rcar_du_pm_suspend,
++ .resume = rcar_du_pm_resume,
++ .freeze = rcar_du_pm_freeze,
++ .thaw = rcar_du_pm_thaw,
++ .poweroff = rcar_du_pm_suspend,
++ .restore = rcar_du_pm_restore,
++#else
+ SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
++#endif
+ };
+
+ /* -----------------------------------------------------------------------------
+@@ -620,6 +679,13 @@ static const struct rcar_du_device_info rcar_du_r8a7791_info = {
+ .possible_clones = 0,
+ .encoder_type = DRM_MODE_ENCODER_NONE,
+ },
++#if defined(CONFIG_MACH_FTEN)
++ [RCAR_DU_OUTPUT_COMPOSITE] = {
++ .possible_crtcs = BIT(1),
++ .possible_clones = 0,
++ .encoder_type = DRM_MODE_ENCODER_TVDAC,
++ },
++#endif
+ },
+ .num_lvds = 1,
+ .drgbs_bit = 1,
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0007-Add-rcar-i2c-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0007-Add-rcar-i2c-hibernation-code.patch
new file mode 100755
index 000000000..bba1eb401
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0007-Add-rcar-i2c-hibernation-code.patch
@@ -0,0 +1,69 @@
+From 6c133013b75d88d5b4514dfecb3089f830b82d65 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:35:37 +0900
+Subject: [PATCH 07/15] Add rcar-i2c hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/i2c/busses/i2c-rcar.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
+index 8242002..c6a5a4b 100644
+--- a/drivers/i2c/busses/i2c-rcar.c
++++ b/drivers/i2c/busses/i2c-rcar.c
+@@ -754,6 +754,43 @@ static int rcar_i2c_probe(struct platform_device *pdev)
+
+ return 0;
+ }
++static int rcar_i2c_suspend(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
++ pr_debug("suspend: i2c adapter name %s", priv->adap.name);
++ pr_debug("suspend: ICSCR: %08x\n", readl(priv->io + ICSCR));
++ pr_debug("suspend: ICMCR: %08x\n", readl(priv->io + ICMCR));
++ pr_debug("suspend: ICSSR: %08x\n", readl(priv->io + ICSSR));
++ pr_debug("suspend: ICMSR: %08x\n", readl(priv->io + ICMSR));
++ pr_debug("suspend: ICSIER: %08x\n", readl(priv->io + ICSIER));
++ pr_debug("suspend: ICMIER: %08x\n", readl(priv->io + ICMIER));
++ pr_debug("suspend: ICCCR: %08x\n", readl(priv->io + ICCCR));
++ pr_debug("suspend: ICSAR: %08x\n", readl(priv->io + ICSAR));
++ pr_debug("suspend: ICMAR: %08x\n", readl(priv->io + ICMAR));
++ clk_disable(priv->clk);
++ return 0;
++}
++static int rcar_i2c_resume(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
++ clk_enable(priv->clk);
++ pr_debug("resume: i2c adapter name %s", priv->adap.name);
++ pr_debug("resume: ICSCR: %08x\n", readl(priv->io + ICSCR));
++ pr_debug("resume: ICMCR: %08x\n", readl(priv->io + ICMCR));
++ pr_debug("resume: ICSSR: %08x\n", readl(priv->io + ICSSR));
++ pr_debug("resume: ICMSR: %08x\n", readl(priv->io + ICMSR));
++ pr_debug("resume: ICSIER: %08x\n", readl(priv->io + ICSIER));
++ pr_debug("resume: ICMIER: %08x\n", readl(priv->io + ICMIER));
++ pr_debug("resume: ICCCR: %08x\n", readl(priv->io + ICCCR));
++ pr_debug("resume: ICSAR: %08x\n", readl(priv->io + ICSAR));
++ pr_debug("resume: ICMAR: %08x\n", readl(priv->io + ICMAR));
++ return 0;
++}
++static const struct dev_pm_ops rcar_i2c_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume)
++};
+
+ static int rcar_i2c_remove(struct platform_device *pdev)
+ {
+@@ -780,6 +817,7 @@ static struct platform_driver rcar_i2c_driver = {
+ .name = "i2c-rcar",
+ .owner = THIS_MODULE,
+ .of_match_table = rcar_i2c_dt_ids,
++ .pm = &rcar_i2c_pm_ops,
+ },
+ .probe = rcar_i2c_probe,
+ .remove = rcar_i2c_remove,
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0008-Add-rcar-mmc-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0008-Add-rcar-mmc-hibernation-code.patch
new file mode 100755
index 000000000..34b40a147
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0008-Add-rcar-mmc-hibernation-code.patch
@@ -0,0 +1,414 @@
+From 9d1d9be70ed3cf6670ae12a1caed337833f7bba8 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:38:11 +0900
+Subject: [PATCH 08/15] Add rcar mmc hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/mmc/host/sh_mmcif.c | 65 +++++++++++++++++++++-
+ drivers/mmc/host/sh_mobile_sdhi.c | 112 +++++++++++++++++++++++++++++++++++++-
+ drivers/mmc/host/tmio_mmc.h | 1 +
+ drivers/mmc/host/tmio_mmc_pio.c | 49 ++++++++++++-----
+ 4 files changed, 210 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
+index 7290e6e..4ecf62c 100644
+--- a/drivers/mmc/host/sh_mmcif.c
++++ b/drivers/mmc/host/sh_mmcif.c
+@@ -232,6 +232,7 @@ struct sh_mmcif_host {
+ struct platform_device *pd;
+ struct clk *hclk;
+ unsigned int clk;
++ int clkrate;
+ int bus_width;
+ unsigned char timing;
+ bool sd_error;
+@@ -257,6 +258,8 @@ struct sh_mmcif_host {
+ struct dma_chan *chan_tx;
+ struct completion dma_complete;
+ bool dma_active;
++#define N_REGS 10
++ u32 regs[N_REGS];
+ };
+
+ static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
+@@ -1457,6 +1460,8 @@ static int sh_mmcif_probe(struct platform_device *pdev)
+ }
+ }
+
++ host->clkrate = clk_get_rate(host->hclk);
++
+ ret = sh_mmcif_clk_update(host);
+ if (ret < 0)
+ goto eclkupdate;
+@@ -1503,6 +1508,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
+ dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
+ dev_dbg(&pdev->dev, "chip ver H'%04x\n",
+ sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
++ device_enable_async_suspend(&pdev->dev);
+ return ret;
+
+ emmcaddh:
+@@ -1574,15 +1580,68 @@ static int sh_mmcif_suspend(struct device *dev)
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+ pm_runtime_put(dev);
+
+- return 0;
++ return mmc_suspend_host(host->mmc);
+ }
+
+ static int sh_mmcif_resume(struct device *dev)
+ {
+- return 0;
++ struct sh_mmcif_host *host = dev_get_drvdata(dev);
++ return mmc_resume_host(host->mmc);
++}
++#endif
++
++#ifdef CONFIG_PM
++static int sh_mmcif_restore(struct device *dev)
++{
++ struct sh_mmcif_host *host = dev_get_drvdata(dev);
++ int ret;
++ ret = clk_set_rate(host->hclk, host->clkrate);
++ if (ret < 0)
++ goto eclkupdate;
++ ret = sh_mmcif_clk_update(host);
++ if (ret < 0)
++ goto eclkupdate;
++ ret = pm_runtime_resume(dev);
++ if (ret < 0)
++ goto eresume;
++ sh_mmcif_sync_reset(host);
++#ifdef CONFIG_MACH_FTEN
++ sh_mmcif_writel(host->addr, 0x00000080, 0x00000100);
++#endif
++ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
++ clk_disable_unprepare(host->hclk);
++ dev_info(dev, "restore: chip ver H'%04x\n",
++ sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
++ sh_mmcif_writel(host->addr, MMCIF_CE_CMD_CTRL, host->regs[0]);
++ sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, host->regs[1]);
++ sh_mmcif_writel(host->addr, MMCIF_CE_CLK_CTRL, host->regs[2]);
++ sh_mmcif_writel(host->addr, MMCIF_CE_BUF_ACC, host->regs[3]);
++ sh_mmcif_release_dma(host);
++ return mmc_resume_host(host->mmc);
++eclkupdate:
++ pr_info("Can't set clock\n");
++ return -EINVAL;
++eresume:
++ pr_info("Can't resume PM\n");
++ return -ENODEV;
+ }
++
++static int sh_mmcif_freeze(struct device *dev)
++{
++ struct sh_mmcif_host *host = dev_get_drvdata(dev);
++ int ret = mmc_suspend_host(host->mmc);
++ host->regs[0] = sh_mmcif_readl(host->addr, MMCIF_CE_CMD_CTRL);
++ host->regs[1] = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET);
++ host->regs[2] = sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL);
++ host->regs[3] = sh_mmcif_readl(host->addr, MMCIF_CE_BUF_ACC);
++ return ret;
++}
++#else
++#define sh_mmcif_restore NULL
++#define sh_mmcif_freeze NULL
+ #endif
+
++
+ static const struct of_device_id mmcif_of_match[] = {
+ { .compatible = "renesas,sh-mmcif" },
+ { }
+@@ -1591,6 +1650,8 @@ MODULE_DEVICE_TABLE(of, mmcif_of_match);
+
+ static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sh_mmcif_suspend, sh_mmcif_resume)
++ .restore = sh_mmcif_restore,
++ .freeze = sh_mmcif_freeze,
+ };
+
+ static struct platform_driver sh_mmcif_driver = {
+diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
+index 1b59cdf..c7f3abf 100644
+--- a/drivers/mmc/host/sh_mobile_sdhi.c
++++ b/drivers/mmc/host/sh_mobile_sdhi.c
+@@ -156,6 +156,8 @@ struct sh_mobile_sdhi {
+ struct tmio_mmc_dma dma_priv;
+ unsigned int type;
+ struct sh_mobile_sdhi_vlt vlt;
++ int wifi_xrst;
++ int save_clk_rate;
+ };
+
+ static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
+@@ -647,6 +649,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
+ if (ret < 0)
+ dev_err(&pdev->dev,
+ "cannot set clock rate: %d\n", ret);
++ priv->save_clk_rate = clk_rate;
+
+ clk_disable_unprepare(priv->clk);
+ }
+@@ -841,6 +844,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
+ }
+ }
+
++ device_enable_async_suspend(&pdev->dev);
+ dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
+ mmc_hostname(host->mmc), (unsigned long)
+ (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
+@@ -865,17 +869,123 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
++#ifdef CONFIG_MACH_FTEN_DT
++ int ret;
++ struct sh_mobile_sdhi *priv = container_of(host->pdata,
++ struct sh_mobile_sdhi,
++ mmc_data);
++#endif
+
+ tmio_mmc_host_remove(host);
+
+ if (p && p->cleanup)
+ p->cleanup(pdev);
+
++#ifdef CONFIG_MACH_FTEN_DT
++ ret = gpio_request(priv->wifi_xrst, "sh_mobile_sdhi");
++ if (ret != 0) {
++ dev_err(&pdev->dev,
++ "gpio_request(%d) failed(%d) remove\n",
++ priv->wifi_xrst, ret);
++ goto skip_wifi;
++ }
++ ret = gpio_direction_output(priv->wifi_xrst, 0);
++ if (ret != 0) {
++ dev_err(&pdev->dev,
++ "gpio_direction_output(%d) failed(%d) remove\n",
++ priv->wifi_xrst, ret);
++ }
++ gpio_free(priv->wifi_xrst);
++skip_wifi:
++#endif
++
++ return 0;
++}
++
++static int sh_mobile_sdhi_restore_noirq(struct device *dev)
++{
++ struct mmc_host *mmc = dev_get_drvdata(dev);
++ struct tmio_mmc_host *host = mmc_priv(mmc);
++
++ sd_ctrl_write32(host, CTL_IRQ_MASK, 0x8b7f031d);
++ sd_ctrl_write32(host, CTL_STATUS, 0);
++#if 0
++ sh_mobile_sdhi_enable_sdbuf_acc32(host, false);
++ /* FIXME - should we set stop clock reg here */
++ sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
++ /* implicit BUG_ON(!res) */
++ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
++ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
++ msleep(2);
++ sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
++ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
++ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
++ msleep(2);
++ sd_ctrl_write32(host, CTL_IRQ_MASK, 0x8b7f031d);
++ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0040);
++ sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80E0);
++ sd_ctrl_write16(host, CTL_DMA_ENABLE, 0x1002);
++#endif
++ return 0;
++}
++
++static int sh_mobile_sdhi_restore(struct device *dev)
++{
++ struct mmc_host *mmc = dev_get_drvdata(dev);
++ struct tmio_mmc_host *host = mmc_priv(mmc);
++ struct sh_mobile_sdhi *priv = container_of(host->pdata,
++ struct sh_mobile_sdhi,
++ mmc_data);
++#if defined(CONFIG_MACH_FTEN_DT) || defined(CONFIG_PM_SLEEP)
++ int ret;
++#endif
++ int dma_size;
++ host->restore = true;
++
++#ifdef CONFIG_MACH_FTEN_DT
++ /* priv->wifi_xrst is 0 or more. */
++ if (priv->wifi_xrst >= 0) {
++ ret = gpio_request(priv->wifi_xrst, "sh_mobile_sdhi");
++ if (ret != 0) {
++ dev_err(dev, "gpio_request(%d) failed(%d) restore\n",
++ priv->wifi_xrst, ret);
++ goto skip_wifi;
++ }
++ ret = gpio_direction_output(priv->wifi_xrst, 1);
++ if (ret != 0) {
++ dev_err(dev, "gpio_direction_output(%d) failed(%d) restore\n",
++ priv->wifi_xrst, ret);
++ }
++ gpio_free(priv->wifi_xrst);
++ }
++skip_wifi:
++#endif
++
++ dma_size = sh_mobile_sdhi_get_xmit_size(priv->type,
++ priv->dma_priv.alignment_shift);
++
++ sd_ctrl_write16(host, SD_DMACR(priv->type), dma_size);
++
++#ifdef CONFIG_PM_SLEEP
++ ret = tmio_mmc_host_resume(dev);
++ host->restore = false;
++ return ret;
++#else
++ host->restore = false;
+ return 0;
++#endif
+ }
+
+ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+- SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume)
++#ifdef CONFIG_PM_SLEEP
++ .suspend = tmio_mmc_host_suspend,
++ .resume = tmio_mmc_host_resume,
++ .freeze = tmio_mmc_host_suspend,
++ .thaw = tmio_mmc_host_resume,
++ .poweroff = tmio_mmc_host_suspend,
++#endif
++ .restore = sh_mobile_sdhi_restore,
++ .restore_noirq = sh_mobile_sdhi_restore_noirq,
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ tmio_mmc_host_runtime_resume,
+ NULL)
+diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
+index c5b12ad..3efe03d 100644
+--- a/drivers/mmc/host/tmio_mmc.h
++++ b/drivers/mmc/host/tmio_mmc.h
+@@ -104,6 +104,7 @@ struct tmio_mmc_host {
+ bool resuming;
+ bool done_tuning;
+ struct completion completion;
++ bool restore;
+ };
+
+ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
+diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
+index 09c0c08..514af15 100644
+--- a/drivers/mmc/host/tmio_mmc_pio.c
++++ b/drivers/mmc/host/tmio_mmc_pio.c
+@@ -167,8 +167,20 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
+ if (host->set_clk_div)
+ host->set_clk_div(host->pdev, (clk>>22) & 1);
+
++#ifdef CONFIG_MACH_FTEN
++ clk |= sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL) & 0x0100;
++ if (host->pdata->flags & TMIO_MMC_SDCLK_AUTO_CONTROL &&
++ new_clock > host->mmc->f_init)
++ clk |= SDCLKOFFEN;
++ dev_dbg(&host->pdev->dev,
++ "clock=%d, clk=%08x, new_clock=%d, f_init=%d\n",
++ clock, clk, new_clock, host->mmc->f_init);
++ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x3ff);
++#else
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
+- msleep(10);
++#endif
++ if (!host->restore)
++ msleep(2);
+ }
+
+ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
+@@ -176,13 +188,15 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
+ /* implicit BUG_ON(!res) */
+ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
+- if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
++ if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP)
++ && !host->restore)
+ msleep(10);
+ }
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+- if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
++ if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP)
++ && !host->restore)
+ msleep(10);
+ }
+
+@@ -190,14 +204,16 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
+ {
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+- if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+- msleep(10);
++ if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP)
++ && !host->restore)
++ msleep(2);
+
+ /* implicit BUG_ON(!res) */
+ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
+- if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
+- msleep(10);
++ if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP)
++ && !host->restore)
++ msleep(2);
+ }
+ }
+
+@@ -208,11 +224,11 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
+ /* implicit BUG_ON(!res) */
+ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
+ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
+- msleep(10);
++ msleep(2);
+ sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
+ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
+ sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
+- msleep(10);
++ msleep(2);
+ }
+
+ static void tmio_mmc_reset_work(struct work_struct *work)
+@@ -1134,16 +1150,21 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ * is kept positive, so no suspending actually takes place.
+ */
+ if (ios->power_mode == MMC_POWER_ON && ios->clock) {
++ int reset_needed = 0;
+ if (host->power != TMIO_MMC_ON_RUN) {
+ tmio_mmc_clk_update(mmc);
+ pm_runtime_get_sync(dev);
+- if (host->resuming) {
+- tmio_mmc_reset(host);
+- host->resuming = false;
+- }
++ if (host->resuming)
++ reset_needed = 1;
+ }
++
+ if (host->power == TMIO_MMC_OFF_STOP)
++ reset_needed = 1;
++ if (reset_needed) {
+ tmio_mmc_reset(host);
++ if (host->resuming)
++ host->resuming = false;
++ }
+ tmio_mmc_set_clock(host, ios->clock);
+ if (host->power == TMIO_MMC_OFF_STOP)
+ /* power up SD card and the bus */
+@@ -1497,7 +1518,7 @@ int tmio_mmc_host_resume(struct device *dev)
+
+ /* The MMC core will perform the complete set up */
+ host->resuming = true;
+- return mmc_resume_host(mmc);
++ return mmc_resume_host(mmc);
+ }
+ EXPORT_SYMBOL(tmio_mmc_host_resume);
+ #endif
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0009-Add-hibernation-store-area.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0009-Add-hibernation-store-area.patch
new file mode 100755
index 000000000..a3495e650
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0009-Add-hibernation-store-area.patch
@@ -0,0 +1,62 @@
+From 5509937666792520b755ed61a110c956478d089d Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:41:19 +0900
+Subject: [PATCH 09/15] Add hibernation store area
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/mtd/Makefile | 3 ++-
+ drivers/mtd/devices/Makefile | 4 +++-
+ drivers/mtd/devices/phram.c | 5 ++++-
+ 3 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+index 99bb9a1..b48049c 100644
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -30,7 +30,8 @@ obj-$(CONFIG_MTD_SWAP) += mtdswap.o
+ nftl-objs := nftlcore.o nftlmount.o
+ inftl-objs := inftlcore.o inftlmount.o
+
++obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
++
+ obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
+
+-obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
+ obj-$(CONFIG_MTD_UBI) += ubi/
+diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
+index d83bd73..969f0e8 100644
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -3,8 +3,10 @@
+ #
+
+ obj-$(CONFIG_MTD_DOCG3) += docg3.o
+-obj-$(CONFIG_MTD_SLRAM) += slram.o
++# obj-$(CONFIG_MTD_SLRAM) += slram.o
++# obj-$(CONFIG_MTD_PHRAM) += phram.o
+ obj-$(CONFIG_MTD_PHRAM) += phram.o
++obj-$(CONFIG_MTD_SLRAM) += slram.o
+ obj-$(CONFIG_MTD_PMC551) += pmc551.o
+ obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
+ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
+diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
+index 67823de..f05947f 100644
+--- a/drivers/mtd/devices/phram.c
++++ b/drivers/mtd/devices/phram.c
+@@ -293,8 +293,11 @@ static void __exit cleanup_phram(void)
+ {
+ unregister_devices();
+ }
+-
++#ifdef __MODULE__
+ module_init(init_phram);
++#else
++late_initcall(init_phram);
++#endif
+ module_exit(cleanup_phram);
+
+ MODULE_LICENSE("GPL");
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0010-Add-rcar-eth-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0010-Add-rcar-eth-hibernation-code.patch
new file mode 100755
index 000000000..55d1216fe
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0010-Add-rcar-eth-hibernation-code.patch
@@ -0,0 +1,238 @@
+From 1d20d3bd16eac561e14513c9e6cac543fab5a3f0 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:42:33 +0900
+Subject: [PATCH 10/15] Add rcar-eth hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/net/ethernet/renesas/sh_eth.c | 57 +++++++++++++++++++++++++++++++++--
+ drivers/net/phy/phy_device.c | 41 +++++++++++++++++++++++++
+ 2 files changed, 95 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
+index 991fa1e..7e91b26 100644
+--- a/drivers/net/ethernet/renesas/sh_eth.c
++++ b/drivers/net/ethernet/renesas/sh_eth.c
+@@ -33,6 +33,7 @@
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/of_irq.h>
++#include <linux/of_gpio.h>
+ #include <linux/of_net.h>
+ #include <linux/phy.h>
+ #include <linux/cache.h>
+@@ -999,6 +1000,7 @@ static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
+ struct bb_info {
+ void (*set_gate)(void *addr);
+ struct mdiobb_ctrl ctrl;
++ struct sh_eth_private *mdp;
+ void *addr;
+ u32 mmd_msk;/* MMD */
+ u32 mdo_msk;
+@@ -1029,6 +1031,8 @@ static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
+ {
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
++ pm_runtime_get_sync(&bitbang->mdp->pdev->dev);
++
+ if (bitbang->set_gate)
+ bitbang->set_gate(bitbang->addr);
+
+@@ -1036,6 +1040,8 @@ static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
+ bb_set(bitbang->addr, bitbang->mmd_msk);
+ else
+ bb_clr(bitbang->addr, bitbang->mmd_msk);
++
++ pm_runtime_put_sync(&bitbang->mdp->pdev->dev);
+ }
+
+ /* Set bit data*/
+@@ -1043,6 +1049,8 @@ static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
+ {
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
++ pm_runtime_get_sync(&bitbang->mdp->pdev->dev);
++
+ if (bitbang->set_gate)
+ bitbang->set_gate(bitbang->addr);
+
+@@ -1050,17 +1058,26 @@ static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
+ bb_set(bitbang->addr, bitbang->mdo_msk);
+ else
+ bb_clr(bitbang->addr, bitbang->mdo_msk);
++
++ pm_runtime_put_sync(&bitbang->mdp->pdev->dev);
+ }
+
+ /* Get bit data*/
+ static int sh_get_mdio(struct mdiobb_ctrl *ctrl)
+ {
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
++ unsigned int ret;
++
++ pm_runtime_get_sync(&bitbang->mdp->pdev->dev);
+
+ if (bitbang->set_gate)
+ bitbang->set_gate(bitbang->addr);
+
+- return bb_read(bitbang->addr, bitbang->mdi_msk);
++ ret = bb_read(bitbang->addr, bitbang->mdi_msk);
++
++ pm_runtime_put_sync(&bitbang->mdp->pdev->dev);
++
++ return ret;
+ }
+
+ /* MDC pin control */
+@@ -1068,6 +1085,8 @@ static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
+ {
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
++ pm_runtime_get_sync(&bitbang->mdp->pdev->dev);
++
+ if (bitbang->set_gate)
+ bitbang->set_gate(bitbang->addr);
+
+@@ -1075,6 +1094,8 @@ static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
+ bb_set(bitbang->addr, bitbang->mdc_msk);
+ else
+ bb_clr(bitbang->addr, bitbang->mdc_msk);
++
++ pm_runtime_put_sync(&bitbang->mdp->pdev->dev);
+ }
+
+ /* mdio bus control struct */
+@@ -2664,6 +2685,7 @@ static int sh_mdio_init(struct sh_eth_private *mdp,
+ bitbang->mdo_msk = PIR_MDO;
+ bitbang->mmd_msk = PIR_MMD;
+ bitbang->mdc_msk = PIR_MDC;
++ bitbang->mdp = mdp;
+ bitbang->ctrl.ops = &bb_ops;
+
+ /* MII controller setting */
+@@ -3002,9 +3024,38 @@ static int sh_eth_runtime_nop(struct device *dev)
+ return 0;
+ }
+
++static int sh_eth_suspend(struct device *dev)
++{
++ int ret = 0;
++ struct net_device *ndev = dev_get_drvdata(dev);
++
++ if (netif_running(ndev)) {
++ netif_device_detach(ndev);
++ ret = sh_eth_close(ndev);
++ }
++
++ return ret;
++}
++
++static int sh_eth_resume(struct device *dev)
++{
++ int ret = 0;
++ struct net_device *ndev = dev_get_drvdata(dev);
++
++ if (netif_running(ndev)) {
++ ret = sh_eth_open(ndev);
++ if (ret < 0)
++ goto err;
++ netif_device_attach(ndev);
++ }
++
++err:
++ return ret;
++}
++
+ static const struct dev_pm_ops sh_eth_dev_pm_ops = {
+- .runtime_suspend = sh_eth_runtime_nop,
+- .runtime_resume = sh_eth_runtime_nop,
++ SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL)
++ SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume)
+ };
+ #define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops)
+ #else
+diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
+index 3657b4a..3ceb4f9 100644
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -510,6 +510,32 @@ int phy_init_hw(struct phy_device *phydev)
+ return phydev->drv->config_init(phydev);
+ }
+
++int phy_suspend(struct phy_device *phydev)
++{
++ struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
++ struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
++
++ /* If the device has WOL enabled, we cannot suspend the PHY */
++ phy_ethtool_get_wol(phydev, &wol);
++ if (wol.wolopts)
++ return -EBUSY;
++
++ if (phydrv->suspend)
++ return phydrv->suspend(phydev);
++ return 0;
++}
++EXPORT_SYMBOL(phy_suspend);
++
++int phy_resume(struct phy_device *phydev)
++{
++ struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
++
++ if (phydrv->resume)
++ return phydrv->resume(phydev);
++ return 0;
++}
++EXPORT_SYMBOL(phy_resume);
++
+ /**
+ * phy_attach_direct - attach a network device to a given PHY device pointer
+ * @dev: network device to attach
+@@ -528,6 +554,7 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+ u32 flags, phy_interface_t interface)
+ {
+ struct device *d = &phydev->dev;
++ struct module *bus_module;
+ int err;
+
+ /* Assume that if there is no driver, that it doesn't
+@@ -553,6 +580,14 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+ return -EBUSY;
+ }
+
++ /* Increment the bus module reference count */
++ bus_module = phydev->bus->dev.driver ?
++ phydev->bus->dev.driver->owner : NULL;
++ if (!try_module_get(bus_module)) {
++ dev_err(&dev->dev, "failed to get the bus module\n");
++ return -EIO;
++ }
++
+ phydev->attached_dev = dev;
+ dev->phydev = phydev;
+
+@@ -568,6 +603,8 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+ err = phy_init_hw(phydev);
+ if (err)
+ phy_detach(phydev);
++ else
++ phy_resume(phydev);
+
+ return err;
+ }
+@@ -612,8 +649,12 @@ EXPORT_SYMBOL(phy_attach);
+ */
+ void phy_detach(struct phy_device *phydev)
+ {
++ if (phydev->bus->dev.driver)
++ module_put(phydev->bus->dev.driver->owner);
++
+ phydev->attached_dev->phydev = NULL;
+ phydev->attached_dev = NULL;
++ phy_suspend(phydev);
+
+ /* If the device had no specific driver before (i.e. - it
+ * was using the generic driver), we unbind the device
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0011-Add-rcar-pci-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0011-Add-rcar-pci-hibernation-code.patch
new file mode 100755
index 000000000..bdc9555c8
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0011-Add-rcar-pci-hibernation-code.patch
@@ -0,0 +1,375 @@
+From f8691a62199319d9e37cd451a9b8364aa640c4cb Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:45:19 +0900
+Subject: [PATCH 11/15] Add rcar-pci hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/pci/host/pci-rcar-gen2.c | 281 ++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 266 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c
+index 57b6572..4cb9693 100644
+--- a/drivers/pci/host/pci-rcar-gen2.c
++++ b/drivers/pci/host/pci-rcar-gen2.c
+@@ -23,9 +23,12 @@
+ #include <linux/sizes.h>
+ #include <linux/slab.h>
+ #include <linux/usb/phy.h>
++#include <linux/clk.h>
+
+ /* AHB-PCI Bridge PCI communication registers */
+ #define RCAR_AHBPCI_PCICOM_OFFSET 0x800
++#define RCAR_PCICONF_OHCI 0x0
++#define RCAR_PCICONF_EHCI 0x100
+
+ #define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
+ #define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
+@@ -104,6 +107,14 @@ struct rcar_pci_priv {
+ int domain;
+ int irq;
+ unsigned long window_size;
++ void __iomem *ohci_memdata;
++ void __iomem *ehci_memdata;
++#ifndef MCCILDK_CHANGE_DISABLE
++ u32 store_cfg[12];
++#else
++ u32 store_cfg[9];
++#endif
++ struct usb_phy *phy;
+ };
+
+ /* PCI configuration space operations */
+@@ -276,12 +287,6 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
+ /* Configure AHB master and slave modes */
+ iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
+
+- /* Configure PCI arbiter */
+- val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
+- val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
+- RCAR_PCI_ARBITER_PCIBP_MODE;
+- iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
+-
+ /* PCI-AHB mapping: 0x40000000 base */
+ iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
+ reg + RCAR_PCIAHB_WIN1_CTR_REG);
+@@ -290,9 +295,25 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
+ val = priv->mem_res.start | RCAR_AHBPCI_WIN_CTR_MEM;
+ iowrite32(val, reg + RCAR_AHBPCI_WIN2_CTR_REG);
+
++ /* Enable PCI interrupts */
++ iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
++ reg + RCAR_PCI_INT_ENABLE_REG);
++
++ /* Configure PCI arbiter */
++ val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
++ val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
++ RCAR_PCI_ARBITER_PCIBP_MODE;
++ iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
++
+ /* Enable AHB-PCI bridge PCI configuration access */
+ iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
+ reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ val = ioread32(reg + PCI_COMMAND);
++
++ val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
++ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
++ iowrite32(val, reg + PCI_COMMAND);
++
+ /* Set PCI-AHB Window1 address */
+ iowrite32(0x40000000 | PCI_BASE_ADDRESS_MEM_PREFETCH,
+ reg + PCI_BASE_ADDRESS_1);
+@@ -300,15 +321,6 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
+ val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
+ iowrite32(val, reg + PCI_BASE_ADDRESS_0);
+
+- val = ioread32(reg + PCI_COMMAND);
+- val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+- iowrite32(val, reg + PCI_COMMAND);
+-
+- /* Enable PCI interrupts */
+- iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
+- reg + RCAR_PCI_INT_ENABLE_REG);
+-
+ if (priv->irq > 0)
+ rcar_pci_setup_errirq(priv);
+
+@@ -326,6 +338,8 @@ static struct pci_ops rcar_pci_ops = {
+ .write = rcar_pci_write_config,
+ };
+
++#define RCAR_MAX_PCI_HOSTS 2
++static struct rcar_pci_priv *keep_priv[RCAR_MAX_PCI_HOSTS];
+ static int rcar_pci_probe(struct platform_device *pdev)
+ {
+ struct resource *cfg_res, *mem_res;
+@@ -350,6 +364,7 @@ static int rcar_pci_probe(struct platform_device *pdev)
+ return -ENOMEM;
+
+ priv->mem_res = *mem_res;
++ keep_priv[pdev->id] = priv;
+ /*
+ * The controller does not support/use port I/O,
+ * so setup a dummy port I/O region here.
+@@ -378,6 +393,7 @@ static int rcar_pci_probe(struct platform_device *pdev)
+ return PTR_ERR(phy);
+
+ usb_phy_init(phy);
++ priv->phy = phy;
+
+ hw_private[0] = priv;
+ memset(&hw, 0, sizeof(hw));
+@@ -390,14 +406,249 @@ static int rcar_pci_probe(struct platform_device *pdev)
+ hw.domain = priv->domain;
+ #endif
+ pci_common_init_dev(&pdev->dev, &hw);
++ priv->ohci_memdata = ioremap(cfg_res->start - 0x10000, 0x1000);
++ priv->ehci_memdata = ioremap(cfg_res->start - 0x10000 + 0x1000, 0x1000);
++ return 0;
++}
++
++static int rcar_pci_suspend(struct device *dev)
++{
++ struct clk *clk;
++ clk = clk_get(NULL, "ehci");
++ clk_disable_unprepare(clk);
++ clk_put(clk);
++ return 0;
++}
++static int rcar_pci_resume(struct device *dev)
++{
++ struct clk *clk;
++ clk = clk_get(NULL, "ehci");
++ clk_prepare_enable(clk);
++ clk_put(clk);
++ return 0;
++}
++static u32 rcar_pci_get_conf(struct rcar_pci_priv *priv, int id, int offset)
++{
++ u32 val, kpt;
++ void __iomem *data;
++ kpt = ioread32(priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ val = id ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
++ RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
++
++ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ data = priv->reg + (id >> 1) * 0x100;
++ val = ioread32(data + offset);
++ iowrite32(kpt, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ return val;
++}
++
++static void rcar_pci_set_conf(struct rcar_pci_priv *priv,
++ int id, int offset, u32 d)
++{
++ u32 val, kpt;
++ void __iomem *data;
++ kpt = ioread32(priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ val = id ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
++ RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
++
++ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ data = priv->reg + (id >> 1) * 0x100;
++ iowrite32(d, data + offset);
++ iowrite32(kpt, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++}
++
++
++static int rcar_pci_freeze(struct device *dev)
++{
++ struct rcar_pci_priv *priv = keep_priv[to_platform_device(dev)->id];
++ struct clk *clk;
++ clk = clk_get(NULL, "ehci");
++ clk_disable_unprepare(clk);
++ clk_put(clk);
++
++#ifndef MCCILDK_CHANGE_DISABLE
++ priv->store_cfg[0] = rcar_pci_get_conf(priv, 0, PCI_COMMAND);
++ priv->store_cfg[1] = rcar_pci_get_conf(priv, 1, PCI_COMMAND);
++ priv->store_cfg[2] = rcar_pci_get_conf(priv, 2, PCI_COMMAND);
++ priv->store_cfg[3] = rcar_pci_get_conf(priv, 0, PCI_CACHE_LINE_SIZE);
++ priv->store_cfg[4] = rcar_pci_get_conf(priv, 1, PCI_CACHE_LINE_SIZE);
++ priv->store_cfg[5] = rcar_pci_get_conf(priv, 2, PCI_CACHE_LINE_SIZE);
++ priv->store_cfg[6] = rcar_pci_get_conf(priv, 0, PCI_INTERRUPT_LINE);
++ priv->store_cfg[7] = rcar_pci_get_conf(priv, 1, PCI_INTERRUPT_LINE);
++ priv->store_cfg[8] = rcar_pci_get_conf(priv, 2, PCI_INTERRUPT_LINE);
++ priv->store_cfg[9] = rcar_pci_get_conf(priv, 0, PCI_BASE_ADDRESS_0);
++ priv->store_cfg[10] = rcar_pci_get_conf(priv, 1, PCI_BASE_ADDRESS_0);
++ priv->store_cfg[11] = rcar_pci_get_conf(priv, 2, PCI_BASE_ADDRESS_0);
++#else
++ priv->store_cfg[0] = rcar_pci_get_conf(priv, 0, 0x04);
++ priv->store_cfg[1] = rcar_pci_get_conf(priv, 1, 0x04);
++ priv->store_cfg[2] = rcar_pci_get_conf(priv, 2, 0x04);
++ priv->store_cfg[3] = rcar_pci_get_conf(priv, 0, 0x0c);
++ priv->store_cfg[4] = rcar_pci_get_conf(priv, 1, 0x0c);
++ priv->store_cfg[5] = rcar_pci_get_conf(priv, 2, 0x0c);
++ priv->store_cfg[6] = rcar_pci_get_conf(priv, 0, 0x3c);
++ priv->store_cfg[7] = rcar_pci_get_conf(priv, 1, 0x3c);
++ priv->store_cfg[8] = rcar_pci_get_conf(priv, 2, 0x3c);
++#endif
++ pm_runtime_disable(priv->dev);
++ return 0;
++}
++
++static int rcar_pci_restore(struct device *dev)
++{
++ struct clk *clk;
++ void *m;
++ u32 val;
++ struct rcar_pci_priv *priv = keep_priv[to_platform_device(dev)->id];
++ void __iomem *reg = priv->reg;
++ int id = to_platform_device(dev)->id;
++
++ pm_runtime_enable(priv->dev);
++ pm_runtime_get_sync(priv->dev);
++
++ clk = clk_get(NULL, "ehci");
++ clk_prepare_enable(clk);
++ clk_put(clk);
++ clk = clk_get(NULL, "hsusb");
++ clk_prepare_enable(clk);
++ clk_put(clk);
++ usb_phy_set_suspend(priv->phy, 0);
++ m = ioremap(0xe61501c4, 4);
++ val = readl(m);
++ iounmap(m);
++ m = ioremap(0xe615014c, 4);
++ writel(val & ~(3 << 3), m);
++ iounmap(m);
++ val = ioread32(reg + RCAR_PCI_UNIT_REV_REG);
++ dev_info(priv->dev, "PCI: bus%u revision %x\n", id, val);
++
++ /* Disable Direct Power Down State and assert reset */
++ val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD;
++#ifndef MCCILDK_CHANGE_DISABLE
++ val |= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST;
++#else
++ val |= RCAR_USBCTR_USBH_RST;
++#endif
++ iowrite32(val, reg + RCAR_USBCTR_REG);
++ udelay(4);
++ /* De-assert reset */
++#ifndef MCCILDK_CHANGE_DISABLE
++ val &= ~(RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST
++ | RCAR_USBCTR_PCICLK_MASK);
++ iowrite32(val, reg + RCAR_USBCTR_REG);
++ /* reset PCIAHB window size */
++ val &= ~RCAR_USBCTR_PCIAHB_WIN1_MASK;
++ val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
++ iowrite32(val, reg + RCAR_USBCTR_REG);
++#else
++ val &= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST
++ | RCAR_USBCTR_PCICLK_MASK;
++ iowrite32(val, reg + RCAR_USBCTR_REG);
++ val &= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST
++ | RCAR_USBCTR_PCICLK_MASK;
++ iowrite32(val, reg + RCAR_USBCTR_REG);
++ /* reset PCIAHB window size */
++ val &= RCAR_USBCTR_PCIAHB_WIN1_MASK;
++ val |= RCAR_USBCTR_PCIAHB_WIN1_1G;
++ iowrite32(val, reg + RCAR_USBCTR_REG);
++#endif
++
++ /* Configure AHB master and slave modes */
++ iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
++
++ /* PCI-AHB mapping: 0x40000000 base */
++ iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
++ reg + RCAR_PCIAHB_WIN1_CTR_REG);
++
++ /* AHB-PCI mapping: OHCI/EHCI registers */
++ val = priv->mem_res.start | RCAR_AHBPCI_WIN_CTR_MEM;
++ iowrite32(val, reg + RCAR_AHBPCI_WIN2_CTR_REG);
++
++ /* Enable PCI interrupts */
++ iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
++ reg + RCAR_PCI_INT_ENABLE_REG);
++
++ /* Configure PCI arbiter */
++ val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
++ val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
++ RCAR_PCI_ARBITER_PCIBP_MODE;
++ iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
++
++ /* Enable AHB-PCI bridge PCI configuration access */
++ iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
++ reg + RCAR_AHBPCI_WIN1_CTR_REG);
++
++ val = ioread32(reg + PCI_COMMAND);
++ val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
++ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
++ iowrite32(val, reg + PCI_COMMAND);
++
++ /* Set PCI-AHB Window1 address */
++ iowrite32(0x40000000 | PCI_BASE_ADDRESS_MEM_PREFETCH,
++ reg + PCI_BASE_ADDRESS_1);
++ /* Set AHB-PCI bridge PCI communication area address */
++ val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
++ iowrite32(val, reg + PCI_BASE_ADDRESS_0);
++
++ if (priv->irq > 0)
++ rcar_pci_setup_errirq(priv);
++#ifndef MCCILDK_CHANGE_DISABLE
++ rcar_pci_set_conf(priv, 0, PCI_COMMAND, priv->store_cfg[0]);
++ rcar_pci_set_conf(priv, 1, PCI_COMMAND, priv->store_cfg[1]);
++ rcar_pci_set_conf(priv, 2, PCI_COMMAND, priv->store_cfg[2]);
++ rcar_pci_set_conf(priv, 0, PCI_CACHE_LINE_SIZE, priv->store_cfg[3]);
++ rcar_pci_set_conf(priv, 1, PCI_CACHE_LINE_SIZE, priv->store_cfg[4]);
++ rcar_pci_set_conf(priv, 2, PCI_CACHE_LINE_SIZE, priv->store_cfg[5]);
++ rcar_pci_set_conf(priv, 0, PCI_INTERRUPT_LINE, priv->store_cfg[6]);
++ rcar_pci_set_conf(priv, 1, PCI_INTERRUPT_LINE, priv->store_cfg[7]);
++ rcar_pci_set_conf(priv, 2, PCI_INTERRUPT_LINE, priv->store_cfg[8]);
++ rcar_pci_set_conf(priv, 1, PCI_BASE_ADDRESS_0, priv->store_cfg[10]);
++ rcar_pci_set_conf(priv, 2, PCI_BASE_ADDRESS_0, priv->store_cfg[11]);
++#else
++ rcar_pci_set_conf(priv, 1, PCI_COMMAND, PCI_COMMAND_SERR
++ | PCI_COMMAND_PARITY | PCI_COMMAND_MEMORY
++ | PCI_COMMAND_MASTER);
++ rcar_pci_set_conf(priv, 1, PCI_BASE_ADDRESS_0
++ priv->cfg_res->start - 0x10000);
++ rcar_pci_set_conf(priv, 2, PCI_COMMAND, PCI_COMMAND_SERR
++ | PCI_COMMAND_PARITY | PCI_COMMAND_MEMORY
++ | PCI_COMMAND_MASTER);
++ rcar_pci_set_conf(priv, 2, PCI_BASE_ADDRESS_0,
++ priv->cfg_res->start - 0x10000 + 0x1000);
++ rcar_pci_set_conf(priv, 0, PCI_CACHE_LINE_SIZE, priv->store_cfg[3]);
++ rcar_pci_set_conf(priv, 1, PCI_CACHE_LINE_SIZE, priv->store_cfg[4]);
++ rcar_pci_set_conf(priv, 2, PCI_CACHE_LINE_SIZE, priv->store_cfg[5]);
++ rcar_pci_set_conf(priv, 0, PCI_INTERRUPT_LINE, 0x00020100);
++ rcar_pci_set_conf(priv, 1, PCI_INTERRUPT_LINE, 0x2a010100);
++ rcar_pci_set_conf(priv, 2, PCI_INTERRUPT_LINE, 0x22100200);
++ val = RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG;
++ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++ val = ioread32(priv->reg + 0x04);
++ iowrite32(val | (1 << 1), priv->reg + 0x04);
++ val = ioread32(priv->reg + 0x104);
++ iowrite32(val | (1 << 1), priv->reg + 0x104);
++
++ val = RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
++ iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
++#endif
+ return 0;
+ }
+
++static const struct dev_pm_ops rcar_pci_pm_ops = {
++ .suspend = rcar_pci_suspend,
++ .resume = rcar_pci_resume,
++ .freeze_noirq = rcar_pci_freeze,
++ .restore_noirq = rcar_pci_restore,
++ .thaw = rcar_pci_resume,
++ .poweroff = rcar_pci_suspend
++};
++
+ static struct platform_driver rcar_pci_driver = {
+ .driver = {
+ .name = "pci-rcar-gen2",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
++ .pm = &rcar_pci_pm_ops,
+ },
+ .probe = rcar_pci_probe,
+ };
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0012-Add-rcar-gpio-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0012-Add-rcar-gpio-hibernation-code.patch
new file mode 100755
index 000000000..9b2aff4f9
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0012-Add-rcar-gpio-hibernation-code.patch
@@ -0,0 +1,230 @@
+From bf20be14fc1b3f7e096bdac9c5ff67362b391479 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:46:24 +0900
+Subject: [PATCH 12/15] Add rcar-gpio hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/pinctrl/sh-pfc/core.c | 141 +++++++++++++++++++++++++++++++++++++++---
+ drivers/pinctrl/sh-pfc/core.h | 4 ++
+ 2 files changed, 138 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
+index b9e025d..c37418e 100644
+--- a/drivers/pinctrl/sh-pfc/core.c
++++ b/drivers/pinctrl/sh-pfc/core.c
+@@ -24,6 +24,7 @@
+ #include <linux/pinctrl/machine.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/cpu_pm.h>
+
+ #include "core.h"
+
+@@ -201,19 +202,117 @@ static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
+ }
+ }
+
++#ifdef CONFIG_CPU_PM
++struct reg_record {
++ void __iomem *reg;
++ unsigned long width;
++ unsigned long data;
++};
++
++struct reg_config {
++ bool unlock;
++ struct reg_record unlock_reg;
++ struct reg_record actual_reg;
++ struct list_head list;
++};
++
++static struct reg_config *regs_list;
++
++struct reg_range {
++ int start;
++ int end;
++};
++
++static int sh_pfc_cpu_pm_notify(struct notifier_block *self,
++ unsigned long action, void *hcpu)
++{
++ struct reg_config *tmp = NULL;
++ struct sh_pfc *pfc = container_of(self, struct sh_pfc, pm_notify);
++ /* We don't setup pinmux in kernel - store all registers */
++ struct reg_range ranges[] = {
++ {0x0, 0x5c}, {0x160, 0x160}, {0x90, 0x98},
++ {0x100, 0x118}, {0x70, 0x70}, {0x60, 0x64},
++ {0x84, 0x8c}, {0x240, 0x248},
++ };
++
++ if (action == CPU_PM_ENTER) {
++ if (!regs_list) {
++ /* No pinmux configuration, storing all registers */
++ int store_cnt = 0;
++ int i;
++ for (i = 0; i < ARRAY_SIZE(ranges); i++) {
++ int j;
++ for (j = ranges[i].start; j <= ranges[i].end; j += sizeof(u32)) {
++ pfc->stored_regs[store_cnt] =
++ sh_pfc_read_raw_reg(sh_pfc_phys_to_virt(pfc, 0xe6060000 + j), 32);
++ pr_debug("PFC: %08x => %08x\n", 0xe6060000 + j, pfc->stored_regs[store_cnt]);
++ store_cnt++;
++ if (store_cnt >= ARRAY_SIZE(pfc->stored_regs)) {
++ pr_err("read: Register store overflow\n");
++ goto out;
++ }
++ }
++ }
++ }
++ } else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) {
++ if (!regs_list) {
++ /* No list, restoring all registers */
++ int store_cnt = 0;
++ int i;
++ for (i = 0; i < ARRAY_SIZE(ranges); i++) {
++ int j;
++ for (j = ranges[i].start; j <= ranges[i].end; j += sizeof(u32)) {
++ sh_pfc_write_raw_reg(sh_pfc_phys_to_virt(pfc, 0xe6060000 + j), 32,
++ pfc->stored_regs[store_cnt]);
++ pr_debug("PFC: %08x => %08x\n", 0xe6060000 + j, pfc->stored_regs[store_cnt]);
++ store_cnt++;
++ if (store_cnt >= ARRAY_SIZE(pfc->stored_regs)) {
++ pr_err("write: Register store overflow\n");
++ goto out;
++ }
++ }
++ }
++ goto out;
++ }
++ list_for_each_entry(tmp , &(regs_list->list), list) {
++ if (tmp->unlock)
++ sh_pfc_write_raw_reg(tmp->unlock_reg.reg,
++ tmp->unlock_reg.width,
++ tmp->unlock_reg.data);
++ sh_pfc_write_raw_reg(tmp->actual_reg.reg,
++ tmp->actual_reg.width,
++ tmp->actual_reg.data);
++ }
++ }
++out:
++ return NOTIFY_OK;
++}
++
++static int __init sh_pfc_cpu_pm_init(struct sh_pfc *pfc)
++{
++ memset(&pfc->pm_notify, 0, sizeof(pfc->pm_notify));
++ pfc->pm_notify.notifier_call = sh_pfc_cpu_pm_notify;
++ return cpu_pm_register_notifier(&pfc->pm_notify);
++}
++#else
++static int __init sh_pfc_cpu_pm_init(struct sh_pfc *pfc)
++{
++ return 0;
++}
++#endif
++
++
+ static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
+ const struct pinmux_cfg_reg *crp,
+ unsigned long field, unsigned long value)
+ {
+ void __iomem *mapped_reg;
+ unsigned long mask, pos, data;
+-
++#ifdef CONFIG_CPU_PM
++ struct reg_config *tmp;
++#endif
+ sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
+
+- dev_dbg(pfc->dev, "write_reg addr = %lx, value = %ld, field = %ld, "
+- "r_width = %ld, f_width = %ld\n",
+- crp->reg, value, field, crp->reg_width, crp->field_width);
+-
+ mask = ~(mask << pos);
+ value = value << pos;
+
+@@ -221,14 +320,39 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
+ data &= mask;
+ data |= value;
+
+- if (pfc->info->unlock_reg)
++#ifdef CONFIG_CPU_PM
++ tmp = kzalloc(sizeof(struct reg_config), GFP_KERNEL);
++ BUG_ON(!tmp);
++
++ if (!regs_list) {
++ regs_list = tmp;
++ INIT_LIST_HEAD(&regs_list->list);
++ }
++#endif
++
++ if (pfc->info->unlock_reg) {
++#ifdef CONFIG_CPU_PM
++ tmp->unlock = true;
++ tmp->unlock_reg.reg = sh_pfc_phys_to_virt(pfc,
++ pfc->info->unlock_reg);
++ tmp->unlock_reg.width = 32;
++ tmp->unlock_reg.data = ~data;
++#endif
+ sh_pfc_write_raw_reg(
+ sh_pfc_phys_to_virt(pfc, pfc->info->unlock_reg), 32,
+ ~data);
++ }
++
++#ifdef CONFIG_CPU_PM
++ tmp->actual_reg.reg = mapped_reg;
++ tmp->actual_reg.width = crp->reg_width;
++ tmp->actual_reg.data = data;
++
++ list_add(&tmp->list, &regs_list->list);
++#endif
+
+ sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
+ }
+-
+ static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id,
+ const struct pinmux_cfg_reg **crp, int *fieldp,
+ int *valuep)
+@@ -574,6 +698,8 @@ static int sh_pfc_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, pfc);
+
++ sh_pfc_cpu_pm_init(pfc);
++
+ dev_info(pfc->dev, "%s support registered\n", info->name);
+
+ return 0;
+@@ -596,6 +722,7 @@ static int sh_pfc_remove(struct platform_device *pdev)
+ if (pfc->info->ops && pfc->info->ops->exit)
+ pfc->info->ops->exit(pfc);
+
++
+ return 0;
+ }
+
+diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
+index 75ecb67..5471a6c 100644
+--- a/drivers/pinctrl/sh-pfc/core.h
++++ b/drivers/pinctrl/sh-pfc/core.h
+@@ -14,6 +14,7 @@
+ #include <linux/compiler.h>
+ #include <linux/spinlock.h>
+ #include <linux/types.h>
++#include <linux/notifier.h>
+
+ #include "sh_pfc.h"
+
+@@ -51,6 +52,9 @@ struct sh_pfc {
+ struct sh_pfc_chip *func;
+
+ struct sh_pfc_pinctrl *pinctrl;
++ struct notifier_block pm_notify;
++#define STORE_REGS_COUNT 50
++ u32 stored_regs[STORE_REGS_COUNT];
+ };
+
+ int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0013-Add-rcar-spi-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0013-Add-rcar-spi-hibernation-code.patch
new file mode 100755
index 000000000..515b08b12
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0013-Add-rcar-spi-hibernation-code.patch
@@ -0,0 +1,168 @@
+From c1b129172a91046a7555a3c198b49eb1b45aafd7 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:58:28 +0900
+Subject: [PATCH 13/15] Add rcar-spi hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/spi/spi-rspi.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 108 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
+index 215be3b..a2432de 100644
+--- a/drivers/spi/spi-rspi.c
++++ b/drivers/spi/spi-rspi.c
+@@ -38,6 +38,7 @@
+ #include <linux/sh_dma.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/rspi.h>
++#include <linux/delay.h>
+
+ #define RSPI_SPCR 0x00 /* Control Register */
+ #define RSPI_SSLP 0x01 /* Slave Select Polarity Register */
+@@ -208,6 +209,12 @@ struct rspi_data {
+ u8 sppcr;
+ int rx_irq, tx_irq;
+ const struct spi_ops *ops;
++ u32 save_spbmul0;
++ u32 save_spbmul1;
++ u32 save_spbmul2;
++ u32 save_spbmul3;
++ u8 save_spbfcr;
++ u8 save_spscr;
+
+ unsigned dma_callbacked:1;
+ unsigned byte_access:1;
+@@ -238,6 +245,11 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
+ return ioread16(rspi->addr + offset);
+ }
+
++static u16 rspi_read32(const struct rspi_data *rspi, u16 offset)
++{
++ return ioread32(rspi->addr + offset);
++}
++
+ #define rspi_update8(spi, mask, val, reg) \
+ rspi_write8(spi, (rspi_read8(spi, reg) & ~mask) | val, reg);
+
+@@ -504,7 +516,6 @@ static int rspi_pio_transfer_in(struct rspi_data *rspi, u8 *rx, unsigned int n)
+ if (!rx)
+ return 0;
+
+-
+ while (n > 0) {
+ count = min(n, SPI_BUFFER_SIZE);
+ if (count >= SPI_BUFFER_SIZE) {
+@@ -1278,6 +1289,101 @@ error1:
+ return ret;
+ }
+
++int rspi_suspend(struct device *dev)
++{
++ struct rspi_data *rspi = platform_get_drvdata(to_platform_device(dev));
++ clk_disable_unprepare(rspi->clk);
++ return 0;
++}
++
++int rspi_resume(struct device *dev)
++{
++ struct rspi_data *rspi = platform_get_drvdata(to_platform_device(dev));
++ clk_prepare_enable(rspi->clk);
++ return 0;
++}
++
++#define PR_REG8(dev, rspi, reg) \
++ dev_dbg(dev, "QSPI REG: " #reg " = %08x\n", \
++ rspi_read8(rspi, reg))
++#define PR_REG16(dev, rspi, reg) \
++ dev_dbg(dev, "QSPI REG: " #reg " = %08x\n", \
++ rspi_read16(rspi, reg))
++#define PR_REG32(dev, rspi, reg) \
++ dev_dbg(dev, "QSPI REG: " #reg " = %08x\n", \
++ rspi_read32(rspi, reg))
++
++#ifdef DEBUG
++static void pr_regs(struct device *dev)
++{
++ struct rspi_data *rspi = platform_get_drvdata(to_platform_device(dev));
++ PR_REG8(dev, rspi, RSPI_SPCR);
++ PR_REG8(dev, rspi, RSPI_SSLP);
++ PR_REG8(dev, rspi, RSPI_SPPCR);
++ PR_REG8(dev, rspi, RSPI_SPDR);
++ PR_REG8(dev, rspi, RSPI_SPSCR);
++ PR_REG8(dev, rspi, RSPI_SPBR);
++ PR_REG8(dev, rspi, RSPI_SPDCR);
++ PR_REG8(dev, rspi, RSPI_SPCKD);
++ PR_REG8(dev, rspi, RSPI_SSLND);
++ PR_REG8(dev, rspi, RSPI_SPND);
++ PR_REG16(dev, rspi, RSPI_SPCMD0);
++ PR_REG16(dev, rspi, RSPI_SPCMD1);
++ PR_REG16(dev, rspi, RSPI_SPCMD2);
++ PR_REG16(dev, rspi, RSPI_SPCMD3);
++ PR_REG8(dev, rspi, QSPI_SPBFCR);
++ PR_REG16(dev, rspi, QSPI_SPBDCR);
++ PR_REG32(dev, rspi, QSPI_SPBMUL0);
++ PR_REG32(dev, rspi, QSPI_SPBMUL1);
++ PR_REG32(dev, rspi, QSPI_SPBMUL2);
++ PR_REG32(dev, rspi, QSPI_SPBMUL3);
++}
++#endif
++
++int rspi_freeze(struct device *dev)
++{
++ struct rspi_data *rspi = platform_get_drvdata(to_platform_device(dev));
++ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
++ rspi->save_spbmul0 = rspi_read32(rspi, QSPI_SPBMUL0);
++ rspi->save_spbmul1 = rspi_read32(rspi, QSPI_SPBMUL1);
++ rspi->save_spbmul2 = rspi_read32(rspi, QSPI_SPBMUL2);
++ rspi->save_spbmul3 = rspi_read32(rspi, QSPI_SPBMUL3);
++ rspi->save_spbfcr = rspi_read8(rspi, QSPI_SPBFCR);
++ rspi->save_spscr = rspi_read8(rspi, RSPI_SPSCR);
++ dev_info(dev, "freeze\n");
++#ifdef DEBUG
++ pr_regs(dev);
++#endif
++ return 0;
++}
++
++
++int rspi_restore(struct device *dev)
++{
++ struct rspi_data *rspi = platform_get_drvdata(to_platform_device(dev));
++ clk_prepare_enable(rspi->clk);
++ udelay(16);
++ set_config_register(rspi, 8);
++ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
++ rspi_write8(rspi, rspi->save_spscr, RSPI_SPSCR);
++ rspi_write8(rspi, rspi->save_spbfcr, QSPI_SPBFCR);
++ rspi_write32(rspi, rspi->save_spbmul3, QSPI_SPBMUL3);
++ rspi_write32(rspi, rspi->save_spbmul2, QSPI_SPBMUL2);
++ rspi_write32(rspi, rspi->save_spbmul1, QSPI_SPBMUL1);
++ rspi_write32(rspi, rspi->save_spbmul0, QSPI_SPBMUL0);
++ dev_info(dev, "restore\n");
++#ifdef DEBUG
++ pr_regs(dev);
++#endif
++ return 0;
++}
++
++const struct dev_pm_ops rspi_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(rspi_suspend, rspi_resume)
++ .restore = rspi_restore,
++ .freeze = rspi_freeze,
++};
++
+ static struct platform_device_id spi_driver_ids[] = {
+ { "rspi", (kernel_ulong_t)&rspi_ops },
+ { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
+@@ -1295,6 +1401,7 @@ static struct platform_driver rspi_driver = {
+ .name = "renesas_spi",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rspi_of_match),
++ .pm = &rspi_pm_ops,
+ },
+ };
+ module_platform_driver(rspi_driver);
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0014-Add-rcar-sci-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0014-Add-rcar-sci-hibernation-code.patch
new file mode 100755
index 000000000..c70f515a2
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0014-Add-rcar-sci-hibernation-code.patch
@@ -0,0 +1,41 @@
+From 947b9e15ff36a9dcd517bb932303cc32f8356550 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 17:59:40 +0900
+Subject: [PATCH 14/15] Add rcar-sci hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/tty/serial/sh-sci.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
+index e3abfb7..2f0dc7a 100644
+--- a/drivers/tty/serial/sh-sci.c
++++ b/drivers/tty/serial/sh-sci.c
+@@ -2852,6 +2852,7 @@ static int sci_probe(struct platform_device *dev)
+ return 0;
+ }
+
++#ifdef CONFIG_PM_SLEEP
+ static int sci_suspend(struct device *dev)
+ {
+ struct sci_port *sport = dev_get_drvdata(dev);
+@@ -2871,10 +2872,13 @@ static int sci_resume(struct device *dev)
+
+ return 0;
+ }
++#else
++#define sci_suspend NULL
++#define sci_resume NULL
++#endif
+
+ static const struct dev_pm_ops sci_dev_pm_ops = {
+- .suspend = sci_suspend,
+- .resume = sci_resume,
++ SET_SYSTEM_SLEEP_PM_OPS(sci_suspend, sci_resume)
+ };
+
+ static struct platform_driver sci_driver = {
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0015-Add-rcar-usbphy-hibernation-code.patch b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0015-Add-rcar-usbphy-hibernation-code.patch
new file mode 100755
index 000000000..c0c2b1675
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0015-Add-rcar-usbphy-hibernation-code.patch
@@ -0,0 +1,83 @@
+From 28393daa686ef43966e3fa1652bcd8d860698ef4 Mon Sep 17 00:00:00 2001
+From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+Date: Thu, 18 May 2017 18:00:39 +0900
+Subject: [PATCH 15/15] Add rcar-usbphy hibernation code
+
+Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
+---
+ drivers/usb/phy/phy-rcar-gen2-usb.c | 35 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c
+index 9e7205d..05849e7 100644
+--- a/drivers/usb/phy/phy-rcar-gen2-usb.c
++++ b/drivers/usb/phy/phy-rcar-gen2-usb.c
+@@ -148,6 +148,7 @@ static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend)
+
+ devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+ devm_iounmap(&pdev->dev, priv->base);
++ priv->base = NULL;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+@@ -178,6 +179,7 @@ static int rcar_gen2_usb_phy_init(struct usb_phy *phy)
+ devm_release_mem_region(&pdev->dev, res->start,
+ resource_size(res));
+ devm_iounmap(&pdev->dev, priv->base);
++ priv->base = NULL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ return 0;
+@@ -209,6 +211,7 @@ static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy)
+ devm_release_mem_region(&pdev->dev, res->start,
+ resource_size(res));
+ devm_iounmap(&pdev->dev, priv->base);
++ priv->base = NULL;
+ }
+ out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+@@ -431,9 +434,41 @@ static int phy_rcar_gen2_pm_resume(struct device *dev)
+ return 0;
+ }
+
++static int phy_rcar_gen2_pm_freeze(struct device *dev)
++{
++ struct rcar_gen2_usb_phy_priv *priv = dev_get_drvdata(dev);
++ pr_info("freeze: %p\n", priv->base);
++
++ return phy_rcar_gen2_pm_suspend(dev);
++}
++
++static int phy_rcar_gen2_pm_restore(struct device *dev)
++{
++ struct rcar_gen2_usb_phy_priv *priv = dev_get_drvdata(dev);
++ struct resource *res;
++
++ res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
++ priv->base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->base)) {
++ pr_info("restore: pointer error %ld\n", PTR_ERR(priv->base));
++ return PTR_ERR(priv->base);
++ }
++ pr_info("restore: %p\n", priv->base);
++ __rcar_gen2_usb_phy_init(priv);
++ devm_release_mem_region(dev, res->start,
++ resource_size(res));
++ devm_iounmap(dev, priv->base);
++ priv->base = NULL;
++ return phy_rcar_gen2_pm_resume(dev);
++}
++
+ static const struct dev_pm_ops phy_rcar_gen2_dev_pm_ops = {
+ .suspend = phy_rcar_gen2_pm_suspend,
+ .resume = phy_rcar_gen2_pm_resume,
++ .freeze_noirq = phy_rcar_gen2_pm_freeze,
++ .restore = phy_rcar_gen2_pm_restore,
++ .thaw = phy_rcar_gen2_pm_resume,
++ .poweroff = phy_rcar_gen2_pm_suspend,
+ };
+ #endif
+
+--
+1.8.3.1
+
diff --git a/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/hibernation.cfg b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/hibernation.cfg
new file mode 100755
index 000000000..45521d25d
--- /dev/null
+++ b/meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/hibernation.cfg
@@ -0,0 +1,10 @@
+CONFIG_SWSUSP_AREA=0x7A000000
+CONFIG_SWSUSP_AREA_SIZE=0x4000000
+CONFIG_HIBERNATE_CALLBACKS=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION=""
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_MTD_SWAP=y
+CONFIG_MTD_PHRAM=y
+CONFIG_MMC_UNSAFE_RESUME=y
+