1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-or-later */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * linux/arch/arm/mach-omap2/sleep.S 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * (C) Copyright 2004 6*4882a593Smuzhiyun * Texas Instruments, <www.ti.com> 7*4882a593Smuzhiyun * Richard Woodruff <r-woodruff2@ti.com> 8*4882a593Smuzhiyun * 9*4882a593Smuzhiyun * (C) Copyright 2006 Nokia Corporation 10*4882a593Smuzhiyun * Fixed idle loop sleep 11*4882a593Smuzhiyun * Igor Stoppa <igor.stoppa@nokia.com> 12*4882a593Smuzhiyun */ 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun#include <linux/linkage.h> 15*4882a593Smuzhiyun#include <asm/assembler.h> 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun#include "omap24xx.h" 18*4882a593Smuzhiyun#include "sdrc.h" 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun/* First address of reserved address space? apparently valid for OMAP2 & 3 */ 21*4882a593Smuzhiyun#define A_SDRC0_V (0xC0000000) 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun .text 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun/* 26*4882a593Smuzhiyun * omap24xx_cpu_suspend() - Forces OMAP into deep sleep state by completing 27*4882a593Smuzhiyun * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore 28*4882a593Smuzhiyun * SDRC. 29*4882a593Smuzhiyun * 30*4882a593Smuzhiyun * Input: 31*4882a593Smuzhiyun * R0 : DLL ctrl value pre-Sleep 32*4882a593Smuzhiyun * R1 : SDRC_DLLA_CTRL 33*4882a593Smuzhiyun * R2 : SDRC_POWER 34*4882a593Smuzhiyun * 35*4882a593Smuzhiyun * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on 36*4882a593Smuzhiyun * when we get called, but the DLL probably isn't. We will wait a bit more in 37*4882a593Smuzhiyun * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even 38*4882a593Smuzhiyun * if in unlocked mode. 39*4882a593Smuzhiyun * 40*4882a593Smuzhiyun * For less than 242x-ES2.2 upon wake from a sleep mode where the external 41*4882a593Smuzhiyun * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz 42*4882a593Smuzhiyun * clock can pass into the PRCM can cause problems at DSP and IVA. 43*4882a593Smuzhiyun * To work around this the code will switch to the 32kHz source prior to sleep. 44*4882a593Smuzhiyun * Post sleep we will shift back to using the DPLL. Apparently, 45*4882a593Smuzhiyun * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait 46*4882a593Smuzhiyun * 3x12MHz + 3x32kHz clocks for a full switch. 47*4882a593Smuzhiyun * 48*4882a593Smuzhiyun * The DLL load value is not kept in RETENTION or OFF. It needs to be restored 49*4882a593Smuzhiyun * at wake 50*4882a593Smuzhiyun */ 51*4882a593Smuzhiyun .align 3 52*4882a593SmuzhiyunENTRY(omap24xx_cpu_suspend) 53*4882a593Smuzhiyun stmfd sp!, {r0 - r12, lr} @ save registers on stack 54*4882a593Smuzhiyun mov r3, #0x0 @ clear for mcr call 55*4882a593Smuzhiyun mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished 56*4882a593Smuzhiyun nop 57*4882a593Smuzhiyun nop 58*4882a593Smuzhiyun ldr r4, [r2] @ read SDRC_POWER 59*4882a593Smuzhiyun orr r4, r4, #0x40 @ enable self refresh on idle req 60*4882a593Smuzhiyun mov r5, #0x2000 @ set delay (DPLL relock + DLL relock) 61*4882a593Smuzhiyun str r4, [r2] @ make it so 62*4882a593Smuzhiyun nop 63*4882a593Smuzhiyun mcr p15, 0, r3, c7, c0, 4 @ wait for interrupt 64*4882a593Smuzhiyun nop 65*4882a593Smuzhiyunloop: 66*4882a593Smuzhiyun subs r5, r5, #0x1 @ awake, wait just a bit 67*4882a593Smuzhiyun bne loop 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun /* The DPLL has to be on before we take the DDR out of self refresh */ 70*4882a593Smuzhiyun bic r4, r4, #0x40 @ now clear self refresh bit. 71*4882a593Smuzhiyun str r4, [r2] @ write to SDRC_POWER 72*4882a593Smuzhiyun ldr r4, A_SDRC0 @ make a clock happen 73*4882a593Smuzhiyun ldr r4, [r4] @ read A_SDRC0 74*4882a593Smuzhiyun nop @ start auto refresh only after clk ok 75*4882a593Smuzhiyun movs r0, r0 @ see if DDR or SDR 76*4882a593Smuzhiyun strne r0, [r1] @ rewrite DLLA to force DLL reload 77*4882a593Smuzhiyun addne r1, r1, #0x8 @ move to DLLB 78*4882a593Smuzhiyun strne r0, [r1] @ rewrite DLLB to force DLL reload 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun mov r5, #0x1000 81*4882a593Smuzhiyunloop2: 82*4882a593Smuzhiyun subs r5, r5, #0x1 83*4882a593Smuzhiyun bne loop2 84*4882a593Smuzhiyun /* resume*/ 85*4882a593Smuzhiyun ldmfd sp!, {r0 - r12, pc} @ restore regs and return 86*4882a593Smuzhiyun 87*4882a593SmuzhiyunA_SDRC0: 88*4882a593Smuzhiyun .word A_SDRC0_V 89*4882a593Smuzhiyun 90*4882a593SmuzhiyunENTRY(omap24xx_cpu_suspend_sz) 91*4882a593Smuzhiyun .word . - omap24xx_cpu_suspend 92