From: Wenzeng Chen <wzch@xxxxxxxxxxx> VPF/CPU mode/CP15 saved and restored by open source code L2$ controller/debug register/performance monitor saved and restored by our own code. Change-Id: I5bd5209d1ca6ca79e9bba30c48b677934fd5f205 Signed-off-by: Wenzeng Chen <wzch@xxxxxxxxxxx> --- arch/arm/mach-pxa/ca9_asm.S | 541 ++++------------------------ arch/arm/mach-pxa/cmd_ca9_idle.c | 79 +++-- arch/arm/mach-pxa/dvfm.c | 3 - arch/arm/mach-pxa/include/mach/ca9_asm.h | 12 +- arch/arm/mach-pxa/include/mach/ca9_regs.h | 82 ----- arch/arm/mach-pxa/include/mach/pxa95x_pm.h | 10 +- arch/arm/mach-pxa/mspm_idle.c | 8 +- arch/arm/mach-pxa/pxa95x_pm.c | 27 +- 8 files changed, 142 insertions(+), 620 deletions(-) delete mode 100644 arch/arm/mach-pxa/include/mach/ca9_regs.h diff --git a/arch/arm/mach-pxa/ca9_asm.S b/arch/arm/mach-pxa/ca9_asm.S index 62bad28..dc74715 100644 --- a/arch/arm/mach-pxa/ca9_asm.S +++ b/arch/arm/mach-pxa/ca9_asm.S @@ -1,15 +1,8 @@ -#define PWRMODE_REG 0x40f40080 - -#define mode_usr 0x10 -#define mode_fiq 0x11 -#define mode_irq 0x12 -#define mode_svc 0x13 -#define mode_abt 0x17 -#define mode_und 0x1b -#define mode_sys 0x1f - - - +#include <asm/hardware/cache-l2x0.h> +#define PXA978_L2CACHE_BASE 0x58120000 +#define OSCR_PHY_ADDR 0x40A00010 +#define OSCR_VIRTUAL_ADDR 0xF2A00010 +#define POWER_MODE_BASE 0x40F40080 .global dump_cop_regs dump_cop_regs: stmfd sp!, {r4-r12,lr} @@ -68,137 +61,18 @@ dump_cop_regs: ldmfd sp!,{r4-r12,pc} - .global save_pl310 -save_pl310: - stmfd sp!, {r4-r12,lr} @r0 context, r1 pl310 virtual address - ldr r2, [r1, #0x100] @ control - str r2, [r0] - ldr r2, [r1, #0x104] @aux_control - str r2, [r0, #4] - ldr r2, [r1, #0x108] @tag_ram_control - str r2, [r0, #8] - ldr r2, [r1, #0x10C] @data_ram_control - str r2, [r0, #12] - ldr r2, [r1, #0x200] @ev_counter_ctrl - str r2, [r0, #16] - ldr r2, [r1, #0x204] @ev_counter1_cfg - str r2, [r0, #20] - ldr r2, [r1, #0x208] @ev_counter0_cfg - str r2, [r0, #24] - ldr r2, [r1, #0x20C] @ev_counter1 - str r2, [r0, #28] - ldr r2, [r1, #0x210] @ev_counter0 - str r2, [r0, #32] - ldr r2, [r1, #0x214] @int_mask - str r2, [r0, #36] - ldr r2, [r1, #0x950] @lock_line_en - str r2, [r0, #40] - - mov r2, r0 - mov r3, #0 -LOOP1: - add r4, r3, #288 @lockdown_reg - add r3, r3, #1 - cmp r3, #8 - add r5, r1,r4, lsl #3 - ldr r6, [r5] - ldr r4, [r5, #4] - str r6, [r2, #44] - str r4, [r2, #48] - add r2, r2,#8 - bne LOOP1 - ldr r2, [r1, #0xF40] @debug_ctrl - str r2, [r0, #120] - ldr r2, [r1, #0xF60] @prefetch_ctrl - str r2, [r0, #124] - ldr r2, [r1, #0xF80] @power_ctrl - str r2, [r0, #128] - add r1, r0, #132 @ the size of pl310_context - @.extern flushL2VaRange @ we call clean all before WFI, so this one is uncessary - @bl flushL2VaRange - ldmfd sp!, {r4-r12,pc} - - .global restore_pl310 -restore_pl310: - @r0 context, r1 pl310 virtual address - ldr r3, [r1, #0x100] @control - cmp r3, #0 - beq restore_reg - mov r3, #0 - str r3, [r1, #0x730] @cache sync + .global pxa978_enter_c1 +pxa978_enter_c1: dsb - str r3, [r1, #0x100] @control -restore_reg: - ldr r3, [r0, #4] @aux control - str r3, [r1, #0x104] - ldr r3, [r0, #8] @tag_ram_control - str r3, [r1, #0x108] - ldr r3, [r0, #12] @data_ram_control - str r3, [r1, #0x10C] - ldr r3, [r0, #16] @ev_counter_ctrl - str r3, [r1, #0x200] - ldr r3, [r0, #20] @ev_counter1_cfg - str r3, [r1, #0x204] - ldr r3, [r0, #24] @ev_counter0_cfg - str r3, [r1, #0x208] - ldr r3, [r0, #28] @ev_counter1 - str r3, [r1, #0x20C] - ldr r3, [r0, #32] @ev_counter0 - str r3, [r1, #0x210] - ldr r3, [r0, #36] @int_mask - str r3, [r1, #0x214] - ldr r3, [r0, #40] @lock_line_en - str r3, [r1, #0x950] - mov r3, #0 - mov r5, r0 -LOOP2: - add r4, r3, #288 @lockdown_reg - ldr r6, [r5, #44] - ldr r7, [r5, #48] - add r3, r3, #1 - add r8, r1, r4, lsl #3 - cmp r3, #8 - str r6, [r8] - str r7, [r8, #4] - add r5, r5, #8 - bne LOOP2 - ldr r3, [r0, #120] @debug_ctrl - str r3, [r1, #0xF40] - ldr r3, [r0, #124] @prefetch_ctrl - str r3, [r1, #0xF60] - ldr r3, [r0, #128] @power_ctrl - str r3, [r1, #0xF80] - dsb - mov r4, r0 - mov r5, r1 - cmp r2, #0 - .extern invalidL2All - blne invalidL2All - ldr r3, [r4] - str r3, [r5, #0x100] - dsb - pop {r4-r12,pc} - - .global ca9_enter_c2_wrapper -ca9_enter_c2_wrapper: - push {r4-r12,lr} - mov r4,r0 - mov r5,r1 - mov r6,r2 - mov r7,r3 - bl save_pl310 - mov r0, r7 - bl ca9_enter_c2 - mov r0, r4 - mov r1, r5 - mov r2, r6 - b restore_pl310 - - .global ca9_enter_c2 -ca9_enter_c2: - stmfd sp!, {r4-r12,lr} - @ align: [13..0]=0 + wfi + bx lr + .global pxa978_cpu_suspend +pxa978_cpu_suspend: + cmp r2, #0x0 + beq pxa978_enter_c1 + mov r6, r1 @l2c base address virtual + mov r7, r3 @PWR_MODE mov r2, r0, lsr #14 mov r2, r2, lsl #14 @ copy reset handler to SRAM @@ -206,262 +80,75 @@ ca9_enter_c2: ldrd r0, [r3] strd r0, [r2] - adr r0, ca9_c2_restore - bl VirtualToPhysical @ modified r0,r1 + adr r0, pxa978_c2_restore + bl VirtualToPhysical @ modified r0,r1 str r0, [r2, #0x08] add r0, r2, #0x10 mov r5, r0 - bl VirtualToPhysical @ modified r0,r1 + bl VirtualToPhysical @ modified r0,r1 str r0, [r2, #0x0c] mov r0, r5 - -@ Save CPU registers - cps #mode_abt - mrs r1, spsr - stm r0!,{r1,sp,lr} - cps #mode_und - mrs r1, spsr - stm r0!,{r1,sp,lr} - cps #mode_sys - stm r0!,{sp,lr} - cps #mode_irq - mrs r1, spsr - stm r0!,{r1,sp,lr} - cps #mode_fiq - mrs r1, spsr - stm r0!,{r1,r8-r12,sp,lr} - cps #mode_svc - mrs r1,spsr - stm r0!,{r1,sp} @ others will be restored from stack when exiting - bic r1, r1, #0x1f @ clear mode - orr r1, r1, #mode_usr - msr spsr, r1 - stm r0,{sp,lr}^ @ fetch user mode regs as spsr is set to user mode - add r0,r0,#8 @ Cannot use base register update in stm above - @ don't restore svc mode spsr as we won't need it until restored later -@ Save cp15 - mrc p15,2,r1,c0,c0,0 @ CSSELR - mrc p15,0,r2,c1,c0,1 @ ACTLR - mrc p15,0,r3,c1,c0,0 @ SCTLR - mrc p15,0,r4,c1,c0,2 @ CPACR - stm r0!, {r1-r4} - - mrc p15,0,r1,c1,c0,0 @ SCTLR disable L1 cache - bic r1, r1, #0x1000 - bic r1, r1, #0x0004 - mcr p15,0,r1,c1,c0,0 - - mrc p15,0,r1,c12,c0,0 @ VBAR - mrc p15,0,r2,c2,c0,0 @ TTBR0 - mrc p15,0,r3,c2,c0,1 @ TTBR1 - mrc p15,0,r4,c2,c0,2 @ TTBCR - stm r0!, {r1-r4} - - mrc p15,0,r1,c3,c0,0 @ DACR - mrc p15,0,r2,c7,c4,0 @ PAR - mrc p15,0,r3,c10,c2,0 @ PRRR - mrc p15,0,r4,c10,c2,1 @ NMRR - stm r0!, {r1-r4} - - @ TBD: CP15 registers 9 and 11 - mrc p15,0,r1,c13,c0,1 @ CONTEXTIDR - mrc p15,0,r2,c13,c0,2 @ TPIDRURW - mrc p15,0,r3,c13,c0,3 @ TPIDRURO - mrc p15,0,r4,c13,c0,4 @ TPIDRPRW - stm r0!, {r1-r4} - - @ Adding new coop regs ASTODO - mrc p15,0,r1,c12,c0,1 @ MVBAR - mrc p15,5,r2,c15,c5,2 @ Main TLB VA register - mrc p15,5,r3,c15,c6,2 @ Main TLB PA register - mrc p15,5,r4,c15,c7,2 @ Main TLB Attribute - stm r0!, {r1-r4} - - @ Adding new coop regs ASTODO - mrc p15,0,r1,c1,c1,0 @ SCRd - mrc p15,0,r2,c1,c1,1 @ SDERc - mrc p15,0,r3,c1,c1,2 @ NSACR - mrc p15,0,r4,c1,c1,3 @ VCR - stm r0!, {r1-r4} - - @ Adding new coop regs ASTODO - mrc p15,0,r1,c10,c0,0 @ TLB Lockdown Register - mrc p15,0,r2,c12,c1,1 @ Virtualization Interrupt Register - mrc p15,0,r3,c13,c0,0 @ FCSEIDR - mrc p15,0,r4,c13,c0,1 @ CONTEXTIDR - stm r0!, {r1-r4} - - mrc p15,0,r1,c15,c0,0 @ power control reg - str r1, [r0], #4 - mrc p15,0,r1,c0,c0,0 @ Read Main ID Register - ubfx r1, r1, #20, #4 @ Extract major version number - cmp r3, #2 - blt savenople @ PLE only possible in r2p0 onwards - mrc p15,0,r1,c11,c0,0 @ Read PLE IDR - cmp r3, #0 - beq savenople @ No PLE present - - mrc p15,0,r1,c11,c1,0 @ Read PLE UAR - mrc p15,0,r2,c11,c1,1 @ Read PLE PCR - stm r0!, {r1, r2} -savenople: -@ Clean and invalidate L1 D-cache: this does not survive C2 -@ .extern cleanAndInvalidateCache -@ bl cleanAndInvalidateCache - -@ v7_flush_dcache_all corrupts r0-r7, r9-r11 - .extern v7_flush_dcache_all - push {r0-r7,r9-r11} - bl v7_flush_dcache_all - pop {r0-r7,r9-r11} - - .extern v7_flush_icache_all - bl v7_flush_icache_all - @ Clean L2 areas that will be used on restore before L2 is reenabled - @mov r0, sp - @add r1, r0, #0x40 @ actually 9 regs saved on stack - @.extern flushL2VaRange - @bl flushL2VaRange - @mmu page table may in L2 cache, it is diffcult to get page table addr - @so we clean all L2 cache as a temp WR - .extern cleanL2VaRange - bl cleanL2VaRange -@ C2 entry +save_pl310: + ldr r1, [r6, #L2X0_CTRL] + ldr r2, [r6, #L2X0_AUX_CTRL] + ldr r3, [r6, #L2X0_TAG_LATENCY_CTRL] + ldr r4, [r6, #L2X0_DATA_LATENCY_CTRL] + stm r0!,{r1-r4} + ldr r1, [r6, #L2X0_PREFETCH_CTRL] + ldr r2, [r6, #L2X0_POWER_CTRL] + stm r0!,{r1-r2} +/*C2 entry*/ dsb wfi -@ in case a wakeup is pending, CPU will fall through without being reset! +/*in case a wakeup is pending, CPU will fall through without being reset!*/ .align 5 - mov r0, r5 @ setup the saved register base and restore as usual - ldr r8, =0xf2e0011c - mov r9, #0x2000 - str r9, [r8] - mov r5, #0x1 + mov r0, r5 @ setup the saved register base and restore as usual + ldr r1, =OSCR_VIRTUAL_ADDR b set_l2_redundency -@ return here from reset chunk -ca9_c2_restore: +/*return here from reset chunk*/ +pxa978_c2_restore: + ldr r6, =PXA978_L2CACHE_BASE + ldr r1, =OSCR_PHY_ADDR + ldr r2, =POWER_MODE_BASE + ldr r7, [r2] + and r7, r7, #0x40 set_l2_redundency: -@ mov r2, #0xC3 @60usec + mov r2, #0xC3 @60usec @ mov r2, #0x140 -@ orr r2, #0x5 @100usec - mov r2, #0x790 - orr r2, #0xE @600usec - - cmp r5, #0x1 - bne no_mmu - ldr r1,=0xf2a00010 +@ orr r2, #0x5 @100usec +@ mov r2, #0x790 +@ orr r2, #0xE @600usec ldr r3, [r1] - b loop - -no_mmu: - ldr r1,=0x40a00010 - ldr r3, [r1] - b loop loop: ldr r4, [r1] sub r4, r4, r3 cmp r4, r2 ble loop - cps #mode_abt - ldm r0!,{r1,sp,lr} - msr spsr, r1 - cps #mode_und - ldm r0!,{r1,sp,lr} - msr spsr, r1 - cps #mode_sys - ldm r0!,{sp,lr} - msr spsr, r1 - cps #mode_irq - ldm r0!,{r1,sp,lr} - msr spsr, r1 - cps #mode_fiq - ldm r0!,{r1,r8-r12,sp,lr} - msr spsr, r1 - cps #mode_svc - ldm r0!,{r1,sp} @ others will be restored from stack when exiting - mov r2, r1 - bic r1, r1, #0x1f @ clear mode - orr r1, r1, #mode_usr - msr spsr, r1 - ldm r0,{sp,lr}^ @ set user mode regs as spsr is set to user mode - add r0,r0,#8 @ cannot use base register update in ldm above - msr spsr, r2 @ now restore the svc mode spsr -@ Restore cp15 - ldm r0!, {r1-r4} - mcr p15,2,r1,c0,c0,0 @ CSSELR - mcr p15,0,r2,c1,c0,1 @ ACTLR - @ mcr p15,0,r3,c1,c0,0 @ SCTLR - mov r5, r3 @ keep until ready to enable MMU - mcr p15,0,r4,c1,c0,2 @ CPACR - - ldm r0!, {r1-r4} - mcr p15,0,r1,c12,c0,0 @ VBAR - mcr p15,0,r2,c2,c0,0 @ TTBR0 - mcr p15,0,r3,c2,c0,1 @ TTBR1 - mcr p15,0,r4,c2,c0,2 @ TTBCR - - ldm r0!, {r1-r4} - mcr p15,0,r1,c3,c0,0 @ DACR - mcr p15,0,r2,c7,c4,0 @ PAR - mcr p15,0,r3,c10,c2,0 @ PRRR - mcr p15,0,r4,c10,c2,1 @ NMRR - - @ TBD: CP15 registers 9 and 11 - ldm r0!, {r1-r4} - mcr p15,0,r1,c13,c0,1 @ CONTEXTIDR - mcr p15,0,r2,c13,c0,2 @ TPIDRURW - mcr p15,0,r3,c13,c0,3 @ TPIDRURO - mcr p15,0,r4,c13,c0,4 @ TPIDRPRW - - @ Adding new coop regs ASTODO - ldm r0!, {r1-r4} - mcr p15,0,r1,c12,c0,1 @ MVBAR - mcr p15,5,r2,c15,c5,2 @ Main TLB VA register - mcr p15,5,r3,c15,c6,2 @ Main TLB PA register - mcr p15,5,r4,c15,c7,2 @ Main TLB Attribute - - @ Adding new coop regs ASTODO - ldm r0!, {r1-r4} - mcr p15,0,r1,c1,c1,0 @ SCRd - mcr p15,0,r2,c1,c1,1 @ SDERc - mcr p15,0,r3,c1,c1,2 @ NSACR - mcr p15,0,r4,c1,c1,3 @ VCR - - @ Adding new coop regs ASTODO - ldm r0!, {r1-r4} - mrc p15,0,r1,c10,c0,0 @ TLB Lockdown Register - mrc p15,0,r2,c12,c1,1 @ Virtualization Interrupt Register - mrc p15,0,r3,c13,c0,0 @ FCSEIDR - mrc p15,0,r4,c13,c0,1 @ CONTEXTIDR - - @ others - ldr r1, [r0], #4 - mcr p15,0,r1,c15,c0,0 @ power control reg - mrc p15,0,r1,c0,c0,0 @ Read Main ID Register - ubfx r1, r1, #20, #4 @ Extract major version number - cmp r3, #2 - blt restorenople @ PLE only possible in r2p0 onwards - mrc p15,0,r1,c11,c0,0 @ Read PLE IDR - cmp r3, #0 - beq restorenople @ No PLE present - - ldm r0!, {r1, r2} - mcr p15,0,r1,c11,c1,0 @ set PLE UAR - mcr p15,0,r2,c11,c1,1 @ set PLE PCR -restorenople: - @ Enable MMU now - ldr r0, return_addr @ this addr is with MMU on - b cont -.align 5 -cont: - mcr p15,0,r5,c1,c0,0 @ SCTLR - bx r0 -return_on_exit: - ldmfd sp!,{r4-r12,pc} -return_addr: - .long return_on_exit - -@ reset handler for C2 exit + cmp r7, #0 + beq restore_pl310 +pl310_inv_all: + mov r1, #0xFF + str r1, [r6, #L2X0_INV_WAY] +inv_wait: + ldr r2, [r6,#L2X0_INV_WAY] + and r2, r2, r1 + cmp r2, #0 + bne inv_wait + str r2, [r6, #L2X0_CACHE_SYNC] +restore_pl310: + ldm r0!, {r2-r5} + str r3, [r6, #L2X0_AUX_CTRL] + str r4, [r6, #L2X0_TAG_LATENCY_CTRL] + str r5, [r6, #L2X0_DATA_LATENCY_CTRL] + ldm r0!, {r3-r4} + str r3, [r6, #L2X0_PREFETCH_CTRL] + str r4, [r6, #L2X0_POWER_CTRL] + mov r2, #1 + str r2, [r6, #L2X0_CTRL] @enable L2$ + b cpu_resume + +/*reset handler for C2 exit */ reset_chunk: ldr r0, c2_data ldr pc, c2_restore @@ -483,94 +170,6 @@ VirtualToPhysical: orr r0, r0, r1 bx lr - .fpu neon -/* See arch/arm/include/asm/vfp.h */ -#define FPEXC cr8 -#define FPSCR cr1 -#define MVFR0 cr7 - .macro VMRS, rd, sysreg, cond - MRC\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMRX \rd, \sysreg - .endm - - .macro VMSR, sysreg, rd, cond - MCR\cond p10, 7, \rd, \sysreg, cr0, 0 @ FMXR \sysreg, \rd - .endm - - .global save_vfp -save_vfp: - @ FPU state save/restore. - @ FPSID,MVFR0 and MVFR1 don't get serialized/saved (Read Only). - MRC p15,0,r3,c1,c0,2 @ CPACR allows CP10 and CP11 access - ORR r2,r3,#0xF00000 - MCR p15,0,r2,c1,c0,2 - ISB - MRC p15,0,r2,c1,c0,2 - AND r2,r2,#0xF00000 - CMP r2,#0xF00000 - BEQ L000 - MOVS r2, #0 - @ Override to 0 to indicate that no FPU is present - @ STR r2,[r11,#DM_VFP] ; TODO: autodetect VFP in C!! - B L001 - -L000: @ Save configuration registers and enable. - VMRS r12,FPEXC - STR r12,[r0],#4 @ Save the FPEXC - @ Enable FPU access to save/restore the other registers. - LDR r2,=0x40000000 - VMSR FPEXC,r2 - VMRS r2,FPSCR - STR r2,[r0],#4 @ Save the FPSCR - @ Store the VFP-D16 registers. - VSTM r0!, {D0-D15} - @ Check for Advanced SIMD/VFP-D32 support - VMRS r2,MVFR0 - AND r2,r2,#0xF @ extract the A_SIMD bitfield - CMP r2, #0x2 - BLT L001 - @ Store the Advanced SIMD/VFP-D32 additional registers. - VSTM r0!, {D16-D31} - - @ IMPLEMENTATION DEFINED: save any subarchitecture defined state - @ NOTE: Don't change the order of the FPEXC and CPACR restores - VMSR FPEXC,r10 @ Restore the original En bit of FPU. -L001: - MCR p15,0,r3,c1,c0,2 @ Restore the original CPACR value. - BX lr - - .global restore_vfp -restore_vfp: - @ FPU state save/restore. Obviously FPSID,MVFR0 and MVFR1 don't get - @ serialized (RO). - @ Modify CPACR to allow CP10 and CP11 access - MRC p15,0,r2,c1,c0,2 - ORR r2,r2,#0x00F00000 - MCR p15,0,r2,c1,c0,2 - @ Enable FPU access to save/restore the rest of registers. - LDR r2,=0x40000000 - VMSR FPEXC, r2 - @ Recover FPEXC and FPSCR. These will be restored later. - LDM r0!,{r3,r12} - @ Restore the VFP-D16 registers. - VLDM r0!, {D0-D15} - @ Check for Advanced SIMD/VFP-D32 support - VMRS r2, MVFR0 - AND r2,r2,#0xF @ extract the A_SIMD bitfield - CMP r2, #0x2 - BLT L0000 - - @ Store the Advanced SIMD/VFP-D32 additional registers. - VLDM r0!, {D16-D31} - - @ IMPLEMENTATION DEFINED: restore any subarchitecture defined state - -L0000: @ Restore configuration registers and enable. - @ Restore FPSCR _before_ FPEXC since FPEXC could disable FPU - @ and make setting FPSCR unpredictable. - VMSR FPSCR,r12 - VMSR FPEXC,r3 @ Restore FPEXC after FPSCR - BX lr - .global save_performance_monitors save_performance_monitors: PUSH {r4, r8, r9, r10} @@ -690,8 +289,8 @@ L40: MCR p15,0,r1,c9,c12,0 @ clear the PMCR global enable bit POP {r4-r5, r8-r10, pc} @ Debug: see DDI0388F, 10.2.1 - .global save_ca9_debug -save_ca9_debug: + .global save_pxa978_debug +save_pxa978_debug: @ push {r4} push {r1-r4} mrc p14, 0, r1, c0, c6, 0 @@ -731,8 +330,8 @@ save_ca9_debug: @ pop {r4} pop {r1-r4} bx lr - .global restore_ca9_debug -restore_ca9_debug: + .global restore_pxa978_debug +restore_pxa978_debug: @ push {r4} push {r1-r4} ldm r0!,{r1-r4} diff --git a/arch/arm/mach-pxa/cmd_ca9_idle.c b/arch/arm/mach-pxa/cmd_ca9_idle.c index 992d9e1..3849da9 100644 --- a/arch/arm/mach-pxa/cmd_ca9_idle.c +++ b/arch/arm/mach-pxa/cmd_ca9_idle.c @@ -17,12 +17,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - #include <mach/ca9_asm.h> -#include <mach/ca9_regs.h> -#include <mach/pxa95x_pm.h> #include <asm/outercache.h> +#include <linux/suspend.h> +#include <asm/cacheflush.h> +#include <asm/suspend.h> +#include <linux/cpu_pm.h> +#include <mach/pxa95x_pm.h> +#include <asm/io.h> #include <mach/pxa3xx-regs.h> +#include <linux/delay.h> + /* Part of the code based on the below ARM code and modified */ /* * Copyright (C) 2008-2010 ARM Limited @@ -44,43 +49,53 @@ * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ - -#define __nop() do { asm volatile ("nop" : : : "memory"); } while (0) - -void flushL2VaRange(phys_addr_t start, phys_addr_t end) +#define PWRMODE_L2_DIS_IN_C2 0x40 +static int pxa978_suspend_finish(unsigned int core_mode) { - outer_flush_range(VirtualToPhysical(start), VirtualToPhysical(end)); + unsigned int power_mode = PWRMODE; + if (power_mode & PWRMODE_L2_DIS_IN_C2) { + /* In L2$ non-retentive mode, two option: + *1. clean all before c2, inv all after c2 + *2. flush all before c2 + *but we mush use the first one. for after power on, L2 is + *in an unpredicatable state of all data, tag, status bit + */ + /*this will actually call clean_all() */ + outer_clean_range(0, 0xFFFFFFFF); + } + pxa978_cpu_suspend(get_c2_sram_base(), pl310_membase, core_mode, + power_mode & PWRMODE_L2_DIS_IN_C2); + return 0; } -void cleanL2VaRange(phys_addr_t start, phys_addr_t end) +void c2_address_unremap(void) { - /*actually this will clean all because the range > L2 cache size*/ - outer_clean_range(0, 0x10000000); + __raw_writel(0, remap_c2_reg); } -void invalidL2All(void) + +void c2_address_remap(void) { - outer_inv_all(); + unsigned c2_addr = VirtualToPhysical(get_c2_sram_base()); + __raw_writel(((c2_addr >> 13) | 1) & 0x1FFF, remap_c2_reg); } -#define PWRMODE_L2_DIS_IN_C2 0x40 - -void ca9_enter_idle(unsigned int pwrmode, unsigned int sramaddr, unsigned int l2c_base_address) +void pxa978_pm_enter(unsigned int core_mode) { - struct pl310_context pl310; - unsigned int remap_addr = VirtualToPhysical(sramaddr); - unsigned int pmu_context[PMU_DATA_SIZE/sizeof(unsigned int)]; - unsigned int vfp_context[VFP_DATA_SIZE/sizeof(unsigned int)]; - unsigned int debug_context[DEBUG_DATA_SIZE/sizeof(unsigned int)]; - /* Remap 0 physical to SRAM so reset will runs the C2 restore code */ - *remap_c2_reg = ((remap_addr>>13)|1)&0x1fff; - save_vfp((unsigned int *)&vfp_context); - save_ca9_debug((unsigned int *)&debug_context); - save_performance_monitors((unsigned int *)&pmu_context); - - ca9_enter_c2_wrapper(&pl310, l2c_base_address, pwrmode & PWRMODE_L2_DIS_IN_C2, sramaddr); + unsigned int debug_context[DEBUG_DATA_SIZE / sizeof(unsigned int)]; + unsigned int pmu_context[PMU_DATA_SIZE / sizeof(unsigned int)]; + if (core_mode == PWRDM_POWER_C2) { + c2_address_remap(); + save_pxa978_debug((unsigned int *)&debug_context); + save_performance_monitors((unsigned int *)&pmu_context); + cpu_pm_enter(); + cpu_suspend(core_mode, pxa978_suspend_finish); + } else if (core_mode == PWRDM_POWER_C1) + pxa978_suspend_finish(core_mode); - restore_performance_monitors((unsigned int *)&pmu_context); - restore_ca9_debug((unsigned int *)&debug_context); - restore_vfp((unsigned int *)&vfp_context); - *remap_c2_reg = 0; + if (core_mode == PWRDM_POWER_C2) { + cpu_pm_exit(); + restore_performance_monitors((unsigned int *)&pmu_context); + restore_pxa978_debug((unsigned int *)&debug_context); + c2_address_unremap(); + } } diff --git a/arch/arm/mach-pxa/dvfm.c b/arch/arm/mach-pxa/dvfm.c index 90d8517..ed76ba1 100644 --- a/arch/arm/mach-pxa/dvfm.c +++ b/arch/arm/mach-pxa/dvfm.c @@ -285,14 +285,11 @@ static ssize_t dvfm_c2_allow_store(struct sys_device *sys_dev, return len; } -extern unsigned int *remap_c2_reg; - static ssize_t dvfm_c2_allow_show(struct sys_device *sys_dev, struct sysdev_attribute *attr, char *buf) { unsigned int len; printk("\n [%s] c2_allow = %d", __func__, c2_allow); - printk("\n [%s] REMAP reg = 0x%x, value = 0x%x", __func__, remap_c2_reg, *remap_c2_reg); return len; } SYSDEV_ATTR(c2_allow, 0644, dvfm_c2_allow_show, dvfm_c2_allow_store); diff --git a/arch/arm/mach-pxa/include/mach/ca9_asm.h b/arch/arm/mach-pxa/include/mach/ca9_asm.h index 350daa9..db3e354 100644 --- a/arch/arm/mach-pxa/include/mach/ca9_asm.h +++ b/arch/arm/mach-pxa/include/mach/ca9_asm.h @@ -1,21 +1,17 @@ - unsigned VirtualToPhysical(unsigned); /*-----------------------------------------------------------------*/ #define PMU_DATA_SIZE 128 void save_performance_monitors(unsigned int *pointer); void restore_performance_monitors(unsigned int *pointer); /*-----------------------------------------------------------------*/ -#define VFP_DATA_SIZE 288 -void save_vfp(unsigned int *pointer); -void restore_vfp(unsigned int *pointer); -/*-----------------------------------------------------------------*/ #define DEBUG_DATA_SIZE 128 -void save_ca9_debug(unsigned int *pointer); -void restore_ca9_debug(unsigned int *pointer); +void save_pxa978_debug(unsigned int *pointer); +void restore_pxa978_debug(unsigned int *pointer); /*-----------------------------------------------------------------*/ /* Critical registers saved/restored inside one assembly function. sramaddr[13..0]=0 is enforced. These registers are saved in SRAM at the given address, right after the reset vector code. Aproximae size: 0xc0 bytes. */ -void ca9_enter_c2_wrapper(struct pl310_context *pl310, unsigned l2c_base_address, unsigned pwrmode, unsigned sramaddr); +void pxa978_cpu_suspend(unsigned int sramaddr, unsigned int l2c_base_address, + unsigned int core_mode, unsigned int pwrmode); diff --git a/arch/arm/mach-pxa/include/mach/ca9_regs.h b/arch/arm/mach-pxa/include/mach/ca9_regs.h deleted file mode 100644 index b259185..0000000 --- a/arch/arm/mach-pxa/include/mach/ca9_regs.h +++ /dev/null @@ -1,82 +0,0 @@ - -#include <linux/kernel.h> - -#define L2310_ADDR_START 0x58120000 -#define L2310_ADDR_END 0x58120FFF - -struct lockdown_regs { - unsigned int d, i; -}; - -struct pl310_registers { - const unsigned cache_id; - const unsigned cache_type; - char padding1[0x0F8]; - volatile unsigned control; - volatile unsigned aux_control; - volatile unsigned tag_ram_control; - volatile unsigned data_ram_control; - char padding2[0x0F0]; - volatile unsigned ev_counter_ctrl; - volatile unsigned ev_counter1_cfg; - volatile unsigned ev_counter0_cfg; - volatile unsigned ev_counter1; - volatile unsigned ev_counter0; - volatile unsigned int_mask; - const volatile unsigned int_mask_status; - const volatile unsigned int_raw_status; - volatile unsigned int_clear; - char padding3[0x50C]; - volatile unsigned cache_sync; - char padding4[0x03C]; - volatile unsigned inv_pa; - char padding5[0x008]; - volatile unsigned inv_way; - char padding6[0x030]; - volatile unsigned clean_pa; - char padding7[0x004]; - volatile unsigned clean_index; - volatile unsigned clean_way; - char padding8[0x030]; - volatile unsigned clean_inv_pa; - char padding9[0x004]; - volatile unsigned clean_inv_index; - volatile unsigned clean_inv_way; - char paddinga[0x100]; - volatile struct lockdown_regs lockdown[8]; - char paddingb[0x010]; - volatile unsigned lock_line_en; - volatile unsigned unlock_way; - char paddingc[0x2A8]; - volatile unsigned addr_filtering_start; - volatile unsigned addr_filtering_end; - char paddingd[0x338]; - volatile unsigned debug_ctrl; - char paddinge[0x01C]; - volatile unsigned prefetch_ctrl; - char paddingf[0x01C]; - volatile unsigned power_ctrl; - unsigned int *memset; -}; - - -struct pl310_context { - unsigned int control; - unsigned int aux_control; - unsigned int tag_ram_control; - unsigned int data_ram_control; - unsigned int ev_counter_ctrl; - unsigned int ev_counter1_cfg; - unsigned int ev_counter0_cfg; - unsigned int ev_counter1; - unsigned int ev_counter0; - unsigned int int_mask; - unsigned int lock_line_en; - struct lockdown_regs lockdown[8]; - unsigned int unlock_way; - unsigned int addr_filtering_start; - unsigned int addr_filtering_end; - unsigned int debug_ctrl; - unsigned int prefetch_ctrl; - unsigned int power_ctrl; -}; diff --git a/arch/arm/mach-pxa/include/mach/pxa95x_pm.h b/arch/arm/mach-pxa/include/mach/pxa95x_pm.h index 7163df6..642bab1 100644 --- a/arch/arm/mach-pxa/include/mach/pxa95x_pm.h +++ b/arch/arm/mach-pxa/include/mach/pxa95x_pm.h @@ -371,6 +371,11 @@ #define SleepState_end (SleepState_flushFunc + WORD_SIZE) #define SleepState_size (SleepState_end - SleepState_begin) +/*pxa978 core power mode*/ +#define PWRDM_POWER_C1 0x0 +#define PWRDM_POWER_C2 0x1 + + #ifndef __ASSEMBLY__ typedef struct { @@ -565,6 +570,7 @@ struct pxa95x_peripheral_wakeup_ops { int (*cmwdt) (pm_wakeup_src_t src, int enable); }; extern unsigned int *remap_c2_reg; +extern unsigned int *pl310_membase; #define GC_PWR_ENABLE (1) #define GC_PWR_DISABLE (0) @@ -578,8 +584,8 @@ extern unsigned int pm_core_pwdn(unsigned int powerState); extern unsigned int pm_enter_cgm_deepidle(unsigned int); extern int pxa95x_query_gwsr(int); extern u32 get_mipi_reference_control(void); -extern void ca9_enter_idle(unsigned int pwrmode, unsigned int sramaddr, unsigned int l2c_base_address); - +extern unsigned int get_c2_sram_base(void); +extern void pxa978_pm_enter(unsigned int save_mode); #endif #endif #endif diff --git a/arch/arm/mach-pxa/mspm_idle.c b/arch/arm/mach-pxa/mspm_idle.c index 79ad678..e1750e4 100644 --- a/arch/arm/mach-pxa/mspm_idle.c +++ b/arch/arm/mach-pxa/mspm_idle.c @@ -32,7 +32,6 @@ #include <mach/regs-ost.h> #include <mach/pxa95x_dvfm.h> #include <mach/mspm_prof.h> -#include <mach/ca9_regs.h> #ifdef CONFIG_ISPT #include <mach/pxa_ispt.h> #endif @@ -120,15 +119,12 @@ static unsigned int pm_enter_deepidle(unsigned int x) BUG_ON(1); } #endif -extern unsigned int get_sram_base(void); -extern struct pl310_registers pl310_regs; extern unsigned int c2_allow; static void pxa95x_cpu_idle(void) { unsigned int c1_enter_time, c1_exit_time, pollreg; struct op_info *info = NULL; int op; - unsigned int sram_base = get_sram_base(); static unsigned int counter, counter2; DVFMLPMGlobalCount.D0C1_Enter_count++; op = dvfm_get_op(&info); @@ -151,14 +147,14 @@ static void pxa95x_cpu_idle(void) mipsram_disable_counter(); #endif if (cpu_is_pxa978()) { - if (sram_base && c2_allow) { + if (c2_allow) { PWRMODE = 0x0; PWRMODE = (PXA978_PM_S0D0CG | PXA95x_PM_I_Q_BIT); do { pollreg = PWRMODE; } while (pollreg != (PXA978_PM_S0D0CG | PXA95x_PM_I_Q_BIT)); - ca9_enter_idle(pollreg, sram_base + 0x8000, (unsigned int)pl310_regs.memset); + pxa978_pm_enter(PWRDM_POWER_C2); counter++; if (counter == 10000) { counter2++; diff --git a/arch/arm/mach-pxa/pxa95x_pm.c b/arch/arm/mach-pxa/pxa95x_pm.c index 9935840..e3e599f 100644 --- a/arch/arm/mach-pxa/pxa95x_pm.c +++ b/arch/arm/mach-pxa/pxa95x_pm.c @@ -34,7 +34,6 @@ #include <mach/mfp-pxa3xx.h> #include <mach/gpio.h> #include <mach/debug_pm.h> -#include <mach/ca9_regs.h> #ifdef CONFIG_ISPT #include <mach/pxa_ispt.h> #endif @@ -54,7 +53,6 @@ /* mtd.h declares another DEBUG macro definition */ #undef DEBUG #include <linux/mtd/mtd.h> - /* The first 32KB is reserved and can't be accessed by kernel. * This restrict is only valid on BootROM V2. */ @@ -187,8 +185,8 @@ EXPORT_SYMBOL(dmc_membase); unsigned char __iomem *ost_membase; EXPORT_SYMBOL(ost_membase); unsigned char __iomem *pm_membase; - -unsigned int *remap_c2_reg; +unsigned int __iomem *pl310_membase; +unsigned int __iomem *remap_c2_reg; extern void pxa95x_cpu_sleep(unsigned int, unsigned int); extern void pxa95x_cpu_resume(void); @@ -458,8 +456,6 @@ static void pxa95x_gpio_restore(struct gpio_regs *context) GFER2 = context->gfer2; GFER3 = context->gfer3; } - -struct pl310_registers pl310_regs; static void pxa95x_sysbus_init(struct pxa95x_pm_regs *context) { context->smc.membase = ioremap(SMC_START, SMC_END - SMC_START + 1); @@ -477,9 +473,7 @@ static void pxa95x_sysbus_init(struct pxa95x_pm_regs *context) */ context->data_pool = (unsigned char *)0xC0000000; if (cpu_is_pxa978()) { - pl310_regs.memset = ioremap(L2310_ADDR_START, L2310_ADDR_END - L2310_ADDR_START + 1); - printk(KERN_DEBUG "pl310_regs.memset = 0x%lx, Start: 0x%lx END: 0x%lx\n", - pl310_regs.memset, L2310_ADDR_START, L2310_ADDR_END); + pl310_membase = ioremap(0x58120000, 0x1000); } } @@ -1249,6 +1243,11 @@ unsigned int get_sram_base(void) | VLSCR_LVL3_SINGLE_RAIL | VLSCR_LVL0_SINGLE_RAIL \ | VLSCR_VCT0_LVL0_REMAP_MASK | VLSCR_VCT0_LVL1_REMAP_MASK \ | VLSCR_VCT0_LVL2_REMAP_MASK | VLSCR_VCT0_LVL3_REMAP_MASK) +unsigned int get_c2_sram_base(void) +{ + return (unsigned int) (pxa95x_pm_regs.sram_map + 0x8000); +} + void enter_lowpower_mode(int state) { unsigned int start_tick = 0, end_tick = 0; @@ -1342,9 +1341,7 @@ void enter_lowpower_mode(int state) vlscr &= ~(VLSCR_SINGLE_RAIL_MASK); vlscr |= (VLSCR_D1_VALUE); VLSCR = vlscr; - - ca9_enter_idle(pollreg, sram + 0x8000, - (u32)pl310_regs.memset); + pxa978_pm_enter(PWRDM_POWER_C2); } else { pxa95x_cpu_standby(sram + 0x8000, sram + 0xa000 - 4, @@ -1454,9 +1451,8 @@ void enter_lowpower_mode(int state) vlscr &= ~(VLSCR_SINGLE_RAIL_MASK); vlscr |= (VLSCR_D2_VALUE); VLSCR = vlscr; + pxa978_pm_enter(PWRDM_POWER_C2); - ca9_enter_idle(pollreg, sram + 0x8000, - (u32)pl310_regs.memset); } else { pxa95x_cpu_standby(sram + 0x8000, sram + 0xa000 - 4, @@ -1619,8 +1615,7 @@ void enter_lowpower_mode(int state) */ sram = (unsigned int) pxa95x_pm_regs.sram_map; if (cpu_is_pxa978()) { - ca9_enter_idle(pollreg, sram + 0x8000, - (u32)pl310_regs.memset); + pxa978_pm_enter(PWRDM_POWER_C2); } else { if (cur_op < 2) pm_enter_cgm_deepidle -- 1.7.4.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html