diff --git a/.gitignore b/.gitignore
index 44749fc89317230f7b7822ba865acf27f2d6699c..23193f69deb58681817ec0b61af97c9c28780c4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ KERNEL
 dl
 deploy
 ignore
+kernel_version
 patches/patch-*.bz2
 patches/current_defconfig
 patches/previous_defconfig
diff --git a/patch.sh b/patch.sh
index 42e60d5156a05c006d43b5d7dc8825a906487d89..30cea8b650f92c26b4a9963cd458997a863722d2 100644
--- a/patch.sh
+++ b/patch.sh
@@ -467,6 +467,36 @@ beaglebone () {
 		number=9
 		cleanup
 	fi
+
+	echo "dir: beaglebone/suspend"
+	#regenerate="enable"
+	if [ "x${regenerate}" = "xenable" ] ; then
+		start_cleanup
+	fi
+
+	${git} "${DIR}/patches/beaglebone/suspend/0001-ARM-OMAP2-Use-pdata-quirks-for-wkup_m3-reset-managem.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0002-ARM-dts-AM33xx-Update-and-move-wkup_m3-node-to-l4-no.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0003-ARM-dts-AM4372-Add-the-wkupm3-rproc-node.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0004-asm-generic-io-Add-exec-versions-of-ioremap.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0005-lib-devres-Add-exec-versions-of-devm_ioremap_resourc.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0006-misc-SRAM-Add-option-to-map-SRAM-to-allow-code-execu.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0007-Documentation-dt-add-bindings-for-TI-Wakeup-M3-IPC-d.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0008-soc-ti-Add-wkup_m3_ipc-driver.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0009-ARM-dts-AM33xx-Add-the-wkup_m3_ipc-node.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0010-ARM-dts-AM4372-Add-the-wkup_m3_ipc-node.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0011-Documentation-dt-add-ti-am3352-emif-bindings.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0012-memory-ti-emif-sram-introduce-relocatable-suspend-re.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0013-ARM-dts-am33xx-Add-emif-node.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0014-ARM-OMAP2-timer-Add-suspend-resume-callbacks-for-clk.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0015-ARM-OMAP2-AM33XX-Add-assembly-code-for-PM-operations.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0016-ARM-OMAP2-AM33XX-Basic-suspend-resume-support.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0017-ARM-OMAP2-AM33XX-Hookup-AM33XX-PM-code-into-OMAP-bui.patch"
+	${git} "${DIR}/patches/beaglebone/suspend/0018-ARM-OMAP2-pdata-quirks-provide-wkup_m3_ipc-ops-to-pl.patch"
+
+	if [ "x${regenerate}" = "xenable" ] ; then
+		number=18
+		cleanup
+	fi
 }
 
 sgx () {
diff --git a/patches/beaglebone/suspend/0001-ARM-OMAP2-Use-pdata-quirks-for-wkup_m3-reset-managem.patch b/patches/beaglebone/suspend/0001-ARM-OMAP2-Use-pdata-quirks-for-wkup_m3-reset-managem.patch
new file mode 100644
index 0000000000000000000000000000000000000000..cf58f93949501b9b2a0b5c4655e614f16f7b9eab
--- /dev/null
+++ b/patches/beaglebone/suspend/0001-ARM-OMAP2-Use-pdata-quirks-for-wkup_m3-reset-managem.patch
@@ -0,0 +1,68 @@
+From 1a1bd80e8076090ce6ec25441d9da2dee7f12c4b Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Wed, 18 Mar 2015 17:54:04 -0600
+Subject: [PATCH 01/18] ARM: OMAP2+: Use pdata-quirks for wkup_m3 reset
+ management
+
+Use pdata-quirks to provide platform data required for reset
+management during boot and shutdown of the wkup_m3 processor
+on both the AM33xx and AM43xx SoCs. The WkupM3 remote processor
+is used to implement and achieve low-power functionality on
+the AM33xx & AM43xx SoCs.
+
+Signed-off-by: Suman Anna <s-anna@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/mach-omap2/pdata-quirks.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
+index af11511..88ff116 100644
+--- a/arch/arm/mach-omap2/pdata-quirks.c
++++ b/arch/arm/mach-omap2/pdata-quirks.c
+@@ -17,6 +17,7 @@
+ 
+ #include <linux/platform_data/pinctrl-single.h>
+ #include <linux/platform_data/iommu-omap.h>
++#include <linux/platform_data/wkup_m3.h>
+ 
+ #include "common.h"
+ #include "common-board-devices.h"
+@@ -257,6 +258,14 @@ static struct iommu_platform_data omap4_iommu_pdata = {
+ };
+ #endif
+ 
++#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
++static struct wkup_m3_platform_data wkup_m3_data = {
++	.reset_name = "wkup_m3",
++	.assert_reset = omap_device_assert_hardreset,
++	.deassert_reset = omap_device_deassert_hardreset,
++};
++#endif
++
+ #ifdef CONFIG_SOC_OMAP5
+ static void __init omap5_uevm_legacy_init(void)
+ {
+@@ -319,6 +328,10 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+ 	OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
+ 		       &am35xx_emac_pdata),
+ #endif
++#ifdef CONFIG_SOC_AM33XX
++	OF_DEV_AUXDATA("ti,am3352-wkup-m3", 0x44d00000, "44d00000.wkup_m3",
++		       &wkup_m3_data),
++#endif
+ #ifdef CONFIG_ARCH_OMAP4
+ 	OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a100040, "4a100040.pinmux", &pcs_pdata),
+ 	OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a31e040, "4a31e040.pinmux", &pcs_pdata),
+@@ -332,6 +345,8 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+ #endif
+ #ifdef CONFIG_SOC_AM43XX
+ 	OF_DEV_AUXDATA("ti,am437-padconf", 0x44e10800, "44e10800.pinmux", &pcs_pdata),
++	OF_DEV_AUXDATA("ti,am4372-wkup-m3", 0x44d00000, "44d00000.wkup_m3",
++		       &wkup_m3_data),
+ #endif
+ #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
+ 	OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu",
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0002-ARM-dts-AM33xx-Update-and-move-wkup_m3-node-to-l4-no.patch b/patches/beaglebone/suspend/0002-ARM-dts-AM33xx-Update-and-move-wkup_m3-node-to-l4-no.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b64a68e751c1b8485435487e9dee22814c01d6b6
--- /dev/null
+++ b/patches/beaglebone/suspend/0002-ARM-dts-AM33xx-Update-and-move-wkup_m3-node-to-l4-no.patch
@@ -0,0 +1,57 @@
+From 4988cd1d3a81b2ab3f54e0cefb9231390c1796d4 Mon Sep 17 00:00:00 2001
+From: Suman Anna <s-anna@ti.com>
+Date: Tue, 25 Mar 2014 09:59:16 -0500
+Subject: [PATCH 02/18] ARM: dts: AM33xx: Update and move wkup_m3 node to l4
+ node
+
+The WakeupM3 remote processor device node has been moved to
+be a child node of the newly created l4_wkup node, to reflect
+its presence properly within the SoC. The node was added
+previously before any driver support, it is now updated as
+per the wkup_m3_rproc bindings added alongside the driver
+support.
+
+Signed-off-by: Suman Anna <s-anna@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/boot/dts/am33xx.dtsi | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
+index 09532d6..b31783f 100644
+--- a/arch/arm/boot/dts/am33xx.dtsi
++++ b/arch/arm/boot/dts/am33xx.dtsi
+@@ -103,6 +103,15 @@
+ 			#size-cells = <1>;
+ 			ranges = <0 0x44c00000 0x280000>;
+ 
++			wkup_m3: wkup_m3@100000 {
++				compatible = "ti,am3352-wkup-m3";
++				reg = <0x100000 0x4000>,
++				      <0x180000	0x2000>;
++				reg-names = "umem", "dmem";
++				ti,hwmods = "wkup_m3";
++				ti,pm-firmware = "am335x-pm-firmware.elf";
++			};
++
+ 			prcm: prcm@200000 {
+ 				compatible = "ti,am3-prcm";
+ 				reg = <0x200000 0x4000>;
+@@ -800,14 +809,6 @@
+ 			reg = <0x40300000 0x10000>; /* 64k */
+ 		};
+ 
+-		wkup_m3: wkup_m3@44d00000 {
+-			compatible = "ti,am3353-wkup-m3";
+-			reg = <0x44d00000 0x4000	/* M3 UMEM */
+-			       0x44d80000 0x2000>;	/* M3 DMEM */
+-			ti,hwmods = "wkup_m3";
+-			ti,no-reset-on-init;
+-		};
+-
+ 		elm: elm@48080000 {
+ 			compatible = "ti,am3352-elm";
+ 			reg = <0x48080000 0x2000>;
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0003-ARM-dts-AM4372-Add-the-wkupm3-rproc-node.patch b/patches/beaglebone/suspend/0003-ARM-dts-AM4372-Add-the-wkupm3-rproc-node.patch
new file mode 100644
index 0000000000000000000000000000000000000000..94f0a47af69bd046790ad76359b219e8d530fe1c
--- /dev/null
+++ b/patches/beaglebone/suspend/0003-ARM-dts-AM4372-Add-the-wkupm3-rproc-node.patch
@@ -0,0 +1,42 @@
+From e35bebd3be2db5ba457cd31518f0b6ca4a502bad Mon Sep 17 00:00:00 2001
+From: Suman Anna <s-anna@ti.com>
+Date: Wed, 18 Mar 2015 03:00:12 -0500
+Subject: [PATCH 03/18] ARM: dts: AM4372: Add the wkupm3 rproc node
+
+Add the Wakeup M3 remote processor device node for
+the AM4372 SoC. The WkupM3 remote processor is used
+to implement and achieve low-power functionality on
+the AM33xx & AM43xx SoCs.
+
+This node is added as a child of the recently added
+l4_wkup node to reflect its presence within the SoC.
+
+Signed-off-by: Suman Anna <s-anna@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/boot/dts/am4372.dtsi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
+index c80a3e2..136d1af 100644
+--- a/arch/arm/boot/dts/am4372.dtsi
++++ b/arch/arm/boot/dts/am4372.dtsi
+@@ -83,6 +83,15 @@
+ 			#size-cells = <1>;
+ 			ranges = <0 0x44c00000 0x287000>;
+ 
++			wkup_m3: wkup_m3@100000 {
++				compatible = "ti,am4372-wkup-m3";
++				reg = <0x100000 0x4000>,
++				      <0x180000	0x2000>;
++				reg-names = "umem", "dmem";
++				ti,hwmods = "wkup_m3";
++				ti,pm-firmware = "am335x-pm-firmware.elf";
++			};
++
+ 			prcm: prcm@1f0000 {
+ 				compatible = "ti,am4-prcm";
+ 				reg = <0x1f0000 0x11000>;
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0004-asm-generic-io-Add-exec-versions-of-ioremap.patch b/patches/beaglebone/suspend/0004-asm-generic-io-Add-exec-versions-of-ioremap.patch
new file mode 100644
index 0000000000000000000000000000000000000000..241b2b0ba3056a9fe66961e540340a63ab994a87
--- /dev/null
+++ b/patches/beaglebone/suspend/0004-asm-generic-io-Add-exec-versions-of-ioremap.patch
@@ -0,0 +1,48 @@
+From ff0303bb2a5f99ce8d387ca26c27e118d4cfca7f Mon Sep 17 00:00:00 2001
+From: Russ Dill <Russ.Dill@ti.com>
+Date: Tue, 17 Sep 2013 05:43:27 -0700
+Subject: [PATCH 04/18] asm-generic: io: Add exec versions of ioremap
+
+If code is to be copied into and area (such as SRAM) and run,
+it needs to be marked as exec. Currently only an ARM version
+of this exists.
+
+Signed-off-by: Russ Dill <Russ.Dill@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/include/asm/io.h   | 2 ++
+ include/asm-generic/iomap.h | 5 +++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
+index db58deb..901fe45 100644
+--- a/arch/arm/include/asm/io.h
++++ b/arch/arm/include/asm/io.h
+@@ -336,6 +336,8 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
+ #define ioremap_nocache(cookie,size)	__arm_ioremap((cookie), (size), MT_DEVICE)
+ #define ioremap_cache(cookie,size)	__arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
+ #define ioremap_wc(cookie,size)		__arm_ioremap((cookie), (size), MT_DEVICE_WC)
++#define ioremap_exec(cookie,size)	__arm_ioremap_exec((cookie), (size), true)
++#define ioremap_exec_nocache(cookie,size) __arm_ioremap_exec((cookie), (size), false)
+ #define iounmap				__arm_iounmap
+ 
+ /*
+diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
+index 1b41011..6648ff3 100644
+--- a/include/asm-generic/iomap.h
++++ b/include/asm-generic/iomap.h
+@@ -66,6 +66,11 @@ extern void ioport_unmap(void __iomem *);
+ #define ioremap_wc ioremap_nocache
+ #endif
+ 
++#ifndef ARCH_HAS_IOREMAP_EXEC
++#define ioremap_exec ioremap
++#define ioremap_exec_nocache ioremap_nocache
++#endif
++
+ #ifdef CONFIG_PCI
+ /* Destroy a virtual mapping cookie for a PCI BAR (memory or IO) */
+ struct pci_dev;
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0005-lib-devres-Add-exec-versions-of-devm_ioremap_resourc.patch b/patches/beaglebone/suspend/0005-lib-devres-Add-exec-versions-of-devm_ioremap_resourc.patch
new file mode 100644
index 0000000000000000000000000000000000000000..66ccbe29401efa13181d04afd6881464ea49852b
--- /dev/null
+++ b/patches/beaglebone/suspend/0005-lib-devres-Add-exec-versions-of-devm_ioremap_resourc.patch
@@ -0,0 +1,222 @@
+From 70c32958ae4606b93466c2197b07852ebc5627fd Mon Sep 17 00:00:00 2001
+From: Russ Dill <Russ.Dill@ti.com>
+Date: Tue, 17 Sep 2013 05:43:28 -0700
+Subject: [PATCH 05/18] lib: devres: Add exec versions of devm_ioremap_resource
+ and friends
+
+Now that there is an _exec version of ioremap, add devm support for it.
+
+Signed-off-by: Russ Dill <Russ.Dill@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ include/linux/device.h |  19 +++++++-
+ include/linux/io.h     |   5 ++
+ lib/devres.c           | 125 +++++++++++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 145 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/device.h b/include/linux/device.h
+index 6558af9..ad8fbd834 100644
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -636,7 +636,24 @@ extern unsigned long devm_get_free_pages(struct device *dev,
+ 					 gfp_t gfp_mask, unsigned int order);
+ extern void devm_free_pages(struct device *dev, unsigned long addr);
+ 
+-void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
++void __iomem *__devm_ioremap_resource(struct device *dev, struct resource *res,
++				      bool exec);
++static inline void __iomem *devm_ioremap_resource(struct device *dev,
++						  struct resource *res)
++{
++	return __devm_ioremap_resource(dev, res, false);
++}
++void __iomem *devm_request_and_ioremap(struct device *dev,
++				       struct resource *res);
++
++static inline void __iomem *devm_ioremap_exec_resource(struct device *dev,
++						       struct resource *res)
++{
++	return __devm_ioremap_resource(dev, res, true);
++}
++
++void __iomem *devm_request_and_ioremap_exec(struct device *dev,
++					    struct resource *res);
+ 
+ /* allows to add/remove a custom action to devres stack */
+ int devm_add_action(struct device *dev, void (*action)(void *), void *data);
+diff --git a/include/linux/io.h b/include/linux/io.h
+index 986f2bf..b2ac93c 100644
+--- a/include/linux/io.h
++++ b/include/linux/io.h
+@@ -74,6 +74,11 @@ void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
+ 				   resource_size_t size);
+ void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
+ 				   resource_size_t size);
++void __iomem *devm_ioremap_exec(struct device *dev, resource_size_t offset,
++				unsigned long size);
++void __iomem *devm_ioremap_exec_nocache(struct device *dev,
++					resource_size_t offset,
++					unsigned long size);
+ void devm_iounmap(struct device *dev, void __iomem *addr);
+ int check_signature(const volatile void __iomem *io_addr,
+ 			const unsigned char *signature, int length);
+diff --git a/lib/devres.c b/lib/devres.c
+index fbe2aac..5c99964 100644
+--- a/lib/devres.c
++++ b/lib/devres.c
+@@ -100,6 +100,64 @@ void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
+ EXPORT_SYMBOL(devm_ioremap_wc);
+ 
+ /**
++ * devm_ioremap_exec - Managed ioremap_exec()
++ * @dev: Generic device to remap IO address for
++ * @offset: BUS offset to map
++ * @size: Size of map
++ *
++ * Managed ioremap_exec().  Map is automatically unmapped on driver detach.
++ */
++void __iomem *devm_ioremap_exec(struct device *dev, resource_size_t offset,
++				unsigned long size)
++{
++	void __iomem **ptr, *addr;
++
++	ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
++	if (!ptr)
++		return NULL;
++
++	addr = ioremap_exec(offset, size);
++	if (addr) {
++		*ptr = addr;
++		devres_add(dev, ptr);
++	} else
++		devres_free(ptr);
++
++	return addr;
++}
++EXPORT_SYMBOL(devm_ioremap_exec);
++
++/**
++ * devm_ioremap_exec_nocache - Managed ioremap_exec_nocache()
++ * @dev: Generic device to remap IO address for
++ * @offset: BUS offset to map
++ * @size: Size of map
++ *
++ * Managed ioremap_exec_nocache().  Map is automatically unmapped on driver
++ * detach.
++ */
++void __iomem *devm_ioremap_exec_nocache(struct device *dev,
++					resource_size_t offset,
++					unsigned long size)
++{
++	void __iomem **ptr, *addr;
++
++	ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
++	if (!ptr)
++		return NULL;
++
++	addr = ioremap_exec_nocache(offset, size);
++	if (addr) {
++		*ptr = addr;
++		devres_add(dev, ptr);
++	} else
++		devres_free(ptr);
++
++	return addr;
++}
++EXPORT_SYMBOL(devm_ioremap_exec_nocache);
++
++/**
+  * devm_iounmap - Managed iounmap()
+  * @dev: Generic device to unmap for
+  * @addr: Address to unmap
+@@ -132,7 +190,8 @@ EXPORT_SYMBOL(devm_iounmap);
+  *	if (IS_ERR(base))
+  *		return PTR_ERR(base);
+  */
+-void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
++void __iomem *__devm_ioremap_resource(struct device *dev, struct resource *res,
++				      bool exec)
+ {
+ 	resource_size_t size;
+ 	const char *name;
+@@ -153,7 +212,11 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
+ 		return IOMEM_ERR_PTR(-EBUSY);
+ 	}
+ 
+-	if (res->flags & IORESOURCE_CACHEABLE)
++	if (exec && res->flags & IORESOURCE_CACHEABLE)
++		dest_ptr = devm_ioremap_exec(dev, res->start, size);
++	else if (exec)
++		dest_ptr = devm_ioremap_exec_nocache(dev, res->start, size);
++	else if (res->flags & IORESOURCE_CACHEABLE)
+ 		dest_ptr = devm_ioremap(dev, res->start, size);
+ 	else
+ 		dest_ptr = devm_ioremap_nocache(dev, res->start, size);
+@@ -166,7 +229,63 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
+ 
+ 	return dest_ptr;
+ }
+-EXPORT_SYMBOL(devm_ioremap_resource);
++EXPORT_SYMBOL(__devm_ioremap_resource);
++
++/**
++ * devm_request_and_ioremap() - Check, request region, and ioremap resource
++ * @dev: Generic device to handle the resource for
++ * @res: resource to be handled
++ *
++ * Takes all necessary steps to ioremap a mem resource. Uses managed device, so
++ * everything is undone on driver detach. Checks arguments, so you can feed
++ * it the result from e.g. platform_get_resource() directly. Returns the
++ * remapped pointer or NULL on error. Usage example:
++ *
++ *	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ *	base = devm_request_and_ioremap(&pdev->dev, res);
++ *	if (!base)
++ *		return -EADDRNOTAVAIL;
++ */
++void __iomem *devm_request_and_ioremap(struct device *device,
++				       struct resource *res)
++{
++	void __iomem *dest_ptr;
++
++	dest_ptr = devm_ioremap_resource(device, res);
++	if (IS_ERR(dest_ptr))
++		return NULL;
++
++	return dest_ptr;
++}
++EXPORT_SYMBOL(devm_request_and_ioremap);
++
++/**
++ * devm_request_and_ioremap_exec() - Check, request region, and ioremap resource
++ * @dev: Generic device to handle the resource for
++ * @res: resource to be handled
++ *
++ * Takes all necessary steps to ioremap a mem resource. Uses managed device, so
++ * everything is undone on driver detach. Checks arguments, so you can feed
++ * it the result from e.g. platform_get_resource() directly. Returns the
++ * remapped pointer or NULL on error. Usage example:
++ *
++ *	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ *	base = devm_request_and_ioremap_exec(&pdev->dev, res);
++ *	if (!base)
++ *		return -EADDRNOTAVAIL;
++ */
++void __iomem *devm_request_and_ioremap_exec(struct device *device,
++					    struct resource *res)
++{
++	void __iomem *dest_ptr;
++
++	dest_ptr = devm_ioremap_exec_resource(device, res);
++	if (IS_ERR(dest_ptr))
++		return NULL;
++
++	return dest_ptr;
++}
++EXPORT_SYMBOL(devm_request_and_ioremap_exec);
+ 
+ #ifdef CONFIG_HAS_IOPORT_MAP
+ /*
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0006-misc-SRAM-Add-option-to-map-SRAM-to-allow-code-execu.patch b/patches/beaglebone/suspend/0006-misc-SRAM-Add-option-to-map-SRAM-to-allow-code-execu.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ba6903c9d4dbfe5f4bb513e8bd889df47b89465c
--- /dev/null
+++ b/patches/beaglebone/suspend/0006-misc-SRAM-Add-option-to-map-SRAM-to-allow-code-execu.patch
@@ -0,0 +1,97 @@
+From 1d24a05836618bc5817e41d3c8f115f2f61c1fb6 Mon Sep 17 00:00:00 2001
+From: Russ Dill <Russ.Dill@ti.com>
+Date: Tue, 17 Sep 2013 05:43:29 -0700
+Subject: [PATCH 06/18] misc: SRAM: Add option to map SRAM to allow code
+ execution
+
+Allow option for mapping SRAM as executable. This is useful for
+platforms using the sram driver that need to run PM code from sram
+like several ARM platforms.
+
+Signed-off-by: Russ Dill <Russ.Dill@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ Documentation/devicetree/bindings/misc/sram.txt |  1 +
+ drivers/misc/sram.c                             | 13 ++++++++++++-
+ include/linux/platform_data/sram.h              |  8 ++++++++
+ 3 files changed, 21 insertions(+), 1 deletion(-)
+ create mode 100644 include/linux/platform_data/sram.h
+
+diff --git a/Documentation/devicetree/bindings/misc/sram.txt b/Documentation/devicetree/bindings/misc/sram.txt
+index 36cbe5a..c5ecde4 100644
+--- a/Documentation/devicetree/bindings/misc/sram.txt
++++ b/Documentation/devicetree/bindings/misc/sram.txt
+@@ -33,6 +33,7 @@ Optional properties in the area nodes:
+ 
+ - compatible : standard definition, should contain a vendor specific string
+                in the form <vendor>,[<device>-]<usage>
++- map-exec :   Map range to allow code execution
+ 
+ Example:
+ 
+diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
+index eeaaf5f..014552d 100644
+--- a/drivers/misc/sram.c
++++ b/drivers/misc/sram.c
+@@ -31,6 +31,7 @@
+ #include <linux/slab.h>
+ #include <linux/spinlock.h>
+ #include <linux/genalloc.h>
++#include <linux/platform_data/sram.h>
+ 
+ #define SRAM_GRANULARITY	32
+ 
+@@ -56,6 +57,7 @@ static int sram_reserve_cmp(void *priv, struct list_head *a,
+ 
+ static int sram_probe(struct platform_device *pdev)
+ {
++	struct sram_platform_data *pdata = pdev->dev.platform_data;
+ 	void __iomem *virt_base;
+ 	struct sram_dev *sram;
+ 	struct resource *res;
+@@ -64,10 +66,16 @@ static int sram_probe(struct platform_device *pdev)
+ 	struct sram_reserve *rblocks, *block;
+ 	struct list_head reserve_list;
+ 	unsigned int nblocks;
++	bool map_exec = false;
+ 	int ret;
+ 
+ 	INIT_LIST_HEAD(&reserve_list);
+ 
++	if (of_get_property(pdev->dev.of_node, "map-exec", NULL))
++		map_exec = true;
++	if (pdata && pdata->map_exec)
++		map_exec |= true;
++
+ 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 	if (!res) {
+ 		dev_err(&pdev->dev, "found no memory resource\n");
+@@ -82,7 +90,10 @@ static int sram_probe(struct platform_device *pdev)
+ 		return -EBUSY;
+ 	}
+ 
+-	virt_base = devm_ioremap_wc(&pdev->dev, res->start, size);
++	if (map_exec)
++		virt_base = devm_ioremap_exec_resource(&pdev->dev, res);
++	else
++		virt_base = devm_ioremap_wc(&pdev->dev, res->start, size);
+ 	if (IS_ERR(virt_base))
+ 		return PTR_ERR(virt_base);
+ 
+diff --git a/include/linux/platform_data/sram.h b/include/linux/platform_data/sram.h
+new file mode 100644
+index 0000000..8f5c4ba
+--- /dev/null
++++ b/include/linux/platform_data/sram.h
+@@ -0,0 +1,8 @@
++#ifndef _LINUX_SRAM_H
++#define _LINUX_SRAM_H
++
++struct sram_platform_data {
++	bool map_exec;
++};
++
++#endif
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0007-Documentation-dt-add-bindings-for-TI-Wakeup-M3-IPC-d.patch b/patches/beaglebone/suspend/0007-Documentation-dt-add-bindings-for-TI-Wakeup-M3-IPC-d.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1b1fe4d9756ac2fd98dcc1d09702a8182bd9efc0
--- /dev/null
+++ b/patches/beaglebone/suspend/0007-Documentation-dt-add-bindings-for-TI-Wakeup-M3-IPC-d.patch
@@ -0,0 +1,85 @@
+From 2e3ad947a20189db7aa4f938c48f6c45bd4d0070 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Wed, 5 Nov 2014 14:04:59 -0600
+Subject: [PATCH 07/18] Documentation: dt: add bindings for TI Wakeup M3 IPC
+ device
+
+Add the device tree bindings document for the TI Wakeup M3 IPC
+device on AM33xx and AM43xx SoCs. These devices are used by the
+TI wkup_m3_ipc driver, and contain the registers upon which the
+IPC protocol to communicate with the Wakeup M3 processor is
+implemented.
+
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+Signed-off-by: Suman Anna <s-anna@ti.com>
+---
+ .../devicetree/bindings/soc/ti/wkup_m3_ipc.txt     | 57 ++++++++++++++++++++++
+ 1 file changed, 57 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt
+
+diff --git a/Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt b/Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt
+new file mode 100644
+index 0000000..4015504
+--- /dev/null
++++ b/Documentation/devicetree/bindings/soc/ti/wkup_m3_ipc.txt
+@@ -0,0 +1,57 @@
++Wakeup M3 IPC Driver
++=====================
++
++The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor
++(commonly referred to as Wakeup M3 or CM3) to help with various low power tasks
++that cannot be controlled from the MPU, like suspend/resume and certain deep
++C-states for CPU Idle. Once the wkup_m3_ipc driver uses the wkup_m3_rproc driver
++to boot the wkup_m3, it handles communication with the CM3 using IPC registers
++present in the SoC's control module and a mailbox. The wkup_m3_ipc exposes an
++API to allow the SoC PM code to execute specific PM tasks.
++
++Wkup M3 Device Node:
++====================
++A wkup_m3_ipc device node is used to represent the IPC registers within an
++SoC.
++
++Required properties:
++--------------------
++- compatible:		Should be,
++				"ti,am3352-wkup-m3-ipc" for AM33xx SoCs
++				"ti,am4372-wkup-m3-ipc" for AM43xx SoCs
++- reg:			Contains the IPC register address space to communicate
++			with the Wakeup M3 processor
++- interrupts:		Contains the interrupt information for the wkup_m3
++			interrupt that signals the MPU.
++- ti,rproc:		phandle to the wkup_m3 rproc node so the IPC driver
++			can boot it.
++- mboxes:		phandles used by IPC framework to get correct mbox
++			channel for communication. Must point to appropriate
++			mbox_wkupm3 child node.
++
++Example:
++--------
++/* AM33xx */
++	l4_wkup: l4_wkup@44c00000 {
++		...
++
++		scm: scm@210000 {
++			compatible = "ti,am3-scm", "simple-bus";
++			reg = <0x210000 0x2000>;
++			#address-cells = <1>;
++			#size-cells = <1>;
++			ranges = <0 0x210000 0x2000>;
++
++			...
++
++			wkup_m3_ipc: wkup_m3_ipc@1324 {
++				compatible = "ti,am3352-wkup-m3-ipc";
++				reg = <0x1324 0x24>;
++				interrupts = <78>;
++				ti,rproc = <&wkup_m3>;
++				mboxes = <&mailbox &mbox_wkupm3>;
++			};
++
++			...
++		};
++	};
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0008-soc-ti-Add-wkup_m3_ipc-driver.patch b/patches/beaglebone/suspend/0008-soc-ti-Add-wkup_m3_ipc-driver.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e51b25388024316def98d89004c9498c86eca711
--- /dev/null
+++ b/patches/beaglebone/suspend/0008-soc-ti-Add-wkup_m3_ipc-driver.patch
@@ -0,0 +1,576 @@
+From bfca30623c232d92f0a335bf03509309aceb4ccf Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Tue, 25 Mar 2014 09:59:16 -0500
+Subject: [PATCH 08/18] soc: ti: Add wkup_m3_ipc driver
+
+Introduce a wkup_m3_ipc driver to handle communication between the MPU
+and Cortex M3 wkup_m3 present on am335x.
+
+This driver is responsible for actually booting the wkup_m3_rproc and
+also handling all IPC which is done using the IPC registers in the control
+module, a mailbox, and a separate interrupt back from the wkup_m3. A small
+API is exposed for executing specific power commands, which include
+configuring for low power mode, request a transition to a low power mode,
+and status info on a previous transition.
+
+Also in this patch add platform data structures to be used to pass required
+wkup_m3 APIs to platform code as that must remain built in at this time
+which this driver supports loading as a module.
+
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ drivers/soc/ti/Kconfig                    |  10 +
+ drivers/soc/ti/Makefile                   |   1 +
+ drivers/soc/ti/wkup_m3_ipc.c              | 476 ++++++++++++++++++++++++++++++
+ include/linux/platform_data/wkup_m3_ipc.h |  28 ++
+ 4 files changed, 515 insertions(+)
+ create mode 100644 drivers/soc/ti/wkup_m3_ipc.c
+ create mode 100644 include/linux/platform_data/wkup_m3_ipc.h
+
+diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
+index 7266b21..b3b8dcf 100644
+--- a/drivers/soc/ti/Kconfig
++++ b/drivers/soc/ti/Kconfig
+@@ -28,4 +28,14 @@ config KEYSTONE_NAVIGATOR_DMA
+ 
+ 	  If unsure, say N.
+ 
++config WKUP_M3_IPC
++	tristate "TI AM33XX Wkup-M3 IPC Driver"
++	depends on WKUP_M3_RPROC
++	depends on OMAP2PLUS_MBOX
++	help
++	  TI AM33XX has a Cortex M3 to handle low power transitions. This IPC
++	  driver provides the necessary API to communicate and use the wkup m3
++	  for PM features like Suspend/Resume and boots the wkup_m3 using
++	  wkup_m3_rproc driver.
++
+ endif # SOC_TI
+diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
+index 135bdad..48ff3a7 100644
+--- a/drivers/soc/ti/Makefile
++++ b/drivers/soc/ti/Makefile
+@@ -4,3 +4,4 @@
+ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS)	+= knav_qmss.o
+ knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
+ obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)	+= knav_dma.o
++obj-$(CONFIG_WKUP_M3_IPC)		+= wkup_m3_ipc.o
+diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c
+new file mode 100644
+index 0000000..1ecce43
+--- /dev/null
++++ b/drivers/soc/ti/wkup_m3_ipc.c
+@@ -0,0 +1,476 @@
++/*
++ * AMx3 Wkup M3 IPC driver
++ *
++ * Copyright (C) 2015 Texas Instruments, Inc.
++ *
++ * Dave Gerlach <d-gerlach@ti.com>
++ *
++ * 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.
++ */
++
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/kthread.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/mailbox_client.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/omap-mailbox.h>
++#include <linux/platform_device.h>
++#include <linux/remoteproc.h>
++#include <linux/suspend.h>
++#include <linux/platform_data/wkup_m3_ipc.h>
++
++#define AM33XX_CTRL_IPC_REG_COUNT	0x8
++#define AM33XX_CTRL_IPC_REG_OFFSET(m)	(0x4 + 4 * (m))
++
++/* AM33XX M3_TXEV_EOI register */
++#define AM33XX_CONTROL_M3_TXEV_EOI	0x00
++
++#define AM33XX_M3_TXEV_ACK		(0x1 << 0)
++#define AM33XX_M3_TXEV_ENABLE		(0x0 << 0)
++
++#define IPC_CMD_DS0			0x4
++#define IPC_CMD_STANDBY			0xc
++#define IPC_CMD_RESET			0xe
++#define DS_IPC_DEFAULT			0xffffffff
++#define M3_VERSION_UNKNOWN		0x0000ffff
++#define M3_BASELINE_VERSION		0x187
++#define M3_STATUS_RESP_MASK		(0xffff << 16)
++#define M3_FW_VERSION_MASK		0xffff
++
++#define M3_STATE_UNKNOWN		0
++#define M3_STATE_RESET			1
++#define M3_STATE_INITED			2
++#define M3_STATE_MSG_FOR_LP		3
++#define M3_STATE_MSG_FOR_RESET		4
++
++struct wkup_m3_ipc {
++	struct rproc *rproc;
++
++	void __iomem *ipc_mem_base;
++	struct device *dev;
++
++	int mem_type;
++	unsigned long resume_addr;
++	int state;
++
++	struct completion sync_complete;
++	struct mbox_client mbox_client;
++	struct mbox_chan *mbox;
++};
++
++static struct wkup_m3_ipc m3_ipc_state;
++
++static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc)
++{
++	writel(AM33XX_M3_TXEV_ACK,
++	       m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI);
++}
++
++static void am33xx_txev_enable(struct wkup_m3_ipc *m3_ipc)
++{
++	writel(AM33XX_M3_TXEV_ENABLE,
++	       m3_ipc->ipc_mem_base + AM33XX_CONTROL_M3_TXEV_EOI);
++}
++
++static void wkup_m3_ctrl_ipc_write(struct wkup_m3_ipc *m3_ipc,
++				   u32 val, int ipc_reg_num)
++{
++	if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT,
++		 "ipc register operation out of range"))
++		return;
++
++	writel(val, m3_ipc->ipc_mem_base +
++	       AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num));
++}
++
++static unsigned int wkup_m3_ctrl_ipc_read(struct wkup_m3_ipc *m3_ipc,
++					  int ipc_reg_num)
++{
++	if (WARN(ipc_reg_num < 0 || ipc_reg_num > AM33XX_CTRL_IPC_REG_COUNT,
++		 "ipc register operation out of range"))
++		return 0;
++
++	return readl(m3_ipc->ipc_mem_base +
++		     AM33XX_CTRL_IPC_REG_OFFSET(ipc_reg_num));
++}
++
++static int wkup_m3_fw_version_read(struct wkup_m3_ipc *m3_ipc)
++{
++	int val;
++
++	val = wkup_m3_ctrl_ipc_read(m3_ipc, 2);
++
++	return val & M3_FW_VERSION_MASK;
++}
++
++static irqreturn_t wkup_m3_txev_handler(int irq, void *ipc_data)
++{
++	struct wkup_m3_ipc *m3_ipc = ipc_data;
++	struct device *dev = m3_ipc->dev;
++	int ver = 0;
++
++	am33xx_txev_eoi(m3_ipc);
++
++	switch (m3_ipc->state) {
++	case M3_STATE_RESET:
++		ver = wkup_m3_fw_version_read(m3_ipc);
++
++		if (ver == M3_VERSION_UNKNOWN ||
++		    ver < M3_BASELINE_VERSION) {
++			dev_warn(dev, "CM3 Firmware Version %x not supported\n",
++				 ver);
++		} else {
++			dev_info(dev, "CM3 Firmware Version = 0x%x\n", ver);
++		}
++
++		m3_ipc->state = M3_STATE_INITED;
++		complete(&m3_ipc->sync_complete);
++		break;
++	case M3_STATE_MSG_FOR_RESET:
++		m3_ipc->state = M3_STATE_INITED;
++		complete(&m3_ipc->sync_complete);
++		break;
++	case M3_STATE_MSG_FOR_LP:
++		complete(&m3_ipc->sync_complete);
++		break;
++	case M3_STATE_UNKNOWN:
++		dev_warn(dev, "Unknown CM3 State\n");
++	}
++
++	am33xx_txev_enable(m3_ipc);
++
++	return IRQ_HANDLED;
++}
++
++static void wkup_m3_mbox_callback(struct mbox_client *client, void *data)
++{
++	struct wkup_m3_ipc *m3_ipc = container_of(client, struct wkup_m3_ipc,
++						  mbox_client);
++
++	omap_mbox_disable_irq(m3_ipc->mbox, IRQ_RX);
++}
++
++static int wkup_m3_ping(struct wkup_m3_ipc *m3_ipc)
++{
++	struct device *dev = m3_ipc->dev;
++	mbox_msg_t dummy_msg = 0;
++	int ret;
++
++	if (!m3_ipc->mbox) {
++		dev_err(dev,
++			"No IPC channel to communicate with wkup_m3!\n");
++		return -EIO;
++	}
++
++	/*
++	 * Write a dummy message to the mailbox in order to trigger the RX
++	 * interrupt to alert the M3 that data is available in the IPC
++	 * registers. We must enable the IRQ here and disable it after in
++	 * the RX callback to avoid multiple interrupts being received
++	 * by the CM3.
++	 */
++	omap_mbox_enable_irq(m3_ipc->mbox, IRQ_RX);
++	ret = mbox_send_message(m3_ipc->mbox, &dummy_msg);
++	if (ret < 0) {
++		dev_err(dev, "%s: mbox_send_message() failed: %d\n",
++			__func__, ret);
++		return ret;
++	}
++
++	ret = wait_for_completion_timeout(&m3_ipc->sync_complete,
++					  msecs_to_jiffies(500));
++	if (!ret) {
++		dev_err(dev, "MPU<->CM3 sync failure\n");
++		m3_ipc->state = M3_STATE_UNKNOWN;
++		return -EIO;
++	}
++
++	return 0;
++}
++
++static int wkup_m3_is_available(struct wkup_m3_ipc *m3_ipc)
++{
++	return (m3_ipc->state != M3_STATE_RESET);
++}
++
++/* Public functions */
++/**
++ * wkup_m3_set_mem_type - Pass wkup_m3 which type of memory is in use
++ * @mem_type: memory type value read directly from emif
++ *
++ * wkup_m3 must know what memory type is in use to properly suspend
++ * and resume.
++ */
++void wkup_m3_set_mem_type(int mem_type)
++{
++	m3_ipc_state.mem_type = mem_type;
++}
++
++/**
++ * wkup_m3_set_resume_address - Pass wkup_m3 resume address
++ * @addr: Physical address from which resume code should execute
++ */
++void wkup_m3_set_resume_address(void *addr)
++{
++	m3_ipc_state.resume_addr = (unsigned long)addr;
++}
++
++/**
++ * wkup_m3_set_resume_address - Retrieve wkup_m3 status code after suspend
++ *
++ * Returns code representing the status of a low power mode transition.
++ *	0 - Successful transition
++ *	1 - Failure to transition to low power state
++ */
++int wkup_m3_request_pm_status(void)
++{
++	struct wkup_m3_ipc *m3_ipc = &m3_ipc_state;
++	unsigned int i;
++	int val;
++
++	val = wkup_m3_ctrl_ipc_read(m3_ipc, 1);
++
++	i = M3_STATUS_RESP_MASK & val;
++	i >>= __ffs(M3_STATUS_RESP_MASK);
++
++	return i;
++}
++
++/**
++ * wkup_m3_prepare_low_power - Request preparation for transition to
++ *			       low power state
++ * @state: A kernel suspend state to enter, either MEM or STANDBY
++ *
++ * Returns 0 if preparation was successful, otherwise returns error code
++ */
++int wkup_m3_prepare_low_power(int state)
++{
++	struct wkup_m3_ipc *m3_ipc = &m3_ipc_state;
++	struct device *dev = m3_ipc_state.dev;
++	int m3_power_state;
++	int ret = 0;
++
++	if (!wkup_m3_is_available(m3_ipc)) {
++		dev_err(dev, "wkup_m3 not available. DeepSleep entry not possible.\n");
++		return -ENODEV;
++	}
++
++	switch (state) {
++	case PM_SUSPEND_MEM:
++		m3_power_state = IPC_CMD_DS0;
++		break;
++	default:
++		return 1;
++	}
++
++	/* Program each required IPC register then write defaults to others */
++	wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc_state.resume_addr, 0);
++	wkup_m3_ctrl_ipc_write(m3_ipc, m3_power_state, 1);
++	wkup_m3_ctrl_ipc_write(m3_ipc, m3_ipc_state.mem_type, 4);
++
++	wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2);
++	wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 3);
++	wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 5);
++	wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 6);
++	wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 7);
++
++	m3_ipc->state = M3_STATE_MSG_FOR_LP;
++
++	ret = wkup_m3_ping(m3_ipc);
++	if (ret) {
++		dev_err(dev, "Unable to ping CM3\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++/**
++ * wkup_m3_finish_low_power - Return m3 to reset state
++ *
++ * Returns 0 if reset was successful, otherwise returns error code
++ */
++int wkup_m3_finish_low_power(void)
++{
++	struct wkup_m3_ipc *m3_ipc = &m3_ipc_state;
++	struct device *dev = m3_ipc_state.dev;
++	int ret = 0;
++
++	if (!wkup_m3_is_available(m3_ipc))
++		return -ENODEV;
++
++	wkup_m3_ctrl_ipc_write(m3_ipc, IPC_CMD_RESET, 1);
++	wkup_m3_ctrl_ipc_write(m3_ipc, DS_IPC_DEFAULT, 2);
++
++	m3_ipc->state = M3_STATE_MSG_FOR_RESET;
++
++	ret = wkup_m3_ping(m3_ipc);
++	if (ret) {
++		dev_err(dev, "Unable to ping CM3\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static struct wkup_m3_pm_ipc_ops pm_ipc_ops = {
++	.set_mem_type = wkup_m3_set_mem_type,
++	.set_resume_address = wkup_m3_set_resume_address,
++	.prepare_low_power = wkup_m3_prepare_low_power,
++	.finish_low_power = wkup_m3_finish_low_power,
++	.request_pm_status = wkup_m3_request_pm_status,
++};
++
++static void wkup_m3_rproc_boot_thread(struct rproc *rproc)
++{
++	struct device *dev = &rproc->dev;
++	int ret;
++
++	wait_for_completion(&rproc->firmware_loading_complete);
++
++	init_completion(&m3_ipc_state.sync_complete);
++
++	ret = rproc_boot(rproc);
++	if (ret)
++		dev_err(dev, "rproc_boot failed\n");
++
++	do_exit(0);
++}
++
++static int wkup_m3_ipc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	int irq, ret;
++	uint32_t rproc_phandle;
++	struct rproc *m3_rproc;
++	struct resource *res;
++	struct task_struct *task;
++	struct wkup_m3_ipc_data *pdata = dev->platform_data;
++
++	if (!(pdata && pdata->set_pm_ipc_ops)) {
++		dev_err(dev, "Platform data missing!\n");
++		return -ENODEV;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	m3_ipc_state.ipc_mem_base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(m3_ipc_state.ipc_mem_base)) {
++		dev_err(dev, "could not ioremap ipc_mem\n");
++		ret = PTR_ERR(m3_ipc_state.ipc_mem_base);
++		return ret;
++	}
++
++	irq = platform_get_irq(pdev, 0);
++	if (!irq) {
++		dev_err(&pdev->dev, "no irq resource\n");
++		ret = -ENXIO;
++		return ret;
++	}
++
++	ret = devm_request_irq(dev, irq, wkup_m3_txev_handler,
++			       0, "wkup_m3_txev", &m3_ipc_state);
++	if (ret) {
++		dev_err(dev, "request_irq failed\n");
++		return ret;
++	}
++
++	m3_ipc_state.mbox_client.dev = dev;
++	m3_ipc_state.mbox_client.tx_done = NULL;
++	m3_ipc_state.mbox_client.rx_callback = wkup_m3_mbox_callback;
++	m3_ipc_state.mbox_client.tx_block = false;
++	m3_ipc_state.mbox_client.knows_txdone = false;
++
++	m3_ipc_state.mbox = mbox_request_channel(&m3_ipc_state.mbox_client, 0);
++	if (IS_ERR(m3_ipc_state.mbox)) {
++		dev_err(dev, "IPC Request for A8->M3 Channel failed! %ld\n",
++			PTR_ERR(m3_ipc_state.mbox));
++		ret = PTR_ERR(m3_ipc_state.mbox);
++		m3_ipc_state.mbox = NULL;
++		return ret;
++	}
++
++	if (of_property_read_u32(dev->of_node, "ti,rproc", &rproc_phandle)) {
++		dev_err(&pdev->dev, "could not get rproc phandle\n");
++		ret = -ENODEV;
++		goto err;
++	}
++
++	m3_rproc = rproc_get_by_phandle(rproc_phandle);
++	if (!m3_rproc) {
++		dev_err(&pdev->dev, "could not get rproc handle\n");
++		ret = -EPROBE_DEFER;
++		goto err;
++	}
++
++	m3_ipc_state.rproc = m3_rproc;
++	m3_ipc_state.dev = dev;
++	m3_ipc_state.state = M3_STATE_RESET;
++
++	/*
++	 * Wait for firmware loading completion in a thread so we
++	 * can boot the wkup_m3 as soon as it's ready without holding
++	 * up kernel boot
++	 */
++	task = kthread_run((void *)wkup_m3_rproc_boot_thread, m3_rproc,
++			   "wkup_m3_rproc_loader");
++
++	if (IS_ERR(task)) {
++		dev_err(dev, "can't create rproc_boot thread\n");
++		goto err_put_rproc;
++	}
++
++	pdata->set_pm_ipc_ops(&pm_ipc_ops);
++
++	return 0;
++
++err_put_rproc:
++	rproc_put(m3_rproc);
++err:
++	mbox_free_channel(m3_ipc_state.mbox);
++	return ret;
++}
++
++static int wkup_m3_ipc_remove(struct platform_device *pdev)
++{
++	struct wkup_m3_ipc_data *pdata = pdev->dev.platform_data;
++
++	pdata->set_pm_ipc_ops(NULL);
++
++	mbox_free_channel(m3_ipc_state.mbox);
++
++	rproc_shutdown(m3_ipc_state.rproc);
++	rproc_put(m3_ipc_state.rproc);
++
++	return 0;
++}
++
++static const struct of_device_id wkup_m3_ipc_of_match[] = {
++	{ .compatible = "ti,am3352-wkup-m3-ipc", },
++	{ .compatible = "ti,am4372-wkup-m3-ipc", },
++	{},
++};
++
++static struct platform_driver wkup_m3_ipc_driver = {
++	.probe = wkup_m3_ipc_probe,
++	.remove = wkup_m3_ipc_remove,
++	.driver = {
++		.name = "wkup_m3_ipc",
++		.of_match_table = wkup_m3_ipc_of_match,
++	},
++};
++
++module_platform_driver(wkup_m3_ipc_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("wkup m3 remote processor ipc driver");
++MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
+diff --git a/include/linux/platform_data/wkup_m3_ipc.h b/include/linux/platform_data/wkup_m3_ipc.h
+new file mode 100644
+index 0000000..99963a8
+--- /dev/null
++++ b/include/linux/platform_data/wkup_m3_ipc.h
+@@ -0,0 +1,28 @@
++/*
++ * omap wkup_m3_ipc: platform data
++ *
++ * Copyright (C) 2015 Texas Instruments, Inc.
++ *
++ * Dave Gerlach <d-gerlach@ti.com>
++ *
++ * 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.
++ */
++
++#ifndef _LINUX_PLATFORM_DATA_WKUP_M3_IPC_H
++#define _LINUX_PLATFORM_DATA_WKUP_M3_IPC_H
++
++struct wkup_m3_pm_ipc_ops {
++	void (*set_mem_type)(int mem_type);
++	void (*set_resume_address)(void *addr);
++	int (*prepare_low_power)(int state);
++	int (*finish_low_power)(void);
++	int (*request_pm_status)(void);
++};
++
++struct wkup_m3_ipc_data {
++	void (*set_pm_ipc_ops)(struct wkup_m3_pm_ipc_ops *ops);
++};
++
++#endif /* _LINUX_PLATFORM_DATA_WKUP_M3_IPC_H */
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0009-ARM-dts-AM33xx-Add-the-wkup_m3_ipc-node.patch b/patches/beaglebone/suspend/0009-ARM-dts-AM33xx-Add-the-wkup_m3_ipc-node.patch
new file mode 100644
index 0000000000000000000000000000000000000000..aaf8739464663bed8466446813db17ef1c466b8f
--- /dev/null
+++ b/patches/beaglebone/suspend/0009-ARM-dts-AM33xx-Add-the-wkup_m3_ipc-node.patch
@@ -0,0 +1,37 @@
+From 41baa60468afd8ba8126525347a007818c84ce94 Mon Sep 17 00:00:00 2001
+From: Suman Anna <s-anna@ti.com>
+Date: Mon, 23 Mar 2015 22:25:18 -0600
+Subject: [PATCH 09/18] ARM: dts: AM33xx: Add the wkup_m3_ipc node
+
+Add the Wakeup M3 IPC node for the wkup_m3_ipc driver on AM33xx SoCs.
+This node uses the IPC registers, part of the Control Module, and is
+therefore added as a child of the scm node.
+
+Signed-off-by: Suman Anna <s-anna@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/boot/dts/am33xx.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
+index b31783f..501017e 100644
+--- a/arch/arm/boot/dts/am33xx.dtsi
++++ b/arch/arm/boot/dts/am33xx.dtsi
+@@ -153,6 +153,14 @@
+ 					};
+ 				};
+ 
++				wkup_m3_ipc: wkup_m3_ipc@1324 {
++					compatible = "ti,am3352-wkup-m3-ipc";
++					reg = <0x1324 0x24>;
++					interrupts = <78>;
++					ti,rproc = <&wkup_m3>;
++					mboxes = <&mailbox &mbox_wkupm3>;
++				};
++
+ 				scm_clockdomains: clockdomains {
+ 				};
+ 			};
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0010-ARM-dts-AM4372-Add-the-wkup_m3_ipc-node.patch b/patches/beaglebone/suspend/0010-ARM-dts-AM4372-Add-the-wkup_m3_ipc-node.patch
new file mode 100644
index 0000000000000000000000000000000000000000..128cb823629bb66b097230d4b27ac4a194149780
--- /dev/null
+++ b/patches/beaglebone/suspend/0010-ARM-dts-AM4372-Add-the-wkup_m3_ipc-node.patch
@@ -0,0 +1,37 @@
+From 7dee8940dd35b66872a84873882a995725a57994 Mon Sep 17 00:00:00 2001
+From: Suman Anna <s-anna@ti.com>
+Date: Wed, 18 Mar 2015 12:51:07 -0500
+Subject: [PATCH 10/18] ARM: dts: AM4372: Add the wkup_m3_ipc node
+
+Add the Wakeup M3 IPC device node for the wkup_m3_ipc driver on
+AM4372 SoC. This node uses the IPC registers, part of the Control
+Module, and is therefore added as a child of the scm node.
+
+Signed-off-by: Suman Anna <s-anna@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/boot/dts/am4372.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
+index 136d1af..e72bff9 100644
+--- a/arch/arm/boot/dts/am4372.dtsi
++++ b/arch/arm/boot/dts/am4372.dtsi
+@@ -136,6 +136,14 @@
+ 					};
+ 				};
+ 
++				wkup_m3_ipc: wkup_m3_ipc@1324 {
++					compatible = "ti,am4372-wkup-m3-ipc";
++					reg = <0x1324 0x44>;
++					interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
++					ti,rproc = <&wkup_m3>;
++					mboxes = <&mailbox &mbox_wkupm3>;
++				};
++
+ 				scm_clockdomains: clockdomains {
+ 				};
+ 			};
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0011-Documentation-dt-add-ti-am3352-emif-bindings.patch b/patches/beaglebone/suspend/0011-Documentation-dt-add-ti-am3352-emif-bindings.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e5643224e27220917870024903b9f4b567c804ff
--- /dev/null
+++ b/patches/beaglebone/suspend/0011-Documentation-dt-add-ti-am3352-emif-bindings.patch
@@ -0,0 +1,53 @@
+From 1b318c4cd4c2c51e05dd39dfe91b3886f6be23c7 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Mon, 17 Nov 2014 20:12:42 -0600
+Subject: [PATCH 11/18] Documentation: dt: add ti,am3352-emif bindings
+
+Add the device tree bindings document for ti,am3352-emif which
+is used by the ti-emif-sram driver to provide low-level PM
+functionality.
+---
+ .../bindings/memory-controllers/ti/emif-sram.txt   | 31 ++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti/emif-sram.txt
+
+diff --git a/Documentation/devicetree/bindings/memory-controllers/ti/emif-sram.txt b/Documentation/devicetree/bindings/memory-controllers/ti/emif-sram.txt
+new file mode 100644
+index 0000000..72d6db0
+--- /dev/null
++++ b/Documentation/devicetree/bindings/memory-controllers/ti/emif-sram.txt
+@@ -0,0 +1,31 @@
++EMIF SRAM Driver
++=====================
++
++TI AMx3 family of devices use a similar EMIF to other TI SoCs but have
++different PM requirements. Late suspend code runs from SRAM and requires
++save and restore of EMIF context and placing the SDRAM in and out of
++self-refresh. Because of this, the ti-emif-sram driver introduces
++relocatable PM function that can run from SRAM and place the EMIF in
++the proper state for low-power mode transition.
++
++EMIF Device Node:
++====================
++A emif node is used to represent an EMIF IP instance within an SoC. The node
++must contain a phandle to an sram node so the ti-emif-sram driver can allocate
++space within the sram and copy the relocatable PM functions.
++
++Required properties:
++--------------------
++- compatible:		Should be "ti,am3352-emif" for AM33xx SoCs
++- reg:			Contains the emif register address ranges.
++- sram:			Phandle for generic sram node for the driver
++			to use to copy PM functions to.
++
++Example:
++--------
++/* AM33xx */
++emif: emif@4c000000 {
++	compatible = "ti,am3352-emif";
++	reg =	<0x4C000000 0x1000>;
++	sram = <&ocmcram>;
++};
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0012-memory-ti-emif-sram-introduce-relocatable-suspend-re.patch b/patches/beaglebone/suspend/0012-memory-ti-emif-sram-introduce-relocatable-suspend-re.patch
new file mode 100644
index 0000000000000000000000000000000000000000..95408c8836e2421b6f1b5b4b2b0050380410b79f
--- /dev/null
+++ b/patches/beaglebone/suspend/0012-memory-ti-emif-sram-introduce-relocatable-suspend-re.patch
@@ -0,0 +1,562 @@
+From 6ab807a520d0eb74ba00a5a0ab849a18b934f88f Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Fri, 7 Nov 2014 14:19:15 -0600
+Subject: [PATCH 12/18] memory: ti-emif-sram: introduce relocatable
+ suspend/resume handlers
+
+Certain SoCs like Texas Instruments AM335x and AM437x require parts
+of the EMIF PM code to run late in the suspend sequence from SRAM,
+such as saving and restoring the EMIF context and placing the memory
+into self-refresh.
+
+One requirement for these SoC's to suspend and enter it's lowest power
+mode, called DeepSleep0, is that the PER power domain must be shut
+off. Because the EMIF (DDR Controller) resides within this power
+domain, it will lose context during a suspend operation, so we must
+save it to restore once we resume. However, we cannot execute this
+code from external memory, as it is not available at this point, so
+the code must be executed late in the suspend path from SRAM.
+
+This patch introduces a ti-emif-sram driver that includes several
+functions written in ARM ASM that are relocatable so the PM SRAM
+code can use them. It can export a table containing the absolute
+addresses of the available PM functions so that other SRAM code
+can branch to them. This code is required for suspend/resume on
+AM335x and AM437x to work.
+---
+ drivers/memory/Kconfig           |  10 ++
+ drivers/memory/Makefile          |   3 +
+ drivers/memory/emif.h            |   8 ++
+ drivers/memory/ti-emif-sram-pm.S | 233 +++++++++++++++++++++++++++++++++++++++
+ drivers/memory/ti-emif-sram.c    | 195 ++++++++++++++++++++++++++++++++
+ include/linux/ti-emif-sram.h     |  26 +++++
+ 6 files changed, 475 insertions(+)
+ create mode 100644 drivers/memory/ti-emif-sram-pm.S
+ create mode 100644 drivers/memory/ti-emif-sram.c
+ create mode 100644 include/linux/ti-emif-sram.h
+
+diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
+index 868036f..bb06346 100644
+--- a/drivers/memory/Kconfig
++++ b/drivers/memory/Kconfig
+@@ -49,6 +49,16 @@ config OMAP_GPMC
+ 	  interfacing to a variety of asynchronous as well as synchronous
+ 	  memory drives like NOR, NAND, OneNAND, SRAM.
+ 
++config TI_EMIF_SRAM
++	bool "Texas Instruments EMIF SRAM driver"
++	depends on SOC_AM33XX
++	help
++	  This driver is for the EMIF module available on Texas Instruments
++	  AM33XX SoCs and is required for PM. Certain parts of the EMIF PM
++	  code must run from on-chip SRAM late in the suspend sequence so
++	  this driver provides several relocatable PM functions for the SoC
++	  PM code to use.
++
+ config MVEBU_DEVBUS
+ 	bool "Marvell EBU Device Bus Controller"
+ 	default y
+diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
+index b670441..132cdc4 100644
+--- a/drivers/memory/Makefile
++++ b/drivers/memory/Makefile
+@@ -16,3 +16,6 @@ obj-$(CONFIG_TEGRA20_MC)	+= tegra20-mc.o
+ obj-$(CONFIG_JZ4780_NEMC)	+= jz4780-nemc.o
+ 
+ obj-$(CONFIG_TEGRA_MC)		+= tegra/
++obj-$(CONFIG_TI_EMIF_SRAM)	+= ti-emif-sram.o ti-emif-sram-pm.o
++
++AFLAGS_ti-emif-sram-pm.o	:=-Wa,-march=armv7-a
+diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
+index bfe08ba..8e86eb2 100644
+--- a/drivers/memory/emif.h
++++ b/drivers/memory/emif.h
+@@ -585,5 +585,13 @@ struct emif_regs {
+ 	u32 ext_phy_ctrl_3_shdw;
+ 	u32 ext_phy_ctrl_4_shdw;
+ };
++
++struct ti_emif_pm_functions;
++
++extern unsigned int ti_emif_sram;
++extern unsigned int ti_emif_sram_sz;
++extern void __iomem *ti_emif_base_addr_virt;
++extern void __iomem *ti_emif_base_addr_phys;
++extern struct ti_emif_pm_functions ti_emif_pm;
+ #endif /* __ASSEMBLY__ */
+ #endif /* __EMIF_H */
+diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S
+new file mode 100644
+index 0000000..49b0be4
+--- /dev/null
++++ b/drivers/memory/ti-emif-sram-pm.S
+@@ -0,0 +1,233 @@
++/*
++ * Low level PM code for TI EMIF
++ *
++ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
++ *	Dave Gerlach
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/linkage.h>
++#include <asm/memory.h>
++#include <asm/assembler.h>
++
++#include "emif.h"
++
++#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES	0x00a0
++#define EMIF_POWER_MGMT_SR_TIMER_MASK			0x00f0
++#define EMIF_POWER_MGMT_SELF_REFRESH_MODE		0x0200
++#define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK		0x0700
++
++#define EMIF_SDCFG_TYPE_DDR2				0x2 << SDRAM_TYPE_SHIFT
++#define EMIF_STATUS_READY				0x4
++
++	.text
++	.align 3
++
++ENTRY(ti_emif_sram)
++
++/*
++ * void ti_emif_save_context(void)
++ *
++ * Used during suspend to save the context of all required EMIF registers
++ * to local memory if the EMIF is going to lose context during the sleep
++ * transition. Operates on the VIRTUAL address of the EMIF.
++ */
++ENTRY(ti_emif_save_context)
++	stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
++
++	ldr	r0, ti_emif_base_addr_virt
++
++	/* Save EMIF configuration */
++	ldr	r1, [r0, #EMIF_SDRAM_CONFIG]
++	str	r1, emif_sdcfg_val
++	ldr	r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
++	str	r1, emif_ref_ctrl_val
++	ldr	r1, [r0, #EMIF_SDRAM_TIMING_1]
++	str	r1, emif_timing1_val
++	ldr	r1, [r0, #EMIF_SDRAM_TIMING_2]
++	str	r1, emif_timing2_val
++	ldr	r1, [r0, #EMIF_SDRAM_TIMING_3]
++	str	r1, emif_timing3_val
++	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
++	str	r1, emif_pmcr_val
++	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
++	str	r1, emif_pmcr_shdw_val
++	ldr	r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
++	str	r1, emif_zqcfg_val
++	ldr	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
++	str	r1, emif_rd_lat_val
++
++	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
++ENDPROC(ti_emif_save_context)
++
++/*
++ * void ti_emif_restore_context(void)
++ *
++ * Used during resume to restore the context of all required EMIF registers
++ * from local memory after the EMIF has lost context during a sleep transition.
++ * Operates on the PHYSICAL address of the EMIF.
++ */
++ENTRY(ti_emif_restore_context)
++	stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
++
++	ldr     r0, ti_emif_base_addr_phys
++
++	/* Config EMIF Timings */
++	ldr	r1, emif_rd_lat_val
++	str	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
++	str	r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
++	ldr	r1, emif_timing1_val
++	str	r1, [r0, #EMIF_SDRAM_TIMING_1]
++	str	r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
++	ldr	r1, emif_timing2_val
++	str	r1, [r0, #EMIF_SDRAM_TIMING_2]
++	str	r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
++	ldr	r1, emif_timing3_val
++	str	r1, [r0, #EMIF_SDRAM_TIMING_3]
++	str	r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
++	ldr	r1, emif_ref_ctrl_val
++	str	r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
++	str	r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
++	ldr	r1, emif_pmcr_shdw_val
++	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
++
++	/*
++	 * Output impedence calib needed only for DDR3
++	 * but since the initial state of this will be
++	 * disabled for DDR2 no harm in restoring the
++	 * old configuration
++	 */
++	ldr	r1, emif_zqcfg_val
++	str	r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
++
++	/* Write to sdcfg last for DDR2 only */
++	ldr	r1, emif_sdcfg_val
++	and	r2, r1, #SDRAM_TYPE_MASK
++	cmp	r2, #EMIF_SDCFG_TYPE_DDR2
++	streq	r1, [r0, #EMIF_SDRAM_CONFIG]
++
++	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
++ENDPROC(ti_emif_restore_context)
++
++/*
++ * void ti_emif_enter_sr(void)
++ *
++ * Programs the EMIF to tell the SDRAM to enter into self-refresh
++ * mode during a sleep transition. Operates on the VIRTUAL address
++ * of the EMIF.
++ */
++ENTRY(ti_emif_enter_sr)
++	stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
++
++	ldr	r0, ti_emif_base_addr_virt
++
++	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
++	bic	r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
++	orr	r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
++	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
++
++	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
++ENDPROC(ti_emif_enter_sr)
++
++/*
++ * void ti_emif_exit_sr(void)
++ *
++ * Programs the EMIF to tell the SDRAM to exit self-refresh mode
++ * after a sleep transition. Operates on the PHYSICAL address of
++ * the EMIF.
++ */
++ENTRY(ti_emif_exit_sr)
++	stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
++
++	ldr	r0, ti_emif_base_addr_phys
++
++	/*
++	 * Toggle EMIF to exit refresh mode:
++	 * if EMIF lost context, PWR_MGT_CTRL is currently 0, writing disable
++	 *   (0x0), wont do diddly squat! so do a toggle from SR(0x2) to disable
++	 *   (0x0) here.
++	 * *If* EMIF did not lose context, nothing broken as we write the same
++	 *   value(0x2) to reg before we write a disable (0x0).
++	 */
++	ldr	r1, emif_pmcr_val
++	bic	r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
++	orr	r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE
++	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
++	bic	r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
++	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
++
++        /* Wait for EMIF to become ready */
++1:	ldr     r1, [r0, #EMIF_STATUS]
++	tst     r1, #EMIF_STATUS_READY
++	beq     1b
++
++	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
++ENDPROC(ti_emif_exit_sr)
++
++/*
++ * void ti_emif_abort_sr(void)
++ *
++ * Disables self-refresh after a failed transition to a low-power
++ * state so the kernel can jump back to DDR and follow abort path.
++ * Operates on the VIRTUAL address of the EMIF.
++ */
++ENTRY(ti_emif_abort_sr)
++	stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
++
++	ldr	r0, ti_emif_base_addr_virt
++
++	ldr	r1, emif_pmcr_val
++	bic	r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK
++	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
++
++	/* Wait for EMIF to become ready */
++1:	ldr     r1, [r0, #EMIF_STATUS]
++	tst     r1, #EMIF_STATUS_READY
++	beq     1b
++
++	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
++ENDPROC(ti_emif_abort_sr)
++
++	.align 3
++/* DDR related defines */
++emif_addr_virt:
++	.word	0xDEADBEEF
++emif_rd_lat_val:
++	.word	0xDEADBEEF
++emif_timing1_val:
++	.word	0xDEADBEEF
++emif_timing2_val:
++	.word	0xDEADBEEF
++emif_timing3_val:
++	.word	0xDEADBEEF
++emif_sdcfg_val:
++	.word	0xDEADBEEF
++emif_ref_ctrl_val:
++	.word	0xDEADBEEF
++emif_zqcfg_val:
++	.word	0xDEADBEEF
++emif_pmcr_val:
++	.word	0xDEADBEEF
++emif_pmcr_shdw_val:
++	.word	0xDEADBEEF
++
++ENTRY(ti_emif_base_addr_virt)
++        .word   0x00000000
++ENTRY(ti_emif_base_addr_phys)
++        .word   0x00000000
++ENTRY(ti_emif_pm)
++	.word	ti_emif_save_context - ti_emif_sram
++	.word	ti_emif_restore_context - ti_emif_sram
++	.word	ti_emif_enter_sr - ti_emif_sram
++	.word	ti_emif_exit_sr - ti_emif_sram
++	.word	ti_emif_abort_sr - ti_emif_sram
++ENTRY(ti_emif_sram_sz)
++        .word   . - ti_emif_save_context
+diff --git a/drivers/memory/ti-emif-sram.c b/drivers/memory/ti-emif-sram.c
+new file mode 100644
+index 0000000..e843a3b
+--- /dev/null
++++ b/drivers/memory/ti-emif-sram.c
+@@ -0,0 +1,195 @@
++/*
++ * TI AM33XX SRAM EMIF Driver
++ *
++ * Copyright (C) 2014 Texas Instruments Inc.
++ *          Dave Gerlach <d-gerlach@ti.com>
++ *
++ * 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.
++ */
++
++#include <linux/err.h>
++#include <linux/genalloc.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++
++#include <asm/fncpy.h>
++
++#include "emif.h"
++
++#define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES		0x00a0
++
++struct ti_emif_pm_functions {
++	u32 save_context;
++	u32 restore_context;
++	u32 enter_sr;
++	u32 exit_sr;
++	u32 abort_sr;
++} __packed;
++
++static void __iomem *ti_emif_sram_phys;
++static void __iomem *ti_emif_sram_virt;
++
++static u32 sram_suspend_address(unsigned long fn_offset)
++{
++	return (unsigned long)ti_emif_sram_virt + fn_offset;
++}
++
++static u32 sram_resume_address(unsigned long fn_offset)
++{
++	return (unsigned long)ti_emif_sram_phys + fn_offset;
++}
++
++static int ti_emif_push_sram(struct device_node *np)
++{
++	struct gen_pool *sram_pool;
++	phys_addr_t ocmcram_location;
++
++	sram_pool = of_get_named_gen_pool(np, "sram", 0);
++
++	if (!sram_pool)
++		pr_warn("PM: %s: Unable to allocate sram pool for ocmcram\n",
++			__func__);
++
++	ocmcram_location = gen_pool_alloc(sram_pool, ti_emif_sram_sz);
++	if (!ocmcram_location)
++		return -EINVAL;
++
++	/* Save physical address to calculate resume offset during pm init */
++	ti_emif_sram_phys = (void *)gen_pool_virt_to_phys(sram_pool,
++							  ocmcram_location);
++	ti_emif_sram_virt = (void *)fncpy((void *)ocmcram_location,
++					 &ti_emif_sram,
++					 ti_emif_sram_sz);
++
++	/*
++	 * These functions are called during suspend path while MMU is
++	 * still on so add virtual base to offset for absolute address
++	 */
++	ti_emif_pm.save_context = sram_suspend_address(ti_emif_pm.save_context);
++	ti_emif_pm.enter_sr = sram_suspend_address(ti_emif_pm.enter_sr);
++	ti_emif_pm.abort_sr = sram_suspend_address(ti_emif_pm.abort_sr);
++
++	/*
++	 * These are called during resume path when MMU is not enabled
++	 * so physical address is used instead
++	 */
++	ti_emif_pm.restore_context =
++		sram_resume_address(ti_emif_pm.restore_context);
++	ti_emif_pm.exit_sr = sram_resume_address(ti_emif_pm.exit_sr);
++
++	return 0;
++}
++
++/*
++ * Due to Usage Note 3.1.2 "DDR3: JEDEC Compliance for Maximum
++ * Self-Refresh Command Limit" found in AM335x Silicon Errata
++ * (Document SPRZ360F Revised November 2013) we must configure
++ * the self refresh delay timer to 0xA (8192 cycles) to avoid
++ * generating too many refresh command from the EMIF.
++ */
++static void ti_emif_configure_sr_delay(void)
++{
++	writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
++	       (void *)(ti_emif_base_addr_virt +
++			EMIF_POWER_MANAGEMENT_CONTROL));
++
++	writel(EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES,
++	       (void *)(ti_emif_base_addr_virt +
++			EMIF_POWER_MANAGEMENT_CTRL_SHDW));
++}
++
++/**
++ * ti_emif_copy_pm_function_table - copy mapping of pm funcs in sram
++ * @dst: void * to address that table should be copied
++ *
++ * Returns 0 if success other error code if table is not available
++ */
++int ti_emif_copy_pm_function_table(void *dst)
++{
++	if (!ti_emif_sram_virt)
++		return -ENODEV;
++
++	memcpy_toio(dst, &ti_emif_pm, sizeof(ti_emif_pm));
++
++	return 0;
++}
++
++/**
++ * ti_emif_get_mem_type - return type for memory type in use
++ *
++ * Returns memory type value read from EMIF or error code if fails
++ */
++int ti_emif_get_mem_type(void)
++{
++	unsigned long temp;
++
++	if (!ti_emif_base_addr_virt || IS_ERR(ti_emif_base_addr_virt))
++		return -ENODEV;
++
++	temp = readl((void *)ti_emif_base_addr_virt + EMIF_SDRAM_CONFIG);
++
++	temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
++	return temp;
++}
++
++static const struct of_device_id ti_emif_of_match[] = {
++	{ .compatible = "ti,am3352-emif", },
++	{},
++};
++
++static int ti_emif_probe(struct platform_device *pdev)
++{
++	int ret = -ENODEV;
++	struct resource *res;
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	ti_emif_base_addr_virt = devm_ioremap_resource(dev, res);
++	if (IS_ERR(ti_emif_base_addr_virt)) {
++		dev_err(dev, "could not ioremap emif mem\n");
++		return PTR_ERR(ti_emif_base_addr_virt);
++	}
++
++	ti_emif_base_addr_phys = (void *)res->start;
++
++	ti_emif_configure_sr_delay();
++
++	ret = ti_emif_push_sram(np);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int ti_emif_remove(struct platform_device *pdev)
++{
++	return 0;
++}
++
++static struct platform_driver ti_emif_driver = {
++	.probe = ti_emif_probe,
++	.remove = ti_emif_remove,
++	.driver = {
++		.name = KBUILD_MODNAME,
++		.of_match_table = of_match_ptr(ti_emif_of_match),
++	},
++};
++
++module_platform_driver(ti_emif_driver);
++
++MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
++MODULE_DESCRIPTION("Texas Instruments SRAM EMIF driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" KBUILD_MODNAME);
+diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h
+new file mode 100644
+index 0000000..e0ec7fa
+--- /dev/null
++++ b/include/linux/ti-emif-sram.h
+@@ -0,0 +1,26 @@
++/*
++ * TI AM33XX EMIF Routines
++ *
++ * Copyright (C) 2014 Texas Instruments Inc.
++ *          Dave Gerlach <d-gerlach@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#ifndef __LINUX_TI_EMIF_H
++#define __LINUX_TI_EMIF_H
++
++#ifdef CONFIG_TI_EMIF_SRAM
++int ti_emif_copy_pm_function_table(void *dst);
++int ti_emif_get_mem_type(void);
++#else
++static inline int ti_emif_copy_pm_function_table(void *dst) { return -ENODEV; }
++static inline int ti_emif_get_mem_type(void) { return -ENODEV; }
++#endif /* CONFIG_TI_EMIF_SRAM */
++#endif /* __LINUX_TI_EMIF_H */
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0013-ARM-dts-am33xx-Add-emif-node.patch b/patches/beaglebone/suspend/0013-ARM-dts-am33xx-Add-emif-node.patch
new file mode 100644
index 0000000000000000000000000000000000000000..78bd92772e393570b59e689990d578cad334b061
--- /dev/null
+++ b/patches/beaglebone/suspend/0013-ARM-dts-am33xx-Add-emif-node.patch
@@ -0,0 +1,31 @@
+From 84f652af5602f534bca8d1aa77f73bac376dd836 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Fri, 7 Nov 2014 14:19:39 -0600
+Subject: [PATCH 13/18] ARM: dts: am33xx: Add emif node
+
+Add node for Texas Instruments AM335x EMIF to make use of the
+ti-emif-sram driver.
+---
+ arch/arm/boot/dts/am33xx.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
+index 501017e..634f10b 100644
+--- a/arch/arm/boot/dts/am33xx.dtsi
++++ b/arch/arm/boot/dts/am33xx.dtsi
+@@ -182,6 +182,12 @@
+ 			#dma-cells = <1>;
+ 		};
+ 
++		emif: emif@4c000000 {
++			compatible = "ti,am3352-emif";
++			reg =	<0x4C000000 0x1000>;
++			sram = <&ocmcram>;
++		};
++
+ 		gpio0: gpio@44e07000 {
+ 			compatible = "ti,omap4-gpio";
+ 			ti,hwmods = "gpio1";
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0014-ARM-OMAP2-timer-Add-suspend-resume-callbacks-for-clk.patch b/patches/beaglebone/suspend/0014-ARM-OMAP2-timer-Add-suspend-resume-callbacks-for-clk.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c480cd10d92b70f29de83d3870dc2c3af556dfe3
--- /dev/null
+++ b/patches/beaglebone/suspend/0014-ARM-OMAP2-timer-Add-suspend-resume-callbacks-for-clk.patch
@@ -0,0 +1,79 @@
+From d0a222c0639981ad446a5226a9c3db62ed703faa Mon Sep 17 00:00:00 2001
+From: Vaibhav Bedia <vaibhav.bedia@ti.com>
+Date: Sun, 6 Oct 2013 21:14:22 -0500
+Subject: [PATCH 14/18] ARM: OMAP2+: timer: Add suspend-resume callbacks for
+ clkevent device
+
+OMAP timer code registers two timers - one as clocksource
+and one as clockevent. Since AM33XX has only one usable timer
+in the WKUP domain one of the timers needs suspend-resume
+support to restore the configuration to pre-suspend state.
+
+commit adc78e6b9946 ("timekeeping: Add suspend and resume
+of clock event devices") introduced .suspend and .resume
+callbacks for clock event devices. Leverage these
+callbacks to have AM33XX clockevent timer behave properly
+across system suspend.
+
+Signed-off-by: Vaibhav Bedia <vaibhav.bedia@ti.com>
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/mach-omap2/timer.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
+index cac46d8..6c3b3e7 100644
+--- a/arch/arm/mach-omap2/timer.c
++++ b/arch/arm/mach-omap2/timer.c
+@@ -68,6 +68,9 @@
+ static struct omap_dm_timer clkev;
+ static struct clock_event_device clockevent_gpt;
+ 
++/* Clockevent hwmod for am335x and am437x suspend */
++struct omap_hwmod *clockevent_gpt_hwmod;
++
+ #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
+ static unsigned long arch_timer_freq;
+ 
+@@ -129,6 +132,23 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
+ 	}
+ }
+ 
++static void omap_clkevt_idle(struct clock_event_device *unused)
++{
++	if (!clockevent_gpt_hwmod)
++		return;
++
++	omap_hwmod_idle(clockevent_gpt_hwmod);
++}
++
++static void omap_clkevt_unidle(struct clock_event_device *unused)
++{
++	if (!clockevent_gpt_hwmod)
++		return;
++
++	omap_hwmod_enable(clockevent_gpt_hwmod);
++	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
++}
++
+ static struct clock_event_device clockevent_gpt = {
+ 	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ 	.rating		= 300,
+@@ -355,6 +375,14 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
+ 					3, /* Timer internal resynch latency */
+ 					0xffffffff);
+ 
++	if (soc_is_am33xx()) {
++		clockevent_gpt.suspend = omap_clkevt_idle;
++		clockevent_gpt.resume = omap_clkevt_unidle;
++
++		clockevent_gpt_hwmod =
++			omap_hwmod_lookup(clockevent_gpt.name);
++	}
++
+ 	pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name,
+ 		clkev.rate);
+ }
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0015-ARM-OMAP2-AM33XX-Add-assembly-code-for-PM-operations.patch b/patches/beaglebone/suspend/0015-ARM-OMAP2-AM33XX-Add-assembly-code-for-PM-operations.patch
new file mode 100644
index 0000000000000000000000000000000000000000..23d8a6f5137068608972bfdcb176bbea3ed2e9fd
--- /dev/null
+++ b/patches/beaglebone/suspend/0015-ARM-OMAP2-AM33XX-Add-assembly-code-for-PM-operations.patch
@@ -0,0 +1,263 @@
+From 54fba0b305ba110ba3736d40af43854b4f5733b8 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Thu, 10 Jul 2014 17:43:02 -0500
+Subject: [PATCH 15/18] ARM: OMAP2+: AM33XX: Add assembly code for PM
+ operations
+
+In preparation for suspend-resume support for AM33XX, add
+the assembly file with the code which is copied to internal
+memory (OCMC RAM) during bootup and runs from there.
+
+As part of the low power entry (DeepSleep0 mode in AM33XX TRM),
+the code running from OCMC RAM does the following
+1. Calls routine to store the EMIF configuration
+2. Calls routine to place external memory in self-refresh
+3. Disables EMIF clock
+4. Executes WFI after writing to MPU_CLKCTRL register.
+
+If no interrupts have come, WFI execution on MPU gets registered
+as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling
+some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes
+care of clockdomain and powerdomain transitions as part of the
+DeepSleep0 mode entry.
+
+In case a late interrupt comes in, WFI ends up as a NOP and MPU
+continues execution from internal memory. The 'abort path' code
+undoes whatever was done as part of the low power entry and indicates
+a suspend failure by passing a non-zero value to the cpu_resume routine.
+
+The 'resume path' code is similar to the 'abort path' with the key
+difference of MMU being enabled in the 'abort path' but being
+disabled in the 'resume path' due to MPU getting powered off.
+
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/mach-omap2/sleep33xx.S | 216 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 216 insertions(+)
+ create mode 100644 arch/arm/mach-omap2/sleep33xx.S
+
+diff --git a/arch/arm/mach-omap2/sleep33xx.S b/arch/arm/mach-omap2/sleep33xx.S
+new file mode 100644
+index 0000000..9399a16
+--- /dev/null
++++ b/arch/arm/mach-omap2/sleep33xx.S
+@@ -0,0 +1,216 @@
++/*
++ * Low level suspend code for AM33XX SoCs
++ *
++ * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/
++ *	Vaibhav Bedia, Dave Gerlach
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/linkage.h>
++#include <asm/memory.h>
++#include <asm/assembler.h>
++
++#include "iomap.h"
++#include "cm33xx.h"
++
++#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE			0x0003
++#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE			0x0002
++
++	.text
++	.align 3
++
++ENTRY(am33xx_do_wfi)
++	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
++
++	/*
++	 * Flush all data from the L1 and L2 data cache before disabling
++	 * SCTLR.C bit.
++	 */
++	ldr	r1, kernel_flush
++	blx	r1
++
++	/*
++	 * Clear the SCTLR.C bit to prevent further data cache
++	 * allocation. Clearing SCTLR.C would make all the data accesses
++	 * strongly ordered and would not hit the cache.
++	 */
++	mrc	p15, 0, r0, c1, c0, 0
++	bic	r0, r0, #(1 << 2)	@ Disable the C bit
++	mcr	p15, 0, r0, c1, c0, 0
++	isb
++
++	/*
++	 * Invalidate L1 and L2 data cache.
++	 */
++	ldr	r1, kernel_flush
++	blx	r1
++
++	ldr	r1, ti_emif_save_context
++	blx	r1
++
++	ldr	r1, ti_emif_enter_sr
++	blx	r1
++
++	/* Disable EMIF */
++	ldr     r1, virt_emif_clkctrl
++	ldr     r2, [r1]
++	bic     r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
++	str     r2, [r1]
++
++	ldr	r1, virt_emif_clkctrl
++wait_emif_disable:
++	ldr	r2, [r1]
++	ldr	r3, module_disabled_val
++	cmp	r2, r3
++	bne	wait_emif_disable
++
++	/*
++	 * For the MPU WFI to be registered as an interrupt
++	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
++	 * to DISABLED
++	 */
++	ldr	r1, virt_mpu_clkctrl
++	ldr	r2, [r1]
++	bic	r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
++	str	r2, [r1]
++
++	/*
++	 * Execute an ISB instruction to ensure that all of the
++	 * CP15 register changes have been committed.
++	 */
++	isb
++
++	/*
++	 * Execute a barrier instruction to ensure that all cache,
++	 * TLB and branch predictor maintenance operations issued
++	 * have completed.
++	 */
++	dsb
++	dmb
++
++	/*
++	 * Execute a WFI instruction and wait until the
++	 * STANDBYWFI output is asserted to indicate that the
++	 * CPU is in idle and low power state. CPU can specualatively
++	 * prefetch the instructions so add NOPs after WFI. Thirteen
++	 * NOPs as per Cortex-A8 pipeline.
++	 */
++	wfi
++
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++
++	/* We come here in case of an abort due to a late interrupt */
++
++	/* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
++	ldr	r1, virt_mpu_clkctrl
++	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
++	str	r2, [r1]
++
++	/* Re-enable EMIF */
++	ldr	r1, virt_emif_clkctrl
++	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
++	str	r2, [r1]
++wait_emif_enable:
++	ldr	r3, [r1]
++	cmp	r2, r3
++	bne	wait_emif_enable
++
++	ldr	r1, ti_emif_abort_sr
++	blx	r1
++
++	/*
++	 * Set SCTLR.C bit to allow data cache allocation
++	 */
++	mrc	p15, 0, r0, c1, c0, 0
++	orr	r0, r0, #(1 << 2)	@ Enable the C bit
++	mcr	p15, 0, r0, c1, c0, 0
++	isb
++
++	/* Let the suspend code know about the abort */
++	mov	r0, #1
++	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
++ENDPROC(am33xx_do_wfi)
++
++	.align
++ENTRY(am33xx_resume_offset)
++	.word . - am33xx_do_wfi
++
++ENTRY(am33xx_resume_from_deep_sleep)
++	/* Re-enable EMIF */
++	ldr	r0, phys_emif_clkctrl
++	mov	r1, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
++	str	r1, [r0]
++wait_emif_enable1:
++	ldr	r2, [r0]
++	cmp	r1, r2
++	bne	wait_emif_enable1
++
++	adr	sp, temp_stack
++
++	ldr	r1, ti_emif_restore_context
++	blx	r1
++
++	ldr	r1, ti_emif_exit_sr
++	blx	r1
++
++resume_to_ddr:
++	/* We are back. Branch to the common CPU resume routine */
++	mov	r0, #0
++	ldr	pc, resume_addr
++ENDPROC(am33xx_resume_from_deep_sleep)
++
++/*
++ * Local variables
++ */
++	.align
++resume_addr:
++	.word	cpu_resume - PAGE_OFFSET + 0x80000000
++kernel_flush:
++	.word   v7_flush_dcache_all
++virt_mpu_clkctrl:
++	.word	AM33XX_CM_MPU_MPU_CLKCTRL
++virt_emif_clkctrl:
++	.word	AM33XX_CM_PER_EMIF_CLKCTRL
++phys_emif_clkctrl:
++	.word	(AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
++		AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)
++module_disabled_val:
++	.word	0x30000
++
++/* DDR related defines */
++ENTRY(am33xx_emif_sram_table)
++ti_emif_save_context:
++	.word	0x00000000
++ti_emif_restore_context:
++	.word	0x00000000
++ti_emif_enter_sr:
++	.word	0x00000000
++ti_emif_exit_sr:
++	.word	0x00000000
++ti_emif_abort_sr:
++	.word	0x00000000
++	.align 3
++	.space 64
++temp_stack:
++ENTRY(am33xx_do_wfi_sz)
++	.word	. - am33xx_do_wfi
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0016-ARM-OMAP2-AM33XX-Basic-suspend-resume-support.patch b/patches/beaglebone/suspend/0016-ARM-OMAP2-AM33XX-Basic-suspend-resume-support.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f92b20103cfd1235865fc1b35894d0dd13190c3d
--- /dev/null
+++ b/patches/beaglebone/suspend/0016-ARM-OMAP2-AM33XX-Basic-suspend-resume-support.patch
@@ -0,0 +1,378 @@
+From 4a67f4822fbd6c9b99b84a7978a7487566c05121 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Thu, 10 Jul 2014 17:43:13 -0500
+Subject: [PATCH 16/18] ARM: OMAP2+: AM33XX: Basic suspend resume support
+
+AM335x supports various low power modes as documented
+in section 8.1.4.3 of the AM335x Technical Reference Manual.
+
+DeepSleep0 mode offers the lowest power mode with limited
+wakeup sources without a system reboot and is mapped as
+the suspend state in the kernel. In this state, MPU and
+PER domains are turned off with the internal RAM held in
+retention to facilitate the resume process. As part of
+the boot process, the assembly code is copied over to OCMCRAM
+so it can be executed to turn of the EMIF and put DDR into self
+refresh.
+
+AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU
+in DeepSleep0 entry and exit. WKUP_M3 takes care
+of the clockdomain and powerdomain transitions based on the
+intended low power state. MPU needs to load the appropriate
+WKUP_M3 binary onto the WKUP_M3 memory space before it can
+leverage any of the PM features like DeepSleep. This loading
+is handled by the remoteproc driver wkup_m3_rproc.
+
+Communication with the WKUP_M3 is handled by a wkup_m3_ipc
+driver that exposes the specific PM functionality to be used
+the PM code.
+
+In the current implementation when the suspend process
+is initiated, MPU interrupts the WKUP_M3 to let it know about
+the intent of entering DeepSleep0 and waits for an ACK. When
+the ACK is received MPU continues with its suspend process
+to suspend all the drivers and then jumps to assembly in
+OCMC RAM. The assembly code puts the external RAM in self-refresh
+mode, gates the MPU clock, and then finally executes the WFI
+instruction. Execution of the WFI instruction with MPU clock gated
+triggers another interrupt to the WKUP_M3 which then continues
+with the power down sequence wherein the clockdomain and
+powerdomain transition takes place. As part of the sleep sequence,
+WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI
+execution on WKUP_M3 causes the hardware to disable the main
+oscillator of the SoC and from here system remains in sleep state
+until a wake source brings the system into resume path.
+
+When a wakeup event occurs, WKUP_M3 starts the power-up
+sequence by switching on the power domains and finally
+enabling the clock to MPU. Since the MPU gets powered down
+as part of the sleep sequence in the resume path ROM code
+starts executing. The ROM code detects a wakeup from sleep
+and then jumps to the resume location in OCMC which was
+populated in one of the IPC registers as part of the suspend
+sequence.
+
+Code is based on work by Vaibhav Bedia.
+
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/boot/dts/am33xx.dtsi |   2 +
+ arch/arm/mach-omap2/pm.h      |   5 +
+ arch/arm/mach-omap2/pm33xx.c  | 269 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 276 insertions(+)
+ create mode 100644 arch/arm/mach-omap2/pm33xx.c
+
+diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
+index 634f10b..3f24864 100644
+--- a/arch/arm/boot/dts/am33xx.dtsi
++++ b/arch/arm/boot/dts/am33xx.dtsi
+@@ -80,6 +80,7 @@
+ 		mpu {
+ 			compatible = "ti,omap3-mpu";
+ 			ti,hwmods = "mpu";
++			sram = <&ocmcram>;
+ 		};
+ 	};
+ 
+@@ -821,6 +822,7 @@
+ 		ocmcram: ocmcram@40300000 {
+ 			compatible = "mmio-sram";
+ 			reg = <0x40300000 0x10000>; /* 64k */
++			map-exec;
+ 		};
+ 
+ 		elm: elm@48080000 {
+diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
+index 425bfcd..4b882f5 100644
+--- a/arch/arm/mach-omap2/pm.h
++++ b/arch/arm/mach-omap2/pm.h
+@@ -81,6 +81,11 @@ extern unsigned int omap3_do_wfi_sz;
+ /* ... and its pointer from SRAM after copy */
+ extern void (*omap3_do_wfi_sram)(void);
+ 
++/* 33xx */
++struct wkup_m3_pm_ipc_ops;
++void am33xx_pm_set_ipc_ops(struct wkup_m3_pm_ipc_ops *ops);
++
++>>>>>>> 839ba7c7... pm33xx: add am33xx_pm_set_ipc_ops for use by pdata_quirks
+ /* save_secure_ram_context function pointer and size, for copy to SRAM */
+ extern int save_secure_ram_context(u32 *addr);
+ extern unsigned int save_secure_ram_context_sz;
+diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
+new file mode 100644
+index 0000000..789e3d9
+--- /dev/null
++++ b/arch/arm/mach-omap2/pm33xx.c
+@@ -0,0 +1,269 @@
++/*
++ * AM33XX Power Management Routines
++ *
++ * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/
++ *	Vaibhav Bedia, Dave Gerlach
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/cpu.h>
++#include <linux/err.h>
++#include <linux/genalloc.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/sizes.h>
++#include <linux/suspend.h>
++#include <linux/ti-emif-sram.h>
++
++#include <linux/platform_data/wkup_m3_ipc.h>
++
++#include <asm/fncpy.h>
++#include <asm/proc-fns.h>
++#include <asm/suspend.h>
++#include <asm/system_misc.h>
++
++#include "clockdomain.h"
++#include "cm33xx.h"
++#include "common.h"
++#include "pm.h"
++#include "powerdomain.h"
++#include "soc.h"
++
++static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
++static struct clockdomain *gfx_l4ls_clkdm;
++
++static int (*am33xx_do_wfi_sram)(unsigned long unused);
++static phys_addr_t am33xx_do_wfi_sram_phys;
++
++static struct wkup_m3_pm_ipc_ops *m3_ops;
++
++#ifdef CONFIG_SUSPEND
++static int am33xx_pm_suspend(void)
++{
++	int i, ret = 0;
++	int status = 0;
++
++	/* Try to put GFX to sleep */
++	omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
++
++	ret = cpu_suspend(0, am33xx_do_wfi_sram);
++
++	status = pwrdm_read_pwrst(gfx_pwrdm);
++	if (status != PWRDM_POWER_OFF)
++		pr_err("PM: GFX domain did not transition\n");
++
++	/*
++	 * BUG: GFX_L4LS clock domain needs to be woken up to
++	 * ensure thet L4LS clock domain does not get stuck in transition
++	 * If that happens L3 module does not get disabled, thereby leading
++	 * to PER power domain transition failing
++	 */
++	clkdm_wakeup(gfx_l4ls_clkdm);
++	clkdm_sleep(gfx_l4ls_clkdm);
++
++	if (ret) {
++		pr_err("PM: Kernel suspend failure\n");
++	} else {
++		i = m3_ops->request_pm_status();
++
++		switch (i) {
++		case 0:
++			pr_info("PM: Successfully put all powerdomains to target state\n");
++
++			/*
++			 * The PRCM registers on AM335x do not contain
++			 * previous state information like those present on
++			 * OMAP4 so we must manually indicate transition so
++			 * state counters are properly incremented
++			 */
++			pwrdm_post_transition(mpu_pwrdm);
++			pwrdm_post_transition(per_pwrdm);
++			break;
++		case 1:
++			pr_err("PM: Could not transition all powerdomains to target state\n");
++			ret = -1;
++			break;
++		default:
++			pr_err("PM: CM3 returned unknown result = %d\n", i);
++			ret = -1;
++		}
++	}
++
++	return ret;
++}
++
++static int am33xx_pm_enter(suspend_state_t suspend_state)
++{
++	int ret = 0;
++
++	switch (suspend_state) {
++	case PM_SUSPEND_MEM:
++		ret = am33xx_pm_suspend();
++		break;
++	default:
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++static int am33xx_pm_begin(suspend_state_t state)
++{
++	int ret = -EINVAL;
++
++	if (!m3_ops) {
++		pr_err("PM: No wkup_m3 ops passed, no PM available.\n");
++		return ret;
++	}
++
++	switch (state) {
++	case PM_SUSPEND_MEM:
++		ret = m3_ops->prepare_low_power(state);
++		break;
++	}
++
++	return ret;
++}
++
++static void am33xx_pm_end(void)
++{
++	if (m3_ops)
++		m3_ops->finish_low_power();
++}
++
++static int am33xx_pm_valid(suspend_state_t state)
++{
++	switch (state) {
++	case PM_SUSPEND_MEM:
++		return 1;
++	default:
++		return 0;
++	}
++}
++
++static const struct platform_suspend_ops am33xx_pm_ops = {
++	.begin		= am33xx_pm_begin,
++	.end		= am33xx_pm_end,
++	.enter		= am33xx_pm_enter,
++	.valid		= am33xx_pm_valid,
++};
++#endif /* CONFIG_SUSPEND */
++
++void am33xx_pm_set_ipc_ops(struct wkup_m3_pm_ipc_ops *ops)
++{
++	void *resume_address;
++	u32 temp;
++
++	m3_ops = ops;
++
++	if (!m3_ops)
++		return;
++
++	temp = ti_emif_get_mem_type();
++	if (temp < 0) {
++		pr_err("PM: Cannot determine memory type, no PM available\n");
++		m3_ops = NULL;
++		return;
++	}
++	m3_ops->set_mem_type(temp);
++
++	/* Physical resume address to be used by ROM code */
++	resume_address = (void *)am33xx_do_wfi_sram_phys +
++			 am33xx_resume_offset + 0x4;
++
++	m3_ops->set_resume_address(resume_address);
++}
++
++/*
++ * Push the minimal suspend-resume code to SRAM
++ */
++static int am33xx_push_sram_idle(void)
++{
++	struct device_node *np;
++	struct gen_pool *sram_pool;
++	phys_addr_t ocmcram_location;
++	int ret;
++
++	ret = ti_emif_copy_pm_function_table(&am33xx_emif_sram_table);
++	if (ret) {
++		pr_err("PM: Cannot copy emif functions to sram, no PM available\n");
++		return -ENODEV;
++	}
++
++	np = of_find_compatible_node(NULL, NULL, "ti,omap3-mpu");
++
++	if (!np) {
++		pr_warn("PM: %s: Unable to find device node for mpu\n",
++			__func__);
++		return -ENODEV;
++	}
++
++	sram_pool = of_get_named_gen_pool(np, "sram", 0);
++
++	if (!sram_pool) {
++		pr_warn("PM: %s: Unable to allocate sram pool for ocmcram\n",
++			__func__);
++		return -ENODEV;
++	}
++
++	ocmcram_location = gen_pool_alloc(sram_pool, am33xx_do_wfi_sz);
++	if (!ocmcram_location)
++		return -EINVAL;
++
++	/* Save physical address to calculate resume offset during pm init */
++	am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
++							ocmcram_location);
++	am33xx_do_wfi_sram = (void *)fncpy((void *)ocmcram_location,
++					   &am33xx_do_wfi,
++					   am33xx_do_wfi_sz);
++
++	return 0;
++}
++
++int __init am33xx_pm_init(void)
++{
++	int ret;
++
++	if (!soc_is_am33xx())
++		return -ENODEV;
++
++	gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
++	per_pwrdm = pwrdm_lookup("per_pwrdm");
++	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
++
++	gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
++
++	if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm) || (!gfx_l4ls_clkdm)) {
++		pr_err("PM: Could not lookup clock and power domains\n");
++		return -ENODEV;
++	}
++
++	(void)clkdm_for_each(omap_pm_clkdms_setup, NULL);
++
++	/* CEFUSE domain can be turned off post bootup */
++	cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
++	if (cefuse_pwrdm)
++		omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
++	else
++		pr_warn("PM: Failed to get cefuse_pwrdm\n");
++
++	ret = am33xx_push_sram_idle();
++	if (ret)
++		return ret;
++
++#ifdef CONFIG_SUSPEND
++	suspend_set_ops(&am33xx_pm_ops);
++#endif /* CONFIG_SUSPEND */
++
++	return 0;
++}
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0017-ARM-OMAP2-AM33XX-Hookup-AM33XX-PM-code-into-OMAP-bui.patch b/patches/beaglebone/suspend/0017-ARM-OMAP2-AM33XX-Hookup-AM33XX-PM-code-into-OMAP-bui.patch
new file mode 100644
index 0000000000000000000000000000000000000000..bb6dafaa54d8d8c751a24ade809b94063550d411
--- /dev/null
+++ b/patches/beaglebone/suspend/0017-ARM-OMAP2-AM33XX-Hookup-AM33XX-PM-code-into-OMAP-bui.patch
@@ -0,0 +1,99 @@
+From 81a93972d4f2b07079ee40e12a10dfb9d6a30508 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Thu, 10 Jul 2014 19:08:38 -0500
+Subject: [PATCH 17/18] ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP
+ builds
+
+With all the requisite changes in place we can now enable basic
+PM support for AM33xx. This patch updates the various OMAP files
+to enable suspend-resume on AM33xx.
+
+Because the suspend resume functionality is different on AM33xx
+than other OMAP platforms due to the need for M3 firmware and an
+IPC channel to be in place, separate PM ops are used instead of
+omap_pm_ops.
+
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+---
+ arch/arm/mach-omap2/Makefile | 2 ++
+ arch/arm/mach-omap2/common.h | 9 +++++++++
+ arch/arm/mach-omap2/io.c     | 1 +
+ arch/arm/mach-omap2/pm.h     | 7 +++++--
+ 4 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
+index 9a2c88e..ca4725a 100644
+--- a/arch/arm/mach-omap2/Makefile
++++ b/arch/arm/mach-omap2/Makefile
+@@ -91,6 +91,7 @@ omap-4-5-pm-common			=  pm44xx.o omap-mpuss-lowpower.o
+ obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-4-5-pm-common)
+ obj-$(CONFIG_SOC_OMAP5)			+= $(omap-4-5-pm-common)
+ obj-$(CONFIG_SOC_DRA7XX)		+= $(omap-4-5-pm-common)
++obj-$(CONFIG_SOC_AM33XX)		+= pm33xx.o sleep33xx.o
+ obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
+ 
+ obj-$(CONFIG_POWER_AVS_OMAP)		+= sr_device.o
+@@ -98,6 +99,7 @@ obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
+ 
+ AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
+ AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a$(plus_sec)
++AFLAGS_sleep33xx.o			:=-Wa,-march=armv7-a$(plus_sec)
+ 
+ endif
+ 
+diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
+index cf3cf22..8449599 100644
+--- a/arch/arm/mach-omap2/common.h
++++ b/arch/arm/mach-omap2/common.h
+@@ -77,6 +77,15 @@ static inline int omap4_pm_init_early(void)
+ }
+ #endif
+ 
++#if defined(CONFIG_PM) && defined(CONFIG_SOC_AM33XX)
++int am33xx_pm_init(void);
++#else
++static inline int am33xx_pm_init(void)
++{
++	return 0;
++}
++#endif
++
+ #ifdef CONFIG_OMAP_MUX
+ int omap_mux_late_init(void);
+ #else
+diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
+index 820dde8..10c5f84 100644
+--- a/arch/arm/mach-omap2/io.c
++++ b/arch/arm/mach-omap2/io.c
+@@ -598,6 +598,7 @@ void __init am33xx_init_early(void)
+ void __init am33xx_init_late(void)
+ {
+ 	omap_common_late_init();
++	am33xx_pm_init();
+ }
+ #endif
+ 
+diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
+index 4b882f5..1ee7062 100644
+--- a/arch/arm/mach-omap2/pm.h
++++ b/arch/arm/mach-omap2/pm.h
+@@ -81,11 +81,14 @@ extern unsigned int omap3_do_wfi_sz;
+ /* ... and its pointer from SRAM after copy */
+ extern void (*omap3_do_wfi_sram)(void);
+ 
+-/* 33xx */
++/* 33xx am33xx_do_wfi function pointer and size, for copy to SRAM */
+ struct wkup_m3_pm_ipc_ops;
+ void am33xx_pm_set_ipc_ops(struct wkup_m3_pm_ipc_ops *ops);
++extern void am33xx_do_wfi(void);
++extern unsigned int am33xx_do_wfi_sz;
++extern unsigned int am33xx_resume_offset;
++extern unsigned long am33xx_emif_sram_table;
+ 
+->>>>>>> 839ba7c7... pm33xx: add am33xx_pm_set_ipc_ops for use by pdata_quirks
+ /* save_secure_ram_context function pointer and size, for copy to SRAM */
+ extern int save_secure_ram_context(u32 *addr);
+ extern unsigned int save_secure_ram_context_sz;
+-- 
+2.1.4
+
diff --git a/patches/beaglebone/suspend/0018-ARM-OMAP2-pdata-quirks-provide-wkup_m3_ipc-ops-to-pl.patch b/patches/beaglebone/suspend/0018-ARM-OMAP2-pdata-quirks-provide-wkup_m3_ipc-ops-to-pl.patch
new file mode 100644
index 0000000000000000000000000000000000000000..83318ad52097ef9aebd791e318374594cfa6fb45
--- /dev/null
+++ b/patches/beaglebone/suspend/0018-ARM-OMAP2-pdata-quirks-provide-wkup_m3_ipc-ops-to-pl.patch
@@ -0,0 +1,68 @@
+From 24485364fb66c2e576e4a70fbdc4aa8176ee5252 Mon Sep 17 00:00:00 2001
+From: Dave Gerlach <d-gerlach@ti.com>
+Date: Tue, 24 Feb 2015 13:28:14 -0600
+Subject: [PATCH 18/18] ARM: OMAP2+: pdata-quirks: provide wkup_m3_ipc ops to
+ plat pm code
+
+Use pdata-quirks to pass wkup_m3_ipc pm ops to the platform pm code.
+The quirks were added for both the AM33xx and AM43xx SoCs. Once the
+pm33xx code can be built as a module we can remove this.
+
+Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
+Signed-off-by: Suman Anna <s-anna@ti.com>
+---
+ arch/arm/mach-omap2/pdata-quirks.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
+index 88ff116..48e8343 100644
+--- a/arch/arm/mach-omap2/pdata-quirks.c
++++ b/arch/arm/mach-omap2/pdata-quirks.c
+@@ -18,6 +18,7 @@
+ #include <linux/platform_data/pinctrl-single.h>
+ #include <linux/platform_data/iommu-omap.h>
+ #include <linux/platform_data/wkup_m3.h>
++#include <linux/platform_data/wkup_m3_ipc.h>
+ 
+ #include "common.h"
+ #include "common-board-devices.h"
+@@ -25,6 +26,7 @@
+ #include "control.h"
+ #include "omap_device.h"
+ #include "omap-secure.h"
++#include "pm.h"
+ #include "soc.h"
+ 
+ struct pdata_init {
+@@ -264,6 +266,10 @@ static struct wkup_m3_platform_data wkup_m3_data = {
+ 	.assert_reset = omap_device_assert_hardreset,
+ 	.deassert_reset = omap_device_deassert_hardreset,
+ };
++
++static struct wkup_m3_ipc_data wkup_m3_ipc_pm_data = {
++	.set_pm_ipc_ops = am33xx_pm_set_ipc_ops,
++};
+ #endif
+ 
+ #ifdef CONFIG_SOC_OMAP5
+@@ -331,6 +337,8 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+ #ifdef CONFIG_SOC_AM33XX
+ 	OF_DEV_AUXDATA("ti,am3352-wkup-m3", 0x44d00000, "44d00000.wkup_m3",
+ 		       &wkup_m3_data),
++	OF_DEV_AUXDATA("ti,am3352-wkup-m3-ipc", 0x44e11324, "44e11324.wkup_m3",
++		       &wkup_m3_ipc_pm_data),
+ #endif
+ #ifdef CONFIG_ARCH_OMAP4
+ 	OF_DEV_AUXDATA("ti,omap4-padconf", 0x4a100040, "4a100040.pinmux", &pcs_pdata),
+@@ -347,6 +355,8 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+ 	OF_DEV_AUXDATA("ti,am437-padconf", 0x44e10800, "44e10800.pinmux", &pcs_pdata),
+ 	OF_DEV_AUXDATA("ti,am4372-wkup-m3", 0x44d00000, "44d00000.wkup_m3",
+ 		       &wkup_m3_data),
++	OF_DEV_AUXDATA("ti,am4372-wkup-m3-ipc", 0x44e11324, "44e11324.wkup_m3",
++		       &wkup_m3_ipc_pm_data),
+ #endif
+ #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
+ 	OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu",
+-- 
+2.1.4
+
diff --git a/patches/defconfig b/patches/defconfig
index d7455dd968ce49cff14905d4ee07a6479d74ff13..09954c223d87723c509e0528b17a1018148084c4 100644
--- a/patches/defconfig
+++ b/patches/defconfig
@@ -200,6 +200,7 @@ CONFIG_OPROFILE=y
 CONFIG_HAVE_OPROFILE=y
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
+CONFIG_OPTPROBES=y
 CONFIG_UPROBES=y
 # CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
 CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
@@ -207,6 +208,7 @@ CONFIG_ARCH_USE_BUILTIN_BSWAP=y
 CONFIG_KRETPROBES=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_OPTPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_DMA_ATTRS=y
 CONFIG_HAVE_DMA_CONTIGUOUS=y
@@ -498,10 +500,9 @@ CONFIG_HZ_100=y
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=100
 CONFIG_SCHED_HRTICK=y
-CONFIG_THUMB2_KERNEL=y
-CONFIG_THUMB2_AVOID_R_ARM_THM_JUMP11=y
-CONFIG_ARM_ASM_UNIFIED=y
+# CONFIG_THUMB2_KERNEL is not set
 CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
 CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
 # CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
 # CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
@@ -4751,6 +4752,7 @@ CONFIG_WKUP_M3_RPROC=y
 # SOC (System On Chip) specific Drivers
 #
 CONFIG_SOC_TI=y
+CONFIG_WKUP_M3_IPC=y
 CONFIG_PM_DEVFREQ=y
 
 #
@@ -4779,6 +4781,7 @@ CONFIG_EXTCON_USB_GPIO=y
 CONFIG_MEMORY=y
 CONFIG_TI_EMIF=y
 CONFIG_OMAP_GPMC=y
+# CONFIG_TI_EMIF_SRAM is not set
 CONFIG_IIO=m
 CONFIG_IIO_BUFFER=y
 # CONFIG_IIO_BUFFER_CB is not set
@@ -5377,6 +5380,7 @@ CONFIG_UNUSED_SYMBOLS=y
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
@@ -5451,6 +5455,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_LATENCYTOP is not set
 CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
@@ -5466,6 +5471,7 @@ CONFIG_GENERIC_TRACER=y
 CONFIG_TRACING_SUPPORT=y
 CONFIG_FTRACE=y
 CONFIG_FUNCTION_TRACER=y
+CONFIG_FUNCTION_GRAPH_TRACER=y
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 CONFIG_FTRACE_SYSCALLS=y
@@ -5524,6 +5530,7 @@ CONFIG_KDB_CONTINUE_CATASTROPHIC=0
 # CONFIG_ARM_PTDUMP is not set
 # CONFIG_STRICT_DEVMEM is not set
 CONFIG_ARM_UNWIND=y
+CONFIG_OLD_MCOUNT=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_LL is not set
 CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
diff --git a/patches/ref_omap2plus_defconfig b/patches/ref_omap2plus_defconfig
index e94edeffd1f7d1bf5dae063eb8ce30b6dc115dda..4019548bfa591bbbb950e8170690fda2a8e7dfc9 100644
--- a/patches/ref_omap2plus_defconfig
+++ b/patches/ref_omap2plus_defconfig
@@ -3147,6 +3147,7 @@ CONFIG_EXTCON_USB_GPIO=m
 CONFIG_MEMORY=y
 CONFIG_TI_EMIF=m
 CONFIG_OMAP_GPMC=y
+# CONFIG_TI_EMIF_SRAM is not set
 # CONFIG_IIO is not set
 CONFIG_PWM=y
 CONFIG_PWM_SYSFS=y
diff --git a/patches/sgx/0004-ARM-OMAP2-Use-pdata-quirks-for-sgx-deassert_hardrese.patch b/patches/sgx/0004-ARM-OMAP2-Use-pdata-quirks-for-sgx-deassert_hardrese.patch
index a41a5b13dc921e7cddb91a281fe0f51d095ea6d5..a7014efb6d32e135374b8144a1a57ecd60cd42a6 100644
--- a/patches/sgx/0004-ARM-OMAP2-Use-pdata-quirks-for-sgx-deassert_hardrese.patch
+++ b/patches/sgx/0004-ARM-OMAP2-Use-pdata-quirks-for-sgx-deassert_hardrese.patch
@@ -17,7 +17,7 @@ Signed-off-by: Darren Etheridge <detheridge@ti.com>
  create mode 100644 include/linux/platform_data/sgx-omap.h
 
 diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
-index af11511..1e708a2 100644
+index 48e8343..664dbb7 100644
 --- a/arch/arm/mach-omap2/pdata-quirks.c
 +++ b/arch/arm/mach-omap2/pdata-quirks.c
 @@ -17,6 +17,7 @@
@@ -25,10 +25,10 @@ index af11511..1e708a2 100644
  #include <linux/platform_data/pinctrl-single.h>
  #include <linux/platform_data/iommu-omap.h>
 +#include <linux/platform_data/sgx-omap.h>
+ #include <linux/platform_data/wkup_m3.h>
+ #include <linux/platform_data/wkup_m3_ipc.h>
  
- #include "common.h"
- #include "common-board-devices.h"
-@@ -34,6 +35,13 @@ struct pdata_init {
+@@ -37,6 +38,13 @@ struct pdata_init {
  struct of_dev_auxdata omap_auxdata_lookup[];
  static struct twl4030_gpio_platform_data twl_gpio_auxdata;
  
@@ -42,9 +42,9 @@ index af11511..1e708a2 100644
  #ifdef CONFIG_MACH_NOKIA_N8X0
  static void __init omap2420_n8x0_legacy_init(void)
  {
-@@ -319,6 +327,10 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
- 	OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
- 		       &am35xx_emac_pdata),
+@@ -340,6 +348,10 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+ 	OF_DEV_AUXDATA("ti,am3352-wkup-m3-ipc", 0x44e11324, "44e11324.wkup_m3",
+ 		       &wkup_m3_ipc_pm_data),
  #endif
 +#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
 +	OF_DEV_AUXDATA("ti,sgx", 0x56000000, "56000000.sgx",
diff --git a/version.sh b/version.sh
index 9fa1c9d33e951b3ef04e9e31afbc5dbcd024662f..a8aebab3cea8bce9eb5ab204f78c024e3a38955f 100644
--- a/version.sh
+++ b/version.sh
@@ -14,7 +14,7 @@ toolchain="gcc_linaro_gnueabihf_4_9"
 #Kernel/Build
 KERNEL_REL=4.1
 KERNEL_TAG=${KERNEL_REL}.1
-BUILD=bone9.4
+BUILD=bone9.5
 
 #v3.X-rcX + upto SHA
 #prev_KERNEL_SHA=""