/* * sh7372 lowlevel sleep code for "Core Standby Mode" * * Copyright (C) 2011 Magnus Damm * * In "Core Standby Mode" the ARM core is off, but L2 cache is still on * * Based on mach-omap2/sleep34xx.S * * (C) Copyright 2007 Texas Instruments * Karthik Dasu * * (C) Copyright 2004 Texas Instruments, * Richard Woodruff * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #define SMFRAM 0xe6a70000 .align kernel_flush: .word v7_flush_dcache_all .align 3 ENTRY(sh7372_cpu_suspend) stmfd sp!, {r0-r12, lr} @ save registers on stack ldr r8, =SMFRAM mov r4, sp @ Store sp mrs r5, spsr @ Store spsr mov r6, lr @ Store lr stmia r8!, {r4-r6} mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register 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} mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register mrc p15, 0, r5, c10, c2, 0 @ PRRR mrc p15, 0, r6, c10, c2, 1 @ NMRR stmia r8!,{r4-r6} mrc p15, 0, r4, c13, c0, 1 @ Context ID mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address mrs r7, cpsr @ Store current cpsr stmia r8!, {r4-r7} mrc p15, 0, r4, c1, c0, 0 @ save control register stmia r8!, {r4} /* * jump out to kernel flush routine * - reuse that code is better * - it executes in a cached space so is faster than refetch per-block * - should be faster and will change with kernel * - 'might' have to copy address, load and jump to it * Flush all data from the L1 data cache before disabling * SCTLR.C bit. */ ldr r1, kernel_flush mov lr, pc bx r1 /* * 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. */ ldr r1, kernel_flush blx r1 /* * The kernel doesn't interwork: v7_flush_dcache_all in particluar will * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled. * This sequence switches back to ARM. Note that .align may insert a * nop: bx pc needs to be word-aligned in order to work. */ THUMB( .thumb ) THUMB( .align ) THUMB( bx pc ) THUMB( nop ) .arm /* Data memory barrier and Data sync barrier */ dsb dmb /* * =================================== * == WFI instruction => Enter idle == * =================================== */ wfi @ wait for interrupt /* * =================================== * == Resume path for non-OFF modes == * =================================== */ mrc p15, 0, r0, c1, c0, 0 tst r0, #(1 << 2) @ Check C bit enabled? orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared mcreq p15, 0, r0, c1, c0, 0 isb /* * =================================== * == Exit point from non-OFF modes == * =================================== */ ldmfd sp!, {r0-r12, pc} @ restore regs and return .pool .align 12 .text .global sh7372_cpu_resume sh7372_cpu_resume: mov r1, #0 /* * Invalidate all instruction caches to PoU * and flush branch target cache */ mcr p15, 0, r1, c7, c5, 0 ldr r3, =SMFRAM ldmia r3!, {r4-r6} mov sp, r4 @ Restore sp msr spsr_cxsf, r5 @ Restore spsr mov lr, r6 @ Restore lr ldmia r3!, {r4-r7} mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register mcr p15, 0, r5, c2, c0, 0 @ TTBR0 mcr p15, 0, r6, c2, c0, 1 @ TTBR1 mcr p15, 0, r7, c2, c0, 2 @ TTBCR ldmia r3!,{r4-r6} mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register mcr p15, 0, r5, c10, c2, 0 @ PRRR mcr p15, 0, r6, c10, c2, 1 @ NMRR ldmia r3!,{r4-r7} mcr p15, 0, r4, c13, c0, 1 @ Context ID mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address msr cpsr, r7 @ store cpsr /* Starting to enable MMU here */ mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */ and r7, #0x7 cmp r7, #0x0 beq usettbr0 ttbr_error: /* * More work needs to be done to support N[0:2] value other than 0 * So looping here so that the error can be detected */ b ttbr_error .align cache_pred_disable_mask: .word 0xFFFFE7FB ttbrbit_mask: .word 0xFFFFC000 table_index_mask: .word 0xFFF00000 table_entry: .word 0x00000C02 usettbr0: mrc p15, 0, r2, c2, c0, 0 ldr r5, ttbrbit_mask and r2, r5 mov r4, pc ldr r5, table_index_mask and r4, r5 @ r4 = 31 to 20 bits of pc /* Extract the value to be written to table entry */ ldr r6, table_entry /* r6 has the value to be written to table entry */ add r6, r6, r4 /* Getting the address of table entry to modify */ lsr r4, #18 /* r2 has the location which needs to be modified */ add r2, r4 ldr r4, [r2] str r6, [r2] /* modify the table entry */ mov r7, r6 mov r5, r2 mov r6, r4 /* r5 = original page table address */ /* r6 = original page table data */ mov r0, #0 mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB /* * Restore control register. This enables the MMU. * The caches and prediction are not enabled here, they * will be enabled after restoring the MMU table entry. */ ldmia r3!, {r4} stmia r3!, {r5} /* save original page table address */ stmia r3!, {r6} /* save original page table data */ stmia r3!, {r7} /* save modified page table data */ ldr r2, cache_pred_disable_mask and r4, r2 mcr p15, 0, r4, c1, c0, 0 dsb isb ldr r0, =restoremmu_on bx r0 /* * ============================== * == Exit point from OFF mode == * ============================== */ restoremmu_on: ldmfd sp!, {r0-r12, pc} @ restore regs and return