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=""