summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGary King <GKing@nvidia.com>2010-01-29 19:41:10 -0800
committerGerrit Code Review <gerrit2@git-master-01.nvidia.com>2010-01-29 19:41:10 -0800
commit2abd636499694b73514380ef389666a9993aa107 (patch)
tree3d94f7c373adb91de63f048f5500aaab256fda62 /arch
parent48d6ff95dc299ab433f28c576d406697fe665cb1 (diff)
parent926b1312dcecf0ed985a2950cdbfc6c50a937b2d (diff)
Merge "tegra power: Add save/restore code for additional hw blocks." into android-tegra-2.6.29
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/idle-t2.c7
-rw-r--r--arch/arm/mach-tegra/power-context-t2.c822
-rw-r--r--arch/arm/mach-tegra/power.h36
3 files changed, 862 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/idle-t2.c b/arch/arm/mach-tegra/idle-t2.c
index 4461381e0cfc..1d8b5a07673a 100644
--- a/arch/arm/mach-tegra/idle-t2.c
+++ b/arch/arm/mach-tegra/idle-t2.c
@@ -47,6 +47,7 @@ extern struct wake_lock main_wake_lock;
#define CPU_CONTEXT_SAVE_AREA_SIZE 4096
#define TEMP_SAVE_AREA_SIZE 16
#define ENABLE_LP2 1
+#define ENABLE_LP0 0
#define NV_POWER_LP2_IDLE_THRESHOLD_MS 700
#define NV_POWER_IDLE_WINDOW_SIZE 100
#define MAX_LP2_TIME_US 1000000
@@ -60,6 +61,7 @@ void mach_tegra_reset(void);
void mach_tegra_idle(void);
extern void enter_lp2(NvU32, NvU32);
extern void exit_power_state(void);
+extern void module_context_init(void);
extern void NvSpareTimerTrigger(unsigned long); /* timer.c */
NvU32 lp2count = 0, lp3count = 0, lp2safe = 0;
@@ -107,7 +109,10 @@ void __init NvAp20InitFlowController(void)
(uintptr_t)kmalloc(CPU_CONTEXT_SAVE_AREA_SIZE, GFP_ATOMIC);
g_contextSavePA = virt_to_phys((void*)g_contextSaveVA);
g_NumActiveCPUs = num_online_cpus();
- g_enterLP2PA = virt_to_phys((void*)enter_lp2);
+ g_enterLP2PA = virt_to_phys((void*)enter_lp2);
+#if ENABLE_LP0
+ module_context_init();
+#endif
}
/*
diff --git a/arch/arm/mach-tegra/power-context-t2.c b/arch/arm/mach-tegra/power-context-t2.c
index 83e4bd7b35df..e4f982acfabd 100644
--- a/arch/arm/mach-tegra/power-context-t2.c
+++ b/arch/arm/mach-tegra/power-context-t2.c
@@ -30,11 +30,26 @@ static void wake_pad_configure(NvRmDeviceHandle hRmDeviceHandle);
static void setup_wakeup_events(void);
static NvU32* save_clockreset_context(PowerModuleContext Context,
struct power_context *pAnchor, NvU32 *pCM);
+static NvU32* save_intc_context(PowerModuleContext Context,
+ struct power_context *pAnchor, NvU32 *pCM);
+static NvU32* save_misc_context(PowerModuleContext Context,
+ struct power_context *pAnchor, NvU32 *pCM);
+static NvU32* save_gpio_context(PowerModuleContext Context,
+ struct power_context *pAnchor, NvU32 *pCM);
+static NvU32* save_apbdma_context(PowerModuleContext Context,
+ struct power_context *pAnchor, NvU32 *pCM);
+static NvU32* save_apbdmachan_context(PowerModuleContext Context,
+ struct power_context *pAnchor, NvU32 *pCM);
+static NvU32* save_mc_context(PowerModuleContext Context,
+ struct power_context *pAnchor, NvU32 *pCM);
NvU32* perform_context_operation(PowerModuleContext Context);
void prepare_for_wb0(void);
struct power_context *s_pModulesContextAnchor = NULL;
+#define WORKAROUND_573705 1
+#define MODULE_CONTEXT_SAVE_AREA_SIZE 4096
+
static void update_registers_for_lp0(void)
{
NvU32 Reg;
@@ -328,13 +343,786 @@ fail:
return NULL;
}
+static NvU32* save_intc_context(
+ PowerModuleContext Context,
+ struct power_context *pAnchor,
+ NvU32 *pCM)
+{
+ NvU32 Aperture; //Register base address
+ NvU32 ApertureSize; //Register set size
+ NvRmModuleID ModuleId; //Composite module id & instance
+ NvU32 Instance; //Interrupt Controller Instance
+ NvU32 Instances; //Total number of ictlr instances
+ NvU32* pBase; //Ptr to list of register base addresses
+
+ //NOTE: This controller has multiple instances. Therefore,
+ //pAnchor->interrupt.pBase is a pointer to a list of
+ //controller instance base addresses and not the controller's
+ //base address itself.
+
+ //Get the number of interrupt controller instances.
+ Instances = NvRmModuleGetNumInstances(s_hRmGlobal,
+ NvRmPrivModuleID_Interrupt);
+
+ //Get a pointer to the base address list.
+ pBase = pAnchor->interrupt.pBase;
+
+ switch (Context) {
+ case PowerModuleContext_Init:
+ //Already initialized?
+ if (pBase == NULL)
+ {
+ //Anchor the starting point for the list of
+ //instance base addresses.
+ pAnchor->interrupt.pBase = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance)
+ {
+ //Generate the composite module id and instance.
+ ModuleId = NVRM_MODULE_ID(NvRmPrivModuleID_Interrupt,
+ Instance);
+
+ //Retrieve the register base PA
+ NvRmModuleGetBaseAddress(s_hRmGlobal, ModuleId,
+ &Aperture, &ApertureSize);
+
+ //Get the corresponding VA
+ if (NvOsPhysicalMemMap(Aperture,
+ ApertureSize,
+ NvOsMemAttribute_Uncached,
+ NVOS_MEM_READ_WRITE,
+ (void*)pCM))
+ {
+ printk("Failed to map the context save area!\n");
+ goto fail;
+ }
+ pCM++;
+ }
+ }
+ break;
+
+ case PowerModuleContext_Save:
+ case PowerModuleContext_SaveLP1:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->interrupt.pContext = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ //Save module registers...
+ *pCM++ = NV_ICTLR_REGR(*pBase, CPU_IER);
+ *pCM++ = NV_ICTLR_REGR(*pBase, CPU_IEP_CLASS);
+ *pCM++ = NV_ICTLR_REGR(*pBase, COP_IER);
+ *pCM++ = NV_ICTLR_REGR(*pBase, COP_IEP_CLASS);
+ }
+ break;
+
+ case PowerModuleContext_Restore:
+ case PowerModuleContext_RestoreLP1:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->interrupt.pContext)
+ goto fail;
+
+ //Retrieve the anchored starting point for this controller's context.
+ pCM = pAnchor->interrupt.pContext;
+
+ if (pCM == NULL)
+ goto fail;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ //Restore module registers...
+ NV_ICTLR_REGW(*pBase, CPU_IER_SET, *pCM++);
+ NV_ICTLR_REGW(*pBase, CPU_IEP_CLASS, *pCM++);
+ NV_ICTLR_REGW(*pBase, COP_IER_SET, *pCM++);
+ NV_ICTLR_REGW(*pBase, COP_IEP_CLASS, *pCM++);
+ }
+ break;
+
+ case PowerModuleContext_DisableInterrupt:
+ #if !WORKAROUND_573705
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ if (*pBase == 0)
+ goto fail;
+
+ //Disable module interrupts.
+ NV_ICTLR_REGW(*pBase, CPU_IER_CLR, ~0);
+ NV_ICTLR_REGW(*pBase, COP_IER_CLR, ~0);
+ }
+ #endif
+ break;
+
+ default:
+ break;
+ }
+
+ return pCM;
+
+fail:
+ return NULL;
+}
+
+static NvU32* save_misc_context(
+ PowerModuleContext Context,
+ struct power_context *pAnchor,
+ NvU32 *pCM)
+{
+ NvU32* pBase; //Pointer to register base addresses
+ NvU32 Aperture; // Register base address
+ NvU32 ApertureSize; // Register set size
+ NvRmModuleID ModuleId; // Composite module id & instance
+
+ //Get a pointer to the base address for the registers.
+ pBase = pAnchor->misc.pBase;
+
+ switch (Context) {
+ case PowerModuleContext_Init:
+ //Already initialized?
+ if (pBase == NULL)
+ {
+ //Generate the composite module id and instance.
+ ModuleId = NVRM_MODULE_ID(NvRmModuleID_Misc, 0);
+
+ //Retrieve the register base PA
+ NvRmModuleGetBaseAddress(s_hRmGlobal, ModuleId,
+ &Aperture, &ApertureSize);
+
+ //Get the corresponding VA
+ if (NvOsPhysicalMemMap(Aperture,
+ ApertureSize,
+ NvOsMemAttribute_Uncached,
+ NVOS_MEM_READ_WRITE,
+ (void*)&(pAnchor->misc.pBase)))
+ {
+ printk("Failed to map the context save area!\n");
+ goto fail;
+ }
+ }
+ break;
+ case PowerModuleContext_Save:
+ //Register base address must have been set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->misc.pContext = pCM;
+
+ *pCM++ = NV_MISC_REGR(pBase, PP_TRISTATE_REG_A);
+ *pCM++ = NV_MISC_REGR(pBase, PP_TRISTATE_REG_B);
+ *pCM++ = NV_MISC_REGR(pBase, PP_TRISTATE_REG_C);
+ *pCM++ = NV_MISC_REGR(pBase, PP_TRISTATE_REG_D);
+
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_A);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_B);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_C);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_D);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_E);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_F);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_G);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PIN_MUX_CTL_H);
+
+ *pCM++ = NV_MISC_REGR(pBase, PP_PULLUPDOWN_REG_A);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PULLUPDOWN_REG_B);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PULLUPDOWN_REG_C);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PULLUPDOWN_REG_D);
+ *pCM++ = NV_MISC_REGR(pBase, PP_PULLUPDOWN_REG_E);
+ break;
+ case PowerModuleContext_Restore:
+ //Register base address must have been set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->misc.pContext)
+ goto fail;
+
+ //Retrieve the anchored starting point for this controller's context.
+ pCM = pAnchor->misc.pContext;
+ if (pCM == NULL)
+ goto fail;
+
+ NV_MISC_REGW(pBase, PP_TRISTATE_REG_A, *pCM++);
+ NV_MISC_REGW(pBase, PP_TRISTATE_REG_B, *pCM++);
+ NV_MISC_REGW(pBase, PP_TRISTATE_REG_C, *pCM++);
+ NV_MISC_REGW(pBase, PP_TRISTATE_REG_D, *pCM++);
+
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_A, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_B, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_C, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_D, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_E, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_F, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_G, *pCM++);
+ NV_MISC_REGW(pBase, PP_PIN_MUX_CTL_H, *pCM++);
+
+ NV_MISC_REGW(pBase, PP_PULLUPDOWN_REG_A, *pCM++);
+ NV_MISC_REGW(pBase, PP_PULLUPDOWN_REG_B, *pCM++);
+ NV_MISC_REGW(pBase, PP_PULLUPDOWN_REG_C, *pCM++);
+ NV_MISC_REGW(pBase, PP_PULLUPDOWN_REG_D, *pCM++);
+ NV_MISC_REGW(pBase, PP_PULLUPDOWN_REG_E, *pCM++);
+ break;
+ case PowerModuleContext_SaveLP1:
+ case PowerModuleContext_RestoreLP1:
+ case PowerModuleContext_DisableInterrupt:
+ //Do nothing.
+ break;
+ default:
+ break;
+ }
+
+ return pCM;
+fail:
+ return NULL;
+}
+
+static NvU32* save_gpio_context(
+ PowerModuleContext Context,
+ struct power_context *pAnchor,
+ NvU32 *pCM)
+{
+ NvU32 Aperture; // Register base address
+ NvU32 ApertureSize; // Register set size
+ NvRmModuleID ModuleId; // Composite module id & instance
+ NvU8 Instance; // GPIO Instance
+ NvU32 Instances; // Total number of gpio instances
+ NvU32* pBase; // Ptr to list of register base addresses
+
+ //NOTE: This controller has multiple instances.
+ //Therefore, pAnchor->Gpio.pBase is a pointer to a list
+ //of controller instance base addresses and not the
+ //controller's base address itself.
+
+ //Get the number of GPIO controller instances.
+ Instances = NvRmModuleGetNumInstances(s_hRmGlobal, NvRmPrivModuleID_Gpio);
+
+ //Get a pointer to the base address list.
+ pBase = pAnchor->gpio.pBase;
+
+ switch (Context) {
+ case PowerModuleContext_Init:
+ //Already initialized?
+ if (pBase == NULL)
+ {
+ //Anchor the starting point for the list
+ //of instance base addresses.
+ pAnchor->gpio.pBase = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance)
+ {
+ //Generate the composite module id and instance.
+ ModuleId = NVRM_MODULE_ID(NvRmPrivModuleID_Gpio, Instance);
+
+ //Retrieve the register base PA
+ NvRmModuleGetBaseAddress(s_hRmGlobal, ModuleId,
+ &Aperture, &ApertureSize);
+
+ //Get the corresponding VA
+ if (NvOsPhysicalMemMap(Aperture,
+ ApertureSize,
+ NvOsMemAttribute_Uncached,
+ NVOS_MEM_READ_WRITE,
+ (void*)pCM))
+ {
+ printk("Failed to map the context save area!\n");
+ goto fail;
+ }
+ pCM++;
+ }
+ }
+ break;
+ case PowerModuleContext_Save:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->gpio.pContext = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ //Save the GPIO configuration.
+ *pCM++ = NV_GPIO_REGR(*pBase, CNF_0);
+ *pCM++ = NV_GPIO_REGR(*pBase, CNF_1);
+ *pCM++ = NV_GPIO_REGR(*pBase, CNF_2);
+ *pCM++ = NV_GPIO_REGR(*pBase, CNF_3);
+
+ //Save the GPIO output settings.
+ *pCM++ = NV_GPIO_REGR(*pBase, OUT_0);
+ *pCM++ = NV_GPIO_REGR(*pBase, OUT_1);
+ *pCM++ = NV_GPIO_REGR(*pBase, OUT_2);
+ *pCM++ = NV_GPIO_REGR(*pBase, OUT_3);
+
+ //Save the GPIO output enable settings.
+ *pCM++ = NV_GPIO_REGR(*pBase, OE_0);
+ *pCM++ = NV_GPIO_REGR(*pBase, OE_1);
+ *pCM++ = NV_GPIO_REGR(*pBase, OE_2);
+ *pCM++ = NV_GPIO_REGR(*pBase, OE_3);
+
+ //Save the GPIO level enables.
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_0);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_1);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_2);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_3);
+
+ //Save the GPIO
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_LVL_0);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_LVL_1);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_LVL_2);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_LVL_3);
+ }
+ break;
+ case PowerModuleContext_Restore:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->gpio.pContext)
+ goto fail;
+
+ //Retrieve the anchored starting point for this controller's context.
+ pCM = pAnchor->gpio.pContext;
+ if (pCM == NULL)
+ goto fail;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ //Restore the GPIO configuration.
+ NV_GPIO_REGW(*pBase, CNF_0, *pCM++);
+ NV_GPIO_REGW(*pBase, CNF_1, *pCM++);
+ NV_GPIO_REGW(*pBase, CNF_2, *pCM++);
+ NV_GPIO_REGW(*pBase, CNF_3, *pCM++);
+
+ //Restore the GPIO output settings.
+ NV_GPIO_REGW(*pBase, OUT_0, *pCM++);
+ NV_GPIO_REGW(*pBase, OUT_1, *pCM++);
+ NV_GPIO_REGW(*pBase, OUT_2, *pCM++);
+ NV_GPIO_REGW(*pBase, OUT_3, *pCM++);
+
+ //Restore the GPIO output enable settings.
+ NV_GPIO_REGW(*pBase, OE_0, *pCM++);
+ NV_GPIO_REGW(*pBase, OE_1, *pCM++);
+ NV_GPIO_REGW(*pBase, OE_2, *pCM++);
+ NV_GPIO_REGW(*pBase, OE_3, *pCM++);
+
+ //Restore the GPIO level enables.
+ NV_GPIO_REGW(*pBase, INT_ENB_0, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_ENB_1, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_ENB_2, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_ENB_3, *pCM++);
+
+ //Restore the shadowed GPIO level settings.
+ NV_GPIO_REGW(*pBase, INT_LVL_0, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_LVL_1, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_LVL_2, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_LVL_3, *pCM++);
+ }
+ break;
+ case PowerModuleContext_SaveLP1:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->gpio.pContext = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ //Save the GPIO enables.
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_0);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_1);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_2);
+ *pCM++ = NV_GPIO_REGR(*pBase, INT_ENB_3);
+ }
+ break;
+ case PowerModuleContext_RestoreLP1:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->gpio.pContext)
+ goto fail;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ // Restore the GPIO enables.
+ NV_GPIO_REGW(*pBase, INT_ENB_0, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_ENB_1, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_ENB_2, *pCM++);
+ NV_GPIO_REGW(*pBase, INT_ENB_3, *pCM++);
+ }
+ break;
+ case PowerModuleContext_DisableInterrupt:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ #if !WORKAROUND_573705
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ //Disable module interrupts.
+ NV_GPIO_REGW(*pBase, INT_ENB_0, 0);
+ NV_GPIO_REGW(*pBase, INT_ENB_1, 0);
+ NV_GPIO_REGW(*pBase, INT_ENB_2, 0);
+ NV_GPIO_REGW(*pBase, INT_ENB_3, 0);
+ }
+ #endif
+ break;
+ default:
+ break;
+ }
+
+ return pCM;
+fail:
+ return NULL;
+}
+
+static NvU32* save_apbdma_context(
+ PowerModuleContext Context,
+ struct power_context *pAnchor,
+ NvU32 *pCM)
+{
+ NvU32 Aperture; //Register base address
+ NvU32 ApertureSize; //Register set size
+ NvRmModuleID ModuleId; //Composite module id & instance
+ NvU32* pBase; //Pointer to register base addresses
+
+ //Get a pointer to the base address for the registers.
+ pBase = pAnchor->apb_dma.pBase;
+
+ switch (Context) {
+ case PowerModuleContext_Init:
+ //Already initialized?
+ if (pBase == NULL)
+ {
+ //Generate the composite module id and instance.
+ ModuleId = NVRM_MODULE_ID(NvRmPrivModuleID_ApbDma, 0);
+
+ //Retrieve the register base PA
+ NvRmModuleGetBaseAddress(s_hRmGlobal, ModuleId,
+ &Aperture, &ApertureSize);
+
+ //Get the corresponding VA
+ if (NvOsPhysicalMemMap(Aperture,
+ ApertureSize,
+ NvOsMemAttribute_Uncached,
+ NVOS_MEM_READ_WRITE,
+ (void*)&(pAnchor->apb_dma.pBase)))
+ {
+ printk("Failed to map the context save area!\n");
+ goto fail;
+ }
+ }
+ break;
+ case PowerModuleContext_Save:
+ //Register base address must have been set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->apb_dma.pContext = pCM;
+
+ *pCM++ = NV_APBDMA_REGR(pBase, COMMAND);
+ *pCM++ = NV_APBDMA_REGR(pBase, CNTRL_REG);
+ *pCM++ = NV_APBDMA_REGR(pBase, IRQ_MASK);
+ break;
+ case PowerModuleContext_Restore:
+ //Register base address must have been set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->apb_dma.pContext || pCM == NULL)
+ goto fail;
+
+ NV_APBDMA_REGW(pBase, COMMAND, *pCM++);
+ NV_APBDMA_REGW(pBase, CNTRL_REG, *pCM++);
+ NV_APBDMA_REGW(pBase, IRQ_MASK_SET, *pCM++);
+ break;
+ case PowerModuleContext_SaveLP1:
+ case PowerModuleContext_RestoreLP1:
+ case PowerModuleContext_DisableInterrupt:
+ break;
+ default:
+ break;
+ }
+
+ return pCM;
+fail:
+ return NULL;
+}
+
+static NvU32* save_apbdmachan_context(
+ PowerModuleContext Context,
+ struct power_context *pAnchor,
+ NvU32 *pCM)
+{
+ NvU32 Aperture; //Register base address
+ NvU32 ApertureSize; //Register set size
+ NvRmModuleID ModuleId; //Composite module id & instance
+ NvU32 Instance; //DMA Channel Instances
+ NvU32 Instances; //Total number of dma instances
+ NvU32* pBase; //Ptr to list of register base addresses
+
+ //NOTE: This controller has multiple instances.
+ //Therefore, pAnchor->ApbDmaChannel.pBase is a pointer
+ //to a list of controller instance base addresses and not the
+ //controller's base address itself.
+
+ //Get the number of APB DMA channels.
+ Instances = NvRmModuleGetNumInstances(s_hRmGlobal,
+ NvRmPrivModuleID_ApbDmaChannel);
+
+ // Get a pointer to the base address list.
+ pBase = pAnchor->apb_dma_chan.pBase;
+
+ switch (Context) {
+ case PowerModuleContext_Init:
+ //Already initialized?
+ if (pBase == NULL)
+ {
+ //Anchor the starting point for the list
+ //of instance base addresses.
+ pAnchor->apb_dma_chan.pBase = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance)
+ {
+ //Generate the composite module id and instance.
+ ModuleId = NVRM_MODULE_ID(NvRmPrivModuleID_ApbDmaChannel,
+ Instance);
+
+ //Retrieve the register base PA
+ NvRmModuleGetBaseAddress(s_hRmGlobal, ModuleId,
+ &Aperture, &ApertureSize);
+
+ //Get the corresponding VA
+ if (NvOsPhysicalMemMap(Aperture,
+ ApertureSize,
+ NvOsMemAttribute_Uncached,
+ NVOS_MEM_READ_WRITE,
+ (void*)pCM))
+ {
+ printk("Failed to map the context save area!\n");
+ goto fail;
+ }
+ pCM++;
+ }
+ }
+ break;
+ case PowerModuleContext_Save:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->apb_dma_chan.pContext = pCM;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ *pCM++ = NV_APBDMACH_REGR(*pBase, CSR);
+ *pCM++ = NV_APBDMACH_REGR(*pBase, STA);
+ *pCM++ = NV_APBDMACH_REGR(*pBase, AHB_PTR);
+ *pCM++ = NV_APBDMACH_REGR(*pBase, AHB_SEQ);
+ *pCM++ = NV_APBDMACH_REGR(*pBase, APB_PTR);
+ *pCM++ = NV_APBDMACH_REGR(*pBase, APB_SEQ);
+ }
+ break;
+ case PowerModuleContext_Restore:
+ //Register base address list must have been
+ //set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->apb_dma_chan.pContext || pCM == NULL)
+ goto fail;
+
+ //For each instance...
+ for (Instance = 0; Instance < Instances; ++Instance, ++pBase)
+ {
+ //Register base address must have been
+ //set by PowerModuleContext_Init.
+ if (*pBase == 0)
+ goto fail;
+
+ NV_APBDMACH_REGW(*pBase, CSR, *pCM++);
+ NV_APBDMACH_REGW(*pBase, STA, *pCM++);
+ NV_APBDMACH_REGW(*pBase, AHB_PTR, *pCM++);
+ NV_APBDMACH_REGW(*pBase, AHB_SEQ, *pCM++);
+ NV_APBDMACH_REGW(*pBase, APB_PTR, *pCM++);
+ NV_APBDMACH_REGW(*pBase, APB_SEQ, *pCM++);
+ }
+ break;
+ case PowerModuleContext_SaveLP1:
+ case PowerModuleContext_RestoreLP1:
+ case PowerModuleContext_DisableInterrupt:
+ break;
+ default:
+ break;
+ }
+
+ return pCM;
+fail:
+ return NULL;
+}
+
+static NvU32* save_mc_context(
+ PowerModuleContext Context,
+ struct power_context *pAnchor,
+ NvU32 *pCM)
+{
+ NvU32* pBase; //Pointer to register base addresses
+ NvU32 Aperture; //Register base address
+ NvU32 ApertureSize; //Register set size
+ NvRmModuleID ModuleId; //Composite module id & instance
+
+ //Get a pointer to the base address for the registers.
+ pBase = pAnchor->mc.pBase;
+
+ switch (Context) {
+ case PowerModuleContext_Init:
+ //Already initialized?
+ if (pBase == NULL)
+ {
+ //Generate the composite module id and instance.
+ ModuleId = NVRM_MODULE_ID(NvRmPrivModuleID_MemoryController, 0);
+
+ //Retrieve the register base PA
+ NvRmModuleGetBaseAddress(s_hRmGlobal, ModuleId,
+ &Aperture, &ApertureSize);
+
+ //Get the corresponding VA
+ if (NvOsPhysicalMemMap(Aperture,
+ ApertureSize,
+ NvOsMemAttribute_Uncached,
+ NVOS_MEM_READ_WRITE,
+ (void*)&(pAnchor->mc.pBase)))
+ {
+ printk("Failed to map the context save area!\n");
+ goto fail;
+ }
+ }
+ break;
+ case PowerModuleContext_Save:
+ //Register base address must have been set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //Anchor the starting point for this controller's context.
+ pAnchor->mc.pContext = pCM;
+
+ *pCM++ = NV_MC_REGR(pBase, SECURITY_CFG0);
+ *pCM++ = NV_MC_REGR(pBase, SECURITY_CFG1);
+ break;
+ case PowerModuleContext_Restore:
+ //Register base address must have been set by PowerModuleContext_Init.
+ if (pBase == NULL)
+ goto fail;
+
+ //We should be at the same place in the context
+ //as when we saved things.
+ if (pCM != pAnchor->mc.pContext || pCM == NULL)
+ goto fail;
+
+ NV_MC_REGW(pBase, SECURITY_CFG0, *pCM++);
+ NV_MC_REGW(pBase, SECURITY_CFG1, *pCM++);
+ break;
+ case PowerModuleContext_SaveLP1:
+ case PowerModuleContext_RestoreLP1:
+ case PowerModuleContext_DisableInterrupt:
+ break;
+ default:
+ break;
+ }
+
+ return pCM;
+fail:
+ return NULL;
+}
+
NvU32* perform_context_operation(PowerModuleContext Context)
{
NvU32* pCM; // Pointer to next available save area location
//First save area location available for module use is located just
//beyond the anchor structure.
- //NV_ASSERT(s_pModulesContextAnchor != NULL);
+ if (s_pModulesContextAnchor == NULL)
+ return NULL;
//Initializing?
if (Context == PowerModuleContext_Init)
@@ -350,7 +1138,12 @@ NvU32* perform_context_operation(PowerModuleContext Context)
}
pCM = save_clockreset_context(Context, s_pModulesContextAnchor, pCM);
- //TODO: Save rest of modules here
+ pCM = save_intc_context(Context, s_pModulesContextAnchor, pCM);
+ pCM = save_misc_context(Context, s_pModulesContextAnchor, pCM);
+ pCM = save_gpio_context(Context, s_pModulesContextAnchor, pCM);
+ pCM = save_apbdma_context(Context, s_pModulesContextAnchor, pCM);
+ pCM = save_apbdmachan_context(Context, s_pModulesContextAnchor, pCM);
+ pCM = save_mc_context(Context, s_pModulesContextAnchor, pCM);
//Check if we went past the context area limits.
if (pCM >= ((NvU32*)s_pModulesContextAnchor +
@@ -360,6 +1153,31 @@ NvU32* perform_context_operation(PowerModuleContext Context)
return pCM;
}
+void module_context_init(void)
+{
+ struct power_context * pAnchor;
+
+ //Get the address of the module context save area. The anchor structure
+ //will be placed here.
+ pAnchor = kmalloc(MODULE_CONTEXT_SAVE_AREA_SIZE, GFP_ATOMIC);
+
+ //Clear the context anchor.
+ NvOsMemset(pAnchor, 0, sizeof(*pAnchor));
+
+ //Initialize the anchor structure.
+ pAnchor->context_size_words = MODULE_CONTEXT_SAVE_AREA_SIZE/sizeof(NvU32);
+
+ //Save the global anchor pointer.
+ s_pModulesContextAnchor = pAnchor;
+
+ //Initialize module contexts.
+ pAnchor->first_context_location =
+ perform_context_operation(PowerModuleContext_Init);
+
+ if (pAnchor->first_context_location == NULL)
+ printk("module_context_init failed!\n");
+}
+
void prepare_for_wb0(void)
{
update_registers_for_lp0();
diff --git a/arch/arm/mach-tegra/power.h b/arch/arm/mach-tegra/power.h
index e18863badaf4..f55556a150b0 100644
--- a/arch/arm/mach-tegra/power.h
+++ b/arch/arm/mach-tegra/power.h
@@ -27,6 +27,12 @@
#include "nvrm_module.h"
#include "ap20/arflow_ctlr.h"
#include "ap20/arclk_rst.h"
+#include "ap20/arapb_misc.h"
+#include "ap20/arapbdma.h"
+#include "ap20/arapbdmachan.h"
+#include "ap20/armc.h"
+#include "ap15/arictlr.h"
+#include "ap15/argpio.h"
#include "nvrm_hardware_access.h"
#include "nvrm_interrupt.h"
#include "nvrm_power.h"
@@ -51,6 +57,36 @@ extern NvRmDeviceHandle s_hRmGlobal;
#define NV_CAR_REGW_OFFSET(pBase, off, val)\
NV_WRITE32( (((NvUPtr)(pBase)) + off), (val))
+#define NV_ICTLR_REGR(pBase, reg)\
+ NV_READ32( (((NvUPtr)(pBase)) + ICTLR_##reg##_0))
+#define NV_ICTLR_REGW(pBase, reg, val)\
+ NV_WRITE32( (((NvUPtr)(pBase)) + ICTLR_##reg##_0), (val))
+
+#define NV_MISC_REGR(pBase, reg)\
+ NV_READ32( (((NvUPtr)(pBase)) + APB_MISC_##reg##_0))
+#define NV_MISC_REGW(pBase, reg, val)\
+ NV_WRITE32( (((NvUPtr)(pBase)) + APB_MISC_##reg##_0), (val))
+
+#define NV_GPIO_REGR(pBase, reg)\
+ NV_READ32( (((NvUPtr)(pBase)) + GPIO_##reg))
+#define NV_GPIO_REGW(pBase, reg, val)\
+ NV_WRITE32( (((NvUPtr)(pBase)) + GPIO_##reg), (val))
+
+#define NV_APBDMA_REGR(pBase, reg)\
+ NV_READ32( (((NvUPtr)(pBase)) + APBDMA_##reg##_0))
+#define NV_APBDMA_REGW(pBase, reg, val)\
+ NV_WRITE32( (((NvUPtr)(pBase)) + APBDMA_##reg##_0), (val))
+
+#define NV_APBDMACH_REGR(pBase, reg)\
+ NV_READ32( (((NvUPtr)(pBase)) + APBDMACHAN_CHANNEL_0_##reg##_0))
+#define NV_APBDMACH_REGW(pBase, reg, val)\
+ NV_WRITE32( (((NvUPtr)(pBase)) + APBDMACHAN_CHANNEL_0_##reg##_0),(val))
+
+#define NV_MC_REGR(pBase, reg)\
+ NV_READ32( (((NvUPtr)(pBase)) + MC_##reg##_0))
+#define NV_MC_REGW(pBase, reg, val)\
+ NV_WRITE32( (((NvUPtr)(pBase)) + MC_##reg##_0), (val))
+
#define CAR_CLK_SOURCES_OFFSET_START CLK_RST_CONTROLLER_CLK_SOURCE_I2S1_0
#define CAR_CLK_SOURCES_OFFSET_END CLK_RST_CONTROLLER_CLK_SOURCE_OSC_0
#define CAR_CLK_SOURCES_REGISTER_COUNT\