1/* 2 * linux/arch/arm/mach-omap1/sleep.S 3 * 4 * Low-level OMAP730/1510/1610 sleep/wakeUp support 5 * 6 * Initial SA1110 code: 7 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> 8 * 9 * Adapted for PXA by Nicolas Pitre: 10 * Copyright (c) 2002 Monta Vista Software, Inc. 11 * 12 * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> 13 * 14 * This program is free software; you can redistribute it and/or modify it 15 * under the terms of the GNU General Public License as published by the 16 * Free Software Foundation; either version 2 of the License, or (at your 17 * option) any later version. 18 * 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 22 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 25 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * You should have received a copy of the GNU General Public License along 31 * with this program; if not, write to the Free Software Foundation, Inc., 32 * 675 Mass Ave, Cambridge, MA 02139, USA. 33 */ 34 35#include <linux/linkage.h> 36#include <asm/assembler.h> 37#include <asm/arch/io.h> 38#include <asm/arch/pm.h> 39 40 .text 41 42/* 43 * Forces OMAP into idle state 44 * 45 * omapXXXX_idle_loop_suspend() 46 * 47 * Note: This code get's copied to internal SRAM at boot. When the OMAP 48 * wakes up it continues execution at the point it went to sleep. 49 * 50 * Note: Because of slightly different configuration values we have 51 * processor specific functions here. 52 */ 53 54#if defined(CONFIG_ARCH_OMAP730) 55ENTRY(omap730_idle_loop_suspend) 56 57 stmfd sp!, {r0 - r12, lr} @ save registers on stack 58 59 @ load base address of ARM_IDLECT1 and ARM_IDLECT2 60 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 61 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 62 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 63 64 @ turn off clock domains 65 @ get ARM_IDLECT2 into r2 66 ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 67 mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff 68 orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 69 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 70 71 @ request ARM idle 72 @ get ARM_IDLECT1 into r1 73 ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 74 orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff 75 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 76 77 mov r5, #IDLE_WAIT_CYCLES & 0xff 78 orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 79l_730: subs r5, r5, #1 80 bne l_730 81/* 82 * Let's wait for the next clock tick to wake us up. 83 */ 84 mov r0, #0 85 mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt 86/* 87 * omap730_idle_loop_suspend()'s resume point. 88 * 89 * It will just start executing here, so we'll restore stuff from the 90 * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. 91 */ 92 93 @ restore ARM_IDLECT1 and ARM_IDLECT2 and return 94 @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 95 strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 96 strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 97 98 ldmfd sp!, {r0 - r12, pc} @ restore regs and return 99 100ENTRY(omap730_idle_loop_suspend_sz) 101 .word . - omap730_idle_loop_suspend 102#endif /* CONFIG_ARCH_OMAP730 */ 103 104#ifdef CONFIG_ARCH_OMAP15XX 105ENTRY(omap1510_idle_loop_suspend) 106 107 stmfd sp!, {r0 - r12, lr} @ save registers on stack 108 109 @ load base address of ARM_IDLECT1 and ARM_IDLECT2 110 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 111 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 112 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 113 114 @ turn off clock domains 115 @ get ARM_IDLECT2 into r2 116 ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 117 mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff 118 orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 119 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 120 121 @ request ARM idle 122 @ get ARM_IDLECT1 into r1 123 ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 124 orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff 125 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 126 127 mov r5, #IDLE_WAIT_CYCLES & 0xff 128 orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 129l_1510: subs r5, r5, #1 130 bne l_1510 131/* 132 * Let's wait for the next clock tick to wake us up. 133 */ 134 mov r0, #0 135 mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt 136/* 137 * omap1510_idle_loop_suspend()'s resume point. 138 * 139 * It will just start executing here, so we'll restore stuff from the 140 * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. 141 */ 142 143 @ restore ARM_IDLECT1 and ARM_IDLECT2 and return 144 @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 145 strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 146 strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 147 148 ldmfd sp!, {r0 - r12, pc} @ restore regs and return 149 150ENTRY(omap1510_idle_loop_suspend_sz) 151 .word . - omap1510_idle_loop_suspend 152#endif /* CONFIG_ARCH_OMAP15XX */ 153 154#if defined(CONFIG_ARCH_OMAP16XX) 155ENTRY(omap1610_idle_loop_suspend) 156 157 stmfd sp!, {r0 - r12, lr} @ save registers on stack 158 159 @ load base address of ARM_IDLECT1 and ARM_IDLECT2 160 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 161 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 162 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 163 164 @ turn off clock domains 165 @ get ARM_IDLECT2 into r2 166 ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 167 mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff 168 orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 169 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 170 171 @ request ARM idle 172 @ get ARM_IDLECT1 into r1 173 ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 174 orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff 175 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 176 177 mov r5, #IDLE_WAIT_CYCLES & 0xff 178 orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 179l_1610: subs r5, r5, #1 180 bne l_1610 181/* 182 * Let's wait for the next clock tick to wake us up. 183 */ 184 mov r0, #0 185 mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt 186/* 187 * omap1610_idle_loop_suspend()'s resume point. 188 * 189 * It will just start executing here, so we'll restore stuff from the 190 * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. 191 */ 192 193 @ restore ARM_IDLECT1 and ARM_IDLECT2 and return 194 @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 195 strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 196 strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 197 198 ldmfd sp!, {r0 - r12, pc} @ restore regs and return 199 200ENTRY(omap1610_idle_loop_suspend_sz) 201 .word . - omap1610_idle_loop_suspend 202#endif /* CONFIG_ARCH_OMAP16XX */ 203 204/* 205 * Forces OMAP into deep sleep state 206 * 207 * omapXXXX_cpu_suspend() 208 * 209 * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed 210 * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 211 * in register r1. 212 * 213 * Note: This code get's copied to internal SRAM at boot. When the OMAP 214 * wakes up it continues execution at the point it went to sleep. 215 * 216 * Note: Because of errata work arounds we have processor specific functions 217 * here. They are mostly the same, but slightly different. 218 * 219 */ 220 221#if defined(CONFIG_ARCH_OMAP730) 222ENTRY(omap730_cpu_suspend) 223 224 @ save registers on stack 225 stmfd sp!, {r0 - r12, lr} 226 227 @ Drain write cache 228 mov r4, #0 229 mcr p15, 0, r0, c7, c10, 4 230 nop 231 232 @ load base address of Traffic Controller 233 mov r6, #TCMIF_ASM_BASE & 0xff000000 234 orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 235 orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 236 237 @ prepare to put SDRAM into self-refresh manually 238 ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 239 orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 240 orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff 241 str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 242 243 @ prepare to put EMIFS to Sleep 244 ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 245 orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff 246 str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 247 248 @ load base address of ARM_IDLECT1 and ARM_IDLECT2 249 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 250 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 251 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 252 253 @ turn off clock domains 254 @ do not disable PERCK (0x04) 255 mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff 256 orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 257 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 258 259 @ request ARM idle 260 mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff 261 orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 262 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 263 264 @ disable instruction cache 265 mrc p15, 0, r9, c1, c0, 0 266 bic r2, r9, #0x1000 267 mcr p15, 0, r2, c1, c0, 0 268 nop 269 270/* 271 * Let's wait for the next wake up event to wake us up. r0 can't be 272 * used here because r0 holds ARM_IDLECT1 273 */ 274 mov r2, #0 275 mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt 276/* 277 * omap730_cpu_suspend()'s resume point. 278 * 279 * It will just start executing here, so we'll restore stuff from the 280 * stack. 281 */ 282 @ re-enable Icache 283 mcr p15, 0, r9, c1, c0, 0 284 285 @ reset the ARM_IDLECT1 and ARM_IDLECT2. 286 strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 287 strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 288 289 @ Restore EMIFF controls 290 str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 291 str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 292 293 @ restore regs and return 294 ldmfd sp!, {r0 - r12, pc} 295 296ENTRY(omap730_cpu_suspend_sz) 297 .word . - omap730_cpu_suspend 298#endif /* CONFIG_ARCH_OMAP730 */ 299 300#ifdef CONFIG_ARCH_OMAP15XX 301ENTRY(omap1510_cpu_suspend) 302 303 @ save registers on stack 304 stmfd sp!, {r0 - r12, lr} 305 306 @ load base address of Traffic Controller 307 mov r4, #TCMIF_ASM_BASE & 0xff000000 308 orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 309 orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 310 311 @ work around errata of OMAP1510 PDE bit for TC shut down 312 @ clear PDE bit 313 ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 314 bic r5, r5, #PDE_BIT & 0xff 315 str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 316 317 @ set PWD_EN bit 318 and r5, r5, #PWD_EN_BIT & 0xff 319 str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 320 321 @ prepare to put SDRAM into self-refresh manually 322 ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 323 orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 324 orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff 325 str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 326 327 @ prepare to put EMIFS to Sleep 328 ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 329 orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff 330 str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 331 332 @ load base address of ARM_IDLECT1 and ARM_IDLECT2 333 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 334 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 335 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 336 337 @ turn off clock domains 338 mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff 339 orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 340 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 341 342 @ request ARM idle 343 mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff 344 orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 345 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 346 347 mov r5, #IDLE_WAIT_CYCLES & 0xff 348 orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 349l_1510_2: 350 subs r5, r5, #1 351 bne l_1510_2 352/* 353 * Let's wait for the next wake up event to wake us up. r0 can't be 354 * used here because r0 holds ARM_IDLECT1 355 */ 356 mov r2, #0 357 mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt 358/* 359 * omap1510_cpu_suspend()'s resume point. 360 * 361 * It will just start executing here, so we'll restore stuff from the 362 * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. 363 */ 364 strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 365 strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 366 367 @ restore regs and return 368 ldmfd sp!, {r0 - r12, pc} 369 370ENTRY(omap1510_cpu_suspend_sz) 371 .word . - omap1510_cpu_suspend 372#endif /* CONFIG_ARCH_OMAP15XX */ 373 374#if defined(CONFIG_ARCH_OMAP16XX) 375ENTRY(omap1610_cpu_suspend) 376 377 @ save registers on stack 378 stmfd sp!, {r0 - r12, lr} 379 380 @ Drain write cache 381 mov r4, #0 382 mcr p15, 0, r0, c7, c10, 4 383 nop 384 385 @ Load base address of Traffic Controller 386 mov r6, #TCMIF_ASM_BASE & 0xff000000 387 orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 388 orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 389 390 @ Prepare to put SDRAM into self-refresh manually 391 ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 392 orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 393 orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff 394 str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 395 396 @ Prepare to put EMIFS to Sleep 397 ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 398 orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff 399 str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 400 401 @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 402 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 403 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 404 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 405 406 @ Turn off clock domains 407 @ Do not disable PERCK (0x04) 408 mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff 409 orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 410 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 411 412 @ Request ARM idle 413 mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff 414 orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 415 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 416 417/* 418 * Let's wait for the next wake up event to wake us up. r0 can't be 419 * used here because r0 holds ARM_IDLECT1 420 */ 421 mov r2, #0 422 mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt 423 424 @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions 425 @ according to this formula: 426 @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV 427 @ Max DPLL_MULT = 18 428 @ DPLL_DIV = 1 429 @ ARMDIV = 1 430 @ => 74 nop-instructions 431 nop 432 nop 433 nop 434 nop 435 nop 436 nop 437 nop 438 nop 439 nop 440 nop @10 441 nop 442 nop 443 nop 444 nop 445 nop 446 nop 447 nop 448 nop 449 nop 450 nop @20 451 nop 452 nop 453 nop 454 nop 455 nop 456 nop 457 nop 458 nop 459 nop 460 nop @30 461 nop 462 nop 463 nop 464 nop 465 nop 466 nop 467 nop 468 nop 469 nop 470 nop @40 471 nop 472 nop 473 nop 474 nop 475 nop 476 nop 477 nop 478 nop 479 nop 480 nop @50 481 nop 482 nop 483 nop 484 nop 485 nop 486 nop 487 nop 488 nop 489 nop 490 nop @60 491 nop 492 nop 493 nop 494 nop 495 nop 496 nop 497 nop 498 nop 499 nop 500 nop @70 501 nop 502 nop 503 nop 504 nop @74 505/* 506 * omap1610_cpu_suspend()'s resume point. 507 * 508 * It will just start executing here, so we'll restore stuff from the 509 * stack. 510 */ 511 @ Restore the ARM_IDLECT1 and ARM_IDLECT2. 512 strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] 513 strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] 514 515 @ Restore EMIFF controls 516 str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] 517 str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] 518 519 @ Restore regs and return 520 ldmfd sp!, {r0 - r12, pc} 521 522ENTRY(omap1610_cpu_suspend_sz) 523 .word . - omap1610_cpu_suspend 524#endif /* CONFIG_ARCH_OMAP16XX */ 525