]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/commitdiff
Merge remote-tracking branch 'rnayak/platform-base-vayu-3.8.y' into vayu-pm-linux...
authorTero Kristo <t-kristo@ti.com>
Mon, 27 May 2013 14:06:42 +0000 (17:06 +0300)
committerTero 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>
20 files changed:
1  2 
arch/arm/configs/omap2plus_defconfig
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/cclock33xx_data.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap-hotplug.c
arch/arm/mach-omap2/omap-mpuss-lowpower.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/pm_omap4plus.c
arch/arm/mach-omap2/powerdomain.c
arch/arm/mach-omap2/powerdomain.h
arch/arm/mach-omap2/sram.c
arch/arm/mach-omap2/sram.h
arch/arm/mach-omap2/timer.c
arch/arm/plat-omap/Kconfig

index e5b58cd8d5c0456471c60d651861e3830b8fb13f,dfa2f6d8af2c2f7143c7fcf45c35c89122911927..4a20e7d62cbfa886f3bc2f74ed4bd8cbcc2c645d
@@@ -34,12 -34,6 +34,12 @@@ CONFIG_ZBOOT_ROM_TEXT=0x
  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
@@@ -58,6 -52,11 +58,11 @@@ CONFIG_IP_PNP_RARP=
  # 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
@@@ -89,6 -88,9 +94,9 @@@ CONFIG_MTD_UBI=
  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
@@@ -114,6 -116,7 +122,7 @@@ CONFIG_USB_KC2190=
  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
@@@ -137,23 -140,13 +146,25 @@@ CONFIG_GPIO_SYSFS=
  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
@@@ -214,18 -207,22 +225,28 @@@ CONFIG_MMC_UNSAFE_RESUME=
  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
@@@ -273,3 -270,4 +294,4 @@@ CONFIG_SOC_OMAP5=
  CONFIG_TI_DAVINCI_MDIO=y
  CONFIG_TI_DAVINCI_CPDMA=y
  CONFIG_TI_CPSW=y
+ CONFIG_SOC_DRA7XX=y
index 00d62eaeca4b6889783f49a8dc07ea0c2a07b4c4,5e91009ef16871a6d07fcfa7a81305939c7cae49..d02efdaa8348a10654086413e6698731348e1143
@@@ -10,7 -10,7 +10,7 @@@ config ARCH_OMAP2PLUS_TYPICA
        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
@@@ -61,7 -58,6 +61,7 @@@ config ARCH_OMAP
        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
@@@ -80,7 -76,6 +80,7 @@@
  
  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
  
@@@ -120,11 -123,9 +128,11 @@@ config SOC_AM33X
        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
index 7a43c6329af020ff4c6cfb8a01d87ed31611f762,e7108e5a86e879dc47d9f26b3f4fab8b4369e71d..fa3b96c543a3ef114f70241ea4bf463ef764eb7a
@@@ -19,6 -19,7 +19,7 @@@ obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-
  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
@@@ -35,6 -36,7 +36,7 @@@ omap-4-5-common                               =  omap4-common.o om
                                           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)
@@@ -83,15 -85,14 +85,16 @@@ obj-$(CONFIG_ARCH_OMAP2)           += sleep24xx.
  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
@@@ -117,6 -118,7 +120,7 @@@ omap-prcm-4-5-common                       =  cminst44xx.o 
                                           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
@@@ -130,6 -132,7 +134,7 @@@ obj-$(CONFIG_SOC_AM33XX)           += $(voltaged
  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
@@@ -145,6 -148,8 +150,8 @@@ obj-$(CONFIG_SOC_AM33XX)           += $(powerdom
  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
@@@ -161,6 -166,8 +168,8 @@@ obj-$(CONFIG_SOC_AM33XX)           += $(clockdom
  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
@@@ -182,6 -189,9 +191,9 @@@ obj-$(CONFIG_SOC_AM33XX)           += $(clock-co
  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
@@@ -204,11 -214,15 +216,12 @@@ obj-$(CONFIG_ARCH_OMAP3)                += omap_hwmod
  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)
  
index b3228cb630df490e561a77041e726d6f9fd0e34d,68b60769908781f3d32088b57bfed322efdf35ae..5a3401a9168f6c702081e70548f6808c68c454fd
@@@ -103,7 -103,6 +103,7 @@@ DT_MACHINE_START(OMAP3_DT, "Generic OMA
        .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,
@@@ -121,7 -120,6 +121,7 @@@ DT_MACHINE_START(OMAP3_GP_DT, "Generic 
        .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,
@@@ -138,7 -136,6 +138,7 @@@ DT_MACHINE_START(AM33XX_DT, "Generic AM
        .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,
@@@ -189,3 -186,24 +189,24 @@@ DT_MACHINE_START(OMAP5_DT, "Generic OMA
        .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
index 70fbe40732ac183a33a1982760f568c2435a7ad3,61fd099b1d60e5fe154ca6241a005942fa5a3817..504b4df74d949589a1d1fab3d994820b95229814
@@@ -904,6 -904,7 +904,6 @@@ static struct omap_clk am33xx_clks[] = 
        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),
  };
  
  
@@@ -978,6 -980,7 +979,7 @@@ static const char *enable_init_clks[] 
        "l4hs_gclk",
        "l4fw_gclk",
        "l4ls_gclk",
+       "clkout2_ck",   /* Required for external peripherals like, Audio codecs */
  };
  
  static struct reparent_init_clks reparent_clks[] = {
index 9874ebea4f2240440d128064fcd4af28a9fbae87,385065d3d11cabb1b9ea6261848d1a22fcfe4a5f..35a3050390b9ed396c0be01c4ccb5792ffb16817
@@@ -49,6 -49,7 +49,7 @@@ struct omap_clk 
  #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)
@@@ -174,6 -175,7 +175,7 @@@ struct clockdomain
  #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)
@@@ -283,8 -285,6 +285,8 @@@ struct dpll_data 
        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;
@@@ -425,8 -425,7 +427,8 @@@ unsigned long omap4_dpll_regm4xen_recal
  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);
  
index aa800679c80a2f3fa224665ca87b016c924a6fc6,5700924f49a07a3f813928667c9bc5bee3642b66..d767b0199874afe9f2fbf258ef82896b1818281b
@@@ -15,6 -15,7 +15,6 @@@
  #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H
  
  #include <linux/init.h>
 -#include <linux/spinlock.h>
  
  #include "powerdomain.h"
  #include "clock.h"
@@@ -91,8 -92,8 +91,8 @@@ struct clkdm_autodep 
  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 */
@@@ -136,8 -137,9 +136,8 @@@ struct clockdomain 
        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;
  };
  
  /**
@@@ -194,16 -196,12 +194,16 @@@ int clkdm_del_sleepdep(struct clockdoma
  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);
@@@ -217,9 -215,9 +217,10 @@@ extern void __init omap3xxx_clockdomain
  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;
@@@ -230,6 -228,4 +231,6 @@@ extern struct clkdm_dep gfx_24xx_wkdeps
  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
index 1c4139795a6639ac35ed6a8cd0dc68a1ca595b37,6895d1772dd1bf275c51266cb91ec69800513838..e8002527c491497d794a791a98887ec9bb61249e
@@@ -68,15 -68,6 +68,15 @@@ static inline int omap4_pm_init(void
  }
  #endif
  
 +#if defined(CONFIG_PM) && defined(CONFIG_SOC_AM33XX)
 +int am33xx_pm_init(void);
 +#else
 +static inline int am33xx_pm_init(void)
 +{
 +      return 0;
 +}
 +#endif
 +
  #ifdef CONFIG_OMAP_MUX
  int omap_mux_late_init(void);
  #else
@@@ -115,11 -106,12 +115,13 @@@ void omap2430_init_late(void)
  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);
@@@ -145,7 -137,8 +147,8 @@@ static inline void omap3xxx_restart(cha
  }
  #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)
@@@ -256,12 -249,13 +259,12 @@@ extern void omap5_secondary_startup(voi
  
  #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;
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
  
@@@ -450,16 -426,6 +457,16 @@@ extern void omap3630_ctrl_disable_rta(v
  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
@@@ -39,6 -39,7 +39,7 @@@
  #include "clock3xxx.h"
  #include "clock44xx.h"
  #include "clock54xx.h"
+ #include "clock7xx.h"
  #include "omap-pm.h"
  #include "sdrc.h"
  #include "control.h"
@@@ -246,7 -247,7 +247,7 @@@ static struct map_desc omap44xx_io_desc
  };
  #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,
@@@ -328,7 -329,7 +329,7 @@@ void __init omap4_map_io(void
  }
  #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));
@@@ -572,7 -573,7 +573,7 @@@ void __init am33xx_init_early(void
        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
@@@ -655,6 -649,36 +656,36 @@@ void __init omap5_init_late(void
  }
  #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)
  {
index 539082a5a991fe017a19a6948211ddf5449f16bf,3a7f50c3d1e2bf14b38db8de364a1ecb357e056a..8a15f77d4f94f9acae8ff6e82094f973d05c6899
@@@ -22,6 -22,7 +22,7 @@@
  #include "omap-wakeupgen.h"
  #include "common.h"
  #include "powerdomain.h"
+ #include "soc.h"
  
  /*
   * platform-specific code to shutdown a CPU
@@@ -47,7 -48,10 +48,10 @@@ void __ref omap4_cpu_die(unsigned int c
                /*
                 * 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();
index 8380b3240a61ae7a531e0228cc63585af01e205f,a257d0966be26c63146734d0042c4e4274cb9ba0..d46a2693efbd29ab4bc297b8a9fe48a81bbfc899
@@@ -75,7 -75,7 +75,7 @@@ struct omap4_cpu_pm_info 
  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);
  };
  
@@@ -98,7 -98,7 +98,7 @@@ static int default_finish_suspend(unsig
  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 = {
@@@ -116,40 -116,66 +116,44 @@@ static inline void set_cpu_wakeup_addr(
  {
        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);
  }
  
@@@ -188,11 -214,8 +192,12 @@@ static void l2x0_pwrst_prepare(unsigne
  {
        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);
  }
  
  /*
@@@ -217,11 -240,11 +222,11 @@@ static void save_l2x0_context(void
  #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;
  }
  
@@@ -372,9 -392,11 +377,11 @@@ int __init omap4_mpuss_init(void
        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;
index 3550c73a324a677ccb688daf2e48255d647d3eb1,bee77531f35bd5d242c030c7ce7fa05c93a6cc90..7b915267c679aaed815302497533f450a189e802
@@@ -3101,8 -3101,11 +3101,8 @@@ static int _am33xx_assert_hardreset(str
  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);
@@@ -4170,7 -4173,7 +4170,7 @@@ void __init omap_hwmod_init(void
                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;
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");
@@@ -105,16 -108,10 +107,16 @@@ static int __init pwrdms_setup(struct p
                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));
  }
  
  /**
@@@ -223,7 -220,7 +225,7 @@@ int __init omap4_pm_init(void
  
        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;
  }
index 72d6ce042edc2a02da2af948f90328439403fb23,6a1f195c12baabe797e199f663f985eaab09df68..6aa4d572d1461ad9507bebb7c89e81ec6d934f62
@@@ -1,17 -1,13 +1,17 @@@
  /*
   * 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)
@@@ -95,7 -79,7 +95,7 @@@ static int _pwrdm_register(struct power
        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;
@@@ -773,56 -260,25 +778,56 @@@ int pwrdm_register_pwrdms(struct powerd
   *
   * 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
@@@ -999,548 -455,631 +1004,548 @@@ struct voltagedomain *pwrdm_get_voltdm(
  }
  
  /**
 - * 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;
  }
 +
index b8f3dbf564c13d0c00e3a1d689cb681702973875,697be254461c11e4cc0b4866fd1e4ada6e390961..55c1201c1943e045e9448b0d41c0943f434e272e
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * 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
@@@ -148,23 -99,12 +148,23 @@@ struct powerdomain
   * @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);
@@@ -264,37 -204,45 +266,38 @@@ int pwrdm_for_each_clkdm(struct powerdo
                                   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;
@@@ -309,11 -257,5 +312,11 @@@ extern u32 omap2_pwrdm_get_mem_bank_sts
  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
index 6c50e4c7fca3b521a03af718c884663283a6b20e,0dc6b7a2060a4053f286e944d1d0c9d7313e3c00..8d40e8eb3bdaa3fd7131116b5611b47f4c82bcda
@@@ -108,6 -108,16 +108,16 @@@ static void __init omap_detect_sram(voi
                        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())
@@@ -146,11 -161,9 +161,11 @@@ static void __init omap2_map_sram(void
  {
        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
@@@ -281,18 -294,10 +296,18 @@@ static inline int omap34xx_sram_init(vo
  }
  #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)
  {
index 6476c38b3da93e792994d03ff9aa661e6aa75343,857f28772e355cd1bd0c33f1e9209e9f46fd8cba..e19ec2ee2f5d3ef8aac9933d0903443b30c9be2e
@@@ -62,10 -62,8 +62,10 @@@ extern unsigned long omap3_sram_configu
  
  #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
index 30ad6f8e3d007841f78bb843da5f9b7f9a26bd5d,22070c419c94f1446971d5790dcfbe5fc7b1f34d..cf18fb851ef268fcb65a93ace03702330e55e566
@@@ -129,36 -129,6 +129,36 @@@ static void omap2_gp_timer_set_mode(enu
        }
  }
  
 +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 = {
@@@ -261,7 -229,7 +261,7 @@@ static int __init omap_dm_timer_init_on
        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;
  
@@@ -352,7 -320,6 +352,7 @@@ static void __init omap2_gp_clockevent_
        int res;
  
        clkev.errata = omap_dm_timer_get_errata();
 +      clkev.id = gptimer_id;
  
        /*
         * For clock-event timers we never read the timer counter and
@@@ -630,8 -597,8 +630,8 @@@ OMAP_SYS_TIMER(3_gp, gptimer)
  #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 */
  
@@@ -666,7 -633,7 +666,7 @@@ static void __init omap4_local_timer_in
  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)
index 5b728b661d8a9aaf74198b42f08e1fa9c1400fde,9c643b67dcdeb1e4e7bffaf3efe638d6c8095a41..98000b22d04726b39482ccc1928d8e23e9011b91
@@@ -31,7 -31,7 +31,7 @@@ config ARCH_OMAP2PLU
        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
  
@@@ -116,6 -116,22 +116,6 @@@ config OMAP_MUX_WARNING
          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
  
@@@ -136,7 -152,7 +136,7 @@@ config OMAP_32K_TIME
          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.