/* * OMAP4 MPUSS low power code * * Copyright (C) 2011 Texas Instruments, Inc. * Written by Santosh Shilimkar * * OMAP4430 MPUSS mainly consists of dual Cortex-A9 with per-CPU * Local timer and Watchdog, GIC, SCU, PL310 L2 cache controller, * CPU0 and CPU1 LPRM modules. * CPU0, CPU1 and MPUSS each have there own power domain and * hence multiple low power combinations of MPUSS are possible. * * The CPU0 and CPU1 can't support Closed switch Retention (CSWR) * because the mode is not supported by hw constraints of dormant * mode. While waking up from the dormant mode, a reset signal * to the Cortex-A9 processor must be asserted by the external * power controller. * * With architectural inputs and hardware recommendations, only * below modes are supported from power gain vs latency point of view. * * CPU0 CPU1 MPUSS * ---------------------------------------------- * ON ON ON * ON(Inactive) OFF ON(Inactive) * OFF OFF CSWR * OFF OFF OSWR * OFF OFF OFF * ---------------------------------------------- * * Note: CPU0 is the master core and it is the last CPU to go down * and first to wake-up when MPUSS low power states are excercised * * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "omap4-sar-layout.h" #include "pm.h" #include "prcm_mpu44xx.h" #include "prminst44xx.h" #include "prcm44xx.h" #include "prm44xx.h" #include "prm-regbits-44xx.h" #include "cm.h" #include "prm.h" #include "cm44xx.h" #include "prcm-common.h" #include "clockdomain.h" #ifdef CONFIG_SMP #define GIC_MASK_ALL 0x0 #define GIC_ISR_NON_SECURE 0xffffffff #define SPI_ENABLE_SET_OFFSET 0x04 #define PPI_PRI_OFFSET 0x1c #define SPI_PRI_OFFSET 0x20 #define SPI_TARGET_OFFSET 0x20 #define SPI_CONFIG_OFFSET 0x20 /* GIC save SAR bank base */ static struct powerdomain *mpuss_pd; /* * Maximum Secure memory storage size. */ #define OMAP4_SECURE_RAM_STORAGE (88 * SZ_1K) /* * Physical address of secure memory storage */ dma_addr_t omap4_secure_ram_phys; static void *secure_ram; struct clk *l3_main_3_ick; /* Variables to store maximum spi(Shared Peripheral Interrupts) registers. */ static u32 max_spi_irq, max_spi_reg; struct omap4_cpu_pm_info { struct powerdomain *pwrdm; void __iomem *scu_sar_addr; }; static void __iomem *gic_dist_base; static void __iomem *gic_cpu_base; static void __iomem *sar_base; static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); #define PPI_CONTEXT_SIZE 11 static DEFINE_PER_CPU(u32[PPI_CONTEXT_SIZE], gic_ppi_context); static DEFINE_PER_CPU(u32, gic_ppi_enable_mask); /* Helper functions */ static inline void sar_writel(u32 val, u32 offset, u8 idx) { __raw_writel(val, sar_base + offset + 4 * idx); } static inline u32 gic_readl(u32 offset, u8 idx) { return __raw_readl(gic_dist_base + offset + 4 * idx); } u32 gic_cpu_read(u32 reg) { return __raw_readl(gic_cpu_base + reg); } /* * 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); } struct reg_tuple { void __iomem *addr; u32 val; }; static struct reg_tuple tesla_reg[] = { {.addr = OMAP4430_CM_TESLA_CLKSTCTRL}, {.addr = OMAP4430_CM_TESLA_TESLA_CLKCTRL}, {.addr = OMAP4430_PM_TESLA_PWRSTCTRL}, }; static struct reg_tuple ivahd_reg[] = { {.addr = OMAP4430_CM_IVAHD_CLKSTCTRL}, {.addr = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL}, {.addr = OMAP4430_CM_IVAHD_SL2_CLKCTRL}, {.addr = OMAP4430_PM_IVAHD_PWRSTCTRL} }; static struct reg_tuple l3instr_reg[] = { {.addr = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL}, {.addr = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL}, {.addr = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL}, }; /* * Store the SCU power status value to scratchpad memory */ static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) { 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: scu_pwr_st = SCU_PM_DORMANT; break; case PWRDM_POWER_OFF: scu_pwr_st = SCU_PM_POWEROFF; break; case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: default: scu_pwr_st = SCU_PM_NORMAL; break; } __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); } static void gic_save_ppi(void) { void __iomem *gic_dist_base = omap4_get_gic_dist_base(); u32 *context = __get_cpu_var(gic_ppi_context); int i = 0; context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x4); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x8); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0xc); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x10); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x14); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x18); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_PRI + 0x1c); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_CONFIG); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_CONFIG + 0x4); context[i++] = readl_relaxed(gic_dist_base + GIC_DIST_ENABLE_SET); BUG_ON(i != PPI_CONTEXT_SIZE); } static void gic_restore_ppi(void) { void __iomem *gic_dist_base = omap4_get_gic_dist_base(); u32 *context = __get_cpu_var(gic_ppi_context); int i = 0; writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x4); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x8); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0xc); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x10); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x14); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x18); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_PRI + 0x1c); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_CONFIG); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_CONFIG + 0x4); writel_relaxed(context[i++], gic_dist_base + GIC_DIST_ENABLE_SET); BUG_ON(i != PPI_CONTEXT_SIZE); } /* * Mask all the PPIs. This should only be called after they have been saved * through secure trap or through save_ppi(). This is primarily needed to * mask the local timer irq that could be pending since timekeeping gets * suspended after the local irqs are disabled. The pending interrupt would * kick the CPU out of WFI immediately, and prevent it from going to the lower * power states. The correct value will be restored when the CPU is brought * back up by restore. */ static void gic_mask_ppi(void) { void __iomem *gic_dist_base = omap4_get_gic_dist_base(); __get_cpu_var(gic_ppi_enable_mask) = readl_relaxed(gic_dist_base + GIC_DIST_ENABLE_SET); writel_relaxed(0xffffffff, gic_dist_base + GIC_DIST_ENABLE_CLEAR); } static void gic_unmask_ppi(void) { void __iomem *gic_dist_base = omap4_get_gic_dist_base(); writel_relaxed(__get_cpu_var(gic_ppi_enable_mask), gic_dist_base + GIC_DIST_ENABLE_SET); } /* * Save GIC context in SAR RAM. Restore is done by ROM code * GIC is lost only when MPU hits OSWR or OFF. It consists * of a distributor and a per-CPU interface module. The GIC * save restore is optimised to save only necessary registers. */ static void gic_save_context(void) { u8 i; u32 val; /* * Interrupt Clear Enable registers are inverse of set enable * and hence not needed to be saved. ROM code programs it * based on Set Enable register values. */ /* Save CPU 0 Interrupt Set Enable register */ val = gic_readl(GIC_DIST_ENABLE_SET, 0); sar_writel(val, ICDISER_CPU0_OFFSET, 0); /* Disable interrupts on CPU1 */ sar_writel(GIC_MASK_ALL, ICDISER_CPU1_OFFSET, 0); /* Save all SPI Set Enable register */ for (i = 0; i < max_spi_reg; i++) { val = gic_readl(GIC_DIST_ENABLE_SET + SPI_ENABLE_SET_OFFSET, i); sar_writel(val, ICDISER_SPI_OFFSET, i); } /* * Interrupt Priority Registers * Secure sw accesses, last 5 bits of the 8 bits (bit[7:3] are used) * Non-Secure sw accesses, last 4 bits (i.e. bits[7:4] are used) * But the Secure Bits[7:3] are shifted by 1 in Non-Secure access. * Secure (bits[7:3] << 1)== Non Secure bits[7:4] * Hence right shift the value by 1 while saving the priority */ /* Save SGI priority registers (Software Generated Interrupt) */ for (i = 0; i < 4; i++) { val = gic_readl(GIC_DIST_PRI, i); /* Save the priority bits of the Interrupts */ sar_writel(val >> 0x1, ICDIPR_SFI_CPU0_OFFSET, i); /* Disable the interrupts on CPU1 */ sar_writel(GIC_MASK_ALL, ICDIPR_SFI_CPU1_OFFSET, i); } /* Save PPI priority registers (Private Peripheral Intterupts) */ val = gic_readl(GIC_DIST_PRI + PPI_PRI_OFFSET, 0); sar_writel(val >> 0x1, ICDIPR_PPI_CPU0_OFFSET, 0); sar_writel(GIC_MASK_ALL, ICDIPR_PPI_CPU1_OFFSET, 0); /* SPI priority registers - 4 interrupts/register */ for (i = 0; i < (max_spi_irq / 4); i++) { val = gic_readl((GIC_DIST_PRI + SPI_PRI_OFFSET), i); sar_writel(val >> 0x1, ICDIPR_SPI_OFFSET, i); } /* SPI Interrupt Target registers - 4 interrupts/register */ for (i = 0; i < (max_spi_irq / 4); i++) { val = gic_readl((GIC_DIST_TARGET + SPI_TARGET_OFFSET), i); sar_writel(val, ICDIPTR_SPI_OFFSET, i); } /* SPI Interrupt Congigeration eegisters- 16 interrupts/register */ for (i = 0; i < (max_spi_irq / 16); i++) { val = gic_readl((GIC_DIST_CONFIG + SPI_CONFIG_OFFSET), i); sar_writel(val, ICDICFR_OFFSET, i); } /* Set the Backup Bit Mask status for GIC */ val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); val |= (SAR_BACKUP_STATUS_GIC_CPU0 | SAR_BACKUP_STATUS_GIC_CPU1); __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); } /* * API to save GIC and Wakeupgen using secure API * for HS/EMU device */ static void save_gic_wakeupgen_secure(void) { u32 ret; ret = omap4_secure_dispatcher(HAL_SAVEGIC_INDEX, FLAG_START_CRITICAL, 0, 0, 0, 0, 0); if (!ret) pr_debug("GIC and Wakeupgen context save failed\n"); } /* * API to save Secure RAM, GIC, WakeupGen Registers using secure API * for HS/EMU device */ static void save_secure_all(void) { u32 ret; ret = omap4_secure_dispatcher(HAL_SAVEALL_INDEX, FLAG_START_CRITICAL, 1, omap4_secure_ram_phys, 0, 0, 0); if (ret) pr_debug("Secure all context save failed\n"); } /* * API to save Secure RAM using secure API * for HS/EMU device */ static void save_secure_ram(void) { u32 ret; ret = omap4_secure_dispatcher(HAL_SAVESECURERAM_INDEX, FLAG_START_CRITICAL, 1, omap4_secure_ram_phys, 0, 0, 0); if (!ret) pr_debug("Secure ram context save failed\n"); } /* Helper functions for MPUSS OSWR */ static inline u32 mpuss_read_prev_logic_pwrst(void) { u32 reg; reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); reg &= OMAP4430_LOSTCONTEXT_DFF_MASK; return reg; } static inline void mpuss_clear_prev_logic_pwrst(void) { u32 reg; reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); omap4_prminst_write_inst_reg(reg, OMAP4430_PRM_PARTITION, OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); } static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id) { u32 reg; if (cpu_id) { reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST, OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET); omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST, OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET); } else { reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST, OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET); omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST, OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET); } } static inline void save_ivahd_tesla_regs(void) { int i; for (i = 0; i < ARRAY_SIZE(tesla_reg); i++) tesla_reg[i].val = __raw_readl(tesla_reg[i].addr); for (i = 0; i < ARRAY_SIZE(ivahd_reg); i++) ivahd_reg[i].val = __raw_readl(ivahd_reg[i].addr); } static inline void restore_ivahd_tesla_regs(void) { int i; for (i = 0; i < ARRAY_SIZE(tesla_reg); i++) __raw_writel(tesla_reg[i].val, tesla_reg[i].addr); for (i = 0; i < ARRAY_SIZE(ivahd_reg); i++) __raw_writel(ivahd_reg[i].val, ivahd_reg[i].addr); } static inline void save_l3instr_regs(void) { int i; for (i = 0; i < ARRAY_SIZE(l3instr_reg); i++) l3instr_reg[i].val = __raw_readl(l3instr_reg[i].addr); } static inline void restore_l3instr_regs(void) { int i; for (i = 0; i < ARRAY_SIZE(l3instr_reg); i++) __raw_writel(l3instr_reg[i].val, l3instr_reg[i].addr); } /* * OMAP4 MPUSS Low Power Entry Function * * The purpose of this function is to manage low power programming * of OMAP4 MPUSS subsystem * Paramenters: * cpu : CPU ID * power_state: Targetted Low power state. * * MPUSS Low power states * The basic rule is that the MPUSS power domain must be at the higher or * equal power state (state that consume more power) than the higher of the * two CPUs. For example, it is illegal for system power to be OFF, while * the power of one or both of the CPU is DORMANT. When an illegal state is * entered, then the hardware behavior is unpredictable. * * MPUSS state for the context save * save_state = * 0 - Nothing lost and no need to save: MPUSS INACTIVE * 1 - CPUx L1 and logic lost: MPUSS CSWR * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF */ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { unsigned int save_state = 0; unsigned int wakeup_cpu; unsigned int inst_clk_enab = 0; if ((cpu >= NR_CPUS) || (omap_rev() == OMAP4430_REV_ES1_0)) goto ret; switch (power_state) { case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: save_state = 0; break; case PWRDM_POWER_OFF: save_state = 1; break; case PWRDM_POWER_RET: default: /* * CPUx CSWR is invalid hardware state. Also CPUx OSWR * doesn't make much scense, since logic is lost and $L1 * needs to be cleaned because of coherency. This makes * CPUx OSWR equivalent to CPUX OFF and hence not supported */ WARN_ON(1); goto ret; } /* * MPUSS book keeping should be executed by master * CPU only which is also the last CPU to go down. */ if (cpu) goto cpu_prepare; pwrdm_pre_transition(); /* * Check MPUSS next state and save GIC if needed * GIC lost during MPU OFF and OSWR */ pwrdm_clear_all_prev_pwrst(mpuss_pd); mpuss_clear_prev_logic_pwrst(); if (omap4_device_next_state_off()) { if (omap_type() == OMAP2_DEVICE_TYPE_GP) { omap_wakeupgen_save(); gic_save_context(); } else { /* FIXME: Check if this can be optimised */ /* l3_main inst clock must be enabled for * a save ram operation */ if (!l3_main_3_ick->usecount) { inst_clk_enab = 1; clk_enable(l3_main_3_ick); } save_secure_all(); if (inst_clk_enab == 1) clk_disable(l3_main_3_ick); save_ivahd_tesla_regs(); save_l3instr_regs(); } save_state = 3; goto cpu_prepare; } switch (pwrdm_read_next_pwrst(mpuss_pd)) { case PWRDM_POWER_RET: /* * MPUSS OSWR - Complete logic lost + L2$ retained. * MPUSS CSWR - Complete logic retained + L2$ retained. */ if (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF) { if (omap_type() == OMAP2_DEVICE_TYPE_GP) { omap_wakeupgen_save(); gic_save_context(); } else { save_gic_wakeupgen_secure(); save_ivahd_tesla_regs(); save_l3instr_regs(); } save_state = 2; } break; case PWRDM_POWER_OFF: /* MPUSS OFF - logic lost + L2$ lost */ if (omap_type() == OMAP2_DEVICE_TYPE_GP) { omap_wakeupgen_save(); gic_save_context(); } else { /* l3_main inst clock must be enabled for * a save ram operation */ if (!l3_main_3_ick->usecount) { inst_clk_enab = 1; clk_enable(l3_main_3_ick); } save_gic_wakeupgen_secure(); save_ivahd_tesla_regs(); save_l3instr_regs(); save_secure_ram(); if (inst_clk_enab == 1) clk_disable(l3_main_3_ick); } save_state = 3; break; case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: /* No need to save MPUSS context */ default: ; } cpu_prepare: if (cpu) gic_save_ppi(); /* * mask all PPIs to prevent them from kicking us out of wfi. */ gic_mask_ppi(); clear_cpu_prev_pwrst(cpu); cpu_clear_prev_logic_pwrst(cpu); set_cpu_next_pwrst(cpu, power_state); scu_pwrst_prepare(cpu, power_state); /* * Call low level function with targeted CPU id * and its low power state. */ stop_critical_timings(); omap4_cpu_suspend(cpu, save_state); start_critical_timings(); /* * Restore the CPUx power state to ON otherwise CPUx * power domain can transitions to programmed low power * state while doing WFI outside the low powe code. On * secure devices, CPUx does WFI which can result in * domain transition */ wakeup_cpu = hard_smp_processor_id(); set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); /* * If we didn't actually get into the low power state (e.g. immediately * exited wfi due to a pending interrupt), the secure side * would not have restored CPU0's GIC PPI enable mask. * For other CPUs, gic_restore_ppi will do that for us. */ if (cpu) gic_restore_ppi(); else gic_unmask_ppi(); /* * If !master cpu return to hotplug-path. * * GIC distributor control register has changed between * CortexA9 r1pX and r2pX. The Control Register secure * banked version is now composed of 2 bits: * bit 0 == Secure Enable * bit 1 == Non-Secure Enable * The Non-Secure banked register has not changed * Because the ROM Code is based on the r1pX GIC, the CPU1 * GIC restoration will cause a problem to CPU0 Non-Secure SW. * The workaround must be: * 1) Before doing the CPU1 wakeup, CPU0 must disable * the GIC distributor * 2) CPU1 must re-enable the GIC distributor on * it's wakeup path. */ if (wakeup_cpu) { if (!cpu_is_omap443x()) gic_dist_enable(); goto ret; } /* Check if MPUSS lost it's logic */ if (mpuss_read_prev_logic_pwrst()) { /* Clear SAR BACKUP status on GP devices */ if (omap_type() == OMAP2_DEVICE_TYPE_GP) __raw_writel(0x0, sar_base + SAR_BACKUP_STATUS_OFFSET); /* Enable GIC distributor and interface on CPU0*/ gic_cpu_enable(); gic_dist_enable(); if (omap_type() != OMAP2_DEVICE_TYPE_GP) { /* * Dummy dispatcher call after OSWR and OFF * Restore the right return Kernel address (with MMU on) for * subsequent calls to secure ROM. Otherwise the return address * will be to a PA return address and the system will hang. */ omap4_secure_dispatcher(PPA_SERVICE_0, FLAG_START_CRITICAL, 0, 0, 0, 0, 0); /* Due to ROM BUG at wake up from MPU OSWR/OFF * on HS/EMU device only (not GP device), * the ROM Code reconfigures some of * IVAHD/TESLA/L3INSTR registers. * So these IVAHD/TESLA and L3INSTR registers * need to be restored.*/ restore_ivahd_tesla_regs(); restore_l3instr_regs(); } } pwrdm_post_transition(); ret: return 0; } static void save_l2x0_auxctrl(void) { #ifdef CONFIG_CACHE_L2X0 /* * Save the L2X0 AUXCTRL value to SAR memory. Its used to * in every restore patch MPUSS OFF path. */ void __iomem *l2x0_base = omap4_get_l2cache_base(); u32 val; val = __raw_readl(l2x0_base + L2X0_AUX_CTRL); __raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET); /* * Save the L2X0 PREFETCH_CTRL value to SAR memory. * Its used in every restore path MPUSS OFF path. */ val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL); __raw_writel(val, sar_base + L2X0_PREFETCHCTRL_OFFSET); /* Save L2X0 LOCKDOWN_OFFSET0 during SAR */ val = readl_relaxed(l2x0_base + 0x900); writel_relaxed(val, sar_base + L2X0_LOCKDOWN_OFFSET0); #endif } /* * Initialise OMAP4 MPUSS */ int __init omap4_mpuss_init(void) { struct omap4_cpu_pm_info *pm_info; u8 i; /* Get GIC and SAR RAM base addresses */ sar_base = omap4_get_sar_ram_base(); gic_dist_base = omap4_get_gic_dist_base(); gic_cpu_base = omap4_get_gic_cpu_base(); if (omap_rev() == OMAP4430_REV_ES1_0) { WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); return -ENODEV; } /* Initilaise per CPU PM information */ pm_info = &per_cpu(omap4_pm_info, 0x0); pm_info->scu_sar_addr = sar_base + SCU_OFFSET0; pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm"); if (!pm_info->pwrdm) { pr_err("Lookup failed for CPU0 pwrdm\n"); return -ENODEV; } /* Clear CPU previous power domain state */ pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); cpu_clear_prev_logic_pwrst(0); /* Initialise CPU0 power domain state to ON */ pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); pm_info = &per_cpu(omap4_pm_info, 0x1); pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); if (!pm_info->pwrdm) { pr_err("Lookup failed for CPU1 pwrdm\n"); return -ENODEV; } /* * Check the OMAP type and store it to scratchpad */ if (omap_type() != OMAP2_DEVICE_TYPE_GP) { /* Memory not released */ secure_ram = dma_alloc_coherent(NULL, OMAP4_SECURE_RAM_STORAGE, (dma_addr_t *)&omap4_secure_ram_phys, GFP_ATOMIC); if (!secure_ram) pr_err("Unable to allocate secure ram storage\n"); writel(0x1, sar_base + OMAP_TYPE_OFFSET); } else { writel(0x0, sar_base + OMAP_TYPE_OFFSET); } /* * Store OMAP revision to scratchpad. * ATM required for POR restore on GP devices. */ writel(omap_rev(), sar_base + OMAP_REV_OFFSET); /* Clear CPU previous power domain state */ pwrdm_clear_all_prev_pwrst(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); /* * Program the wakeup routine address for the CPU0 and CPU1 * used for OFF or DORMANT wakeup. Wakeup routine address * is fixed so programit in init itself. */ __raw_writel(virt_to_phys(omap4_cpu_resume), sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET); __raw_writel(virt_to_phys(omap4_cpu_resume), sar_base + CPU0_WAKEUP_NS_PA_ADDR_OFFSET); mpuss_pd = pwrdm_lookup("mpu_pwrdm"); if (!mpuss_pd) { pr_err("Failed to get lookup for MPUSS pwrdm\n"); return -ENODEV; } l3_main_3_ick = clk_get(NULL, "l3_main_3_ick"); /* Clear CPU previous power domain state */ pwrdm_clear_all_prev_pwrst(mpuss_pd); mpuss_clear_prev_logic_pwrst(); /* * Find out how many interrupts are supported. * OMAP4 supports max of 128 SPIs where as GIC can support * up to 1020 interrupt sources. On OMAP4, maximum SPIs are * fused in DIST_CTR bit-fields as 128. Hence the code is safe * from reserved register writes since its well within 1020. */ max_spi_reg = __raw_readl(gic_dist_base + GIC_DIST_CTR) & 0x1f; max_spi_irq = max_spi_reg * 32; /* * Mark the PPI and SPI interrupts as non-secure. * program the SAR locations for interrupt security registers to * reflect the same. */ if (omap_type() == OMAP2_DEVICE_TYPE_GP) { sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU0_OFFSET, 0); sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU1_OFFSET, 0); for (i = 0; i < max_spi_reg; i++) sar_writel(GIC_ISR_NON_SECURE, ICDISR_SPI_OFFSET, i); } save_l2x0_auxctrl(); return 0; } #endif