From a14e289caaae4c342c2bc686bd5d327ed612b0fc Mon Sep 17 00:00:00 2001
From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
Date: Mon, 22 May 2017 00:15:23 +0900
Subject: 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>
---
 .../recipes-kernel/linux/linux-renesas_%.bbappend  |   20 +
 .../0001-Add-Hibernation-kernel-base-code.patch    |  853 +++++++++++
 ...-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch | 1529 ++++++++++++++++++++
 .../0003-Add-sata-hibernation-code.patch           |   56 +
 .../0004-Add-firmware-hibernation-code.patch       |   25 +
 .../0005-Add-rcar-dma-hibernation-code.patch       |  113 ++
 .../0006-Add-rcar-du-hibernation-code.patch        |  127 ++
 .../0007-Add-rcar-i2c-hibernation-code.patch       |   69 +
 .../0008-Add-rcar-mmc-hibernation-code.patch       |  414 ++++++
 .../0009-Add-hibernation-store-area.patch          |   62 +
 .../0010-Add-rcar-eth-hibernation-code.patch       |  238 +++
 .../0011-Add-rcar-pci-hibernation-code.patch       |  375 +++++
 .../0012-Add-rcar-gpio-hibernation-code.patch      |  230 +++
 .../0013-Add-rcar-spi-hibernation-code.patch       |  168 +++
 .../0014-Add-rcar-sci-hibernation-code.patch       |   41 +
 .../0015-Add-rcar-usbphy-hibernation-code.patch    |   83 ++
 .../linux/linux/hibernation/hibernation.cfg        |   10 +
 17 files changed, 4413 insertions(+)
 mode change 100644 => 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux-renesas_%.bbappend
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0001-Add-Hibernation-kernel-base-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0002-Add-Hibernation-arch-code-Only-R-CAR-M2W.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0003-Add-sata-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0004-Add-firmware-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0005-Add-rcar-dma-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0006-Add-rcar-du-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0007-Add-rcar-i2c-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0008-Add-rcar-mmc-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0009-Add-hibernation-store-area.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0010-Add-rcar-eth-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0011-Add-rcar-pci-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0012-Add-rcar-gpio-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0013-Add-rcar-spi-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0014-Add-rcar-sci-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/0015-Add-rcar-usbphy-hibernation-code.patch
 create mode 100755 meta-agl-bsp/meta-renesas/recipes-kernel/linux/linux/hibernation/hibernation.cfg

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
old mode 100644
new mode 100755
index 29dcc75cb..35b225354
--- 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
+
-- 
cgit