/* * OMAP44xx CPU low power powerdown and powerup code. * * Copyright (C) 2011 Texas Instruments, Inc. * Written by Santosh Shilimkar * * 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 "omap4-sar-layout.h" #ifdef CONFIG_SMP /* Masks used for MMU manipulation */ #define TTRBIT_MASK 0xffffc000 #define TABLE_INDEX_MASK 0xfff00000 #define TABLE_ENTRY 0x00000c02 #define CACHE_DISABLE_MASK 0xffffe7fb #define TABLE_ADDRESS_OFFSET 0x04 #define CR_VALUE_OFFSET 0x08 #define SCU_POWER_SECURE_INDEX 0x108 /* * Macro to call PPA svc when MMU is OFF * Caller must setup r0 and r3 before calling this macro * @r0: PPA service ID * @r3: Pointer to params */ .macro LM_CALL_PPA_SERVICE_PA mov r1, #0x0 @ Process ID mov r2, #0x4 @ Flag mov r6, #0xff mov r12, #0x00 @ Secure Service ID dsb smc #0 .endm /* * Macro to check OMAP4 revision * @a: bits 31:08 of omap_rev */ .macro OMAP4_REV_CMP a ldr r0, =OMAP44XX_SAR_RAM_BASE ldr r1, [r0, #OMAP_REV_OFFSET] lsr r2, r1, #8 and r2, r2, #0xffffff ldr r3, =\a cmp r2, r3 .endm /* * To load POR which was saved in SAR RAM */ POR_params: .word 1, 0 ppa_zero_params: .word 0x0 /* * ============================= * == CPU suspend entry point == * ============================= * * void omap4_cpu_suspend(unsigned int cpu, unsigned int save_state) * * This function code saves the CPU context and performs the CPU * power down sequence. Calling WFI effectively changes the CPU * power domains states to the desired target power state. * * @cpu : contains cpu id (r0) * @save_state : contains context save state (r1) * 0 - No context lost * 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 * @return: This function never returns for CPU OFF and DORMANT power states. * Post WFI, CPU transitions to DORMANT or OFF power state and on wake-up * from this follows a full CPU reset path via ROM code to CPU restore code. * It returns to the caller for CPU INACTIVE and ON power states or in case * CPU failed to transition to targeted OFF/DORMANT state. */ ENTRY(omap4_cpu_suspend) stmfd sp!, {r0-r12, lr} @ Save registers on stack cmp r1, #0x0 beq do_WFI @ Nothing to save, jump to WFI mov r5, r0 mov r6, r1 bl omap4_get_sar_ram_base mov r8, r0 ands r5, r5, #0x0f streq r6, [r8, #L2X0_SAVE_OFFSET0] @ Store save state strne r6, [r8, #L2X0_SAVE_OFFSET1] orreq r8, r8, #CPU0_SAVE_OFFSET orrne r8, r8, #CPU1_SAVE_OFFSET /* * Save only needed CPU CP15 registers. VFP, breakpoint, * performance monitor registers are not saved. Generic * code suppose to take care of those. */ mov r4, sp @ Store sp mrs r5, spsr @ Store spsr mov r6, lr @ Store lr stmia r8!, {r4-r6} /* c1 and c2 registers */ mrc p15, 0, r4, c1, c0, 2 @ CPACR mrc p15, 0, r5, c2, c0, 0 @ TTBR0 mrc p15, 0, r6, c2, c0, 1 @ TTBR1 mrc p15, 0, r7, c2, c0, 2 @ TTBCR stmia r8!, {r4-r7} /* c3 and c10 registers */ mrc p15, 0, r4, c3, c0, 0 @ DACR mrc p15, 0, r5, c10, c2, 0 @ PRRR mrc p15, 0, r6, c10, c2, 1 @ NMRR stmia r8!,{r4-r6} /* c12, c13 and CPSR registers */ mrc p15, 0, r4, c13, c0, 1 @ Context ID mrc p15, 0, r5, c13, c0, 2 @ User r/w thread ID mrc p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR mrs r7, cpsr @ Store CPSR stmia r8!, {r4-r7} /* c1 control register */ mrc p15, 0, r4, c1, c0, 0 @ Save control register stmia r8!, {r4} /* * Flush all data from the L1 data cache before disabling * SCTLR.C bit. */ bl v7_flush_dcache_all bl omap4_get_sar_ram_base ldr r9, [r0, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Check for HS device bne skip_secure_l1_flush mov r0, #SCU_PM_NORMAL mov r1, #0xFF @ clean seucre L1 stmfd r13!, {r4-r12, r14} ldr r12, =SCU_POWER_SECURE_INDEX dsb smc #0 dsb ldmfd r13!, {r4-r12, r14} skip_secure_l1_flush: /* * Clear the SCTLR.C bit to prevent further data cache * allocation. Clearing SCTLR.C would make all the data accesses * strongly ordered and would not hit the cache. */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #(1 << 2) @ Disable the C bit mcr p15, 0, r0, c1, c0, 0 isb /* * Invalidate L1 data cache. Even though only invalidate is * necessary exported flush API is used here. Doing clean * on already clean cache would be almost NOP. */ bl v7_flush_dcache_all /* * Switch the CPU from Symmetric Multiprocessing (SMP) mode * to AsymmetricMultiprocessing (AMP) mode by programming * the SCU power status to DORMANT or OFF mode. * This enables the CPU to be taken out of coherency by * preventing the CPU from receiving cache, TLB, or BTB * maintenance operations broadcast by other CPUs in the cluster. */ bl omap4_get_sar_ram_base mov r8, r0 ldr r9, [r8, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Check for HS device bne scu_gp_set mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f ldreq r0, [r8, #SCU_OFFSET0] ldrne r0, [r8, #SCU_OFFSET1] mov r1, #0x00 @ Secure L1 is clean already stmfd r13!, {r4-r12, r14} ldr r12, =SCU_POWER_SECURE_INDEX dsb smc #0 dsb ldmfd r13!, {r4-r12, r14} b skip_scu_gp_set scu_gp_set: mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f ldreq r1, [r8, #SCU_OFFSET0] ldrne r1, [r8, #SCU_OFFSET1] bl omap4_get_scu_base bl scu_power_mode skip_scu_gp_set: isb dsb mrc p15, 0, r0, c1, c1, 2 @Read NSACR data tst r0, #(1 << 18) mrcne p15, 0, r0, c1, c0, 1 bicne r0, r0, #(1 << 6) mcrne p15, 0, r0, c1, c0, 1 isb #ifdef CONFIG_CACHE_L2X0 /* * Clean and invalidate the L2 cache. * Common cache-l2x0.c functions can't be used here since it * uses spinlocks. We are out of coherency here with data cache * disabled. The spinlock implementation uses exclusive load/store * instruction which can fail without data cache being enabled. * OMAP4 hardware doesn't support exclusive monitor which can * overcome exclusive access issue. Because of this, CPU can * lead to deadlock. */ l2x_clean_inv: bl omap4_get_sar_ram_base mov r8, r0 mrc p15, 0, r5, c0, c0, 5 @ Read MPIDR ands r5, r5, #0x0f ldreq r0, [r8, #L2X0_SAVE_OFFSET0] ldrne r0, [r8, #L2X0_SAVE_OFFSET1] cmp r0, #3 bne do_WFI #ifdef CONFIG_PL310_ERRATA_727915 mov r0, #0x03 mov r12, #0x100 dsb smc #0 dsb #endif bl omap4_get_l2cache_base mov r2, r0 ldr r0, =0xffff str r0, [r2, #L2X0_CLEAN_INV_WAY] wait: ldr r0, [r2, #L2X0_CLEAN_INV_WAY] ands r0, r0, #0xff bne wait #ifdef CONFIG_PL310_ERRATA_727915 mov r0, #0x00 mov r12, #0x100 dsb smc #0 dsb #endif l2x_sync: bl omap4_get_l2cache_base mov r2, r0 mov r0, #0x0 str r0, [r2, #L2X0_CACHE_SYNC] sync: ldr r0, [r2, #L2X0_CACHE_SYNC] ands r0, r0, #0x1 bne sync #endif do_WFI: bl omap_do_wfi /* * CPU is here when it failed to enter OFF/DORMANT or * no low power state was attempted. */ mrc p15, 0, r0, c1, c0, 0 tst r0, #(1 << 2) @ Check C bit enabled? orreq r0, r0, #(1 << 2) @ Enable the C bit mcreq p15, 0, r0, c1, c0, 0 isb /* Enable SMP bit if it's being disabled */ mrc p15, 0, r0, c1, c0, 1 tst r0, #(1 << 6) @ Check SMP bit enabled? orreq r0, r0, #(1 << 6) mcreq p15, 0, r0, c1, c0, 1 isb /* * Ensure the CPU power state is set to NORMAL in * SCU power state so that CPU is back in coherency. * In non-coherent mode CPU can lock-up and lead to * system deadlock. */ bl omap4_get_sar_ram_base mov r8, r0 ldr r9, [r8, #OMAP_TYPE_OFFSET] cmp r9, #0x1 @ Check for HS device bne scu_gp_clear mov r0, #SCU_PM_NORMAL mov r1, #0x00 stmfd r13!, {r4-r12, r14} ldr r12, =SCU_POWER_SECURE_INDEX dsb smc #0 dsb ldmfd r13!, {r4-r12, r14} b skip_scu_gp_clear scu_gp_clear: bl omap4_get_scu_base mov r1, #SCU_PM_NORMAL bl scu_power_mode skip_scu_gp_clear: isb dsb ldmfd sp!, {r0-r12, pc} @ Restore regs and return ENDPROC(omap4_cpu_suspend) /* * ============================ * == CPU resume entry point == * ============================ * * void omap4_cpu_resume(void) * * ROM code jumps to this function while waking up from CPU * OFF or DORMANT state. Physical address of the function is * stored in the SAR RAM while entering to OFF or DORMANT mode. */ ENTRY(omap4_cpu_resume) /* * Each CPU get the device type from SAR RAM and store in r9 */ ldr r8, =OMAP44XX_SAR_RAM_BASE ldr r9, [r8, #OMAP_TYPE_OFFSET] /* * CPU1 must check if CPU0 is alive/awake, * if PL310 is OFF, MPUSS was OFF and CPU0 is still off, * CPU1 must go to sleep and wait for CPU0. * Only CPU0 should enable cache controller. */ mrc p15, 0, r0, c0, c0, 5 @ Get cpuID ands r0, r0, #0x0f @ Continue boot if CPU0 bne is_cpu0_up @ CPU1: Must check if CPU0 is up cmp r9, #0x1 @ CPU0: Check for HS device in r9 beq continue_boot bne gp_cp15_configure is_cpu0_up: ldr r2, =OMAP44XX_L2CACHE_BASE ldr r0, [r2, #L2X0_CTRL] and r0, #0x0f cmp r0, #1 @ is CPU0 already UP? beq cpu1_configure_cp15 /* * When CPU1 is released to control of HLOS in the case of OSWR * and OFF mode, PPA below v1.7.3[1] is not performing all * Memory coherency and TLB operations required. * * For GP devices (PPA never present) this WA path is also taken if * CPU1 wakes up first, this mechanism should be used to synchronize * booting by shutting off CPU1 thus allowing CPU0 to boot first * and restore OMAP context. * * A WA to recover cleanly from this scenario is to switch CPU1 back to * previous OFF state. This forces a reset of CPU1, which in turn * forces CPU1 not to override MMU descriptors already in place in * internal RAM setup by CPU0. CPU1 will also sync to the in-place * descriptors on the next wakeup. CPU1 wakeup is done by * later kernel subsystems depending on suspend or cpuidle path * being exercised. * NOTE - for OSWR, state provided is 2, and for OFF, state is 3, * Since the bug impacts OFF and OSWR, we need to force a 0x3 to * shut off CPU1 * * Since many distributions may not be able to update PPA OR would like * to support platforms with older PPA, we provide a config option. * This is simpler and makes the current code remain cleaner in * comparison to a flag based handling in CPU1 recovery for * board + PPA revision combinations. * * Having this config option enabled even on platforms with fixed PPA * should not impact stability, however, ability to make CPU1 available * for operations a little earlier is curtailed. * * Foot note [1]: * v1.7.3 is the official TI PPA version. Custom PPA could have * the relevant changes ported over to it. */ #ifdef CONFIG_OMAP4_PPA_CPU1_ONLINE_BUG mov r0, #0x03 @ target CPU1 to OFF(mpusspd=OSWR/OFF) mov r1, #0x00 @ Secure L1 is already clean ldr r12, =SCU_POWER_SECURE_INDEX dsb smc #0 isb @ Necessary barriers before wfi dsb dmb wfi @ wait for interrupt nop nop /* * IF we came out of WFI immediately, something unknown happend. * Fall through AND loop back to the checks. Failing which retry WFI. */ #endif /* * CPU0 and CPU1 are release together from OFF mode, however, * CPU0 can be busy doing restore operations while waking * from OFF mode, However, for many PPA services we need * CPU0, so, we ask CPU1 to loop back to stagger CPU1 behind CPU0 */ b omap4_cpu_resume cpu1_configure_cp15: /* * Select right API to set cp15 depending on device type */ cmp r9, #0x1 @ Check for HS device in r9 bne gp_cp15_configure @ Jump to GP API ppa_cp15_cpu1_configure: /* * In HS devices CPU0's CP15 is configured at wakeup by PPA, CPU1 must * call PPA to configure it and CPU0 must be online for any PPA API to * work. In 4430 devices CPU1 this call also enables the access to SMP * bit, on 4460 devices, CPU1 will have SMP bit access by default. */ mov r0, #PPA_SERVICE_DEFAULT_POR_NS_SMP adr r3, ppa_zero_params @ Pointer to parameters LM_CALL_PPA_SERVICE_PA isb dsb cmp r0, #0x0 @ API returns 0 on success. bne ppa_cp15_cpu1_configure @ retry if we did not succeed /* HS device cp15 done, jump to continue_boot */ b continue_boot gp_cp15_configure: /* In GP devices, both CPUs must configure their CP15 */ /* Compute the ARM revision */ mov r3, #0 mrc p15, 0, r1, c0, c0, 0 @ read main ID register and r2, r1, #0x00f00000 @ variant and r3, r1, #0x0000000f @ revision orr r3, r3, r2, lsr #20-4 @ r3: has variant and revision mov r0, #0 #ifdef CONFIG_OMAP4_ARM_ERRATA_742230 cmp r3, #0x10 @ present in r1p0 onwards blt ignore_742230 cmp r3, #0x22 @ not present after r2p2 orrle r0, r0, #0x10 @ Set bit 4 ignore_742230: #endif #ifdef CONFIG_OMAP4_ARM_ERRATA_751472 cmp r3, #0x30 @ present prior to r3p0 orrlt r0, r0, #0x800 @ Set bit 11 #endif #ifdef CONFIG_OMAP4_ARM_ERRATA_743622 cmp r3, #0x20 @ present in r2p0 onwards blt ignore_743622 cmp r3, #0x30 @ not preset in r3p0 onwards orrlt r0, r0, #0x40 @ Set bit 6 ignore_743622: #endif cmp r0, #0 beq continue_boot mov r12, #HAL_DIAGREG_0 dsb smc #0 dsb continue_boot: #ifdef CONFIG_CACHE_L2X0 /* * Restore the L2 AUXCTRL and enable the L2 cache. * 0x109 = Program the L2X0 AUXCTRL * 0x102 = Enable the L2 using L2X0 CTRL * register r0 contains value to be programmed. * L2 cache is already invalidate by ROM code as part * of MPUSS OFF wakeup path. */ ldr r2, =OMAP44XX_L2CACHE_BASE ldr r0, [r2, #L2X0_CTRL] and r0, #0x0f cmp r0, #1 beq skip_l2en @ Skip if already enabled check_por: ldr r0, =OMAP44XX_SAR_RAM_BASE @ Check DEVICE type ldr r1, [r0, #OMAP_TYPE_OFFSET] cmp r1, #0x1 @ Check for HS device bne check_por_gp ldr r0, =PPA_SERVICE_PL310_POR @ Setup PPA HAL call ldr r1, =OMAP44XX_SAR_RAM_BASE ldr r4, [r1, #L2X0_PREFETCHCTRL_OFFSET] adr r3, POR_params str r4, [r3, #0x04] LM_CALL_PPA_SERVICE_PA b skip_por check_por_gp: OMAP4_REV_CMP 0x443022 blt skip_por @ for GP POR setup possible only on >= OMAP4430ES2.2 ldr r3, =OMAP44XX_SAR_RAM_BASE ldr r0, [r3, #L2X0_PREFETCHCTRL_OFFSET] ldr r12, =0x113 @ Setup L2 POR value dsb smc #0 skip_por: ldr r3, =OMAP44XX_SAR_RAM_BASE ldr r0, [r3, #L2X0_AUXCTRL_OFFSET] ldr r12, =0x109 @ Setup L2 AUXCTRL value dsb smc #0 ldr r2, =OMAP44XX_L2CACHE_BASE ldr r4, =OMAP44XX_SAR_RAM_BASE ldr r9, [r4, #L2X0_LOCKDOWN_OFFSET0] str r9, [r2, #L2X0_LOCKDOWN_WAY_D0] str r9, [r2, #L2X0_LOCKDOWN_WAY_D1] str r9, [r2, #L2X0_LOCKDOWN_WAY_I0] str r9, [r2, #L2X0_LOCKDOWN_WAY_I1] dsb mov r0, #0x1 ldr r12, =0x102 @ Enable L2 Cache controller dsb smc #0 dsb skip_l2en: #endif /* Check if we have Public access to SMP bit */ mrc p15, 0, r0, c1, c1, 2 @ Read NSACR data tst r0, #(1 << 18) beq skip_ns_smp_enable @ Skip if still no access /* Set the SMP bit if it is not already set */ mrc p15, 0, r0, c1, c0, 1 tst r0, #(1 << 6) @ Check SMP bit enabled? orreq r0, r0, #(1 << 6) mcreq p15, 0, r0, c1, c0, 1 isb skip_ns_smp_enable: /* * Check the wakeup cpuid and use appropriate * SAR BANK location for context restore. */ ldr r3, =OMAP44XX_SAR_RAM_BASE mov r1, #0 mcr p15, 0, r1, c7, c5, 0 @ Invalidate L1 I mrc p15, 0, r0, c0, c0, 5 @ MPIDR ands r0, r0, #0x0f orreq r3, r3, #CPU0_SAVE_OFFSET orrne r3, r3, #CPU1_SAVE_OFFSET /* Restore cp15 registers */ ldmia r3!, {r4-r6} mov sp, r4 @ Restore sp msr spsr_cxsf, r5 @ Restore spsr mov lr, r6 @ Restore lr /* c1 and c2 registers */ ldmia r3!, {r4-r7} mcr p15, 0, r4, c1, c0, 2 @ CPACR mcr p15, 0, r5, c2, c0, 0 @ TTBR0 mcr p15, 0, r6, c2, c0, 1 @ TTBR1 mcr p15, 0, r7, c2, c0, 2 @ TTBCR /* c3 and c10 registers */ ldmia r3!,{r4-r6} mcr p15, 0, r4, c3, c0, 0 @ DACR mcr p15, 0, r5, c10, c2, 0 @ PRRR mcr p15, 0, r6, c10, c2, 1 @ NMRR /* c12, c13 and CPSR registers */ ldmia r3!,{r4-r7} mcr p15, 0, r4, c13, c0, 1 @ Context ID mcr p15, 0, r5, c13, c0, 2 @ User r/w thread ID mcr p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR msr cpsr, r7 @ store cpsr /* * Enabling MMU here. Page entry needs to be altered * to create temporary 1:1 map and then resore the entry * ones MMU is enabled */ mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl and r7, #0x7 @ Extract N (0:2) to decide cmp r7, #0x0 @ TTBR0/TTBR1 beq use_ttbr0 ttbr_error: b ttbr_error @ Only N = 0 supported use_ttbr0: mrc p15, 0, r2, c2, c0, 0 @ Read TTBR0 ldr r5, =TTRBIT_MASK and r2, r5 mov r4, pc ldr r5, =TABLE_INDEX_MASK and r4, r5 @ r4 = 31 to 20 bits of pc ldr r1, =TABLE_ENTRY add r1, r1, r4 @ r1 has value of table entry lsr r4, #18 @ Address of table entry add r2, r4 @ r2 - location to be modified /* Ensure the modified entry makes it to main memory */ #ifdef CONFIG_CACHE_L2X0 ldr r5, =OMAP44XX_L2CACHE_BASE str r2, [r5, #L2X0_CLEAN_INV_LINE_PA] wait_l2: ldr r0, [r5, #L2X0_CLEAN_INV_LINE_PA] ands r0, #1 bne wait_l2 #endif /* Storing previous entry of location being modified */ ldr r5, =OMAP44XX_SAR_RAM_BASE ldr r4, [r2] mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f streq r4, [r5, #MMU_OFFSET0] @ Modify the table entry strne r4, [r5, #MMU_OFFSET1] str r1, [r2] /* * Storing address of entry being modified * It will be restored after enabling MMU */ ldr r5, =OMAP44XX_SAR_RAM_BASE mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f orreq r5, r5, #MMU_OFFSET0 orrne r5, r5, #MMU_OFFSET1 str r2, [r5, #TABLE_ADDRESS_OFFSET] mov r0, #0 mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB mcr p15, 0, r0, c8, c5, 0 @ Invalidate ITLB mcr p15, 0, r0, c8, c6, 0 @ Invalidate DTLB /* * Restore control register but don't enable Data caches here. * Caches will be enabled after restoring MMU table entry. */ ldmia r3!, {r4} str r4, [r5, #CR_VALUE_OFFSET] @ Store previous value of CR ldr r2, =CACHE_DISABLE_MASK and r4, r2 mcr p15, 0, r4, c1, c0, 0 isb dsb ldr r0, =mmu_on_label bx r0 mmu_on_label: /* Set up the per-CPU stacks */ bl cpu_init /* * Restore the MMU table entry that was modified for * enabling MMU. */ bl omap4_get_sar_ram_base mov r8, r0 mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR ands r0, r0, #0x0f orreq r8, r8, #MMU_OFFSET0 @ Get address of entry that.. orrne r8, r8, #MMU_OFFSET1 @ was modified ldr r2, [r8, #TABLE_ADDRESS_OFFSET] ldr r3, =local_va2pa_offet add r2, r2, r3 ldr r0, [r8] @ Get the previous value.. str r0, [r2] @ which needs to be restored mov r0, #0 mcr p15, 0, r0, c7, c1, 6 @ flush TLB and issue barriers mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB mcr p15, 0, r0, c8, c5, 0 @ Invalidate ITLB mcr p15, 0, r0, c8, c6, 0 @ Invalidate DTLB dsb isb ldr r0, [r8, #CR_VALUE_OFFSET] @ Restore the Control register mcr p15, 0, r0, c1, c0, 0 @ with caches enabled. isb ldmfd sp!, {r0-r12, pc} @ restore regs and return .equ local_va2pa_offet, (PLAT_PHYS_OFFSET + PAGE_OFFSET) ENDPROC(omap4_cpu_resume) ENTRY(omap_bus_sync) stmfd sp!, {r9, lr} /* SO write to drain of MPU-2-DDR T2ASYNC FIFO */ bl omap_get_dram_barrier_base ldr r2, [r0] str r2, [r0] /* SO write to drain MPU-2-L3 T2ASYNC FIFO */ bl omap_get_sram_barrier_base ldr r2, [r0] str r2, [r0] isb ldmfd sp!, {r9, pc} ENDPROC(omap_bus_sync) ENTRY(omap_do_wfi) stmfd sp!, {lr} /* Drain interconnect write buffers. */ bl omap_bus_sync /* * Execute an ISB instruction to ensure that all of the * CP15 register changes have been committed. */ isb /* * Execute a barrier instruction to ensure that all cache, * TLB and branch predictor maintenance operations issued * by any CPU in the cluster have completed. */ dsb dmb /* * Execute a WFI instruction and wait until the * STANDBYWFI output is asserted to indicate that the * CPU is in idle and low power state. CPU can specualatively * prefetch the instructions so add NOPs after WFI. Sixteen * NOPs as per Cortex-A9 pipeline. */ wfi @ Wait For Interrupt nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop ldmfd sp!, {pc} ENDPROC(omap_do_wfi) /* * ============================ * == ARM get revision id == * ============================ * * unsigned int omap_get_arm_rev() * * This function returns the ARM revision id ROM, * eg, 0x20 for arm r2p0, 0x21 for arm r2p1, 0x30 for arm r3p0 */ ENTRY(omap_get_arm_rev) stmfd sp!, {lr} mov r0, #0 mrc p15, 0, r1, c0, c0, 0 @ read main ID register and r2, r1, #0xff000000 @ ARM? teq r2, #0x41000000 bne not_arm and r2, r1, #0x00f00000 @ variant and r3, r1, #0x0000000f @ revision orr r3, r3, r2, lsr #20-4 @ combine variant and revision mov r0, r3 not_arm: ldmfd sp!, {pc} ENDPROC(omap_get_arm_rev) #endif