summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/Makefile16
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c4
-rw-r--r--arch/arm/mach-omap2/common.h7
-rw-r--r--arch/arm/mach-omap2/io.c2
-rw-r--r--arch/arm/mach-omap2/omap_device.c5
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c418
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h7
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c86
-rw-r--r--arch/arm/mach-omap2/pm-asm-offsets.c31
-rw-r--r--arch/arm/mach-omap2/pm.h3
-rw-r--r--arch/arm/mach-omap2/pm33xx-core.c189
-rw-r--r--arch/arm/mach-omap2/sleep33xx.S214
-rw-r--r--arch/arm/mach-omap2/sleep43xx.S387
-rw-r--r--arch/arm/mach-omap2/sr_device.c27
-rw-r--r--arch/arm/mach-omap2/timer.c2
16 files changed, 1351 insertions, 48 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 00b1f17f8d44..9f27b486a536 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -72,6 +72,7 @@ config SOC_AM43XX
select ARM_ERRATA_754322
select ARM_ERRATA_775420
select OMAP_INTERCONNECT
+ select ARM_CPU_SUSPEND if PM
config SOC_DRA7XX
bool "TI DRA7XX"
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index c15bbcad5f67..4603c30fef73 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -88,6 +88,8 @@ omap-4-5-pm-common += pm44xx.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-core.o sleep33xx.o
+obj-$(CONFIG_SOC_AM43XX) += pm33xx-core.o sleep43xx.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
@@ -95,6 +97,8 @@ 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)
+AFLAGS_sleep43xx.o :=-Wa,-march=armv7-a$(plus_sec)
endif
@@ -232,3 +236,15 @@ obj-y += $(omap-hsmmc-m) $(omap-hsmmc-y)
obj-y += omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
+
+arch/arm/mach-omap2/pm-asm-offsets.s: arch/arm/mach-omap2/pm-asm-offsets.c
+ $(call if_changed_dep,cc_s_c)
+
+include/generated/ti-pm-asm-offsets.h: arch/arm/mach-omap2/pm-asm-offsets.s FORCE
+ $(call filechk,offsets,__TI_PM_ASM_OFFSETS_H__)
+
+# For rule to generate ti-emif-asm-offsets.h dependency
+include drivers/memory/Makefile.asm-offsets
+
+arch/arm/mach-omap2/sleep33xx.o: include/generated/ti-pm-asm-offsets.h include/generated/ti-emif-asm-offsets.h
+arch/arm/mach-omap2/sleep43xx.o: include/generated/ti-pm-asm-offsets.h include/generated/ti-emif-asm-offsets.h
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 20f25539d572..75bc18646df6 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -566,11 +566,11 @@ static int n8x0_menelaus_late_init(struct device *dev)
}
#endif
-struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
+struct menelaus_platform_data n8x0_menelaus_platform_data = {
.late_init = n8x0_menelaus_late_init,
};
-struct aic3x_pdata n810_aic33_data __initdata = {
+struct aic3x_pdata n810_aic33_data = {
.gpio_reset = 118,
};
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index bc202835371b..fbe0b78bf489 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -77,6 +77,13 @@ static inline int omap4_pm_init_early(void)
}
#endif
+#if defined(CONFIG_PM) && (defined(CONFIG_SOC_AM33XX) || \
+ defined(CONFIG_SOC_AM43XX))
+void amx3_common_pm_init(void);
+#else
+static inline void amx3_common_pm_init(void) { }
+#endif
+
extern void omap2_init_common_infrastructure(void);
extern void omap_init_time(void);
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index cb5d7314cf99..cf546dfe3b32 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -622,6 +622,7 @@ void __init am33xx_init_early(void)
void __init am33xx_init_late(void)
{
omap_common_late_init();
+ amx3_common_pm_init();
}
#endif
@@ -646,6 +647,7 @@ void __init am43xx_init_late(void)
{
omap_common_late_init();
omap2_clk_enable_autoidle_all();
+ amx3_common_pm_init();
}
#endif
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index f0388058b7da..3b829a50d1db 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -140,6 +140,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
struct omap_device *od;
struct omap_hwmod *oh;
struct device_node *node = pdev->dev.of_node;
+ struct resource res;
const char *oh_name;
int oh_cnt, i, ret = 0;
bool device_active = false;
@@ -150,6 +151,10 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
return -ENODEV;
}
+ /* Use ti-sysc driver instead of omap_device? */
+ if (!omap_hwmod_parse_module_range(NULL, node, &res))
+ return -ENODEV;
+
hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
if (!hwmods) {
ret = -ENOMEM;
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 34156eca8e23..e7d23e200ecc 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -145,6 +145,8 @@
#include <linux/platform_data/ti-sysc.h>
+#include <dt-bindings/bus/ti-sysc.h>
+
#include <asm/system_misc.h>
#include "clock.h"
@@ -2498,7 +2500,7 @@ static void __init _setup_postsetup(struct omap_hwmod *oh)
* affects the IP block hardware, or system integration hardware
* associated with the IP block. Returns 0.
*/
-static int __init _setup(struct omap_hwmod *oh, void *data)
+static int _setup(struct omap_hwmod *oh, void *data)
{
if (oh->_state != _HWMOD_STATE_INITIALIZED)
return 0;
@@ -3060,6 +3062,414 @@ int __init omap_hwmod_setup_one(const char *oh_name)
return 0;
}
+static void omap_hwmod_check_one(struct device *dev,
+ const char *name, s8 v1, u8 v2)
+{
+ if (v1 < 0)
+ return;
+
+ if (v1 != v2)
+ dev_warn(dev, "%s %d != %d\n", name, v1, v2);
+}
+
+/**
+ * omap_hwmod_check_sysc - check sysc against platform sysc
+ * @dev: struct device
+ * @data: module data
+ * @sysc_fields: new sysc configuration
+ */
+static int omap_hwmod_check_sysc(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ struct sysc_regbits *sysc_fields)
+{
+ const struct sysc_regbits *regbits = data->cap->regbits;
+
+ omap_hwmod_check_one(dev, "dmadisable_shift",
+ regbits->dmadisable_shift,
+ sysc_fields->dmadisable_shift);
+ omap_hwmod_check_one(dev, "midle_shift",
+ regbits->midle_shift,
+ sysc_fields->midle_shift);
+ omap_hwmod_check_one(dev, "sidle_shift",
+ regbits->sidle_shift,
+ sysc_fields->sidle_shift);
+ omap_hwmod_check_one(dev, "clkact_shift",
+ regbits->clkact_shift,
+ sysc_fields->clkact_shift);
+ omap_hwmod_check_one(dev, "enwkup_shift",
+ regbits->enwkup_shift,
+ sysc_fields->enwkup_shift);
+ omap_hwmod_check_one(dev, "srst_shift",
+ regbits->srst_shift,
+ sysc_fields->srst_shift);
+ omap_hwmod_check_one(dev, "autoidle_shift",
+ regbits->autoidle_shift,
+ sysc_fields->autoidle_shift);
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_init_regbits - init sysconfig specific register bits
+ * @dev: struct device
+ * @data: module data
+ * @sysc_fields: new sysc configuration
+ */
+static int omap_hwmod_init_regbits(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ struct sysc_regbits **sysc_fields)
+{
+ *sysc_fields = NULL;
+
+ switch (data->cap->type) {
+ case TI_SYSC_OMAP2:
+ case TI_SYSC_OMAP2_TIMER:
+ *sysc_fields = &omap_hwmod_sysc_type1;
+ break;
+ case TI_SYSC_OMAP3_SHAM:
+ *sysc_fields = &omap3_sham_sysc_fields;
+ break;
+ case TI_SYSC_OMAP3_AES:
+ *sysc_fields = &omap3xxx_aes_sysc_fields;
+ break;
+ case TI_SYSC_OMAP4:
+ case TI_SYSC_OMAP4_TIMER:
+ *sysc_fields = &omap_hwmod_sysc_type2;
+ break;
+ case TI_SYSC_OMAP4_SIMPLE:
+ *sysc_fields = &omap_hwmod_sysc_type3;
+ break;
+ case TI_SYSC_OMAP34XX_SR:
+ *sysc_fields = &omap34xx_sr_sysc_fields;
+ break;
+ case TI_SYSC_OMAP36XX_SR:
+ *sysc_fields = &omap36xx_sr_sysc_fields;
+ break;
+ case TI_SYSC_OMAP4_SR:
+ *sysc_fields = &omap36xx_sr_sysc_fields;
+ break;
+ case TI_SYSC_OMAP4_MCASP:
+ *sysc_fields = &omap_hwmod_sysc_type_mcasp;
+ break;
+ case TI_SYSC_OMAP4_USB_HOST_FS:
+ *sysc_fields = &omap_hwmod_sysc_type_usb_host_fs;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return omap_hwmod_check_sysc(dev, data, *sysc_fields);
+}
+
+/**
+ * omap_hwmod_init_reg_offs - initialize sysconfig register offsets
+ * @dev: struct device
+ * @data: module data
+ * @rev_offs: revision register offset
+ * @sysc_offs: sysc register offset
+ * @syss_offs: syss register offset
+ */
+int omap_hwmod_init_reg_offs(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ u32 *rev_offs, u32 *sysc_offs, u32 *syss_offs)
+{
+ *rev_offs = 0;
+ *sysc_offs = 0;
+ *syss_offs = 0;
+
+ if (data->offsets[SYSC_REVISION] > 0)
+ *rev_offs = data->offsets[SYSC_REVISION];
+
+ if (data->offsets[SYSC_SYSCONFIG] > 0)
+ *sysc_offs = data->offsets[SYSC_SYSCONFIG];
+
+ if (data->offsets[SYSC_SYSSTATUS] > 0)
+ *syss_offs = data->offsets[SYSC_SYSSTATUS];
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_init_sysc_flags - initialize sysconfig features
+ * @dev: struct device
+ * @data: module data
+ * @sysc_flags: module configuration
+ */
+int omap_hwmod_init_sysc_flags(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ u32 *sysc_flags)
+{
+ *sysc_flags = 0;
+
+ switch (data->cap->type) {
+ case TI_SYSC_OMAP2:
+ case TI_SYSC_OMAP2_TIMER:
+ /* See SYSC_OMAP2_* in include/dt-bindings/bus/ti-sysc.h */
+ if (data->cfg->sysc_val & SYSC_OMAP2_CLOCKACTIVITY)
+ *sysc_flags |= SYSC_HAS_CLOCKACTIVITY;
+ if (data->cfg->sysc_val & SYSC_OMAP2_EMUFREE)
+ *sysc_flags |= SYSC_HAS_EMUFREE;
+ if (data->cfg->sysc_val & SYSC_OMAP2_ENAWAKEUP)
+ *sysc_flags |= SYSC_HAS_ENAWAKEUP;
+ if (data->cfg->sysc_val & SYSC_OMAP2_SOFTRESET)
+ *sysc_flags |= SYSC_HAS_SOFTRESET;
+ if (data->cfg->sysc_val & SYSC_OMAP2_AUTOIDLE)
+ *sysc_flags |= SYSC_HAS_AUTOIDLE;
+ break;
+ case TI_SYSC_OMAP4:
+ case TI_SYSC_OMAP4_TIMER:
+ /* See SYSC_OMAP4_* in include/dt-bindings/bus/ti-sysc.h */
+ if (data->cfg->sysc_val & SYSC_OMAP4_DMADISABLE)
+ *sysc_flags |= SYSC_HAS_DMADISABLE;
+ if (data->cfg->sysc_val & SYSC_OMAP4_FREEEMU)
+ *sysc_flags |= SYSC_HAS_EMUFREE;
+ if (data->cfg->sysc_val & SYSC_OMAP4_SOFTRESET)
+ *sysc_flags |= SYSC_HAS_SOFTRESET;
+ break;
+ case TI_SYSC_OMAP34XX_SR:
+ case TI_SYSC_OMAP36XX_SR:
+ /* See SYSC_OMAP3_SR_* in include/dt-bindings/bus/ti-sysc.h */
+ if (data->cfg->sysc_val & SYSC_OMAP3_SR_ENAWAKEUP)
+ *sysc_flags |= SYSC_HAS_ENAWAKEUP;
+ break;
+ default:
+ if (data->cap->regbits->emufree_shift >= 0)
+ *sysc_flags |= SYSC_HAS_EMUFREE;
+ if (data->cap->regbits->enwkup_shift >= 0)
+ *sysc_flags |= SYSC_HAS_ENAWAKEUP;
+ if (data->cap->regbits->srst_shift >= 0)
+ *sysc_flags |= SYSC_HAS_SOFTRESET;
+ if (data->cap->regbits->autoidle_shift >= 0)
+ *sysc_flags |= SYSC_HAS_AUTOIDLE;
+ break;
+ }
+
+ if (data->cap->regbits->midle_shift >= 0 &&
+ data->cfg->midlemodes)
+ *sysc_flags |= SYSC_HAS_MIDLEMODE;
+
+ if (data->cap->regbits->sidle_shift >= 0 &&
+ data->cfg->sidlemodes)
+ *sysc_flags |= SYSC_HAS_SIDLEMODE;
+
+ if (data->cfg->quirks & SYSC_QUIRK_UNCACHED)
+ *sysc_flags |= SYSC_NO_CACHE;
+ if (data->cfg->quirks & SYSC_QUIRK_RESET_STATUS)
+ *sysc_flags |= SYSC_HAS_RESET_STATUS;
+
+ if (data->cfg->syss_mask & 1)
+ *sysc_flags |= SYSS_HAS_RESET_STATUS;
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_init_idlemodes - initialize module idle modes
+ * @dev: struct device
+ * @data: module data
+ * @idlemodes: module supported idle modes
+ */
+int omap_hwmod_init_idlemodes(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ u32 *idlemodes)
+{
+ *idlemodes = 0;
+
+ if (data->cfg->midlemodes & BIT(SYSC_IDLE_FORCE))
+ *idlemodes |= MSTANDBY_FORCE;
+ if (data->cfg->midlemodes & BIT(SYSC_IDLE_NO))
+ *idlemodes |= MSTANDBY_NO;
+ if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART))
+ *idlemodes |= MSTANDBY_SMART;
+ if (data->cfg->midlemodes & BIT(SYSC_IDLE_SMART_WKUP))
+ *idlemodes |= MSTANDBY_SMART_WKUP;
+
+ if (data->cfg->sidlemodes & BIT(SYSC_IDLE_FORCE))
+ *idlemodes |= SIDLE_FORCE;
+ if (data->cfg->sidlemodes & BIT(SYSC_IDLE_NO))
+ *idlemodes |= SIDLE_NO;
+ if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART))
+ *idlemodes |= SIDLE_SMART;
+ if (data->cfg->sidlemodes & BIT(SYSC_IDLE_SMART_WKUP))
+ *idlemodes |= SIDLE_SMART_WKUP;
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_check_module - check new module against platform data
+ * @dev: struct device
+ * @oh: module
+ * @data: new module data
+ * @sysc_fields: sysc register bits
+ * @rev_offs: revision register offset
+ * @sysc_offs: sysconfig register offset
+ * @syss_offs: sysstatus register offset
+ * @sysc_flags: sysc specific flags
+ * @idlemodes: sysc supported idlemodes
+ */
+static int omap_hwmod_check_module(struct device *dev,
+ struct omap_hwmod *oh,
+ const struct ti_sysc_module_data *data,
+ struct sysc_regbits *sysc_fields,
+ u32 rev_offs, u32 sysc_offs,
+ u32 syss_offs, u32 sysc_flags,
+ u32 idlemodes)
+{
+ if (!oh->class->sysc)
+ return -ENODEV;
+
+ if (sysc_fields != oh->class->sysc->sysc_fields)
+ dev_warn(dev, "sysc_fields %p != %p\n", sysc_fields,
+ oh->class->sysc->sysc_fields);
+
+ if (rev_offs != oh->class->sysc->rev_offs)
+ dev_warn(dev, "rev_offs %08x != %08x\n", rev_offs,
+ oh->class->sysc->rev_offs);
+ if (sysc_offs != oh->class->sysc->sysc_offs)
+ dev_warn(dev, "sysc_offs %08x != %08x\n", sysc_offs,
+ oh->class->sysc->sysc_offs);
+ if (syss_offs != oh->class->sysc->syss_offs)
+ dev_warn(dev, "syss_offs %08x != %08x\n", syss_offs,
+ oh->class->sysc->syss_offs);
+
+ if (sysc_flags != oh->class->sysc->sysc_flags)
+ dev_warn(dev, "sysc_flags %08x != %08x\n", sysc_flags,
+ oh->class->sysc->sysc_flags);
+
+ if (idlemodes != oh->class->sysc->idlemodes)
+ dev_warn(dev, "idlemodes %08x != %08x\n", idlemodes,
+ oh->class->sysc->idlemodes);
+
+ if (data->cfg->srst_udelay != oh->class->sysc->srst_udelay)
+ dev_warn(dev, "srst_udelay %i != %i\n",
+ data->cfg->srst_udelay,
+ oh->class->sysc->srst_udelay);
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_allocate_module - allocate new module
+ * @dev: struct device
+ * @oh: module
+ * @sysc_fields: sysc register bits
+ * @rev_offs: revision register offset
+ * @sysc_offs: sysconfig register offset
+ * @syss_offs: sysstatus register offset
+ * @sysc_flags: sysc specific flags
+ * @idlemodes: sysc supported idlemodes
+ *
+ * Note that the allocations here cannot use devm as ti-sysc can rebind.
+ */
+int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
+ const struct ti_sysc_module_data *data,
+ struct sysc_regbits *sysc_fields,
+ u32 rev_offs, u32 sysc_offs, u32 syss_offs,
+ u32 sysc_flags, u32 idlemodes)
+{
+ struct omap_hwmod_class_sysconfig *sysc;
+ struct omap_hwmod_class *class;
+ void __iomem *regs = NULL;
+ unsigned long flags;
+
+ sysc = kzalloc(sizeof(*sysc), GFP_KERNEL);
+ if (!sysc)
+ return -ENOMEM;
+
+ sysc->sysc_fields = sysc_fields;
+ sysc->rev_offs = rev_offs;
+ sysc->sysc_offs = sysc_offs;
+ sysc->syss_offs = syss_offs;
+ sysc->sysc_flags = sysc_flags;
+ sysc->idlemodes = idlemodes;
+ sysc->srst_udelay = data->cfg->srst_udelay;
+
+ if (!oh->_mpu_rt_va) {
+ regs = ioremap(data->module_pa,
+ data->module_size);
+ if (!regs)
+ return -ENOMEM;
+ }
+
+ /*
+ * We need new oh->class as the other devices in the same class
+ * may not yet have ioremapped their registers.
+ */
+ class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
+ if (!class)
+ return -ENOMEM;
+
+ class->sysc = sysc;
+
+ spin_lock_irqsave(&oh->_lock, flags);
+ if (regs)
+ oh->_mpu_rt_va = regs;
+ oh->class = class;
+ oh->_state = _HWMOD_STATE_INITIALIZED;
+ _setup(oh, NULL);
+ spin_unlock_irqrestore(&oh->_lock, flags);
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_init_module - initialize new module
+ * @dev: struct device
+ * @data: module data
+ * @cookie: cookie for the caller to use for later calls
+ */
+int omap_hwmod_init_module(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ struct ti_sysc_cookie *cookie)
+{
+ struct omap_hwmod *oh;
+ struct sysc_regbits *sysc_fields;
+ u32 rev_offs, sysc_offs, syss_offs, sysc_flags, idlemodes;
+ int error;
+
+ if (!dev || !data)
+ return -EINVAL;
+
+ oh = _lookup(data->name);
+ if (!oh)
+ return -ENODEV;
+
+ cookie->data = oh;
+
+ error = omap_hwmod_init_regbits(dev, data, &sysc_fields);
+ if (error)
+ return error;
+
+ error = omap_hwmod_init_reg_offs(dev, data, &rev_offs,
+ &sysc_offs, &syss_offs);
+ if (error)
+ return error;
+
+ error = omap_hwmod_init_sysc_flags(dev, data, &sysc_flags);
+ if (error)
+ return error;
+
+ error = omap_hwmod_init_idlemodes(dev, data, &idlemodes);
+ if (error)
+ return error;
+
+ if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
+ oh->flags |= HWMOD_INIT_NO_IDLE;
+ if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
+ oh->flags |= HWMOD_INIT_NO_RESET;
+
+ error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
+ rev_offs, sysc_offs, syss_offs,
+ sysc_flags, idlemodes);
+ if (!error)
+ return error;
+
+ return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
+ rev_offs, sysc_offs, syss_offs,
+ sysc_flags, idlemodes);
+}
+
/**
* omap_hwmod_setup_earlycon_flags - set up flags for early console
*
@@ -3082,6 +3492,12 @@ static void __init omap_hwmod_setup_earlycon_flags(void)
if (np) {
uart = of_get_property(np, "ti,hwmods", NULL);
oh = omap_hwmod_lookup(uart);
+ if (!oh) {
+ uart = of_get_property(np->parent,
+ "ti,hwmods",
+ NULL);
+ oh = omap_hwmod_lookup(uart);
+ }
if (oh)
oh->flags |= DEBUG_OMAPUART_FLAGS;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index 0b8e19f40402..c7122abbf977 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -620,6 +620,13 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
struct device_node *np,
struct resource *res);
+struct ti_sysc_module_data;
+struct ti_sysc_cookie;
+
+int omap_hwmod_init_module(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ struct ti_sysc_cookie *cookie);
+
int omap_hwmod_enable(struct omap_hwmod *oh);
int omap_hwmod_idle(struct omap_hwmod *oh);
int omap_hwmod_shutdown(struct omap_hwmod *oh);
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 6b433fce65a5..6459816c2879 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -17,17 +17,17 @@
#include <linux/wl12xx.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/power/smartreflex.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
#include <linux/platform_data/pinctrl-single.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/platform_data/iommu-omap.h>
+#include <linux/platform_data/ti-sysc.h>
#include <linux/platform_data/wkup_m3.h>
-#include <linux/platform_data/pwm_omap_dmtimer.h>
#include <linux/platform_data/media/ir-rx51.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
-#include <plat/dmtimer.h>
#include "common.h"
#include "common-board-devices.h"
@@ -454,6 +454,43 @@ static void __init dra7x_evm_mmc_quirk(void)
}
#endif
+static int ti_sysc_enable_module(struct device *dev,
+ const struct ti_sysc_cookie *cookie)
+{
+ if (!cookie->data)
+ return -EINVAL;
+
+ return omap_hwmod_enable(cookie->data);
+}
+
+static int ti_sysc_idle_module(struct device *dev,
+ const struct ti_sysc_cookie *cookie)
+{
+ if (!cookie->data)
+ return -EINVAL;
+
+ return omap_hwmod_idle(cookie->data);
+}
+
+static int ti_sysc_shutdown_module(struct device *dev,
+ const struct ti_sysc_cookie *cookie)
+{
+ if (!cookie->data)
+ return -EINVAL;
+
+ return omap_hwmod_shutdown(cookie->data);
+}
+
+static struct of_dev_auxdata omap_auxdata_lookup[];
+
+static struct ti_sysc_platform_data ti_sysc_pdata = {
+ .auxdata = omap_auxdata_lookup,
+ .init_module = omap_hwmod_init_module,
+ .enable_module = ti_sysc_enable_module,
+ .idle_module = ti_sysc_idle_module,
+ .shutdown_module = ti_sysc_shutdown_module,
+};
+
static struct pcs_pdata pcs_pdata;
void omap_pcs_legacy_init(int irq, void (*rearm)(void))
@@ -477,33 +514,6 @@ void omap_auxdata_legacy_init(struct device *dev)
dev->platform_data = &twl_gpio_auxdata;
}
-/* Dual mode timer PWM callbacks platdata */
-#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
-static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = {
- .request_by_node = omap_dm_timer_request_by_node,
- .request_specific = omap_dm_timer_request_specific,
- .request = omap_dm_timer_request,
- .set_source = omap_dm_timer_set_source,
- .get_irq = omap_dm_timer_get_irq,
- .set_int_enable = omap_dm_timer_set_int_enable,
- .set_int_disable = omap_dm_timer_set_int_disable,
- .free = omap_dm_timer_free,
- .enable = omap_dm_timer_enable,
- .disable = omap_dm_timer_disable,
- .get_fclk = omap_dm_timer_get_fclk,
- .start = omap_dm_timer_start,
- .stop = omap_dm_timer_stop,
- .set_load = omap_dm_timer_set_load,
- .set_match = omap_dm_timer_set_match,
- .set_pwm = omap_dm_timer_set_pwm,
- .set_prescaler = omap_dm_timer_set_prescaler,
- .read_counter = omap_dm_timer_read_counter,
- .write_counter = omap_dm_timer_write_counter,
- .read_status = omap_dm_timer_read_status,
- .write_status = omap_dm_timer_write_status,
-};
-#endif
-
static struct ir_rx51_platform_data __maybe_unused rx51_ir_data = {
.set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
};
@@ -542,7 +552,9 @@ static struct pdata_init auxdata_quirks[] __initdata = {
{ /* sentinel */ },
};
-static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
+struct omap_sr_data __maybe_unused omap_sr_pdata[OMAP_SR_NR];
+
+static struct of_dev_auxdata omap_auxdata_lookup[] = {
#ifdef CONFIG_MACH_NOKIA_N8X0
OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
OF_DEV_AUXDATA("menelaus", 0x72, "1-0072", &n8x0_menelaus_platform_data),
@@ -551,6 +563,10 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
#ifdef CONFIG_ARCH_OMAP3
OF_DEV_AUXDATA("ti,omap2-iommu", 0x5d000000, "5d000000.mmu",
&omap3_iommu_pdata),
+ OF_DEV_AUXDATA("ti,omap3-smartreflex-core", 0x480cb000,
+ "480cb000.smartreflex", &omap_sr_pdata[OMAP_SR_CORE]),
+ OF_DEV_AUXDATA("ti,omap3-smartreflex-mpu-iva", 0x480c9000,
+ "480c9000.smartreflex", &omap_sr_pdata[OMAP_SR_MPU]),
OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]),
OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]),
OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_ir_data),
@@ -572,14 +588,17 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("ti,am4372-wkup-m3", 0x44d00000, "44d00000.wkup_m3",
&wkup_m3_data),
#endif
-#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
- OF_DEV_AUXDATA("ti,omap-dmtimer-pwm", 0, NULL, &pwm_dmtimer_pdata),
-#endif
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu",
&omap4_iommu_pdata),
OF_DEV_AUXDATA("ti,omap4-iommu", 0x55082000, "55082000.mmu",
&omap4_iommu_pdata),
+ OF_DEV_AUXDATA("ti,omap4-smartreflex-iva", 0x4a0db000,
+ "4a0db000.smartreflex", &omap_sr_pdata[OMAP_SR_IVA]),
+ OF_DEV_AUXDATA("ti,omap4-smartreflex-core", 0x4a0dd000,
+ "4a0dd000.smartreflex", &omap_sr_pdata[OMAP_SR_CORE]),
+ OF_DEV_AUXDATA("ti,omap4-smartreflex-mpu", 0x4a0d9000,
+ "4a0d9000.smartreflex", &omap_sr_pdata[OMAP_SR_MPU]),
#endif
#ifdef CONFIG_SOC_DRA7XX
OF_DEV_AUXDATA("ti,dra7-hsmmc", 0x4809c000, "4809c000.mmc",
@@ -590,6 +609,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
&dra7_hsmmc_data_mmc3),
#endif
/* Common auxdata */
+ OF_DEV_AUXDATA("ti,sysc", 0, NULL, &ti_sysc_pdata),
OF_DEV_AUXDATA("pinctrl-single", 0, NULL, &pcs_pdata),
{ /* sentinel */ },
};
diff --git a/arch/arm/mach-omap2/pm-asm-offsets.c b/arch/arm/mach-omap2/pm-asm-offsets.c
new file mode 100644
index 000000000000..6d4392da7c11
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-asm-offsets.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TI AM33XX and AM43XX PM Assembly Offsets
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Inc.
+ */
+
+#include <linux/kbuild.h>
+#include <linux/platform_data/pm33xx.h>
+
+int main(void)
+{
+ DEFINE(AMX3_PM_WFI_FLAGS_OFFSET,
+ offsetof(struct am33xx_pm_sram_data, wfi_flags));
+ DEFINE(AMX3_PM_L2_AUX_CTRL_VAL_OFFSET,
+ offsetof(struct am33xx_pm_sram_data, l2_aux_ctrl_val));
+ DEFINE(AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET,
+ offsetof(struct am33xx_pm_sram_data, l2_prefetch_ctrl_val));
+ DEFINE(AMX3_PM_SRAM_DATA_SIZE, sizeof(struct am33xx_pm_sram_data));
+
+ BLANK();
+
+ DEFINE(AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET,
+ offsetof(struct am33xx_pm_ro_sram_data, amx3_pm_sram_data_virt));
+ DEFINE(AMX3_PM_RO_SRAM_DATA_PHYS_OFFSET,
+ offsetof(struct am33xx_pm_ro_sram_data, amx3_pm_sram_data_phys));
+ DEFINE(AMX3_PM_RO_SRAM_DATA_SIZE,
+ sizeof(struct am33xx_pm_ro_sram_data));
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 8e30772cfe32..c73776b82348 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -81,6 +81,9 @@ extern unsigned int omap3_do_wfi_sz;
/* ... and its pointer from SRAM after copy */
extern void (*omap3_do_wfi_sram)(void);
+extern struct am33xx_pm_sram_addr am33xx_pm_sram;
+extern struct am33xx_pm_sram_addr am43xx_pm_sram;
+
extern void omap3_save_scratchpad_contents(void);
#define PM_RTA_ERRATUM_i608 (1 << 0)
diff --git a/arch/arm/mach-omap2/pm33xx-core.c b/arch/arm/mach-omap2/pm33xx-core.c
new file mode 100644
index 000000000000..93c0b5ba9f09
--- /dev/null
+++ b/arch/arm/mach-omap2/pm33xx-core.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AM33XX Arch Power Management Routines
+ *
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach
+ */
+
+#include <asm/smp_scu.h>
+#include <asm/suspend.h>
+#include <linux/errno.h>
+#include <linux/platform_data/pm33xx.h>
+
+#include "cm33xx.h"
+#include "common.h"
+#include "control.h"
+#include "clockdomain.h"
+#include "iomap.h"
+#include "omap_hwmod.h"
+#include "pm.h"
+#include "powerdomain.h"
+#include "prm33xx.h"
+#include "soc.h"
+#include "sram.h"
+
+static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
+static struct clockdomain *gfx_l4ls_clkdm;
+static void __iomem *scu_base;
+
+static int __init am43xx_map_scu(void)
+{
+ scu_base = ioremap(scu_a9_get_base(), SZ_256);
+
+ if (!scu_base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int amx3_common_init(void)
+{
+ gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
+ per_pwrdm = pwrdm_lookup("per_pwrdm");
+ mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+
+ if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm))
+ 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_err("PM: Failed to get cefuse_pwrdm\n");
+
+ return 0;
+}
+
+static int am33xx_suspend_init(void)
+{
+ int ret;
+
+ gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
+
+ if (!gfx_l4ls_clkdm) {
+ pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n");
+ return -ENODEV;
+ }
+
+ ret = amx3_common_init();
+
+ return ret;
+}
+
+static int am43xx_suspend_init(void)
+{
+ int ret = 0;
+
+ ret = am43xx_map_scu();
+ if (ret) {
+ pr_err("PM: Could not ioremap SCU\n");
+ return ret;
+ }
+
+ ret = amx3_common_init();
+
+ return ret;
+}
+
+static void amx3_pre_suspend_common(void)
+{
+ omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
+}
+
+static void amx3_post_suspend_common(void)
+{
+ int status;
+ /*
+ * Because gfx_pwrdm is the only one under MPU control,
+ * comment on transition status
+ */
+ status = pwrdm_read_pwrst(gfx_pwrdm);
+ if (status != PWRDM_POWER_OFF)
+ pr_err("PM: GFX domain did not transition: %x\n", status);
+}
+
+static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long))
+{
+ int ret = 0;
+
+ amx3_pre_suspend_common();
+ ret = cpu_suspend(0, fn);
+ amx3_post_suspend_common();
+
+ /*
+ * 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);
+
+ return ret;
+}
+
+static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long))
+{
+ int ret = 0;
+
+ amx3_pre_suspend_common();
+ scu_power_mode(scu_base, SCU_PM_POWEROFF);
+ ret = cpu_suspend(0, fn);
+ scu_power_mode(scu_base, SCU_PM_NORMAL);
+ amx3_post_suspend_common();
+
+ return ret;
+}
+
+static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
+{
+ if (soc_is_am33xx())
+ return &am33xx_pm_sram;
+ else if (soc_is_am437x())
+ return &am43xx_pm_sram;
+ else
+ return NULL;
+}
+
+static struct am33xx_pm_platform_data am33xx_ops = {
+ .init = am33xx_suspend_init,
+ .soc_suspend = am33xx_suspend,
+ .get_sram_addrs = amx3_get_sram_addrs,
+};
+
+static struct am33xx_pm_platform_data am43xx_ops = {
+ .init = am43xx_suspend_init,
+ .soc_suspend = am43xx_suspend,
+ .get_sram_addrs = amx3_get_sram_addrs,
+};
+
+static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void)
+{
+ if (soc_is_am33xx())
+ return &am33xx_ops;
+ else if (soc_is_am437x())
+ return &am43xx_ops;
+ else
+ return NULL;
+}
+
+void __init amx3_common_pm_init(void)
+{
+ struct am33xx_pm_platform_data *pdata;
+ struct platform_device_info devinfo;
+
+ pdata = am33xx_pm_get_pdata();
+
+ memset(&devinfo, 0, sizeof(devinfo));
+ devinfo.name = "pm33xx";
+ devinfo.data = pdata;
+ devinfo.size_data = sizeof(*pdata);
+ devinfo.id = -1;
+ platform_device_register_full(&devinfo);
+}
diff --git a/arch/arm/mach-omap2/sleep33xx.S b/arch/arm/mach-omap2/sleep33xx.S
new file mode 100644
index 000000000000..218d79930b04
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep33xx.S
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach, Vaibhav Bedia
+ */
+
+#include <generated/ti-emif-asm-offsets.h>
+#include <generated/ti-pm-asm-offsets.h>
+#include <linux/linkage.h>
+#include <linux/ti-emif-sram.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+#include "iomap.h"
+#include "cm33xx.h"
+
+#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 0x00030000
+#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 0x0003
+#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 0x0002
+
+ .arm
+ .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
+
+ adr r9, am33xx_emif_sram_table
+
+ ldr r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
+ blx r3
+
+ ldr r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
+ blx r3
+
+ /* 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]
+ mov r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED
+ 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, [r9, #EMIF_PM_ABORT_SR_OFFSET]
+ 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 r9, am33xx_emif_sram_table
+
+ ldr r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET]
+ blx r1
+
+ ldr r1, [r9, #EMIF_PM_EXIT_SR_OFFSET]
+ 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)
+
+.align 3
+/* DDR related defines */
+am33xx_emif_sram_table:
+ .space EMIF_PM_FUNCTIONS_SIZE
+
+ENTRY(am33xx_pm_sram)
+ .word am33xx_do_wfi
+ .word am33xx_do_wfi_sz
+ .word am33xx_resume_offset
+ .word am33xx_emif_sram_table
+ .word am33xx_pm_ro_sram_data
+
+.align 3
+ENTRY(am33xx_pm_ro_sram_data)
+ .space AMX3_PM_RO_SRAM_DATA_SIZE
+
+ENTRY(am33xx_do_wfi_sz)
+ .word . - am33xx_do_wfi
diff --git a/arch/arm/mach-omap2/sleep43xx.S b/arch/arm/mach-omap2/sleep43xx.S
new file mode 100644
index 000000000000..59770a69396b
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep43xx.S
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Low level suspend code for AM43XX SoCs
+ *
+ * Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach, Vaibhav Bedia
+ */
+
+#include <generated/ti-emif-asm-offsets.h>
+#include <generated/ti-pm-asm-offsets.h>
+#include <linux/linkage.h>
+#include <linux/ti-emif-sram.h>
+
+#include <asm/assembler.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/memory.h>
+
+#include "cm33xx.h"
+#include "common.h"
+#include "iomap.h"
+#include "omap-secure.h"
+#include "omap44xx.h"
+#include "prm33xx.h"
+#include "prcm43xx.h"
+
+#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 0x00030000
+#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 0x0003
+#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 0x0002
+
+#define AM43XX_EMIF_POWEROFF_ENABLE 0x1
+#define AM43XX_EMIF_POWEROFF_DISABLE 0x0
+
+#define AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP 0x1
+#define AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO 0x3
+
+#define AM43XX_CM_BASE 0x44DF0000
+
+#define AM43XX_CM_REGADDR(inst, reg) \
+ AM33XX_L4_WK_IO_ADDRESS(AM43XX_CM_BASE + (inst) + (reg))
+
+#define AM43XX_CM_MPU_CLKSTCTRL AM43XX_CM_REGADDR(AM43XX_CM_MPU_INST, \
+ AM43XX_CM_MPU_MPU_CDOFFS)
+#define AM43XX_CM_MPU_MPU_CLKCTRL AM43XX_CM_REGADDR(AM43XX_CM_MPU_INST, \
+ AM43XX_CM_MPU_MPU_CLKCTRL_OFFSET)
+#define AM43XX_CM_PER_EMIF_CLKCTRL AM43XX_CM_REGADDR(AM43XX_CM_PER_INST, \
+ AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET)
+#define AM43XX_PRM_EMIF_CTRL_OFFSET 0x0030
+
+ .arm
+ .align 3
+
+ENTRY(am43xx_do_wfi)
+ stmfd sp!, {r4 - r11, lr} @ save registers on stack
+
+ /* Retrieve l2 cache virt address BEFORE we shut off EMIF */
+ ldr r1, get_l2cache_base
+ blx r1
+ mov r8, r0
+
+ /*
+ * 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
+ dsb
+
+ /*
+ * Invalidate L1 and L2 data cache.
+ */
+ ldr r1, kernel_flush
+ blx r1
+
+#ifdef CONFIG_CACHE_L2X0
+ /*
+ * Clean and invalidate the L2 cache.
+ */
+#ifdef CONFIG_PL310_ERRATA_727915
+ mov r0, #0x03
+ mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
+ dsb
+ smc #0
+ dsb
+#endif
+ mov r0, r8
+ adr r4, am43xx_pm_ro_sram_data
+ ldr r3, [r4, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
+
+ mov r2, r0
+ ldr r0, [r2, #L2X0_AUX_CTRL]
+ str r0, [r3, #AMX3_PM_L2_AUX_CTRL_VAL_OFFSET]
+ ldr r0, [r2, #L310_PREFETCH_CTRL]
+ str r0, [r3, #AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET]
+
+ ldr r0, l2_val
+ str r0, [r2, #L2X0_CLEAN_INV_WAY]
+wait:
+ ldr r0, [r2, #L2X0_CLEAN_INV_WAY]
+ ldr r1, l2_val
+ ands r0, r0, r1
+ bne wait
+#ifdef CONFIG_PL310_ERRATA_727915
+ mov r0, #0x00
+ mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
+ dsb
+ smc #0
+ dsb
+#endif
+l2x_sync:
+ mov r0, r8
+ mov r2, r0
+ mov r0, #0x0
+ str r0, [r2, #L2X0_CACHE_SYNC]
+sync:
+ ldr r0, [r2, #L2X0_CACHE_SYNC]
+ ands r0, r0, #0x1
+ bne sync
+#endif
+
+ adr r9, am43xx_emif_sram_table
+
+ ldr r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
+ blx r3
+
+ ldr r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
+ blx r3
+
+ /* Disable EMIF */
+ ldr r1, am43xx_virt_emif_clkctrl
+ ldr r2, [r1]
+ bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
+ str r2, [r1]
+
+wait_emif_disable:
+ ldr r2, [r1]
+ mov r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED
+ 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, am43xx_virt_mpu_clkctrl
+ ldr r2, [r1]
+ bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
+ str r2, [r1]
+
+ /*
+ * Put MPU CLKDM to SW_SLEEP
+ */
+ ldr r1, am43xx_virt_mpu_clkstctrl
+ mov r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP
+ str r2, [r1]
+
+ /*
+ * 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. Sixteen
+ * NOPs as per Cortex-A9 pipeline.
+ */
+ wfi
+
+ nop
+ nop
+ nop
+ 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 */
+ ldr r1, am43xx_virt_mpu_clkstctrl
+ mov r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO
+ str r2, [r1]
+
+ /* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
+ ldr r1, am43xx_virt_mpu_clkctrl
+ mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
+ str r2, [r1]
+
+ /* Re-enable EMIF */
+ ldr r1, am43xx_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
+
+ /*
+ * 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
+
+ ldr r1, [r9, #EMIF_PM_ABORT_SR_OFFSET]
+ blx r1
+
+ /* Let the suspend code know about the abort */
+ mov r0, #1
+ ldmfd sp!, {r4 - r11, pc} @ restore regs and return
+ENDPROC(am43xx_do_wfi)
+
+ .align
+ENTRY(am43xx_resume_offset)
+ .word . - am43xx_do_wfi
+
+ENTRY(am43xx_resume_from_deep_sleep)
+ /* Set MPU CLKSTCTRL to HW AUTO so that CPUidle works properly */
+ ldr r1, am43xx_virt_mpu_clkstctrl
+ mov r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO
+ str r2, [r1]
+
+ /* For AM43xx, use EMIF power down until context is restored */
+ ldr r2, am43xx_phys_emif_poweroff
+ mov r1, #AM43XX_EMIF_POWEROFF_ENABLE
+ str r1, [r2, #0x0]
+
+ /* Re-enable EMIF */
+ ldr r1, am43xx_phys_emif_clkctrl
+ mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
+ str r2, [r1]
+wait_emif_enable1:
+ ldr r3, [r1]
+ cmp r2, r3
+ bne wait_emif_enable1
+
+ adr r9, am43xx_emif_sram_table
+
+ ldr r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET]
+ blx r1
+
+ ldr r1, [r9, #EMIF_PM_EXIT_SR_OFFSET]
+ blx r1
+
+ ldr r2, am43xx_phys_emif_poweroff
+ mov r1, #AM43XX_EMIF_POWEROFF_DISABLE
+ str r1, [r2, #0x0]
+
+#ifdef CONFIG_CACHE_L2X0
+ ldr r2, l2_cache_base
+ ldr r0, [r2, #L2X0_CTRL]
+ and r0, #0x0f
+ cmp r0, #1
+ beq skip_l2en @ Skip if already enabled
+
+ adr r4, am43xx_pm_ro_sram_data
+ ldr r3, [r4, #AMX3_PM_RO_SRAM_DATA_PHYS_OFFSET]
+ ldr r0, [r3, #AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET]
+
+ ldr r12, l2_smc1
+ dsb
+ smc #0
+ dsb
+set_aux_ctrl:
+ ldr r0, [r3, #AMX3_PM_L2_AUX_CTRL_VAL_OFFSET]
+ ldr r12, l2_smc2
+ dsb
+ smc #0
+ dsb
+
+ /* L2 invalidate on resume */
+ ldr r0, l2_val
+ ldr r2, l2_cache_base
+ str r0, [r2, #L2X0_INV_WAY]
+wait2:
+ ldr r0, [r2, #L2X0_INV_WAY]
+ ldr r1, l2_val
+ ands r0, r0, r1
+ bne wait2
+#ifdef CONFIG_PL310_ERRATA_727915
+ mov r0, #0x00
+ mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
+ dsb
+ smc #0
+ dsb
+#endif
+l2x_sync2:
+ ldr r2, l2_cache_base
+ mov r0, #0x0
+ str r0, [r2, #L2X0_CACHE_SYNC]
+sync2:
+ ldr r0, [r2, #L2X0_CACHE_SYNC]
+ ands r0, r0, #0x1
+ bne sync2
+
+ mov r0, #0x1
+ ldr r12, l2_smc3
+ dsb
+ smc #0
+ dsb
+#endif
+skip_l2en:
+ /* We are back. Branch to the common CPU resume routine */
+ mov r0, #0
+ ldr pc, resume_addr
+ENDPROC(am43xx_resume_from_deep_sleep)
+
+/*
+ * Local variables
+ */
+ .align
+resume_addr:
+ .word cpu_resume - PAGE_OFFSET + 0x80000000
+get_l2cache_base:
+ .word omap4_get_l2cache_base
+kernel_flush:
+ .word v7_flush_dcache_all
+ddr_start:
+ .word PAGE_OFFSET
+
+am43xx_phys_emif_poweroff:
+ .word (AM43XX_CM_BASE + AM43XX_PRM_DEVICE_INST + \
+ AM43XX_PRM_EMIF_CTRL_OFFSET)
+am43xx_virt_mpu_clkstctrl:
+ .word (AM43XX_CM_MPU_CLKSTCTRL)
+am43xx_virt_mpu_clkctrl:
+ .word (AM43XX_CM_MPU_MPU_CLKCTRL)
+am43xx_virt_emif_clkctrl:
+ .word (AM43XX_CM_PER_EMIF_CLKCTRL)
+am43xx_phys_emif_clkctrl:
+ .word (AM43XX_CM_BASE + AM43XX_CM_PER_INST + \
+ AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET)
+
+/* L2 cache related defines for AM437x */
+l2_cache_base:
+ .word OMAP44XX_L2CACHE_BASE
+l2_smc1:
+ .word OMAP4_MON_L2X0_PREFETCH_INDEX
+l2_smc2:
+ .word OMAP4_MON_L2X0_AUXCTRL_INDEX
+l2_smc3:
+ .word OMAP4_MON_L2X0_CTRL_INDEX
+l2_val:
+ .word 0xffff
+
+.align 3
+/* DDR related defines */
+ENTRY(am43xx_emif_sram_table)
+ .space EMIF_PM_FUNCTIONS_SIZE
+
+ENTRY(am43xx_pm_sram)
+ .word am43xx_do_wfi
+ .word am43xx_do_wfi_sz
+ .word am43xx_resume_offset
+ .word am43xx_emif_sram_table
+ .word am43xx_pm_ro_sram_data
+
+.align 3
+
+ENTRY(am43xx_pm_ro_sram_data)
+ .space AMX3_PM_RO_SRAM_DATA_SIZE
+
+ENTRY(am43xx_do_wfi_sz)
+ .word . - am43xx_do_wfi
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index eef6935e0403..0854ed9ff379 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -89,18 +89,27 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
sr_data->nvalue_count = j;
}
+extern struct omap_sr_data omap_sr_pdata[];
+
static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
{
- struct omap_sr_data *sr_data;
- struct platform_device *pdev;
+ struct omap_sr_data *sr_data = NULL;
struct omap_volt_data *volt_data;
struct omap_smartreflex_dev_attr *sr_dev_attr;
- char *name = "smartreflex";
static int i;
- sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL);
- if (!sr_data)
- return -ENOMEM;
+ if (!strncmp(oh->name, "smartreflex_mpu_iva", 20) ||
+ !strncmp(oh->name, "smartreflex_mpu", 16))
+ sr_data = &omap_sr_pdata[OMAP_SR_MPU];
+ else if (!strncmp(oh->name, "smartreflex_core", 17))
+ sr_data = &omap_sr_pdata[OMAP_SR_CORE];
+ else if (!strncmp(oh->name, "smartreflex_iva", 16))
+ sr_data = &omap_sr_pdata[OMAP_SR_IVA];
+
+ if (!sr_data) {
+ pr_err("%s: Unknown instance %s\n", __func__, oh->name);
+ return -EINVAL;
+ }
sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr;
if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) {
@@ -145,13 +154,9 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
sr_data->enable_on_init = sr_enable_on_init;
- pdev = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data));
- if (IS_ERR(pdev))
- pr_warn("%s: Could not build omap_device for %s: %s\n",
- __func__, name, oh->name);
exit:
i++;
- kfree(sr_data);
+
return 0;
}
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index d61fbd7a2840..4fb4dc24e5e9 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -49,7 +49,7 @@
#include "omap_hwmod.h"
#include "omap_device.h"
#include <plat/counter-32k.h>
-#include <plat/dmtimer.h>
+#include <clocksource/timer-ti-dm.h>
#include "omap-pm.h"
#include "soc.h"
OpenPOWER on IntegriCloud