diff options
author | Gary King <GKing@nvidia.com> | 2010-01-29 19:41:10 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit2@git-master-01.nvidia.com> | 2010-01-29 19:41:10 -0800 |
commit | 2abd636499694b73514380ef389666a9993aa107 (patch) | |
tree | 3d94f7c373adb91de63f048f5500aaab256fda62 /arch/arm | |
parent | 48d6ff95dc299ab433f28c576d406697fe665cb1 (diff) | |
parent | 926b1312dcecf0ed985a2950cdbfc6c50a937b2d (diff) |
Merge "tegra power: Add save/restore code for additional hw blocks." into android-tegra-2.6.29
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/idle-t2.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-tegra/power-context-t2.c | 822 | ||||
-rw-r--r-- | arch/arm/mach-tegra/power.h | 36 |
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\ |