author | Tero Kristo <t-kristo@ti.com> | |
Mon, 27 May 2013 14:06:42 +0000 (17:06 +0300) | ||
committer | Tero Kristo <t-kristo@ti.com> | |
Mon, 27 May 2013 14:06:42 +0000 (17:06 +0300) |
Conflicts:
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/omap-hotplug.c
arch/arm/mach-omap2/omap-mpuss-lowpower.c
arch/arm/mach-omap2/pm_omap4plus.c
Signed-off-by: Tero Kristo <t-kristo@ti.com>
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/omap-hotplug.c
arch/arm/mach-omap2/omap-mpuss-lowpower.c
arch/arm/mach-omap2/pm_omap4plus.c
Signed-off-by: Tero Kristo <t-kristo@ti.com>
20 files changed:
diff --combined arch/arm/configs/omap2plus_defconfig
index e5b58cd8d5c0456471c60d651861e3830b8fb13f,dfa2f6d8af2c2f7143c7fcf45c35c89122911927..4a20e7d62cbfa886f3bc2f74ed4bd8cbcc2c645d
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
CONFIG_KEXEC=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_GENERIC_CPUFREQ_CPU0=y
+# CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set
CONFIG_FPE_NWFPE=y
CONFIG_BINFMT_MISC=y
CONFIG_PM_DEBUG=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
+ CONFIG_CAN=m
+ CONFIG_CAN_RAW=m
+ CONFIG_CAN_BCM=m
+ CONFIG_CAN_C_CAN=m
+ CONFIG_CAN_C_CAN_PLATFORM=m
CONFIG_BT=m
CONFIG_BT_HCIUART=m
CONFIG_BT_HCIUART_H4=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
+ CONFIG_SENSORS_LIS3LV02D=m
+ CONFIG_SENSORS_TSL2550=m
+ CONFIG_SENSORS_LIS3_I2C=m
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_INPUT_JOYDEV=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
+ CONFIG_KEYBOARD_MATRIX=m
CONFIG_KEYBOARD_TWL4030=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_GPIO_TWL4030=y
CONFIG_W1=y
CONFIG_POWER_SUPPLY=y
+ CONFIG_SENSORS_LM75=m
CONFIG_WATCHDOG=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_CPU_THERMAL=y
CONFIG_OMAP_WATCHDOG=y
CONFIG_TWL4030_WATCHDOG=y
CONFIG_MFD_TPS65217=y
+ CONFIG_MFD_TPS65910=y
CONFIG_REGULATOR_TWL4030=y
+CONFIG_MFD_PALMAS=y
+CONFIG_MFD_PALMAS_GPADC=y
+CONFIG_MFD_PALMAS_PWM=y
+CONFIG_MFD_PALMAS_RESOURCE=y
+CONFIG_REGULATOR_PALMAS=y
CONFIG_REGULATOR_TPS65023=y
CONFIG_REGULATOR_TPS6507X=y
CONFIG_REGULATOR_TPS65217=y
CONFIG_SDIO_UART=y
CONFIG_MMC_OMAP=y
CONFIG_MMC_OMAP_HS=y
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_GPIO=y
+ CONFIG_LEDS_TRIGGERS=y
+ CONFIG_LEDS_TRIGGER_TIMER=y
+ CONFIG_LEDS_TRIGGER_ONESHOT=y
+ CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+ CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+ CONFIG_LEDS_TRIGGER_CPU=y
+ CONFIG_LEDS_TRIGGER_GPIO=y
+ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_OMAP=y
CONFIG_RTC_DRV_TWL92330=y
CONFIG_RTC_DRV_TWL4030=y
+CONFIG_RTC_DRV_PALMAS=y
CONFIG_DMADEVICES=y
CONFIG_DMA_OMAP=y
+CONFIG_STAGING=y
+CONFIG_TI_SOC_THERMAL=y
+CONFIG_TI_THERMAL=y
+CONFIG_OMAP4_THERMAL=y
+CONFIG_OMAP5_THERMAL=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
CONFIG_TI_DAVINCI_MDIO=y
CONFIG_TI_DAVINCI_CPDMA=y
CONFIG_TI_CPSW=y
+ CONFIG_SOC_DRA7XX=y
diff --combined arch/arm/mach-omap2/Kconfig
index 00d62eaeca4b6889783f49a8dc07ea0c2a07b4c4,5e91009ef16871a6d07fcfa7a81305939c7cae49..d02efdaa8348a10654086413e6698731348e1143
select I2C
select I2C_OMAP
select MENELAUS if ARCH_OMAP2
- select NEON if ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5
+ select NEON if CPU_V7
select PM_RUNTIME
select REGULATOR
select SERIAL_OMAP
config SOC_HAS_OMAP2_SDRC
bool "OMAP2 SDRAM Controller support"
+config ARCH_HAS_BANDGAP
+ bool
+
config SOC_HAS_REALTIME_COUNTER
bool "Real time free running counter"
- depends on SOC_OMAP5
+ depends on SOC_OMAP5 || SOC_DRA7XX
default y
config ARCH_OMAP2
default y
depends on ARCH_OMAP2PLUS
select ARCH_HAS_OPP
+ select ARCH_HAS_BANDGAP
select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
select ARM_CPU_SUSPEND if PM
select ARM_ERRATA_720789
config SOC_OMAP5
bool "TI OMAP5"
+ select ARCH_HAS_BANDGAP
select ARM_ARCH_TIMER
select ARM_CPU_SUSPEND if PM
select ARM_GIC
select COMMON_CLK
select ARCH_NEEDS_CPU_IDLE_COUPLED
+ config SOC_DRA7XX
+ bool "TI DRA7XX"
+ select ARM_ARCH_TIMER
+ select CPU_V7
+ select ARM_GIC
+ select HAVE_SMP
+ select COMMON_CLK
+
comment "OMAP Core Type"
depends on ARCH_OMAP2
bool "AM33XX support"
default y
select ARM_CPU_SUSPEND if PM
+ select COMMON_CLK
select CPU_V7
+ select MAILBOX if PM
select MULTI_IRQ_HANDLER
- select COMMON_CLK
+ select OMAP2PLUS_MBOX if PM
config OMAP_PACKAGE_ZAF
bool
diff --combined arch/arm/mach-omap2/Makefile
index 7a43c6329af020ff4c6cfb8a01d87ed31611f762,e7108e5a86e879dc47d9f26b3f4fab8b4369e71d..fa3b96c543a3ef114f70241ea4bf463ef764eb7a
obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common)
obj-$(CONFIG_SOC_AM33XX) += irq.o $(hwmod-common)
obj-$(CONFIG_SOC_OMAP5) += prm44xx.o $(hwmod-common) $(secure-common)
+ obj-$(CONFIG_SOC_DRA7XX) += prm44xx.o $(hwmod-common) $(secure-common)
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
obj-y += mcbsp.o
sleep_omap4plus.o
obj-$(CONFIG_ARCH_OMAP4) += $(omap-4-5-common)
obj-$(CONFIG_SOC_OMAP5) += $(omap-4-5-common)
+ obj-$(CONFIG_SOC_DRA7XX) += $(omap-4-5-common)
plus_sec := $(call as-instr,.arch_extension sec,+sec)
AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec)
obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
obj-$(CONFIG_ARCH_OMAP4) += $(omap4plus-common-pm)
obj-$(CONFIG_SOC_OMAP5) += $(omap4plus-common-pm)
+obj-$(CONFIG_SOC_AM33XX) += pm33xx.o sleep33xx.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
+ obj-$(CONFIG_SOC_DRA7XX) += omap-mpuss-lowpower.o
obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
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)
ifeq ($(CONFIG_PM_VERBOSE),y)
CFLAGS_pm_bus.o += -DDEBUG
vc44xx_data.o vp44xx_data.o
obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common)
obj-$(CONFIG_SOC_OMAP5) += $(omap-prcm-4-5-common)
+ obj-$(CONFIG_SOC_DRA7XX) += $(omap-prcm-4-5-common)
# OMAP voltage domains
voltagedomain-common := voltage.o vc.o vp.o
obj-$(CONFIG_SOC_AM33XX) += voltagedomains33xx_data.o
obj-$(CONFIG_SOC_OMAP5) += $(voltagedomain-common)
obj-$(CONFIG_SOC_OMAP5) += voltagedomains54xx_data.o
+ obj-$(CONFIG_SOC_DRA7XX) += $(voltagedomain-common)
# OMAP powerdomain framework
powerdomain-common += powerdomain.o powerdomain-common.o
obj-$(CONFIG_SOC_AM33XX) += powerdomains33xx_data.o
obj-$(CONFIG_SOC_OMAP5) += $(powerdomain-common)
obj-$(CONFIG_SOC_OMAP5) += powerdomains54xx_data.o
+ obj-$(CONFIG_SOC_DRA7XX) += $(powerdomain-common)
+ obj-$(CONFIG_SOC_DRA7XX) += powerdomains7xx_data.o
# PRCM clockdomain control
clockdomain-common += clockdomain.o
obj-$(CONFIG_SOC_AM33XX) += clockdomains33xx_data.o
obj-$(CONFIG_SOC_OMAP5) += $(clockdomain-common)
obj-$(CONFIG_SOC_OMAP5) += clockdomains54xx_data.o
+ obj-$(CONFIG_SOC_DRA7XX) += $(clockdomain-common)
+ obj-$(CONFIG_SOC_DRA7XX) += clockdomains7xx_data.o
# Clock framework
obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o
obj-$(CONFIG_SOC_AM33XX) += cclock33xx_data.o
obj-$(CONFIG_SOC_OMAP5) += $(clock-common) cclock54xx_data.o
obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o
+ obj-$(CONFIG_SOC_DRA7XX) += $(clock-common)
+ obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o
+ obj-$(CONFIG_SOC_DRA7XX) += cclock7xx_data.o
# OMAP2 clock rate set data (old "OPP" data)
obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o
obj-$(CONFIG_SOC_AM33XX) += omap_hwmod_33xx_data.o
obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o
obj-$(CONFIG_SOC_OMAP5) += omap_hwmod_54xx_data.o
+ obj-$(CONFIG_SOC_DRA7XX) += omap_hwmod_7xx_data.o
# EMU peripherals
obj-$(CONFIG_OMAP3_EMU) += emu.o
obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
-obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
-mailbox_mach-objs := mailbox.o
-
iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o
obj-y += $(iommu-m) $(iommu-y)
diff --combined arch/arm/mach-omap2/board-generic.c
index b3228cb630df490e561a77041e726d6f9fd0e34d,68b60769908781f3d32088b57bfed322efdf35ae..5a3401a9168f6c702081e70548f6808c68c454fd
.init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_generic_init,
+ .init_late = omap3_init_late,
.timer = &omap3_timer,
.dt_compat = omap3_boards_compat,
.restart = omap3xxx_restart,
.init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_generic_init,
+ .init_late = omap3_init_late,
.timer = &omap3_secure_timer,
.dt_compat = omap3_gp_boards_compat,
.restart = omap3xxx_restart,
.reserve = omap_reserve,
.map_io = am33xx_map_io,
.init_early = am33xx_init_early,
+ .init_late = am33xx_init_late,
.init_irq = omap_intc_of_init,
.handle_irq = omap3_intc_handle_irq,
.init_machine = omap_generic_init,
.restart = omap44xx_restart,
MACHINE_END
#endif
+
+ #ifdef CONFIG_SOC_DRA7XX
+ static const char *dra7xx_boards_compat[] __initdata = {
+ "ti,dra7",
+ NULL,
+ };
+
+ DT_MACHINE_START(DRA7XX_DT, "Generic DRA7XX (Flattened Device Tree)")
+ .reserve = omap_reserve,
+ .smp = smp_ops(omap4_smp_ops),
+ .map_io = omap5_map_io,
+ .init_early = dra7xx_init_early,
+ .init_irq = omap_gic_of_init,
+ .handle_irq = gic_handle_irq,
+ .init_machine = omap_generic_init,
+ .init_late = dra7xx_init_late,
+ .timer = &omap5_timer,
+ .dt_compat = dra7xx_boards_compat,
+ .restart = omap44xx_restart,
+ MACHINE_END
+ #endif
diff --combined arch/arm/mach-omap2/cclock33xx_data.c
index 70fbe40732ac183a33a1982760f568c2435a7ad3,61fd099b1d60e5fe154ca6241a005942fa5a3817..504b4df74d949589a1d1fab3d994820b95229814
CLK(NULL, "dpll_core_m5_ck", &dpll_core_m5_ck, CK_AM33XX),
CLK(NULL, "dpll_core_m6_ck", &dpll_core_m6_ck, CK_AM33XX),
CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck, CK_AM33XX),
- CLK("cpu0", NULL, &dpll_mpu_ck, CK_AM33XX),
CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck, CK_AM33XX),
CLK(NULL, "dpll_ddr_ck", &dpll_ddr_ck, CK_AM33XX),
CLK(NULL, "dpll_ddr_m2_ck", &dpll_ddr_m2_ck, CK_AM33XX),
CLK(NULL, "trace_pmd_clk_mux_ck", &trace_pmd_clk_mux_ck, CK_AM33XX),
CLK(NULL, "stm_clk_div_ck", &stm_clk_div_ck, CK_AM33XX),
CLK(NULL, "trace_clk_div_ck", &trace_clk_div_ck, CK_AM33XX),
+ CLK(NULL, "clkout2_ck", &clkout2_ck, CK_AM33XX),
};
"l4hs_gclk",
"l4fw_gclk",
"l4ls_gclk",
+ "clkout2_ck", /* Required for external peripherals like, Audio codecs */
};
static struct reparent_init_clks reparent_clks[] = {
diff --combined arch/arm/mach-omap2/clock.h
index 9874ebea4f2240440d128064fcd4af28a9fbae87,385065d3d11cabb1b9ea6261848d1a22fcfe4a5f..35a3050390b9ed396c0be01c4ccb5792ffb16817
#define CK_446X (1 << 8)
#define CK_AM33XX (1 << 9) /* AM33xx specific clocks */
#define CK_54XX (1 << 10) /* OMAP54xx specific clocks */
+ #define CK_7XX (1 << 11)
#define CK_34XX (CK_3430ES1 | CK_3430ES2PLUS)
#define RATE_IN_AM33XX (1 << 8)
#define RATE_IN_TI814X (1 << 9)
#define RATE_IN_54XX (1 << 10)
+ #define RATE_IN_7XX (1 << 11)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
#define RATE_IN_34XX (RATE_IN_3430ES1 | RATE_IN_3430ES2PLUS)
u32 freqsel_mask;
u32 idlest_mask;
u32 dco_mask;
+ u32 dcc_mask;
+ unsigned long dcc_rate;
u32 sddiv_mask;
u32 lpmode_mask;
u32 m4xen_mask;
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
unsigned long target_rate,
unsigned long *parent_rate);
-
+int omap5_mpu_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
void omap2_init_clk_clkdm(struct clk_hw *clk);
void __init omap2_clk_disable_clkdm_control(void);
diff --combined arch/arm/mach-omap2/clockdomain.h
index aa800679c80a2f3fa224665ca87b016c924a6fc6,5700924f49a07a3f813928667c9bc5bee3642b66..d767b0199874afe9f2fbf258ef82896b1818281b
#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H
#include <linux/init.h>
-#include <linux/spinlock.h>
#include "powerdomain.h"
#include "clock.h"
struct clkdm_dep {
const char *clkdm_name;
struct clockdomain *clkdm;
- atomic_t wkdep_usecount;
- atomic_t sleepdep_usecount;
+ s16 wkdep_usecount;
+ s16 sleepdep_usecount;
};
/* Possible flags for struct clockdomain._flags */
const u16 clkdm_offs;
struct clkdm_dep *wkdep_srcs;
struct clkdm_dep *sleepdep_srcs;
- atomic_t usecount;
+ int usecount;
struct list_head node;
- spinlock_t lock;
};
/**
int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm);
+void clkdm_allow_idle_nolock(struct clockdomain *clkdm);
void clkdm_allow_idle(struct clockdomain *clkdm);
+void clkdm_deny_idle_nolock(struct clockdomain *clkdm);
void clkdm_deny_idle(struct clockdomain *clkdm);
bool clkdm_in_hwsup(struct clockdomain *clkdm);
bool clkdm_missing_idle_reporting(struct clockdomain *clkdm);
+int clkdm_wakeup_nolock(struct clockdomain *clkdm);
int clkdm_wakeup(struct clockdomain *clkdm);
+int clkdm_sleep_nolock(struct clockdomain *clkdm);
int clkdm_sleep(struct clockdomain *clkdm);
int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
extern void __init am33xx_clockdomains_init(void);
extern void __init omap44xx_clockdomains_init(void);
extern void __init omap54xx_clockdomains_init(void);
-extern void _clkdm_add_autodeps(struct clockdomain *clkdm);
-extern void _clkdm_del_autodeps(struct clockdomain *clkdm);
+ extern void __init dra7xx_clockdomains_init(void);
+
+extern void clkdm_add_autodeps(struct clockdomain *clkdm);
+extern void clkdm_del_autodeps(struct clockdomain *clkdm);
extern struct clkdm_ops omap2_clkdm_operations;
extern struct clkdm_ops omap3_clkdm_operations;
extern struct clkdm_dep dsp_24xx_wkdeps[];
extern struct clockdomain wkup_common_clkdm;
+extern int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *seq_file);
+
#endif
diff --combined arch/arm/mach-omap2/common.h
index 1c4139795a6639ac35ed6a8cd0dc68a1ca595b37,6895d1772dd1bf275c51266cb91ec69800513838..e8002527c491497d794a791a98887ec9bb61249e
}
#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
void omap3430_init_late(void);
void omap35xx_init_late(void);
void omap3630_init_late(void);
+void am33xx_init_late(void);
void am35xx_init_late(void);
void ti81xx_init_late(void);
void omap5_init_late(void);
int omap2_common_pm_late_init(void);
+ void dra7xx_init_early(void);
+ void dra7xx_init_late(void);
#if defined(CONFIG_SOC_OMAP2420) || defined(CONFIG_SOC_OMAP2430)
void omap2xxx_restart(char mode, const char *cmd);
}
#endif
- #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
+ #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
+ defined(CONFIG_SOC_DRA7XX)
void omap44xx_restart(char mode, const char *cmd);
#else
static inline void omap44xx_restart(char mode, const char *cmd)
#if defined(CONFIG_SMP) && defined(CONFIG_PM)
extern int omap4_mpuss_init(void);
-extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state);
+extern int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst);
extern int omap4_finish_suspend(unsigned long cpu_state);
extern void omap4_cpu_resume(void);
-extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state);
+extern int omap4_mpuss_hotplug_cpu(unsigned int cpu, u8 fpwrst);
#else
-static inline int omap4_enter_lowpower(unsigned int cpu,
- unsigned int power_state)
+static inline int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst)
{
cpu_do_idle();
return 0;
diff --combined arch/arm/mach-omap2/control.h
index 371e9aeb6ae654974f7181ba65a9c2f397006911,17a0128570934cac8b56241bc26107f29cffb516..379b14bab5e3cc2567a73cb77c0d18f129c2c8f1
#define OMAP5XXX_CONTROL_STATUS 0x134
#define OMAP5_DEVICETYPE_MASK (0x7 << 6)
+ /* DRA7XX BOOTSTRAP register */
+ #define DRA7XX_BOOTSTRAP_CONTROL 0x6C4
/*
* REVISIT: This list of registers is not comprehensive - there are more
* that should be added.
#define AM33XX_CONTROL_STATUS_SYSBOOT1_WIDTH 0x2
#define AM33XX_CONTROL_STATUS_SYSBOOT1_MASK (0x3 << 22)
+#define AM33XX_DDR_IO_CTRL 0x0E04
+#define AM33XX_VTP0_CTRL_REG 0x0E0C
+
+/* AM33XX VTP0_CTRL_REG bits */
+#define AM33XX_VTP_CTRL_START_EN (1 << 0)
+#define AM33XX_VTP_CTRL_LOCK_EN (1 << 4)
+#define AM33XX_VTP_CTRL_READY (1 << 5)
+#define AM33XX_VTP_CTRL_ENABLE (1 << 6)
+
+/* AM33XX M3_TXEV_EOI register */
+#define AM33XX_CONTROL_M3_TXEV_EOI 0x1324
+
+#define AM33XX_M3_TXEV_ACK (0x1 << 0)
+#define AM33XX_M3_TXEV_ENABLE (0x0 << 0)
+
+/* AM33XX IPC message registers */
+#define AM33XX_CONTROL_IPC_MSG_REG0 0x1328
+#define AM33XX_CONTROL_IPC_MSG_REG1 0x132C
+#define AM33XX_CONTROL_IPC_MSG_REG2 0x1330
+#define AM33XX_CONTROL_IPC_MSG_REG3 0x1334
+#define AM33XX_CONTROL_IPC_MSG_REG4 0x1338
+#define AM33XX_CONTROL_IPC_MSG_REG5 0x133C
+#define AM33XX_CONTROL_IPC_MSG_REG6 0x1340
+#define AM33XX_CONTROL_IPC_MSG_REG7 0x1344
+
+#define AM33XX_DDR_CMD0_IOCTRL 0x1404
+#define AM33XX_DDR_CMD1_IOCTRL 0x1408
+#define AM33XX_DDR_CMD2_IOCTRL 0x140C
+#define AM33XX_DDR_DATA0_IOCTRL 0x1440
+#define AM33XX_DDR_DATA1_IOCTRL 0x1444
+
+ /* DEV Feature register to identify AM33XX features */
+ #define AM33XX_DEV_FEATURE 0x604
+ #define AM33XX_SGX_SHIFT 29
+ #define AM33XX_SGX_MASK (1 << AM33XX_SGX_SHIFT)
+
/* CONTROL OMAP STATUS register to identify OMAP3 features */
#define OMAP3_CONTROL_OMAP_STATUS 0x044c
extern int omap3_ctrl_save_padconf(void);
extern void omap2_set_globals_control(void __iomem *ctrl,
void __iomem *ctrl_pad);
+struct am33xx_ipc_data {
+ u32 resume_addr;
+ u32 param1;
+ u32 param2;
+ u32 sleep_mode;
+};
+extern void am33xx_wkup_m3_ipc_cmd(struct am33xx_ipc_data *data);
+extern void am33xx_txev_eoi(void);
+extern void am33xx_txev_enable(void);
+
#else
#define omap_ctrl_base_get() 0
#define omap_ctrl_readb(x) 0
diff --combined arch/arm/mach-omap2/io.c
index 9ac384c319c6e4b0fc6663cf87be088bfacbc069,98661a93b40001d3e0f67eee949894af74bbdc63..1c7034462a3f92f3456e1775a10249b7d088f3a3
+++ b/arch/arm/mach-omap2/io.c
#include "clock3xxx.h"
#include "clock44xx.h"
#include "clock54xx.h"
+ #include "clock7xx.h"
#include "omap-pm.h"
#include "sdrc.h"
#include "control.h"
};
#endif
- #ifdef CONFIG_SOC_OMAP5
+ #if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
static struct map_desc omap54xx_io_desc[] __initdata = {
{
.virtual = L3_54XX_VIRT,
}
#endif
- #ifdef CONFIG_SOC_OMAP5
+ #if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
void __init omap5_map_io(void)
{
iotable_init(omap54xx_io_desc, ARRAY_SIZE(omap54xx_io_desc));
omap2_set_globals_prm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE));
omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL);
omap3xxx_check_revision();
- ti81xx_check_features();
+ am33xx_check_features();
am33xx_voltagedomains_init();
am33xx_powerdomains_init();
am33xx_clockdomains_init();
omap_hwmod_init_postsetup();
am33xx_clk_init();
}
+
+void __init am33xx_init_late(void)
+{
+ omap_mux_late_init();
+ omap2_common_pm_late_init();
+ am33xx_pm_init();
+}
#endif
#ifdef CONFIG_ARCH_OMAP4
}
#endif
+ #ifdef CONFIG_SOC_DRA7XX
+ void __init dra7xx_init_early(void)
+ {
+ omap2_set_globals_tap(OMAP54XX_CLASS,
+ OMAP2_L4_IO_ADDRESS(OMAP54XX_SCM_BASE));
+ omap2_set_globals_control(OMAP2_L4_IO_ADDRESS(OMAP54XX_SCM_BASE),
+ OMAP2_L4_IO_ADDRESS(DRA7XX_CTRL_BASE));
+ omap2_set_globals_prm(OMAP2_L4_IO_ADDRESS(OMAP54XX_PRM_BASE));
+ omap2_set_globals_cm(OMAP2_L4_IO_ADDRESS(DRA7XX_CM_CORE_AON_BASE),
+ OMAP2_L4_IO_ADDRESS(OMAP54XX_CM_CORE_BASE));
+ omap2_set_globals_prcm_mpu(OMAP2_L4_IO_ADDRESS(OMAP54XX_PRCM_MPU_BASE));
+ omap_prm_base_init();
+ omap_cm_base_init();
+ dra7xx_check_revision();
+ omap44xx_prm_init();
+ dra7xx_powerdomains_init();
+ dra7xx_clockdomains_init();
+ dra7xx_hwmod_init();
+ omap_hwmod_init_postsetup();
+ dra7xx_clk_init();
+ }
+
+ void __init dra7xx_init_late(void)
+ {
+ omap2_common_pm_late_init();
+ omap4_pm_init();
+ omap2_clk_enable_autoidle_all();
+ }
+ #endif
+
void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
struct omap_sdrc_params *sdrc_cs1)
{
diff --combined arch/arm/mach-omap2/omap-hotplug.c
index 539082a5a991fe017a19a6948211ddf5449f16bf,3a7f50c3d1e2bf14b38db8de364a1ecb357e056a..8a15f77d4f94f9acae8ff6e82094f973d05c6899
#include "omap-wakeupgen.h"
#include "common.h"
#include "powerdomain.h"
+ #include "soc.h"
/*
* platform-specific code to shutdown a CPU
/*
* Enter into low power state
*/
- omap4_mpuss_hotplug_cpu(cpu, PWRDM_FUNC_PWRST_OFF);
+ if (soc_is_dra7xx())
- omap4_hotplug_cpu(cpu, PWRDM_POWER_RET);
++ omap4_mpuss_hotplug_cpu(cpu, PWRDM_FUNC_PWRST_CSWR);
+ else
- omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF);
++ omap4_mpuss_hotplug_cpu(cpu, PWRDM_FUNC_PWRST_OFF);
if (omap_secure_apis_support())
boot_cpu = omap_read_auxcoreboot0();
diff --combined arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 8380b3240a61ae7a531e0228cc63585af01e205f,a257d0966be26c63146734d0042c4e4274cb9ba0..d46a2693efbd29ab4bc297b8a9fe48a81bbfc899
struct cpu_pm_ops {
int (*finish_suspend)(unsigned long cpu_state);
void (*resume)(void);
- void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state);
+ void (*scu_prepare)(unsigned int cpu_id, u8 cpu_state);
void (*hotplug_restart)(void);
};
static void dummy_cpu_resume(void)
{}
-static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state)
+static void dummy_scu_prepare(unsigned int cpu_id, u8 cpu_state)
{}
static struct cpu_pm_ops omap_pm_ops = {
{
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
- __raw_writel(addr, pm_info->wkup_sar_addr);
+ /*
+ * XXX should not be writing directly into another IP block's
+ * address space!
+ */
+ if (pm_info->wkup_sar_addr)
+ __raw_writel(addr, pm_info->wkup_sar_addr);
}
-/*
- * Set the CPUx powerdomain's previous power state
- */
-static inline void set_cpu_next_pwrst(unsigned int cpu_id,
- unsigned int power_state)
-{
- struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
-
- pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
-}
-
-/*
- * Read CPU's previous power state
- */
-static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id)
-{
- struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
-
- return pwrdm_read_prev_pwrst(pm_info->pwrdm);
-}
-
-/*
- * Clear the CPUx powerdomain's previous power state
- */
-static inline void clear_cpu_prev_pwrst(unsigned int cpu_id)
-{
- struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
-
- pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
-}
-
/*
* Store the SCU power status value to scratchpad memory
*/
-static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
+static void scu_pwrst_prepare(unsigned int cpu_id, u8 fpwrst)
{
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
u32 scu_pwr_st;
- switch (cpu_state) {
- case PWRDM_POWER_RET:
+ if (!pm_info->scu_sar_addr)
+ return;
+
+ switch (fpwrst) {
+ case PWRDM_FUNC_PWRST_CSWR:
+ case PWRDM_FUNC_PWRST_OSWR: /* XXX is this accurate? */
scu_pwr_st = SCU_PM_DORMANT;
break;
- case PWRDM_POWER_OFF:
+ case PWRDM_FUNC_PWRST_OFF:
scu_pwr_st = SCU_PM_POWEROFF;
break;
- case PWRDM_POWER_ON:
- case PWRDM_POWER_INACTIVE:
+ case PWRDM_FUNC_PWRST_ON:
+ case PWRDM_FUNC_PWRST_INACTIVE:
default:
scu_pwr_st = SCU_PM_NORMAL;
break;
}
+ /*
+ * XXX should not be writing directly into another IP block's
+ * address space!
+ */
__raw_writel(scu_pwr_st, pm_info->scu_sar_addr);
}
{
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
- __raw_writel(save_state, pm_info->l2x0_sar_addr);
+ /*
+ * XXX should not be writing directly into another IP block's
+ * address space!
+ */
+ if (pm_info->l2x0_sar_addr)
+ __raw_writel(save_state, pm_info->l2x0_sar_addr);
}
/*
#endif
/**
- * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
+ * omap4_mpuss_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
* The purpose of this function is to manage low power programming
* of OMAP4 MPUSS subsystem
* @cpu : CPU ID
- * @power_state: Low power state.
+ * @fpwrst: functional powerstate for the MPUSS to enter
*
* MPUSS states for the context save:
* save_state =
* 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
* 3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
*/
-int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
+int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst)
{
+ struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
unsigned int save_state = 0;
unsigned int wakeup_cpu;
if (omap_rev() == OMAP4430_REV_ES1_0)
return -ENXIO;
- switch (power_state) {
- case PWRDM_POWER_ON:
- case PWRDM_POWER_INACTIVE:
+ switch (fpwrst) {
+ case PWRDM_FUNC_PWRST_ON:
+ case PWRDM_FUNC_PWRST_INACTIVE:
save_state = 0;
break;
- case PWRDM_POWER_OFF:
+ case PWRDM_FUNC_PWRST_OFF:
save_state = 1;
break;
- case PWRDM_POWER_RET:
+ case PWRDM_FUNC_PWRST_CSWR:
+ case PWRDM_FUNC_PWRST_OSWR:
if (cpu_cswr_supported) {
save_state = 0;
break;
/*
* Check MPUSS next state and save interrupt controller if needed.
- * In MPUSS OSWR or device OFF, interrupt controller contest is lost.
+ * In MPUSS OSWR or device OFF, interrupt controller context is lost.
*/
mpuss_clear_prev_logic_pwrst();
- if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
- (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
+ if (pwrdm_read_next_fpwrst(mpuss_pd) == PWRDM_FUNC_PWRST_OSWR)
save_state = 2;
cpu_clear_prev_logic_pwrst(cpu);
- set_cpu_next_pwrst(cpu, power_state);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, fpwrst));
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume));
- omap_pm_ops.scu_prepare(cpu, power_state);
+ omap_pm_ops.scu_prepare(cpu, fpwrst);
l2x0_pwrst_prepare(cpu, save_state);
/*
* domain transition
*/
wakeup_cpu = smp_processor_id();
- set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
pwrdm_post_transition(NULL);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
+
return 0;
}
/**
* omap4_hotplug_cpu: OMAP4 CPU hotplug entry
* @cpu : CPU ID
- * @power_state: CPU low power state.
+ * @fpwrst: functional power state to program the CPU powerdomain to enter
*/
-int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
+int __cpuinit omap4_mpuss_hotplug_cpu(unsigned int cpu, u8 fpwrst)
{
+ struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
unsigned int cpu_state = 0;
if (omap_rev() == OMAP4430_REV_ES1_0)
return -ENXIO;
- if (power_state == PWRDM_POWER_OFF)
+ if (fpwrst == PWRDM_FUNC_PWRST_OFF || fpwrst == PWRDM_FUNC_PWRST_OSWR)
cpu_state = 1;
- clear_cpu_prev_pwrst(cpu);
- set_cpu_next_pwrst(cpu, power_state);
+ pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, fpwrst));
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.hotplug_restart));
- omap_pm_ops.scu_prepare(cpu, power_state);
+ omap_pm_ops.scu_prepare(cpu, fpwrst);
/*
* CPU never retuns back if targeted power state is OFF mode.
*/
omap_pm_ops.finish_suspend(cpu_state);
- set_cpu_next_pwrst(cpu, PWRDM_POWER_ON);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
return 0;
}
else if (soc_is_omap54xx())
cpu_wakeup_addr = OMAP5_CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
pm_info = &per_cpu(omap4_pm_info, 0x0);
- pm_info->scu_sar_addr = sar_base + SCU_OFFSET0;
- pm_info->wkup_sar_addr = sar_base + cpu_wakeup_addr;
- pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0;
+ if (sar_base) {
+ pm_info->scu_sar_addr = sar_base + SCU_OFFSET0;
+ pm_info->wkup_sar_addr = sar_base + cpu_wakeup_addr;
+ pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0;
+ }
pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm");
if (!pm_info->pwrdm) {
pr_err("Lookup failed for CPU0 pwrdm\n");
cpu_clear_prev_logic_pwrst(0);
/* Initialise CPU0 power domain state to ON */
- pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
if (cpu_is_omap44xx())
cpu_wakeup_addr = CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
else if (soc_is_omap54xx())
cpu_wakeup_addr = OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
pm_info = &per_cpu(omap4_pm_info, 0x1);
- pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
- pm_info->wkup_sar_addr = sar_base + cpu_wakeup_addr;
- pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
+ if (sar_base) {
+ pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
+ pm_info->wkup_sar_addr = sar_base + cpu_wakeup_addr;
+ pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
+ }
pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
if (!pm_info->pwrdm) {
cpu_clear_prev_logic_pwrst(1);
/* Initialise CPU1 power domain state to ON */
- pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
mpuss_pd = pwrdm_lookup("mpu_pwrdm");
if (!mpuss_pd) {
mpuss_clear_prev_logic_pwrst();
/* Save device type on scratchpad for low level code to use */
- if (omap_type() != OMAP2_DEVICE_TYPE_GP)
- __raw_writel(1, sar_base + OMAP_TYPE_OFFSET);
- else
- __raw_writel(0, sar_base + OMAP_TYPE_OFFSET);
+ if (sar_base) {
+ if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+ __raw_writel(1, sar_base + OMAP_TYPE_OFFSET);
+ else
+ __raw_writel(0, sar_base + OMAP_TYPE_OFFSET);
- save_l2x0_context();
+ save_l2x0_context();
+ }
if (cpu_is_omap44xx()) {
omap_pm_ops.finish_suspend = omap4_finish_suspend;
omap_pm_ops.resume = omap4_cpu_resume;
omap_pm_ops.scu_prepare = scu_pwrst_prepare;
cpu_context_offset = OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET;
- } else if (soc_is_omap54xx()) {
+ } else if (soc_is_omap54xx() || soc_is_dra7xx()) {
omap_pm_ops.finish_suspend = omap5_finish_suspend;
omap_pm_ops.hotplug_restart = omap5_secondary_startup;
omap_pm_ops.resume = omap5_cpu_resume;
diff --combined arch/arm/mach-omap2/omap_hwmod.c
index 3550c73a324a677ccb688daf2e48255d647d3eb1,bee77531f35bd5d242c030c7ce7fa05c93a6cc90..7b915267c679aaed815302497533f450a189e802
static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- if (ohri->st_shift)
- pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
- oh->name, ohri->name);
-
return am33xx_prm_deassert_hardreset(ohri->rst_shift,
+ ohri->st_shift,
oh->clkdm->pwrdm.ptr->prcm_offs,
oh->prcm.omap4.rstctrl_offs,
oh->prcm.omap4.rstst_offs);
soc_ops.assert_hardreset = _omap2_assert_hardreset;
soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
- } else if (cpu_is_omap44xx() || soc_is_omap54xx()) {
+ } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) {
soc_ops.enable_module = _omap4_enable_module;
soc_ops.disable_module = _omap4_disable_module;
soc_ops.wait_target_ready = _omap4_wait_target_ready;
diff --combined arch/arm/mach-omap2/pm_omap4plus.c
index 0265ed2802c60ffa02e5f52ea3938790154ec4d6,929e0005d5ddf7126f0b71e6d5e5d7255a8a54ec..2389682d3d8a8e576969c5efe7363ca098d37738
struct power_state {
struct powerdomain *pwrdm;
- u32 next_state;
+ u8 next_fpwrst;
#ifdef CONFIG_SUSPEND
- u32 saved_state;
- u32 saved_logic_state;
+ u8 saved_fpwrst;
#endif
struct list_head node;
};
static LIST_HEAD(pwrst_list);
+ u32 cpu_suspend_state;
+ u32 pwrdm_next_state;
#ifdef CONFIG_SUSPEND
static int omap4_pm_suspend(void)
{
struct power_state *pwrst;
- int state, ret = 0;
+ int prev_fpwrst;
+ int ret = 0;
u32 cpu_id = smp_processor_id();
+ /* XXX Seems like these two loops could be combined into one loop? */
+
/* Save current powerdomain state */
- list_for_each_entry(pwrst, &pwrst_list, node) {
- pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
- pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm);
- }
+ list_for_each_entry(pwrst, &pwrst_list, node)
+ pwrst->saved_fpwrst = pwrdm_read_next_fpwrst(pwrst->pwrdm);
/* Set targeted power domain states by suspend */
- list_for_each_entry(pwrst, &pwrst_list, node) {
- omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
- pwrdm_set_logic_retst(pwrst->pwrdm, PWRDM_POWER_OFF);
- }
+ list_for_each_entry(pwrst, &pwrst_list, node)
+ WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
/*
* For MPUSS to hit power domain retention(CSWR or OSWR),
* domain CSWR is not supported by hardware.
* More details can be found in OMAP4430 TRM section 4.3.4.2.
*/
- omap4_mpuss_enter_lowpower(cpu_id, PWRDM_FUNC_PWRST_OFF);
- omap4_enter_lowpower(cpu_id, cpu_suspend_state);
++ omap4_mpuss_enter_lowpower(cpu_id, cpu_suspend_state);
/* Restore next powerdomain state */
list_for_each_entry(pwrst, &pwrst_list, node) {
- state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
- if (state > pwrst->next_state) {
- pr_info("Powerdomain (%s) didn't enter target state %d\n",
- pwrst->pwrdm->name, pwrst->next_state);
+ prev_fpwrst = pwrdm_read_prev_fpwrst(pwrst->pwrdm);
+ if (prev_fpwrst != pwrst->next_fpwrst) {
+ pr_info("Powerdomain (%s) didn't enter target state %s - entered state %s instead\n",
+ pwrst->pwrdm->name,
+ pwrdm_convert_fpwrst_to_name(pwrst->next_fpwrst),
+ pwrdm_convert_fpwrst_to_name(prev_fpwrst));
ret = -1;
}
- omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
- pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
+ WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->saved_fpwrst));
}
if (ret)
pr_crit("Could not enter target state in pm_suspend\n");
return -ENOMEM;
pwrst->pwrdm = pwrdm;
- pwrst->next_state = pwrdm_next_state;
+ /*
+ * XXX This should be replaced by explicit lists of
+ * powerdomains with specific powerstates to set
+ */
- pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
++ pwrst->next_fpwrst = pwrdm_next_state;
+ if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
+ pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON;
list_add(&pwrst->node, &pwrst_list);
- return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+ return WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
}
/**
if (cpu_is_omap44xx())
ret = omap4_init_static_deps();
- else if (soc_is_omap54xx())
+ else if (soc_is_omap54xx() || soc_is_dra7xx())
ret = omap5_init_static_deps();
if (ret) {
if (cpu_is_omap44xx() || soc_is_omap54xx())
omap4_idle_init();
- cpu_suspend_state = PWRDM_POWER_ON;
- pwrdm_next_state = PWRDM_POWER_ON;
+ if (soc_is_dra7xx()) {
- cpu_suspend_state = PWRDM_POWER_OFF;
- pwrdm_next_state = PWRDM_POWER_RET;
++ cpu_suspend_state = PWRDM_FUNC_PWRST_ON;
++ pwrdm_next_state = PWRDM_FUNC_PWRST_ON;
+ } else {
++ cpu_suspend_state = PWRDM_FUNC_PWRST_OFF;
++ pwrdm_next_state = PWRDM_FUNC_PWRST_CSWR;
+ }
+
err2:
return ret;
}
diff --combined arch/arm/mach-omap2/powerdomain.c
index 72d6ce042edc2a02da2af948f90328439403fb23,6a1f195c12baabe797e199f663f985eaab09df68..6aa4d572d1461ad9507bebb7c89e81ec6d934f62
/*
* OMAP powerdomain control
*
- * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2011-2012 Texas Instruments, Inc.
* Copyright (C) 2007-2011 Nokia Corporation
*
* Written by Paul Walmsley
* Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
* State counting code by Tero Kristo <tero.kristo@nokia.com>
*
+ * Contains some code previously from mach-omap2/pm-debug.c, which was:
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
* 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.
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+
#include <trace/events/power.h>
#include "cm2xxx_3xxx.h"
#define PWRDM_TRACE_STATES_FLAG (1<<31)
-enum {
- PWRDM_STATE_NOW = 0,
- PWRDM_STATE_PREV,
-};
-
+/* Types of sleep_switch used in pwrdm_set_fpwrst() */
+#define ALREADYACTIVE_SWITCH 0
+#define FORCEWAKEUP_SWITCH 1
+#define LOWPOWERSTATE_SWITCH 2
+#define ERROR_SWITCH 3
/* pwrdm_list contains all registered struct powerdomains */
static LIST_HEAD(pwrdm_list);
static struct pwrdm_ops *arch_pwrdm;
+/*
+ * _fpwrst_names: human-readable functional powerstate names - should match
+ * the enum pwrdm_func_state order and names
+ */
+static const char * const _fpwrst_names[] = {
+ "OFF", "OSWR", "CSWR", "INACTIVE", "ON"
+};
+
/* Private functions */
static struct powerdomain *_pwrdm_lookup(const char *name)
int i;
struct voltagedomain *voltdm;
- if (!pwrdm || !pwrdm->name)
+ if (!pwrdm->name)
return -EINVAL;
if (cpu_is_omap44xx() &&
if (_pwrdm_lookup(pwrdm->name))
return -EEXIST;
+ if (arch_pwrdm && arch_pwrdm->pwrdm_has_voltdm)
+ if (!arch_pwrdm->pwrdm_has_voltdm())
+ goto skip_voltdm;
+
voltdm = voltdm_lookup(pwrdm->voltdm.name);
if (!voltdm) {
pr_err("powerdomain: %s: voltagedomain %s does not exist\n",
pwrdm->voltdm.ptr = voltdm;
INIT_LIST_HEAD(&pwrdm->voltdm_node);
voltdm_add_pwrdm(voltdm, pwrdm);
- spin_lock_init(&pwrdm->_lock);
+ skip_voltdm:
++ spin_lock_init(&pwrdm->_lock);
list_add(&pwrdm->node, &pwrdm_list);
/* Initialize the powerdomain's state counter */
- for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
- pwrdm->state_counter[i] = 0;
-
- pwrdm->ret_logic_off_counter = 0;
- for (i = 0; i < pwrdm->banks; i++)
- pwrdm->ret_mem_off_counter[i] = 0;
-
- pwrdm_wait_transition(pwrdm);
- pwrdm->state = pwrdm_read_pwrst(pwrdm);
- pwrdm->state_counter[pwrdm->state] = 1;
-
- pr_debug("powerdomain: registered %s\n", pwrdm->name);
+ for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+ pwrdm->fpwrst_counter[i] = 0;
+
+ arch_pwrdm->pwrdm_wait_transition(pwrdm);
+ pwrdm->fpwrst = pwrdm_read_fpwrst(pwrdm);
+ pwrdm->fpwrst_counter[pwrdm->fpwrst - PWRDM_FPWRST_OFFSET] = 1;
+#ifdef CONFIG_PM_DEBUG
+ pwrdm->timer = sched_clock();
+#endif
return 0;
}
-static void _update_logic_membank_counters(struct powerdomain *pwrdm)
+/**
+ * _pwrdm_save_clkdm_state_and_activate - prepare for power state change
+ * @pwrdm: struct powerdomain * to operate on
+ * @pwrst: power state to switch to
+ * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised
+ *
+ * Determine whether the powerdomain needs to be turned on before
+ * attempting to switch power states. Called by
+ * pwrdm_set_fpwrst(). NOTE that if the powerdomain contains
+ * multiple clockdomains, this code assumes that the first clockdomain
+ * supports software-supervised wakeup mode - potentially a problem.
+ * Returns the power state switch mode currently in use (see the
+ * "Types of sleep_switch" comment above).
+ */
+static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
+ u8 pwrst, bool *hwsup)
{
- int i;
- u8 prev_logic_pwrst, prev_mem_pwrst;
+ int curr_pwrst;
+ u8 sleep_switch;
- prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
- if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
- (prev_logic_pwrst == PWRDM_POWER_OFF))
- pwrdm->ret_logic_off_counter++;
+ curr_pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
+ if (curr_pwrst < 0) {
+ WARN_ON(1);
+ sleep_switch = ERROR_SWITCH;
+ } else if (curr_pwrst < PWRDM_POWER_ON) {
+ if (curr_pwrst > pwrst &&
+ pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
+ arch_pwrdm->pwrdm_set_lowpwrstchange) {
+ sleep_switch = LOWPOWERSTATE_SWITCH;
+ } else {
+ *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
+ clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]);
+ sleep_switch = FORCEWAKEUP_SWITCH;
+ }
+ } else {
+ sleep_switch = ALREADYACTIVE_SWITCH;
+ }
- for (i = 0; i < pwrdm->banks; i++) {
- prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
+ return sleep_switch;
+}
- if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
- (prev_mem_pwrst == PWRDM_POWER_OFF))
- pwrdm->ret_mem_off_counter[i]++;
+/**
+ * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change
+ * @pwrdm: struct powerdomain * to operate on
+ * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate()
+ * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode?
+ *
+ * Restore the clockdomain state perturbed by
+ * _pwrdm_save_clkdm_state_and_activate(), and call the power state
+ * bookkeeping code. Called by pwrdm_set_fpwrst(). NOTE that if
+ * the powerdomain contains multiple clockdomains, this assumes that
+ * the first associated clockdomain supports either
+ * hardware-supervised idle control in the register, or
+ * software-supervised sleep. No return value.
+ */
+static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
+ u8 sleep_switch, bool hwsup)
+{
+ switch (sleep_switch) {
+ case FORCEWAKEUP_SWITCH:
+ if (hwsup)
+ clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]);
+ else
+ clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]);
+ break;
+ case LOWPOWERSTATE_SWITCH:
+ if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
+ arch_pwrdm->pwrdm_set_lowpwrstchange)
+ arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
+ pwrdm_state_switch_nolock(pwrdm);
+ break;
}
}
-static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
+/**
+ * _pwrdm_pwrst_is_controllable - can software change the powerdomain pwrst?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the kernel can program the power state that the powerdomain
+ * @pwrdm should enter next, return 1; otherwise, return 0.
+ */
+static bool _pwrdm_pwrst_is_controllable(struct powerdomain *pwrdm)
{
+ return (!pwrdm->pwrsts || pwrdm->pwrsts == PWRSTS_ON) ? 0 : 1;
+}
- int prev, state, trace_state = 0;
+/**
+ * _pwrdm_pwrst_can_change - can the power state of @pwrdm change?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the power state of the powerdomain represented by @pwrdm can
+ * change (i.e., is not always on), and the kernel has some way to
+ * detect this, return 1; otherwise, return 0. XXX The current
+ * implementation of this is based on an assumption and has not been
+ * verified against all OMAPs.
+ */
+static bool _pwrdm_pwrst_can_change(struct powerdomain *pwrdm)
+{
+ return _pwrdm_pwrst_is_controllable(pwrdm);
+}
- if (pwrdm == NULL)
- return -EINVAL;
+/**
+ * _pwrdm_logic_retst_is_controllable - can software change the logic retst?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the kernel can program the power state that the powerdomain
+ * @pwrdm logic should enter when the @pwrdm enters the RETENTION
+ * power state, return 1; otherwise, return 0.
+ */
+static bool _pwrdm_logic_retst_is_controllable(struct powerdomain *pwrdm)
+{
+ return (!pwrdm->pwrsts_logic_ret ||
+ pwrdm->pwrsts_logic_ret == PWRSTS_RET) ? 0 : 1;
+}
- state = pwrdm_read_pwrst(pwrdm);
+/**
+ * _pwrdm_logic_retst_can_change - can the logic retst change on @pwrdm?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the logic powerstate for the powerdomain represented by @pwrdm
+ * can ever be something other than the powerdomain's powerstate, and
+ * the kernel has some way to detect this, return 1; otherwise, return
+ * 0. XXX The current implementation of this is based on an
+ * assumption and has not been verified against all OMAPs.
+ */
+static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm)
+{
+ return _pwrdm_logic_retst_is_controllable(pwrdm);
+}
- switch (flag) {
- case PWRDM_STATE_NOW:
- prev = pwrdm->state;
+/**
+ * Search down then up for a valid state from a list of allowed
+ * states. Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * _pwrdm_fpwrst_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @fpwrst: functional power state
+ * @pwrdm_pwrst: ptr to u8 to return the power state in
+ * @logic_retst: ptr to u8 to return the logic retention state in
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
+ u8 *pwrdm_pwrst, u8 *logic_retst)
+{
+ switch (fpwrst) {
+ case PWRDM_FUNC_PWRST_ON:
+ *pwrdm_pwrst = PWRDM_POWER_ON;
+ *logic_retst = PWRDM_POWER_RET;
+ break;
+ case PWRDM_FUNC_PWRST_INACTIVE:
+ *pwrdm_pwrst = PWRDM_POWER_INACTIVE;
+ *logic_retst = PWRDM_POWER_RET;
break;
- case PWRDM_STATE_PREV:
- prev = pwrdm_read_prev_pwrst(pwrdm);
- if (pwrdm->state != prev)
- pwrdm->state_counter[prev]++;
- if (prev == PWRDM_POWER_RET)
- _update_logic_membank_counters(pwrdm);
+ case PWRDM_FUNC_PWRST_CSWR:
+ *pwrdm_pwrst = PWRDM_POWER_RET;
+ *logic_retst = PWRDM_POWER_RET;
+ break;
+ case PWRDM_FUNC_PWRST_OSWR:
+ *pwrdm_pwrst = PWRDM_POWER_RET;
+ *logic_retst = PWRDM_POWER_OFF;
+ break;
+ case PWRDM_FUNC_PWRST_OFF:
+ *pwrdm_pwrst = PWRDM_POWER_OFF;
/*
- * If the power domain did not hit the desired state,
- * generate a trace event with both the desired and hit states
+ * logic_retst is set to PWRDM_POWER_RET in this case
+ * since the actual value does not matter, and because
+ * some powerdomains don't support a logic_retst of
+ * OFF. XXX Maybe there's some way to indicate a
+ * 'don't care' value here?
*/
- if (state != prev) {
- trace_state = (PWRDM_TRACE_STATES_FLAG |
- ((state & OMAP_POWERSTATE_MASK) << 8) |
- ((prev & OMAP_POWERSTATE_MASK) << 0));
- trace_power_domain_target(pwrdm->name, trace_state,
- smp_processor_id());
- }
+ *logic_retst = PWRDM_POWER_RET;
break;
default:
return -EINVAL;
}
- if (state != prev)
- pwrdm->state_counter[state]++;
+ pr_debug("powerdomain %s: convert fpwrst %0x to pwrst %0x\n",
+ pwrdm->name, fpwrst, *pwrdm_pwrst);
+
+ return 0;
+}
- pm_dbg_update_time(pwrdm, prev);
+/**
+ * _pwrdm_pwrst_to_fpwrst - Convert internal (i.e. registers) to
+ * functional (i.e. logical) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @pwrst: internal powerdomain power state
+ * @logic: internal powerdomain logic power state
+ * @fpwrst: pointer to a u8 to store the corresponding functional power state to
+ *
+ * Returns the functional power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in. @pwrdm, @logic, and @pwrst
+ * are passed in, along with a pointer to the location to store the fpwrst to
+ * in @fpwrst.
+ */
+static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,
+ u8 *fpwrst)
+{
+ switch (pwrst) {
+ case PWRDM_POWER_ON:
+ *fpwrst = PWRDM_FUNC_PWRST_ON;
+ break;
+ case PWRDM_POWER_INACTIVE:
+ *fpwrst = PWRDM_FUNC_PWRST_INACTIVE;
+ break;
+ case PWRDM_POWER_RET:
+ if (logic == PWRDM_POWER_OFF)
+ *fpwrst = PWRDM_FUNC_PWRST_OSWR;
+ else if (logic == PWRDM_POWER_RET)
+ *fpwrst = PWRDM_FUNC_PWRST_CSWR;
+ else
+ return -EINVAL;
+ break;
+ case PWRDM_POWER_OFF:
+ *fpwrst = PWRDM_FUNC_PWRST_OFF;
+ break;
+ default:
+ return -EINVAL;
+ }
- pwrdm->state = state;
+ pr_debug("powerdomain: convert pwrst (%0x,%0x) to fpwrst %0x\n",
+ pwrst, logic, *fpwrst);
return 0;
}
+/**
+ * _set_logic_retst_and_pwrdm_pwrst - program logic retst and pwrdm next pwrst
+ * @pwrdm: struct powerdomain * to program
+ * @logic: logic retention state to attempt to program
+ * @pwrst: powerdomain next-power-state to program
+ *
+ * Program the next-power-state and logic retention power state of the
+ * powerdomain represented by @pwrdm to @pwrst and @logic,
+ * respectively. If the powerdomain next-power-state is not
+ * software-controllable, returns 0; otherwise, passes along the
+ * return value from pwrdm_set_logic_retst() if there is an error
+ * returned by that function, otherwise, passes along the return value
+ * from pwrdm_set_next_fpwrst()
+ */
+static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
+ u8 logic, u8 pwrst)
+{
+ int ret;
+
+ /*
+ * XXX Should return an error, but this means that our PM code
+ * will need to be much more careful about what it programs
+ */
+ if (!_pwrdm_pwrst_is_controllable(pwrdm))
+ return 0;
+
+ if (!(pwrdm->pwrsts & (1 << pwrst)))
+ return -EINVAL;
+
+ if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET) {
+ if (!(pwrdm->pwrsts_logic_ret & (1 << logic)))
+ return -EINVAL;
+
+ ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic);
+ if (ret) {
+ pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
+ __func__, logic, pwrdm->name);
+ return ret;
+ }
+ }
+
+ ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
+ if (ret)
+ pr_err("%s: unable to set power state %0x of powerdomain: %s\n",
+ __func__, pwrst, pwrdm->name);
+
+ return ret;
+}
+
+/**
+ * _pwrdm_read_next_fpwrst - get next powerdomain func power state (lockless)
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Caller must hold @pwrdm->_lock. Returns -EINVAL if the powerdomain
+ * pointer is null or returns the next power state upon success.
+ */
+static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
+{
+ int next_pwrst, next_logic, ret;
+ u8 fpwrst;
+
+ if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID)
+ return pwrdm->next_fpwrst;
+
+ next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
+ if (next_pwrst < 0)
+ return next_pwrst;
+
+ next_logic = next_pwrst;
+ if (_pwrdm_logic_retst_can_change(pwrdm) &&
+ arch_pwrdm->pwrdm_read_logic_pwrst) {
+ next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+ if (next_logic < 0)
+ return next_logic;
+ }
+ ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+ if (!ret) {
+ pwrdm->next_fpwrst = fpwrst;
+ pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+ }
+
+ return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_read_fpwrst - get current func powerdomain power state (lockless)
+ * @pwrdm: struct powerdomain * to get current functional power state
+ *
+ * Return the powerdomain @pwrdm's current functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * current power state upon success.
+ */
+static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)
+{
+ int pwrst, logic_pwrst, ret;
+ u8 fpwrst;
+
+ if (!_pwrdm_pwrst_can_change(pwrdm) ||
+ pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL)
+ return PWRDM_FUNC_PWRST_ON;
+
+ pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
+ if (pwrst < 0)
+ return pwrst;
+
+ logic_pwrst = pwrst;
+ if (_pwrdm_logic_retst_can_change(pwrdm) &&
+ arch_pwrdm->pwrdm_read_logic_pwrst) {
+ logic_pwrst = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+ if (logic_pwrst < 0)
+ return logic_pwrst;
+ }
+
+ ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+
+ return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_read_prev_fpwrst - get previous powerdomain func pwr state (lockless)
+ * @pwrdm: struct powerdomain * to get previous functional power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous functional power state upon success.
+ */
+static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
+{
+ int ret = -EINVAL;
+ int pwrst, logic_pwrst;
+ u8 fpwrst;
+
+ if (!_pwrdm_pwrst_can_change(pwrdm))
+ return PWRDM_FUNC_PWRST_ON;
+
+ if (pwrdm->_flags & _PWRDM_PREV_FPWRST_IS_VALID)
+ return pwrdm->prev_fpwrst;
+
+ pwrst = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
+ if (pwrst < 0)
+ return pwrst;
+
+ logic_pwrst = pwrst;
+ if (_pwrdm_logic_retst_can_change(pwrdm) &&
+ arch_pwrdm->pwrdm_read_prev_logic_pwrst) {
+ logic_pwrst = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
+ if (logic_pwrst < 0)
+ return logic_pwrst;
+ }
+
+ ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+ if (!ret) {
+ pwrdm->prev_fpwrst = fpwrst;
+ pwrdm->_flags |= _PWRDM_PREV_FPWRST_IS_VALID;
+ }
+
+ return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_set_mem_onst - set memory power state while powerdomain ON
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state @pwrst that memory bank @bank of the
+ * powerdomain @pwrdm will enter when the powerdomain enters the ON
+ * state. @bank will be a number from 0 to 3, and represents different
+ * types of memory, depending on the powerdomain. Returns -EINVAL if
+ * the powerdomain pointer is null or the target power state is not
+ * not supported for this memory bank, -EEXIST if the target memory
+ * bank does not exist or is not controllable, or returns 0 upon
+ * success.
+ */
+static int _pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+ int ret = -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
+ pwrdm->name, bank, pwrst);
+
+ if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
+ ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
+
+ return ret;
+}
+
+/**
+ * _pwrdm_set_mem_retst - set memory power state while powerdomain in RET
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state @pwrst that memory bank @bank of the
+ * powerdomain @pwrdm will enter when the powerdomain enters the
+ * RETENTION state. Bank will be a number from 0 to 3, and represents
+ * different types of memory, depending on the powerdomain. @pwrst
+ * will be either RETENTION or OFF, if supported. Returns -EINVAL if
+ * the powerdomain pointer is null or the target power state is not
+ * not supported for this memory bank, -EEXIST if the target memory
+ * bank does not exist or is not controllable, or returns 0 upon
+ * success.
+ */
+static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+ int ret = -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
+ pwrdm->name, bank, pwrst);
+
+ if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
+ ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
+
+ return ret;
+}
+
+/* XXX prev is wrong type */
+/* XXX is sched_clock() correct to use here? */
+/* Update timer for previous state */
+static void _pwrdm_update_pwrst_time(struct powerdomain *pwrdm, int prev)
+{
+#ifdef CONFIG_PM_DEBUG
+ s64 t;
+
+ t = sched_clock();
+
+ pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer;
+
+ pwrdm->timer = t;
+#endif
+}
+
+/**
+ * _pwrdm_state_switch - record powerdomain usage data; track power state
+ * (before powerdomain state transition)
+ * @pwrdm: struct powerdomain * to observe
+ *
+ * If the powerdomain @pwrdm's current power state is not what we last
+ * observed it to be, then increment the counter for that power state.
+ * This is used to track context loss events, and for debugging. Also
+ * if CONFIG_PM_DEBUG=y, track the amount of time the powerdomain has
+ * spent in the current power state. Caller must hold pwrdm->_lock.
+ * Intended to be called immediately before the powerdomain's power
+ * state is likely to change. XXX Note that the counts and durations
+ * observed by this function may be inaccurate. Powerdomains can
+ * transition power states automatically, without the kernel being
+ * involved -- for example, a device can DMA data from memory while
+ * the MPU is asleep. This function does not attempt to account for
+ * that. XXX It may be possible to skip this function completely if
+ * PM debugging is not needed and off-mode and OSWR is disabled (e.g.,
+ * no context loss events). No return value.
+ */
+static void _pwrdm_state_switch(struct powerdomain *pwrdm)
+{
+ int fpwrst;
+
+ fpwrst = _pwrdm_read_fpwrst(pwrdm);
+ if (fpwrst != pwrdm->fpwrst)
+ pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++;
+
+ _pwrdm_update_pwrst_time(pwrdm, pwrdm->fpwrst);
+
+ pwrdm->fpwrst = fpwrst;
+}
+
static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
{
+ /*
+ * XXX It should be possible to avoid the clear_all_prev_pwrst
+ * call for powerdomains if we are programming them to stay on,
+ * for example.
+ */
pwrdm_clear_all_prev_pwrst(pwrdm);
- _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+ _pwrdm_state_switch(pwrdm);
return 0;
}
+/**
+ * _pwrdm_post_transition_cb - record powerdomain usage data; track power state
+ * (after powerdomain power state transition)
+ * @pwrdm: struct powerdomain * to observe
+ *
+ * If the powerdomain @pwrdm's previous power state doesn't match our
+ * recollection of the powerdomain's current power state, then
+ * increment the counter for the previous power state. And if the
+ * powerdomain's previous power state doesn't match the current power
+ * state, increment the counter for the current power state. This
+ * function is used to track context loss events, and for debugging.
+ * Also if CONFIG_PM_DEBUG=y, track the approximate amount of time the
+ * powerdomain has spent in the previous power state. Caller must
+ * hold pwrdm->_lock. XXX Note that the counts and durations observed
+ * by this function may be inaccurate. Powerdomains can transition
+ * power states automatically, without the kernel being involved --
+ * for example, a device can DMA data from memory while the MPU is
+ * asleep. This function does not attempt to account for that. XXX
+ * It may be possible to skip this function completely if PM debugging
+ * is not needed and off-mode and OSWR is disabled (e.g., no context
+ * loss events). No return value.
+ */
static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
{
- _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
+ int prev, fpwrst;
+ int trace_state = 0;
+
+ prev = (pwrdm->next_fpwrst == PWRDM_FUNC_PWRST_ON) ?
+ PWRDM_FUNC_PWRST_ON : _pwrdm_read_prev_fpwrst(pwrdm);
+
+ if (pwrdm->fpwrst != prev)
+ pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++;
+
+ _pwrdm_update_pwrst_time(pwrdm, prev);
+
+ /*
+ * If the power domain did not hit the desired state,
+ * generate a trace event with both the desired and hit states
+ */
+ if (pwrdm->next_fpwrst != prev) {
+ trace_state = (PWRDM_TRACE_STATES_FLAG |
+ pwrdm->next_fpwrst << 8 | prev);
+ trace_power_domain_target(pwrdm->name, trace_state,
+ smp_processor_id());
+ }
+
+ fpwrst = _pwrdm_read_fpwrst(pwrdm);
+ if (fpwrst != prev)
+ pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++;
+
+ pwrdm->fpwrst = fpwrst;
+
return 0;
}
*
* Register the list of function pointers used to implement the
* powerdomain functions on different OMAP SoCs. Should be called
- * before any other pwrdm_register*() function. Returns -EINVAL if
- * @po is null, -EEXIST if platform functions have already been
- * registered, or 0 upon success.
+ * before any other pwrdm_register*() function. Several function
+ * pointers in @po are required to be non-null for the powerdomain
+ * code to function: pwrdm_wait_transition, pwrdm_read_next_pwrst,
+ * pwrdm_read_pwrst, pwrdm_set_next_pwrst, pwrdm_set_logic_retst, and
+ * pwrdm_read_prev_pwrst. Returns -EINVAL if @po is null, -EEXIST if
+ * platform functions have already been registered, or 0 upon success.
*/
int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
{
if (arch_pwrdm)
return -EEXIST;
+ if (!po->pwrdm_wait_transition || !po->pwrdm_read_next_pwrst ||
+ !po->pwrdm_read_pwrst || !po->pwrdm_set_next_pwrst ||
+ !po->pwrdm_set_logic_retst || !po->pwrdm_read_prev_pwrst)
+ return -ENOENT;
+
arch_pwrdm = po;
return 0;
*
* Do whatever is necessary to initialize registered powerdomains and
* powerdomain code. Currently, this programs the next power state
- * for each powerdomain to ON. This prevents powerdomains from
- * unexpectedly losing context or entering high wakeup latency modes
- * with non-power-management-enabled kernels. Must be called after
- * pwrdm_register_pwrdms(). Returns -EACCES if called before
- * pwrdm_register_pwrdms(), or 0 upon success.
+ * for each powerdomain to ON, and programs the memory bank power
+ * states to follow the powerdomain power states. This prevents
+ * powerdomains from unexpectedly losing context or entering high
+ * wakeup latency modes with non-power-management-enabled kernels.
+ * Must be called after pwrdm_register_pwrdms(). Returns -EACCES if
+ * called before pwrdm_register_pwrdms(), or 0 upon success.
*/
int pwrdm_complete_init(void)
{
struct powerdomain *temp_p;
+ int i;
if (list_empty(&pwrdm_list))
return -EACCES;
- list_for_each_entry(temp_p, &pwrdm_list, node)
- pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
+ list_for_each_entry(temp_p, &pwrdm_list, node) {
+ for (i = 0; i < temp_p->banks; i++) {
+ _pwrdm_set_mem_onst(temp_p, i, PWRDM_POWER_ON);
+ _pwrdm_set_mem_retst(temp_p, i, PWRDM_POWER_RET);
+ }
+ WARN_ON(pwrdm_set_next_fpwrst(temp_p, PWRDM_FUNC_PWRST_ON));
+ }
return 0;
}
+/**
+ * pwrdm_lock - acquire a Linux spinlock on a powerdomain
+ * @pwrdm: struct powerdomain * to lock
+ *
+ * Acquire the powerdomain spinlock on @pwrdm. No return value.
+ */
+void pwrdm_lock(struct powerdomain *pwrdm)
+ __acquires(&pwrdm->_lock)
+{
+ spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags);
+}
+
+/**
+ * pwrdm_unlock - release a Linux spinlock on a powerdomain
+ * @pwrdm: struct powerdomain * to unlock
+ *
+ * Release the powerdomain spinlock on @pwrdm. No return value.
+ */
+void pwrdm_unlock(struct powerdomain *pwrdm)
+ __releases(&pwrdm->_lock)
+{
+ spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags);
+}
+
/**
* pwrdm_lookup - look up a powerdomain by name, return a pointer
* @name: name of powerdomain
}
/**
- * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
- * @pwrdm: struct powerdomain *
- *
- * Return the number of controllable memory banks in powerdomain @pwrdm,
- * starting with 1. Returns -EINVAL if the powerdomain pointer is null.
- */
-int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
-{
- if (!pwrdm)
- return -EINVAL;
-
- return pwrdm->banks;
-}
-
-/**
- * pwrdm_set_next_pwrst - set next powerdomain power state
- * @pwrdm: struct powerdomain * to set
- * @pwrst: one of the PWRDM_POWER_* macros
+ * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
+ * @pwrdm: struct powerdomain * to clear
*
- * Set the powerdomain @pwrdm's next power state to @pwrst. The powerdomain
- * may not enter this state immediately if the preconditions for this state
- * have not been satisfied. Returns -EINVAL if the powerdomain pointer is
- * null or if the power state is invalid for the powerdomin, or returns 0
- * upon success.
+ * Clear the powerdomain's previous power state register @pwrdm.
+ * Clears the entire register, including logic and memory bank
+ * previous power states. Returns -EINVAL if the powerdomain pointer
+ * is null, or returns 0 upon success.
*/
-int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
{
int ret = -EINVAL;
if (!pwrdm)
- return -EINVAL;
-
- if (!(pwrdm->pwrsts & (1 << pwrst)))
- return -EINVAL;
-
- pr_debug("powerdomain: %s: setting next powerstate to %0x\n",
- pwrdm->name, pwrst);
+ return ret;
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
- /* Trace the pwrdm desired target state */
- trace_power_domain_target(pwrdm->name, pwrst,
- smp_processor_id());
- /* Program the pwrdm desired target state */
- ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
- }
+ /*
+ * XXX Is there some way for us to skip powerdomains that
+ * don't have a prev pwrst register?
+ */
- return ret;
-}
+ /*
+ * XXX should get the powerdomain's current state here;
+ * warn & fail if it is not ON.
+ */
-/**
- * pwrdm_read_next_pwrst - get next powerdomain power state
- * @pwrdm: struct powerdomain * to get power state
- *
- * Return the powerdomain @pwrdm's next power state. Returns -EINVAL
- * if the powerdomain pointer is null or returns the next power state
- * upon success.
- */
-int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
-{
- int ret = -EINVAL;
+ pr_debug("powerdomain: %s: clearing previous power state reg\n",
+ pwrdm->name);
- if (!pwrdm)
- return -EINVAL;
+ pwrdm->_flags &= ~_PWRDM_PREV_FPWRST_IS_VALID;
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst)
- ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
+ if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
+ ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
return ret;
}
/**
- * pwrdm_read_pwrst - get current powerdomain power state
- * @pwrdm: struct powerdomain * to get power state
+ * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
+ * @pwrdm: struct powerdomain *
*
- * Return the powerdomain @pwrdm's current power state. Returns -EINVAL
- * if the powerdomain pointer is null or returns the current power state
- * upon success. Note that if the power domain only supports the ON state
- * then just return ON as the current state.
+ * Enable automatic context save-and-restore upon power state change
+ * for some devices in the powerdomain @pwrdm. Warning: this only
+ * affects a subset of devices in a powerdomain; check the TRM
+ * closely. Returns -EINVAL if the powerdomain pointer is null or if
+ * the powerdomain does not support automatic save-and-restore, or
+ * returns 0 upon success.
*/
-int pwrdm_read_pwrst(struct powerdomain *pwrdm)
+int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
{
int ret = -EINVAL;
if (!pwrdm)
- return -EINVAL;
+ return ret;
+
+ if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
+ return ret;
- if (pwrdm->pwrsts == PWRSTS_ON)
- return PWRDM_POWER_ON;
+ pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n", pwrdm->name);
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
- ret = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
+ if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
+ ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
return ret;
}
/**
- * pwrdm_read_prev_pwrst - get previous powerdomain power state
- * @pwrdm: struct powerdomain * to get previous power state
+ * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
+ * @pwrdm: struct powerdomain *
*
- * Return the powerdomain @pwrdm's previous power state. Returns -EINVAL
- * if the powerdomain pointer is null or returns the previous power state
- * upon success.
+ * Disable automatic context save-and-restore upon power state change
+ * for some devices in the powerdomain @pwrdm. Warning: this only
+ * affects a subset of devices in a powerdomain; check the TRM
+ * closely. Returns -EINVAL if the powerdomain pointer is null or if
+ * the powerdomain does not support automatic save-and-restore, or
+ * returns 0 upon success.
*/
-int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
+int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
{
int ret = -EINVAL;
if (!pwrdm)
- return -EINVAL;
+ return ret;
+
+ if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
+ return ret;
+
+ pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n", pwrdm->name);
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst)
- ret = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
+ if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
+ ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
return ret;
}
/**
- * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
- * @pwrdm: struct powerdomain * to set
- * @pwrst: one of the PWRDM_POWER_* macros
+ * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
+ * @pwrdm: struct powerdomain *
*
- * Set the next power state @pwrst that the logic portion of the
- * powerdomain @pwrdm will enter when the powerdomain enters retention.
- * This will be either RETENTION or OFF, if supported. Returns
- * -EINVAL if the powerdomain pointer is null or the target power
- * state is not not supported, or returns 0 upon success.
+ * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore
+ * for some devices, or 0 if it does not.
*/
-int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
+bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
+ return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
+}
- if (!pwrdm)
- return -EINVAL;
+int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
+{
+ int ret = 0;
- if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
+ if (!pwrdm || !arch_pwrdm)
return -EINVAL;
- pr_debug("powerdomain: %s: setting next logic powerstate to %0x\n",
- pwrdm->name, pwrst);
+ if (!(pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL))
+ ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
- ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, pwrst);
+ if (!ret)
+ _pwrdm_state_switch(pwrdm);
return ret;
}
-/**
- * pwrdm_set_mem_onst - set memory power state while powerdomain ON
- * @pwrdm: struct powerdomain * to set
- * @bank: memory bank number to set (0-3)
- * @pwrst: one of the PWRDM_POWER_* macros
- *
- * Set the next power state @pwrst that memory bank @bank of the
- * powerdomain @pwrdm will enter when the powerdomain enters the ON
- * state. @bank will be a number from 0 to 3, and represents different
- * types of memory, depending on the powerdomain. Returns -EINVAL if
- * the powerdomain pointer is null or the target power state is not
- * not supported for this memory bank, -EEXIST if the target memory
- * bank does not exist or is not controllable, or returns 0 upon
- * success.
- */
-int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
+ int ret;
- if (!pwrdm)
- return -EINVAL;
+ pwrdm_lock(pwrdm);
+ ret = pwrdm_state_switch_nolock(pwrdm);
+ pwrdm_unlock(pwrdm);
- if (pwrdm->banks < (bank + 1))
- return -EEXIST;
+ return ret;
+}
- if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
- return -EINVAL;
+int pwrdm_pre_transition(struct powerdomain *pwrdm)
+{
+ if (pwrdm)
+ _pwrdm_pre_transition_cb(pwrdm, NULL);
+ else
+ pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
- pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
- pwrdm->name, bank, pwrst);
+ return 0;
+}
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
- ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
+int pwrdm_post_transition(struct powerdomain *pwrdm)
+{
+ if (pwrdm)
+ _pwrdm_post_transition_cb(pwrdm, NULL);
+ else
+ pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
- return ret;
+ return 0;
}
/**
- * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
- * @pwrdm: struct powerdomain * to set
- * @bank: memory bank number to set (0-3)
- * @pwrst: one of the PWRDM_POWER_* macros
+ * pwrdm_get_context_loss_count - get powerdomain's context loss count
+ * @pwrdm: struct powerdomain * to wait for
*
- * Set the next power state @pwrst that memory bank @bank of the
- * powerdomain @pwrdm will enter when the powerdomain enters the
- * RETENTION state. Bank will be a number from 0 to 3, and represents
- * different types of memory, depending on the powerdomain. @pwrst
- * will be either RETENTION or OFF, if supported. Returns -EINVAL if
- * the powerdomain pointer is null or the target power state is not
- * not supported for this memory bank, -EEXIST if the target memory
- * bank does not exist or is not controllable, or returns 0 upon
- * success.
+ * Context loss count is the sum of powerdomain off-mode counter, the
+ * logic off counter and the per-bank memory off counter. Returns negative
+ * (and WARNs) upon error, otherwise, returns the context loss count.
*/
-int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
+ int count;
- if (pwrdm->banks < (bank + 1))
- return -EEXIST;
+ if (!pwrdm) {
+ WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
+ return -ENODEV;
+ }
- if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
- return -EINVAL;
+ count = pwrdm->fpwrst_counter[PWRDM_FUNC_PWRST_OFF -
+ PWRDM_FPWRST_OFFSET];
+ count += pwrdm->fpwrst_counter[PWRDM_FUNC_PWRST_OSWR -
+ PWRDM_FPWRST_OFFSET];
- pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
- pwrdm->name, bank, pwrst);
+ /*
+ * Context loss count has to be a non-negative value. Clear the sign
+ * bit to get a value range from 0 to INT_MAX.
+ */
+ count &= INT_MAX;
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
- ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
+ pr_debug("powerdomain: %s: context loss count = %d\n",
+ pwrdm->name, count);
- return ret;
+ return count;
}
/**
- * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
- * @pwrdm: struct powerdomain * to get current logic retention power state
+ * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
+ * @pwrdm: struct powerdomain *
*
- * Return the power state that the logic portion of powerdomain @pwrdm
- * will enter when the powerdomain enters retention. Returns -EINVAL
- * if the powerdomain pointer is null or returns the logic retention
- * power state upon success.
+ * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
+ * can lose either memory or logic context or if @pwrdm is invalid, or
+ * returns 0 otherwise. This function is not concerned with how the
+ * powerdomain registers are programmed (i.e., to go off or not); it's
+ * concerned with whether it's ever possible for this powerdomain to
+ * go off while some other part of the chip is active. This function
+ * assumes that every powerdomain can go to either ON or INACTIVE.
*/
-int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
+bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
+ int i;
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst)
- ret = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+ if (IS_ERR_OR_NULL(pwrdm)) {
+ pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
+ __func__);
+ return 1;
+ }
- return ret;
-}
+ if (pwrdm->pwrsts & PWRSTS_OFF)
+ return 1;
-/**
- * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
- * @pwrdm: struct powerdomain * to get previous logic power state
- *
- * Return the powerdomain @pwrdm's previous logic power state. Returns
- * -EINVAL if the powerdomain pointer is null or returns the previous
- * logic power state upon success.
- */
-int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
-{
- int ret = -EINVAL;
+ if (pwrdm->pwrsts & PWRSTS_RET) {
+ if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
+ return 1;
- if (!pwrdm)
- return -EINVAL;
+ for (i = 0; i < pwrdm->banks; i++)
+ if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
+ return 1;
+ }
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst)
- ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
+ for (i = 0; i < pwrdm->banks; i++)
+ if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
+ return 1;
- return ret;
+ return 0;
}
+/* Public functions for functional power state handling */
+
/**
- * pwrdm_read_logic_retst - get next powerdomain logic power state
- * @pwrdm: struct powerdomain * to get next logic power state
+ * pwrdm_convert_fpwrst_to_name - return the name of a functional power state
+ * @fpwrst: functional power state to return the name of
*
- * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
- * if the powerdomain pointer is null or returns the next logic
- * power state upon success.
+ * Return a pointer to a string with the human-readable name of the
+ * functional power state (e.g., "ON", "CSWR", etc.) Intended for use
+ * in debugging. Returns NULL if @fpwrst is outside the range of the
+ * known functional power states.
*/
-int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
+const char *pwrdm_convert_fpwrst_to_name(u8 fpwrst)
{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst)
- ret = arch_pwrdm->pwrdm_read_logic_retst(pwrdm);
+ if (fpwrst < PWRDM_FPWRST_OFFSET || fpwrst >= PWRDM_MAX_FUNC_PWRSTS)
+ return NULL;
- return ret;
+ return _fpwrst_names[fpwrst - PWRDM_FPWRST_OFFSET];
}
/**
- * pwrdm_read_mem_pwrst - get current memory bank power state
- * @pwrdm: struct powerdomain * to get current memory bank power state
- * @bank: memory bank number (0-3)
+ * pwrdm_set_next_fpwrst - set next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: one of the PWRDM_POWER_* macros
*
- * Return the powerdomain @pwrdm's current memory power state for bank
- * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
- * the target memory bank does not exist or is not controllable, or
- * returns the current memory power state upon success.
+ * Set the powerdomain @pwrdm's next power state to @fpwrst. The
+ * powerdomain may not enter this state immediately if the
+ * preconditions for this state have not been satisfied. Returns
+ * -EINVAL if the powerdomain pointer is null or if the power state is
+ * invalid for the powerdomin, or returns 0 upon success.
*/
-int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return ret;
-
- if (pwrdm->banks < (bank + 1))
- return ret;
-
- if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
- bank = 1;
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
- ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
+ u8 pwrst, logic;
+ int ret;
- return ret;
-}
+ if (!pwrdm || IS_ERR(pwrdm))
+ return -EINVAL;
-/**
- * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
- * @pwrdm: struct powerdomain * to get previous memory bank power state
- * @bank: memory bank number (0-3)
- *
- * Return the powerdomain @pwrdm's previous memory power state for
- * bank @bank. Returns -EINVAL if the powerdomain pointer is null,
- * -EEXIST if the target memory bank does not exist or is not
- * controllable, or returns the previous memory power state upon
- * success.
- */
-int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
-{
- int ret = -EINVAL;
+ /*
+ * XXX Should return an error, but this means that our PM code
+ * will need to be much more careful about what it programs
+ */
+ if (!_pwrdm_pwrst_is_controllable(pwrdm))
+ return 0;
- if (!pwrdm)
+ ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+ if (ret)
return ret;
- if (pwrdm->banks < (bank + 1))
- return ret;
+ if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID &&
+ pwrdm->next_fpwrst == fpwrst)
+ return 0;
- if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
- bank = 1;
+ pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst,
+ pwrdm->name);
+
+ /* Trace the pwrdm desired target state */
+ trace_power_domain_target(pwrdm->name, fpwrst, smp_processor_id());
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
- ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
+ pwrdm_lock(pwrdm);
+ ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+ if (!ret) {
+ pwrdm->next_fpwrst = fpwrst;
+ pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+ }
+ pwrdm_unlock(pwrdm);
return ret;
}
/**
- * pwrdm_read_mem_retst - get next memory bank power state
- * @pwrdm: struct powerdomain * to get mext memory bank power state
- * @bank: memory bank number (0-3)
+ * pwrdm_read_next_fpwrst - get next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
*
- * Return the powerdomain pwrdm's next memory power state for bank
- * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
- * the target memory bank does not exist or is not controllable, or
- * returns the next memory power state upon success.
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the next power state upon success.
*/
-int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
+int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
+ int ret;
if (!pwrdm)
- return ret;
-
- if (pwrdm->banks < (bank + 1))
- return ret;
+ return -EINVAL;
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
- ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
+ pwrdm_lock(pwrdm);
+ ret = _pwrdm_read_next_fpwrst(pwrdm);
+ pwrdm_unlock(pwrdm);
return ret;
}
/**
- * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
- * @pwrdm: struct powerdomain * to clear
+ * pwrdm_set_fpwrst - program next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: power domain functional state, one of the PWRDM_FUNC_* macros
*
- * Clear the powerdomain's previous power state register @pwrdm.
- * Clears the entire register, including logic and memory bank
- * previous power states. Returns -EINVAL if the powerdomain pointer
- * is null, or returns 0 upon success.
+ * This programs the pwrdm next functional state, sets the dependencies
+ * and waits for the state to be applied.
*/
-int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
+int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
{
- int ret = -EINVAL;
+ u8 next_fpwrst, pwrst, logic, sleep_switch;
+ int ret = 0;
+ bool hwsup = false;
- if (!pwrdm)
- return ret;
+ if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm)
+ return -EINVAL;
/*
- * XXX should get the powerdomain's current state here;
- * warn & fail if it is not ON.
+ * XXX Should return an error, but this means that our PM code
+ * will need to be much more careful about what it programs
*/
+ if (!_pwrdm_pwrst_is_controllable(pwrdm))
+ return 0;
- pr_debug("powerdomain: %s: clearing previous power state reg\n",
- pwrdm->name);
+ ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+ if (ret)
+ return -EINVAL;
- if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
- ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
+ pr_debug("%s: pwrdm %s: set fpwrst %0x\n", __func__, pwrdm->name,
+ fpwrst);
- return ret;
-}
+ pwrdm_lock(pwrdm);
-/**
- * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
- * @pwrdm: struct powerdomain *
- *
- * Enable automatic context save-and-restore upon power state change
- * for some devices in the powerdomain @pwrdm. Warning: this only
- * affects a subset of devices in a powerdomain; check the TRM
- * closely. Returns -EINVAL if the powerdomain pointer is null or if
- * the powerdomain does not support automatic save-and-restore, or
- * returns 0 upon success.
- */
-int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
-{
- int ret = -EINVAL;
+ next_fpwrst = _pwrdm_read_next_fpwrst(pwrdm);
+ if (next_fpwrst == fpwrst)
+ goto psf_out;
- if (!pwrdm)
- return ret;
+ /* Trace the pwrdm desired target state */
+ trace_power_domain_target(pwrdm->name, next_fpwrst,
+ smp_processor_id());
- if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
- return ret;
+ sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, fpwrst,
+ &hwsup);
+ if (sleep_switch == ERROR_SWITCH) {
+ ret = -EINVAL;
+ goto psf_out;
+ }
- pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n", pwrdm->name);
+ ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+ if (ret) {
+ pr_err("%s: unable to set power state of powerdomain: %s\n",
+ __func__, pwrdm->name);
+ } else {
+ pwrdm->next_fpwrst = fpwrst;
+ pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+ }
- if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
- ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
+ _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
+
+psf_out:
+ pwrdm_unlock(pwrdm);
return ret;
}
/**
- * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
- * @pwrdm: struct powerdomain *
+ * pwrdm_read_fpwrst - get current functional powerdomain power state
+ * @pwrdm: struct powerdomain * to get current functional power state
*
- * Disable automatic context save-and-restore upon power state change
- * for some devices in the powerdomain @pwrdm. Warning: this only
- * affects a subset of devices in a powerdomain; check the TRM
- * closely. Returns -EINVAL if the powerdomain pointer is null or if
- * the powerdomain does not support automatic save-and-restore, or
- * returns 0 upon success.
+ * Return the powerdomain @pwrdm's current functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * current power state upon success.
*/
-int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
+int pwrdm_read_fpwrst(struct powerdomain *pwrdm)
{
- int ret = -EINVAL;
+ int ret;
- if (!pwrdm)
- return ret;
+ if (!pwrdm || !arch_pwrdm)
+ return -EINVAL;
- if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
- return ret;
+ if (!_pwrdm_pwrst_can_change(pwrdm))
+ return PWRDM_FUNC_PWRST_ON;
- pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n", pwrdm->name);
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
- ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
+ pwrdm_lock(pwrdm);
+ ret = _pwrdm_read_fpwrst(pwrdm);
+ pwrdm_unlock(pwrdm);
return ret;
}
/**
- * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
- * @pwrdm: struct powerdomain *
+ * pwrdm_read_prev_fpwrst - get previous powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get previous functional power state
*
- * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore
- * for some devices, or 0 if it does not.
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous functional power state upon success.
*/
-bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
-{
- return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
-}
-
-/**
- * pwrdm_set_lowpwrstchange - Request a low power state change
- * @pwrdm: struct powerdomain *
- *
- * Allows a powerdomain to transtion to a lower power sleep state
- * from an existing sleep state without waking up the powerdomain.
- * Returns -EINVAL if the powerdomain pointer is null or if the
- * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0
- * upon success.
- */
-int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
+int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
{
int ret = -EINVAL;
- if (!pwrdm)
+ if (!pwrdm || !arch_pwrdm)
return -EINVAL;
- if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE))
- return -EINVAL;
+ if (!_pwrdm_pwrst_can_change(pwrdm))
+ return PWRDM_FUNC_PWRST_ON;
- pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
- pwrdm->name);
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange)
- ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
+ pwrdm_lock(pwrdm);
+ ret = _pwrdm_read_prev_fpwrst(pwrdm);
+ pwrdm_unlock(pwrdm);
return ret;
}
/**
- * pwrdm_wait_transition - wait for powerdomain power transition to finish
- * @pwrdm: struct powerdomain * to wait for
+ * pwrdm_supports_fpwrst - does the powerdomain @pwrdm support the @fpwrst power
+ * state?
+ * @pwrdm: struct powerdomain * pointing to a powerdomain to test
+ * @fpwrst: functional power state
*
- * If the powerdomain @pwrdm is in the process of a state transition,
- * spin until it completes the power transition, or until an iteration
- * bailout value is reached. Returns -EINVAL if the powerdomain
- * pointer is null, -EAGAIN if the bailout value was reached, or
- * returns 0 upon success.
+ * Returns true if the powerdomain pointed to by @pwrdm can enter the
+ * functional power state @fpwrst, or false if not.
*/
-int pwrdm_wait_transition(struct powerdomain *pwrdm)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition)
- ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
-
- return ret;
-}
-
-int pwrdm_state_switch(struct powerdomain *pwrdm)
+bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
{
+ u8 pwrst, logic;
int ret;
- ret = pwrdm_wait_transition(pwrdm);
- if (!ret)
- ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+ if (!pwrdm || IS_ERR(pwrdm))
+ return false;
- return ret;
-}
-
-int pwrdm_pre_transition(struct powerdomain *pwrdm)
-{
- if (pwrdm)
- _pwrdm_pre_transition_cb(pwrdm, NULL);
- else
- pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
+ ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+ if (ret)
+ return false;
- return 0;
-}
+ if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET &&
+ !(pwrdm->pwrsts_logic_ret & (1 << logic)))
+ return false;
-int pwrdm_post_transition(struct powerdomain *pwrdm)
-{
- if (pwrdm)
- _pwrdm_post_transition_cb(pwrdm, NULL);
- else
- pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
+ if (!(pwrdm->pwrsts & (1 << pwrst)))
+ return false;
- return 0;
+ return true;
}
+/* Powerdomain debugfs-related functions */
+
/**
- * pwrdm_get_context_loss_count - get powerdomain's context loss count
- * @pwrdm: struct powerdomain * to wait for
+ * pwrdm_dbg_show_counter - generate debugfs data for the pwrdm pwrst counters
+ * @pwrdm: struct powerdomain * to generate debugfs data for
+ * @seq_file: struct seq_file * to write data to
*
- * Context loss count is the sum of powerdomain off-mode counter, the
- * logic off counter and the per-bank memory off counter. Returns negative
- * (and WARNs) upon error, otherwise, returns the context loss count.
+ * Dump the powerdomain @pwrdm's power state counters (and current
+ * power state) to the seq_file @seq_file. Currently called by the
+ * mach-omap2/pm-debug.c code. Returns 0.
*/
-int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
+int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *seq_file)
{
- int i, count;
+ struct seq_file *s = (struct seq_file *)seq_file;
+ int i;
+ u8 curr_fpwrst;
- if (!pwrdm) {
- WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
- return -ENODEV;
- }
+ if (!_pwrdm_pwrst_can_change(pwrdm))
+ return 0;
- count = pwrdm->state_counter[PWRDM_POWER_OFF];
- count += pwrdm->ret_logic_off_counter;
+ pwrdm_lock(pwrdm);
- for (i = 0; i < pwrdm->banks; i++)
- count += pwrdm->ret_mem_off_counter[i];
+ curr_fpwrst = _pwrdm_read_fpwrst(pwrdm);
+ if (pwrdm->fpwrst != curr_fpwrst)
+ pr_err("pwrdm state mismatch(%s) %s != %s\n",
+ pwrdm->name,
+ pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst),
+ pwrdm_convert_fpwrst_to_name(curr_fpwrst));
- /*
- * Context loss count has to be a non-negative value. Clear the sign
- * bit to get a value range from 0 to INT_MAX.
- */
- count &= INT_MAX;
+ seq_printf(s, "%s (%s)", pwrdm->name,
+ pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst));
+ for (i = PWRDM_FPWRST_OFFSET; i < PWRDM_MAX_FUNC_PWRSTS; i++)
+ seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i),
+ pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]);
- pr_debug("powerdomain: %s: context loss count = %d\n",
- pwrdm->name, count);
+ seq_printf(s, "\n");
- return count;
+ pwrdm_unlock(pwrdm);
+
+ return 0;
}
/**
- * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
- * @pwrdm: struct powerdomain *
+ * pwrdm_dbg_show_timer - generate debugfs data for the pwrdm pwrst timers
+ * @pwrdm: struct powerdomain * to generate debugfs data for
+ * @seq_file: struct seq_file * to write data to
*
- * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
- * can lose either memory or logic context or if @pwrdm is invalid, or
- * returns 0 otherwise. This function is not concerned with how the
- * powerdomain registers are programmed (i.e., to go off or not); it's
- * concerned with whether it's ever possible for this powerdomain to
- * go off while some other part of the chip is active. This function
- * assumes that every powerdomain can go to either ON or INACTIVE.
+ * Dump the powerdomain @pwrdm's power state residency duration timings
+ * to the seq_file @seq_file. Currently called by the mach-omap2/pm-debug.c
+ * code. Returns 0.
*/
-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
+int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *seq_file)
{
+#ifdef CONFIG_PM_DEBUG
+ struct seq_file *s = (struct seq_file *)seq_file;
int i;
- if (IS_ERR_OR_NULL(pwrdm)) {
- pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
- __func__);
- return 1;
- }
+ if (!_pwrdm_pwrst_can_change(pwrdm))
+ return 0;
- if (pwrdm->pwrsts & PWRSTS_OFF)
- return 1;
+ pwrdm_lock(pwrdm);
- if (pwrdm->pwrsts & PWRSTS_RET) {
- if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
- return 1;
+ pwrdm_state_switch_nolock(pwrdm);
- for (i = 0; i < pwrdm->banks; i++)
- if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
- return 1;
- }
+ seq_printf(s, "%s (%s)", pwrdm->name,
+ pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst));
- for (i = 0; i < pwrdm->banks; i++)
- if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
- return 1;
+ for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+ seq_printf(s, ",%s:%lld",
+ pwrdm_convert_fpwrst_to_name(i + PWRDM_FPWRST_OFFSET),
+ pwrdm->fpwrst_timer[i]);
+ seq_printf(s, "\n");
+
+ pwrdm_unlock(pwrdm);
+#endif
return 0;
}
+
diff --combined arch/arm/mach-omap2/powerdomain.h
index b8f3dbf564c13d0c00e3a1d689cb681702973875,697be254461c11e4cc0b4866fd1e4ada6e390961..55c1201c1943e045e9448b0d41c0943f434e272e
/*
* OMAP2/3/4 powerdomain control
*
- * Copyright (C) 2007-2008, 2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010-2012 Texas Instruments, Inc.
* Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley
#include <linux/types.h>
#include <linux/list.h>
-
-#include <linux/atomic.h>
+#include <linux/spinlock.h>
#include "voltage.h"
+/*
+ * PWRDM_FPWRST_OFFSET: offset of the first functional power state
+ * from 0. This offset can be subtracted from the functional power
+ * state macros to produce offsets suitable for array indices, for
+ * example. The intention behind the addition of this offset is to
+ * prevent functional power states from accidentally being confused
+ * with the low-level, hardware power states.
+ */
+#define PWRDM_FPWRST_OFFSET 0x80
+
+/*
+ * Powerdomain functional power states, used by the external API functions
+ * These must match the order and names in _fpwrst_names[]
+ */
+enum pwrdm_func_state {
+ PWRDM_FUNC_PWRST_OFF = PWRDM_FPWRST_OFFSET,
+ PWRDM_FUNC_PWRST_OSWR,
+ PWRDM_FUNC_PWRST_CSWR,
+ PWRDM_FUNC_PWRST_INACTIVE,
+ PWRDM_FUNC_PWRST_ON,
+ PWRDM_MAX_FUNC_PWRSTS /* Last value, used as the max value */
+};
+
+#define PWRDM_FPWRSTS_COUNT (PWRDM_MAX_FUNC_PWRSTS - PWRDM_FPWRST_OFFSET)
+
/* Powerdomain basic power states */
#define PWRDM_POWER_OFF 0x0
#define PWRDM_POWER_RET 0x1
#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON)
-/* Powerdomain flags */
-#define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */
-#define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits
- * in MEM bank 1 position. This is
- * true for OMAP3430
- */
-#define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /*
- * support to transition from a
- * sleep state to a lower sleep
- * state without waking up the
- * powerdomain
- */
+/*
+ * Powerdomain flags (struct powerdomain.flags)
+ *
+ * PWRDM_HAS_HDWR_SAR - powerdomain has hardware save-and-restore support
+ *
+ * PWRDM_HAS_MPU_QUIRK - MPU pwr domain has MEM bank 0 bits in MEM
+ * bank 1 position. This is true for OMAP3430
+ *
+ * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state
+ * to a lower sleep state without waking up the powerdomain
+ *
+ * PWRDM_ACTIVE_WITH_KERNEL - this powerdomain's current power state is
+ * guaranteed to be ON whenever the kernel is running
+ */
+#define PWRDM_HAS_HDWR_SAR BIT(0)
+#define PWRDM_HAS_MPU_QUIRK BIT(1)
+#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2)
+#define PWRDM_ACTIVE_WITH_KERNEL BIT(3)
+
+/*
+ * Powerdomain internal flags (struct powerdomain._flags)
+ *
+ * _PWRDM_NEXT_FPWRST_IS_VALID: the locally-cached copy of the
+ * powerdomain's next-functional-power-state -- struct
+ * powerdomain.next_fpwrst -- is valid. If this bit is not set,
+ * the code needs to load the current value from the hardware.
+ *
+ * _PWRDM_PREV_FPWRST_IS_VALID: the locally-cached copy of the
+ * powerdomain's previous-functional-power-state -- struct
+ * powerdomain.prev_fpwrst -- is valid. If this bit is not set,
+ * the code needs to load the current value from the hardware. The
+ * previous-functional-power-state cache for the CORE and MPU needs
+ * to be invalidated right before WFI, unless they were not programmed
+ * to change power states.
+ */
+#define _PWRDM_NEXT_FPWRST_IS_VALID BIT(0)
+#define _PWRDM_PREV_FPWRST_IS_VALID BIT(1)
/*
* Number of memory banks that are power-controllable. On OMAP4430, the
* @mem_pwrst_mask: (AM33XX only) mask for mem state bitfield in @pwrstst_offs
* @mem_retst_mask: (AM33XX only) mask for mem retention state bitfield
* in @pwrstctrl_offs
- * @state:
- * @state_counter:
- * @timer:
- * @state_timer:
+ * @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans)
+ * @fpwrst_counter: estimated number of times the pwrdm entered the power states
+ * @next_fpwrst: cache of the powerdomain's next-power-state
+ * @prev_fpwrst: cache of the powerdomain's previous-power-state bitfield
+ * @timer: sched_clock() timestamp of last pwrdm_state_switch()
+ * @fpwrst_timer: estimated nanoseconds of residency in the various power states
+ * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
+ * @_lock_flags: stored flags when @_lock is taken
+ * @_flags: flags (for internal use only)
*
* @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
+ *
+ * @prev_fpwrst is updated during pwrdm_pre_transition(), but presumably
+ * should also be updated upon clock/IP block idle transitions.
+ *
+ * Possible values for @_flags are documented above in the
+ * "Powerdomain internal flags (struct powerdomain._flags)" comments.
*/
struct powerdomain {
const char *name;
const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
const u8 prcm_partition;
+ u8 fpwrst;
+ u8 next_fpwrst;
+ u8 prev_fpwrst;
+ u8 _flags;
struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
struct list_head node;
struct list_head voltdm_node;
- int state;
- unsigned state_counter[PWRDM_MAX_PWRSTS];
- unsigned ret_logic_off_counter;
- unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
-
+ unsigned fpwrst_counter[PWRDM_FPWRSTS_COUNT];
+ spinlock_t _lock;
+ unsigned long _lock_flags;
const u8 pwrstctrl_offs;
const u8 pwrstst_offs;
const u32 logicretstate_mask;
#ifdef CONFIG_PM_DEBUG
s64 timer;
- s64 state_timer[PWRDM_MAX_PWRSTS];
+ s64 fpwrst_timer[PWRDM_FPWRSTS_COUNT];
#endif
};
* @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd
* @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep
* @pwrdm_wait_transition: Wait for a pd state transition to complete
+ * @pwrdm_has_voltdm; Check if a voltdm association is needed
*/
struct pwrdm_ops {
int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst);
int (*pwrdm_disable_hdwr_sar)(struct powerdomain *pwrdm);
int (*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
int (*pwrdm_wait_transition)(struct powerdomain *pwrdm);
+ int (*pwrdm_has_voltdm)(void);
};
int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
struct clockdomain *clkdm));
struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
-int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
-
-int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
-int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
-int pwrdm_read_pwrst(struct powerdomain *pwrdm);
-int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
-int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
-int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
-int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
-
-int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
-int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
-int pwrdm_read_logic_retst(struct powerdomain *pwrdm);
-int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
-int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
-int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank);
-
int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
-int pwrdm_wait_transition(struct powerdomain *pwrdm);
-
+int pwrdm_state_switch_nolock(struct powerdomain *pwrdm);
int pwrdm_state_switch(struct powerdomain *pwrdm);
+int pwrdm_state_switch_nolock(struct powerdomain *pwrdm);
int pwrdm_pre_transition(struct powerdomain *pwrdm);
int pwrdm_post_transition(struct powerdomain *pwrdm);
-int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);
+
+extern const char *pwrdm_convert_fpwrst_to_name(u8 fpwrst);
+extern int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst);
+extern int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm);
+extern int pwrdm_set_fpwrst(struct powerdomain *pwrdm,
+ enum pwrdm_func_state fpwrst);
+extern int pwrdm_read_fpwrst(struct powerdomain *pwrdm);
+extern int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm);
+extern bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst);
+
extern void omap242x_powerdomains_init(void);
extern void omap243x_powerdomains_init(void);
extern void omap3xxx_powerdomains_init(void);
extern void am33xx_powerdomains_init(void);
extern void omap44xx_powerdomains_init(void);
extern void omap54xx_powerdomains_init(void);
+ extern void dra7xx_powerdomains_init(void);
extern struct pwrdm_ops omap2_pwrdm_operations;
extern struct pwrdm_ops omap3_pwrdm_operations;
extern struct powerdomain wkup_omap2_pwrdm;
extern struct powerdomain gfx_omap2_pwrdm;
+extern void pwrdm_lock(struct powerdomain *pwrdm);
+extern void pwrdm_unlock(struct powerdomain *pwrdm);
+
+/* Debugfs functions */
+extern int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *seq_file);
+extern int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *seq_file);
#endif
diff --combined arch/arm/mach-omap2/sram.c
index 6c50e4c7fca3b521a03af718c884663283a6b20e,0dc6b7a2060a4053f286e944d1d0c9d7313e3c00..8d40e8eb3bdaa3fd7131116b5611b47f4c82bcda
omap_sram_size = OMAP5_SRAM_SIZE; /* 128KB */
omap_sram_size -= OMAP5_SRAM_HS_RESERVE;
omap_sram_start += OMAP5_SRAM_HS_RESERVE;
+ } else if (soc_is_dra7xx()) {
+ omap_sram_start = OMAP4_SRAM_START_PA;
+ omap_sram_size = DRA7XX_SRAM_SIZE; /* 512KB */
+ /*
+ * Fix me:
+ * The reservation size might change based on
+ * the PPA requirements.
+ */
+ omap_sram_size -= OMAP5_SRAM_HS_RESERVE;
+ omap_sram_start += OMAP5_SRAM_HS_RESERVE;
} else {
omap_sram_start = OMAP2_SRAM_PUB_PA;
omap_sram_size = 0x800; /* 2K */
omap_sram_size = OMAP5_SRAM_SIZE; /* 128KB */
omap_sram_size -= OMAP5_SRAM_GP_RESERVE;
omap_sram_start += OMAP5_SRAM_GP_RESERVE;
+ } else if (soc_is_dra7xx()) {
+ omap_sram_start = OMAP4_SRAM_START_PA;
+ omap_sram_size = DRA7XX_SRAM_SIZE; /* 512KB */
+ omap_sram_size -= OMAP5_SRAM_GP_RESERVE;
+ omap_sram_start += OMAP5_SRAM_GP_RESERVE;
} else {
omap_sram_start = OMAP2_SRAM_PA;
if (cpu_is_omap242x())
{
int cached = 1;
- omap_sram_size -= OMAP4_ERRATA_I688_SIZE;
-
- if (cpu_is_omap34xx()) {
+#ifdef CONFIG_OMAP4_ERRATA_I688
+ if (cpu_is_omap44xx() || soc_is_omap54xx())
+ omap_sram_size -= OMAP4_ERRATA_I688_SIZE;
+#endif
+ if (cpu_is_omap34xx() || soc_is_am33xx()) {
/*
* SRAM must be marked as non-cached on OMAP3 since the
* CORE DPLL M2 divider change code (in SRAM) runs with the
}
#endif /* CONFIG_ARCH_OMAP3 */
+#ifdef CONFIG_SOC_AM33XX
+static inline int am33xx_sram_init(void)
+{
+ am33xx_push_sram_idle();
+ return 0;
+}
+#else
static inline int am33xx_sram_init(void)
{
return 0;
}
+#endif
int __init omap_sram_init(void)
{
diff --combined arch/arm/mach-omap2/sram.h
index 6476c38b3da93e792994d03ff9aa661e6aa75343,857f28772e355cd1bd0c33f1e9209e9f46fd8cba..e19ec2ee2f5d3ef8aac9933d0903443b30c9be2e
#ifdef CONFIG_PM
extern void omap_push_sram_idle(void);
+extern void am33xx_push_sram_idle(void);
#else
static inline void omap_push_sram_idle(void) {}
+static inline void am33xx_push_sram_idle(void) {}
#endif /* CONFIG_PM */
#endif /* __ASSEMBLY__ */
#define OMAP4_SRAM_SIZE (SZ_64K - SZ_8K)
/* OMAP5 has 128K */
#define OMAP5_SRAM_SIZE SZ_128K
+
+ /* DRA7XX has 512K */
+ #define DRA7XX_SRAM_SIZE SZ_512K
+
/* 16K GP, 52K HS(default) for secure world */
#define OMAP4_SRAM_GP_RESERVE SZ_16K
#ifdef CONFIG_OMAP4_HS_SECURE_SRAM_SIZE
diff --combined arch/arm/mach-omap2/timer.c
index 30ad6f8e3d007841f78bb843da5f9b7f9a26bd5d,22070c419c94f1446971d5790dcfbe5fc7b1f34d..cf18fb851ef268fcb65a93ace03702330e55e566
}
}
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+ char name[10];
+ struct omap_hwmod *oh;
+
+ sprintf(name, "timer%d", clkev.id);
+ oh = omap_hwmod_lookup(name);
+ if (!oh)
+ return;
+
+ __omap_dm_timer_stop(&clkev, 1, clkev.rate);
+ omap_hwmod_idle(oh);
+}
+
+static void omap_clkevt_resume(struct clock_event_device *unused)
+{
+ char name[10];
+ struct omap_hwmod *oh;
+
+ sprintf(name, "timer%d", clkev.id);
+ oh = omap_hwmod_lookup(name);
+ if (!oh)
+ return;
+
+ omap_hwmod_enable(oh);
+ __omap_dm_timer_load_start(&clkev,
+ OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+ __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+}
+
static struct clock_event_device clockevent_gpt = {
.name = "gp_timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.rating = 300,
.set_next_event = omap2_gp_timer_set_next_event,
.set_mode = omap2_gp_timer_set_mode,
+ .suspend = omap_clkevt_suspend,
+ .resume = omap_clkevt_resume,
};
static struct property device_disabled = {
int r = 0;
if (of_have_populated_dt()) {
- np = omap_get_timer_dt(omap_timer_match, NULL);
+ np = omap_get_timer_dt(omap_timer_match, property);
if (!np)
return -ENODEV;
int res;
clkev.errata = omap_dm_timer_get_errata();
+ clkev.id = gptimer_id;
/*
* For clock-event timers we never read the timer counter and
#endif /* CONFIG_ARCH_OMAP3 */
#ifdef CONFIG_SOC_AM33XX
-OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
- 2, OMAP4_MPU_SOURCE);
+OMAP_SYS_GP_TIMER_INIT(3_am33xx, 2, OMAP4_MPU_SOURCE, "ti,timer-non-wkup",
+ 1, OMAP4_MPU_SOURCE);
OMAP_SYS_TIMER(3_am33xx, gptimer);
#endif /* CONFIG_SOC_AM33XX */
OMAP_SYS_TIMER(4, local);
#endif /* CONFIG_ARCH_OMAP4 */
- #ifdef CONFIG_SOC_OMAP5
+ #if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
OMAP_SYS_32K_TIMER_INIT(5, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
2, OMAP5_MPU_SOURCE);
static void __init omap5_realtime_timer_init(void)
diff --combined arch/arm/plat-omap/Kconfig
index 5b728b661d8a9aaf74198b42f08e1fa9c1400fde,9c643b67dcdeb1e4e7bffaf3efe638d6c8095a41..98000b22d04726b39482ccc1928d8e23e9011b91
select SPARSE_IRQ
select USE_OF
help
- "Systems based on OMAP2, OMAP3, OMAP4 or OMAP5"
+ "Systems based on OMAP2, OMAP3, OMAP4, OMAP5 or DRA7XX"
endchoice
to change the pin multiplexing setup. When there are no warnings
printed, it's safe to deselect OMAP_MUX for your product.
-config OMAP_MBOX_FWK
- tristate "Mailbox framework support"
- depends on ARCH_OMAP
- help
- Say Y here if you want to use OMAP Mailbox framework support for
- DSP, IVA1.0 and IVA2 in OMAP1/2/3.
-
-config OMAP_MBOX_KFIFO_SIZE
- int "Mailbox kfifo default buffer size (bytes)"
- depends on OMAP_MBOX_FWK
- default 256
- help
- Specify the default size of mailbox's kfifo buffers (bytes).
- This can also be changed at runtime (via the mbox_kfifo_size
- module parameter).
-
config OMAP_IOMMU_IVA2
bool
This timer saves power compared to the OMAP_MPU_TIMER, and has
support for no tick during idle. The 32KHz timer provides less
intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
- currently only available for OMAP16XX, 24XX, 34XX and OMAP4/5.
+ currently only available for OMAP16XX, 24XX, 34XX, OMAP4/5 and DRA7XX.
On OMAP2PLUS this value is only used for CONFIG_HZ and
CLOCK_TICK_RATE compile time calculation.