1/* 2 * Copyright 2004-2008 Analog Devices Inc. 3 * 4 * Licensed under the GPL-2 or later. 5 */ 6 7#include <linux/linkage.h> 8#include <asm/blackfin.h> 9#include <mach/irq.h> 10#include <asm/dpmc.h> 11 12.section .l1.text 13ENTRY(_sleep_mode) 14 [--SP] = (R7:4, P5:3); 15 [--SP] = RETS; 16 17 call _set_sic_iwr; 18 19 P0.H = hi(PLL_CTL); 20 P0.L = lo(PLL_CTL); 21 R1 = W[P0](z); 22 BITSET (R1, 3); 23 W[P0] = R1.L; 24 25 CLI R2; 26 SSYNC; 27 IDLE; 28 STI R2; 29 30 call _test_pll_locked; 31 32 R0 = IWR_ENABLE(0); 33 R1 = IWR_DISABLE_ALL; 34 R2 = IWR_DISABLE_ALL; 35 36 call _set_sic_iwr; 37 38 P0.H = hi(PLL_CTL); 39 P0.L = lo(PLL_CTL); 40 R7 = w[p0](z); 41 BITCLR (R7, 3); 42 BITCLR (R7, 5); 43 w[p0] = R7.L; 44 IDLE; 45 46 bfin_init_pm_bench_cycles; 47 48 call _test_pll_locked; 49 50 RETS = [SP++]; 51 (R7:4, P5:3) = [SP++]; 52 RTS; 53ENDPROC(_sleep_mode) 54 55/* 56 * This func never returns as it puts the part into hibernate, and 57 * is only called from do_hibernate, so we don't bother saving or 58 * restoring any of the normal C runtime state. When we wake up, 59 * the entry point will be in do_hibernate and not here. 60 * 61 * We accept just one argument -- the value to write to VR_CTL. 62 */ 63 64ENTRY(_hibernate_mode) 65 /* Save/setup the regs we need early for minor pipeline optimization */ 66 R4 = R0; 67 68 P3.H = hi(VR_CTL); 69 P3.L = lo(VR_CTL); 70 /* Disable all wakeup sources */ 71 R0 = IWR_DISABLE_ALL; 72 R1 = IWR_DISABLE_ALL; 73 R2 = IWR_DISABLE_ALL; 74 call _set_sic_iwr; 75 call _set_dram_srfs; 76 SSYNC; 77 78 /* Finally, we climb into our cave to hibernate */ 79 W[P3] = R4.L; 80 81 bfin_init_pm_bench_cycles; 82 83 CLI R2; 84 IDLE; 85.Lforever: 86 jump .Lforever; 87ENDPROC(_hibernate_mode) 88 89ENTRY(_sleep_deeper) 90 [--SP] = (R7:4, P5:3); 91 [--SP] = RETS; 92 93 CLI R4; 94 95 P3 = R0; 96 P4 = R1; 97 P5 = R2; 98 99 R0 = IWR_ENABLE(0); 100 R1 = IWR_DISABLE_ALL; 101 R2 = IWR_DISABLE_ALL; 102 103 call _set_sic_iwr; 104 call _set_dram_srfs; /* Set SDRAM Self Refresh */ 105 106 P0.H = hi(PLL_DIV); 107 P0.L = lo(PLL_DIV); 108 R6 = W[P0](z); 109 R0.L = 0xF; 110 W[P0] = R0.l; /* Set Max VCO to SCLK divider */ 111 112 P0.H = hi(PLL_CTL); 113 P0.L = lo(PLL_CTL); 114 R5 = W[P0](z); 115 R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9; 116 W[P0] = R0.l; /* Set Min CLKIN to VCO multiplier */ 117 118 SSYNC; 119 IDLE; 120 121 call _test_pll_locked; 122 123 P0.H = hi(VR_CTL); 124 P0.L = lo(VR_CTL); 125 R7 = W[P0](z); 126 R1 = 0x6; 127 R1 <<= 16; 128 R2 = 0x0404(Z); 129 R1 = R1|R2; 130 131 R2 = DEPOSIT(R7, R1); 132 W[P0] = R2; /* Set Min Core Voltage */ 133 134 SSYNC; 135 IDLE; 136 137 call _test_pll_locked; 138 139 R0 = P3; 140 R1 = P4; 141 R3 = P5; 142 call _set_sic_iwr; /* Set Awake from IDLE */ 143 144 P0.H = hi(PLL_CTL); 145 P0.L = lo(PLL_CTL); 146 R0 = W[P0](z); 147 BITSET (R0, 3); 148 W[P0] = R0.L; /* Turn CCLK OFF */ 149 SSYNC; 150 IDLE; 151 152 call _test_pll_locked; 153 154 R0 = IWR_ENABLE(0); 155 R1 = IWR_DISABLE_ALL; 156 R2 = IWR_DISABLE_ALL; 157 158 call _set_sic_iwr; /* Set Awake from IDLE PLL */ 159 160 P0.H = hi(VR_CTL); 161 P0.L = lo(VR_CTL); 162 W[P0]= R7; 163 164 SSYNC; 165 IDLE; 166 167 bfin_init_pm_bench_cycles; 168 169 call _test_pll_locked; 170 171 P0.H = hi(PLL_DIV); 172 P0.L = lo(PLL_DIV); 173 W[P0]= R6; /* Restore CCLK and SCLK divider */ 174 175 P0.H = hi(PLL_CTL); 176 P0.L = lo(PLL_CTL); 177 w[p0] = R5; /* Restore VCO multiplier */ 178 IDLE; 179 call _test_pll_locked; 180 181 call _unset_dram_srfs; /* SDRAM Self Refresh Off */ 182 183 STI R4; 184 185 RETS = [SP++]; 186 (R7:4, P5:3) = [SP++]; 187 RTS; 188ENDPROC(_sleep_deeper) 189 190ENTRY(_set_dram_srfs) 191 /* set the dram to self refresh mode */ 192 SSYNC; 193#if defined(EBIU_RSTCTL) /* DDR */ 194 P0.H = hi(EBIU_RSTCTL); 195 P0.L = lo(EBIU_RSTCTL); 196 R2 = [P0]; 197 BITSET(R2, 3); /* SRREQ enter self-refresh mode */ 198 [P0] = R2; 199 SSYNC; 2001: 201 R2 = [P0]; 202 CC = BITTST(R2, 4); 203 if !CC JUMP 1b; 204#else /* SDRAM */ 205 P0.L = lo(EBIU_SDGCTL); 206 P0.H = hi(EBIU_SDGCTL); 207 P1.L = lo(EBIU_SDSTAT); 208 P1.H = hi(EBIU_SDSTAT); 209 210 R2 = [P0]; 211 BITSET(R2, 24); /* SRFS enter self-refresh mode */ 212 [P0] = R2; 213 SSYNC; 214 2151: 216 R2 = w[P1]; 217 SSYNC; 218 cc = BITTST(R2, 1); /* SDSRA poll self-refresh status */ 219 if !cc jump 1b; 220 221 R2 = [P0]; 222 BITCLR(R2, 0); /* SCTLE disable CLKOUT */ 223 [P0] = R2; 224#endif 225 RTS; 226ENDPROC(_set_dram_srfs) 227 228ENTRY(_unset_dram_srfs) 229 /* set the dram out of self refresh mode */ 230 231#if defined(EBIU_RSTCTL) /* DDR */ 232 P0.H = hi(EBIU_RSTCTL); 233 P0.L = lo(EBIU_RSTCTL); 234 R2 = [P0]; 235 BITCLR(R2, 3); /* clear SRREQ bit */ 236 [P0] = R2; 237#elif defined(EBIU_SDGCTL) /* SDRAM */ 238 /* release CLKOUT from self-refresh */ 239 P0.L = lo(EBIU_SDGCTL); 240 P0.H = hi(EBIU_SDGCTL); 241 242 R2 = [P0]; 243 BITSET(R2, 0); /* SCTLE enable CLKOUT */ 244 [P0] = R2 245 SSYNC; 246 247 /* release SDRAM from self-refresh */ 248 R2 = [P0]; 249 BITCLR(R2, 24); /* clear SRFS bit */ 250 [P0] = R2 251#endif 252 253 SSYNC; 254 RTS; 255ENDPROC(_unset_dram_srfs) 256 257ENTRY(_set_sic_iwr) 258#ifdef SIC_IWR0 259 P0.H = hi(SYSMMR_BASE); 260 P0.L = lo(SYSMMR_BASE); 261 [P0 + (SIC_IWR0 - SYSMMR_BASE)] = R0; 262 [P0 + (SIC_IWR1 - SYSMMR_BASE)] = R1; 263# ifdef SIC_IWR2 264 [P0 + (SIC_IWR2 - SYSMMR_BASE)] = R2; 265# endif 266#else 267 P0.H = hi(SIC_IWR); 268 P0.L = lo(SIC_IWR); 269 [P0] = R0; 270#endif 271 272 SSYNC; 273 RTS; 274ENDPROC(_set_sic_iwr) 275 276ENTRY(_test_pll_locked) 277 P0.H = hi(PLL_STAT); 278 P0.L = lo(PLL_STAT); 2791: 280 R0 = W[P0] (Z); 281 CC = BITTST(R0,5); 282 IF !CC JUMP 1b; 283 RTS; 284ENDPROC(_test_pll_locked) 285 286.section .text 287ENTRY(_do_hibernate) 288 bfin_cpu_reg_save; 289 bfin_sys_mmr_save; 290 bfin_core_mmr_save; 291 292 /* Setup args to hibernate mode early for pipeline optimization */ 293 R0 = M3; 294 P1.H = _hibernate_mode; 295 P1.L = _hibernate_mode; 296 297 /* Save Magic, return address and Stack Pointer */ 298 P0 = 0; 299 R1.H = 0xDEAD; /* Hibernate Magic */ 300 R1.L = 0xBEEF; 301 R2.H = .Lpm_resume_here; 302 R2.L = .Lpm_resume_here; 303 [P0++] = R1; /* Store Hibernate Magic */ 304 [P0++] = R2; /* Save Return Address */ 305 [P0++] = SP; /* Save Stack Pointer */ 306 307 /* Must use an indirect call as we need to jump to L1 */ 308 call (P1); /* Goodbye */ 309 310.Lpm_resume_here: 311 312 bfin_core_mmr_restore; 313 bfin_sys_mmr_restore; 314 bfin_cpu_reg_restore; 315 316 [--sp] = RETI; /* Clear Global Interrupt Disable */ 317 SP += 4; 318 319 RTS; 320ENDPROC(_do_hibernate) 321