1/* 2 * This file contains sleep low-level functions for PowerBook G3. 3 * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) 4 * and Paul Mackerras (paulus@samba.org). 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 * 11 */ 12 13#include <asm/processor.h> 14#include <asm/page.h> 15#include <asm/ppc_asm.h> 16#include <asm/cputable.h> 17#include <asm/cache.h> 18#include <asm/thread_info.h> 19#include <asm/asm-offsets.h> 20#include <asm/mmu.h> 21#include <asm/feature-fixups.h> 22 23#define MAGIC 0x4c617273 /* 'Lars' */ 24 25/* 26 * Structure for storing CPU registers on the stack. 27 */ 28#define SL_SP 0 29#define SL_PC 4 30#define SL_MSR 8 31#define SL_SDR1 0xc 32#define SL_SPRG0 0x10 /* 4 sprg's */ 33#define SL_DBAT0 0x20 34#define SL_IBAT0 0x28 35#define SL_DBAT1 0x30 36#define SL_IBAT1 0x38 37#define SL_DBAT2 0x40 38#define SL_IBAT2 0x48 39#define SL_DBAT3 0x50 40#define SL_IBAT3 0x58 41#define SL_DBAT4 0x60 42#define SL_IBAT4 0x68 43#define SL_DBAT5 0x70 44#define SL_IBAT5 0x78 45#define SL_DBAT6 0x80 46#define SL_IBAT6 0x88 47#define SL_DBAT7 0x90 48#define SL_IBAT7 0x98 49#define SL_TB 0xa0 50#define SL_R2 0xa8 51#define SL_CR 0xac 52#define SL_R12 0xb0 /* r12 to r31 */ 53#define SL_SIZE (SL_R12 + 80) 54 55 .section .text 56 .align 5 57 58#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC) || \ 59 (defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)) 60 61/* This gets called by via-pmu.c late during the sleep process. 62 * The PMU was already send the sleep command and will shut us down 63 * soon. We need to save all that is needed and setup the wakeup 64 * vector that will be called by the ROM on wakeup 65 */ 66_GLOBAL(low_sleep_handler) 67#ifndef CONFIG_6xx 68 blr 69#else 70 mflr r0 71 stw r0,4(r1) 72 stwu r1,-SL_SIZE(r1) 73 mfcr r0 74 stw r0,SL_CR(r1) 75 stw r2,SL_R2(r1) 76 stmw r12,SL_R12(r1) 77 78 /* Save MSR & SDR1 */ 79 mfmsr r4 80 stw r4,SL_MSR(r1) 81 mfsdr1 r4 82 stw r4,SL_SDR1(r1) 83 84 /* Get a stable timebase and save it */ 851: mftbu r4 86 stw r4,SL_TB(r1) 87 mftb r5 88 stw r5,SL_TB+4(r1) 89 mftbu r3 90 cmpw r3,r4 91 bne 1b 92 93 /* Save SPRGs */ 94 mfsprg r4,0 95 stw r4,SL_SPRG0(r1) 96 mfsprg r4,1 97 stw r4,SL_SPRG0+4(r1) 98 mfsprg r4,2 99 stw r4,SL_SPRG0+8(r1) 100 mfsprg r4,3 101 stw r4,SL_SPRG0+12(r1) 102 103 /* Save BATs */ 104 mfdbatu r4,0 105 stw r4,SL_DBAT0(r1) 106 mfdbatl r4,0 107 stw r4,SL_DBAT0+4(r1) 108 mfdbatu r4,1 109 stw r4,SL_DBAT1(r1) 110 mfdbatl r4,1 111 stw r4,SL_DBAT1+4(r1) 112 mfdbatu r4,2 113 stw r4,SL_DBAT2(r1) 114 mfdbatl r4,2 115 stw r4,SL_DBAT2+4(r1) 116 mfdbatu r4,3 117 stw r4,SL_DBAT3(r1) 118 mfdbatl r4,3 119 stw r4,SL_DBAT3+4(r1) 120 mfibatu r4,0 121 stw r4,SL_IBAT0(r1) 122 mfibatl r4,0 123 stw r4,SL_IBAT0+4(r1) 124 mfibatu r4,1 125 stw r4,SL_IBAT1(r1) 126 mfibatl r4,1 127 stw r4,SL_IBAT1+4(r1) 128 mfibatu r4,2 129 stw r4,SL_IBAT2(r1) 130 mfibatl r4,2 131 stw r4,SL_IBAT2+4(r1) 132 mfibatu r4,3 133 stw r4,SL_IBAT3(r1) 134 mfibatl r4,3 135 stw r4,SL_IBAT3+4(r1) 136 137BEGIN_MMU_FTR_SECTION 138 mfspr r4,SPRN_DBAT4U 139 stw r4,SL_DBAT4(r1) 140 mfspr r4,SPRN_DBAT4L 141 stw r4,SL_DBAT4+4(r1) 142 mfspr r4,SPRN_DBAT5U 143 stw r4,SL_DBAT5(r1) 144 mfspr r4,SPRN_DBAT5L 145 stw r4,SL_DBAT5+4(r1) 146 mfspr r4,SPRN_DBAT6U 147 stw r4,SL_DBAT6(r1) 148 mfspr r4,SPRN_DBAT6L 149 stw r4,SL_DBAT6+4(r1) 150 mfspr r4,SPRN_DBAT7U 151 stw r4,SL_DBAT7(r1) 152 mfspr r4,SPRN_DBAT7L 153 stw r4,SL_DBAT7+4(r1) 154 mfspr r4,SPRN_IBAT4U 155 stw r4,SL_IBAT4(r1) 156 mfspr r4,SPRN_IBAT4L 157 stw r4,SL_IBAT4+4(r1) 158 mfspr r4,SPRN_IBAT5U 159 stw r4,SL_IBAT5(r1) 160 mfspr r4,SPRN_IBAT5L 161 stw r4,SL_IBAT5+4(r1) 162 mfspr r4,SPRN_IBAT6U 163 stw r4,SL_IBAT6(r1) 164 mfspr r4,SPRN_IBAT6L 165 stw r4,SL_IBAT6+4(r1) 166 mfspr r4,SPRN_IBAT7U 167 stw r4,SL_IBAT7(r1) 168 mfspr r4,SPRN_IBAT7L 169 stw r4,SL_IBAT7+4(r1) 170END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) 171 172 /* Backup various CPU config stuffs */ 173 bl __save_cpu_setup 174 175 /* The ROM can wake us up via 2 different vectors: 176 * - On wallstreet & lombard, we must write a magic 177 * value 'Lars' at address 4 and a pointer to a 178 * memory location containing the PC to resume from 179 * at address 0. 180 * - On Core99, we must store the wakeup vector at 181 * address 0x80 and eventually it's parameters 182 * at address 0x84. I've have some trouble with those 183 * parameters however and I no longer use them. 184 */ 185 lis r5,grackle_wake_up@ha 186 addi r5,r5,grackle_wake_up@l 187 tophys(r5,r5) 188 stw r5,SL_PC(r1) 189 lis r4,KERNELBASE@h 190 tophys(r5,r1) 191 addi r5,r5,SL_PC 192 lis r6,MAGIC@ha 193 addi r6,r6,MAGIC@l 194 stw r5,0(r4) 195 stw r6,4(r4) 196 /* Setup stuffs at 0x80-0x84 for Core99 */ 197 lis r3,core99_wake_up@ha 198 addi r3,r3,core99_wake_up@l 199 tophys(r3,r3) 200 stw r3,0x80(r4) 201 stw r5,0x84(r4) 202 /* Store a pointer to our backup storage into 203 * a kernel global 204 */ 205 lis r3,sleep_storage@ha 206 addi r3,r3,sleep_storage@l 207 stw r5,0(r3) 208 209 .globl low_cpu_die 210low_cpu_die: 211 /* Flush & disable all caches */ 212 bl flush_disable_caches 213 214 /* Turn off data relocation. */ 215 mfmsr r3 /* Save MSR in r7 */ 216 rlwinm r3,r3,0,28,26 /* Turn off DR bit */ 217 sync 218 mtmsr r3 219 isync 220 221BEGIN_FTR_SECTION 222 /* Flush any pending L2 data prefetches to work around HW bug */ 223 sync 224 lis r3,0xfff0 225 lwz r0,0(r3) /* perform cache-inhibited load to ROM */ 226 sync /* (caches are disabled at this point) */ 227END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) 228 229/* 230 * Set the HID0 and MSR for sleep. 231 */ 232 mfspr r2,SPRN_HID0 233 rlwinm r2,r2,0,10,7 /* clear doze, nap */ 234 oris r2,r2,HID0_SLEEP@h 235 sync 236 isync 237 mtspr SPRN_HID0,r2 238 sync 239 240/* This loop puts us back to sleep in case we have a spurrious 241 * wakeup so that the host bridge properly stays asleep. The 242 * CPU will be turned off, either after a known time (about 1 243 * second) on wallstreet & lombard, or as soon as the CPU enters 244 * SLEEP mode on core99 245 */ 246 mfmsr r2 247 oris r2,r2,MSR_POW@h 2481: sync 249 mtmsr r2 250 isync 251 b 1b 252 253/* 254 * Here is the resume code. 255 */ 256 257 258/* 259 * Core99 machines resume here 260 * r4 has the physical address of SL_PC(sp) (unused) 261 */ 262_GLOBAL(core99_wake_up) 263 /* Make sure HID0 no longer contains any sleep bit and that data cache 264 * is disabled 265 */ 266 mfspr r3,SPRN_HID0 267 rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ 268 rlwinm 3,r3,0,18,15 /* clear DCE, ICE */ 269 mtspr SPRN_HID0,r3 270 sync 271 isync 272 273 /* sanitize MSR */ 274 mfmsr r3 275 ori r3,r3,MSR_EE|MSR_IP 276 xori r3,r3,MSR_EE|MSR_IP 277 sync 278 isync 279 mtmsr r3 280 sync 281 isync 282 283 /* Recover sleep storage */ 284 lis r3,sleep_storage@ha 285 addi r3,r3,sleep_storage@l 286 tophys(r3,r3) 287 lwz r1,0(r3) 288 289 /* Pass thru to older resume code ... */ 290/* 291 * Here is the resume code for older machines. 292 * r1 has the physical address of SL_PC(sp). 293 */ 294 295grackle_wake_up: 296 297 /* Restore the kernel's segment registers before 298 * we do any r1 memory access as we are not sure they 299 * are in a sane state above the first 256Mb region 300 */ 301 li r0,16 /* load up segment register values */ 302 mtctr r0 /* for context 0 */ 303 lis r3,0x2000 /* Ku = 1, VSID = 0 */ 304 li r4,0 3053: mtsrin r3,r4 306 addi r3,r3,0x111 /* increment VSID */ 307 addis r4,r4,0x1000 /* address of next segment */ 308 bdnz 3b 309 sync 310 isync 311 312 subi r1,r1,SL_PC 313 314 /* Restore various CPU config stuffs */ 315 bl __restore_cpu_setup 316 317 /* Make sure all FPRs have been initialized */ 318 bl reloc_offset 319 bl __init_fpu_registers 320 321 /* Invalidate & enable L1 cache, we don't care about 322 * whatever the ROM may have tried to write to memory 323 */ 324 bl __inval_enable_L1 325 326 /* Restore the BATs, and SDR1. Then we can turn on the MMU. */ 327 lwz r4,SL_SDR1(r1) 328 mtsdr1 r4 329 lwz r4,SL_SPRG0(r1) 330 mtsprg 0,r4 331 lwz r4,SL_SPRG0+4(r1) 332 mtsprg 1,r4 333 lwz r4,SL_SPRG0+8(r1) 334 mtsprg 2,r4 335 lwz r4,SL_SPRG0+12(r1) 336 mtsprg 3,r4 337 338 lwz r4,SL_DBAT0(r1) 339 mtdbatu 0,r4 340 lwz r4,SL_DBAT0+4(r1) 341 mtdbatl 0,r4 342 lwz r4,SL_DBAT1(r1) 343 mtdbatu 1,r4 344 lwz r4,SL_DBAT1+4(r1) 345 mtdbatl 1,r4 346 lwz r4,SL_DBAT2(r1) 347 mtdbatu 2,r4 348 lwz r4,SL_DBAT2+4(r1) 349 mtdbatl 2,r4 350 lwz r4,SL_DBAT3(r1) 351 mtdbatu 3,r4 352 lwz r4,SL_DBAT3+4(r1) 353 mtdbatl 3,r4 354 lwz r4,SL_IBAT0(r1) 355 mtibatu 0,r4 356 lwz r4,SL_IBAT0+4(r1) 357 mtibatl 0,r4 358 lwz r4,SL_IBAT1(r1) 359 mtibatu 1,r4 360 lwz r4,SL_IBAT1+4(r1) 361 mtibatl 1,r4 362 lwz r4,SL_IBAT2(r1) 363 mtibatu 2,r4 364 lwz r4,SL_IBAT2+4(r1) 365 mtibatl 2,r4 366 lwz r4,SL_IBAT3(r1) 367 mtibatu 3,r4 368 lwz r4,SL_IBAT3+4(r1) 369 mtibatl 3,r4 370 371BEGIN_MMU_FTR_SECTION 372 lwz r4,SL_DBAT4(r1) 373 mtspr SPRN_DBAT4U,r4 374 lwz r4,SL_DBAT4+4(r1) 375 mtspr SPRN_DBAT4L,r4 376 lwz r4,SL_DBAT5(r1) 377 mtspr SPRN_DBAT5U,r4 378 lwz r4,SL_DBAT5+4(r1) 379 mtspr SPRN_DBAT5L,r4 380 lwz r4,SL_DBAT6(r1) 381 mtspr SPRN_DBAT6U,r4 382 lwz r4,SL_DBAT6+4(r1) 383 mtspr SPRN_DBAT6L,r4 384 lwz r4,SL_DBAT7(r1) 385 mtspr SPRN_DBAT7U,r4 386 lwz r4,SL_DBAT7+4(r1) 387 mtspr SPRN_DBAT7L,r4 388 lwz r4,SL_IBAT4(r1) 389 mtspr SPRN_IBAT4U,r4 390 lwz r4,SL_IBAT4+4(r1) 391 mtspr SPRN_IBAT4L,r4 392 lwz r4,SL_IBAT5(r1) 393 mtspr SPRN_IBAT5U,r4 394 lwz r4,SL_IBAT5+4(r1) 395 mtspr SPRN_IBAT5L,r4 396 lwz r4,SL_IBAT6(r1) 397 mtspr SPRN_IBAT6U,r4 398 lwz r4,SL_IBAT6+4(r1) 399 mtspr SPRN_IBAT6L,r4 400 lwz r4,SL_IBAT7(r1) 401 mtspr SPRN_IBAT7U,r4 402 lwz r4,SL_IBAT7+4(r1) 403 mtspr SPRN_IBAT7L,r4 404END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) 405 406 /* Flush all TLBs */ 407 lis r4,0x1000 4081: addic. r4,r4,-0x1000 409 tlbie r4 410 blt 1b 411 sync 412 413 /* restore the MSR and turn on the MMU */ 414 lwz r3,SL_MSR(r1) 415 bl turn_on_mmu 416 417 /* get back the stack pointer */ 418 tovirt(r1,r1) 419 420 /* Restore TB */ 421 li r3,0 422 mttbl r3 423 lwz r3,SL_TB(r1) 424 lwz r4,SL_TB+4(r1) 425 mttbu r3 426 mttbl r4 427 428 /* Restore the callee-saved registers and return */ 429 lwz r0,SL_CR(r1) 430 mtcr r0 431 lwz r2,SL_R2(r1) 432 lmw r12,SL_R12(r1) 433 addi r1,r1,SL_SIZE 434 lwz r0,4(r1) 435 mtlr r0 436 blr 437 438turn_on_mmu: 439 mflr r4 440 tovirt(r4,r4) 441 mtsrr0 r4 442 mtsrr1 r3 443 sync 444 isync 445 rfi 446 447#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */ 448 449 .section .data 450 .balign L1_CACHE_BYTES 451sleep_storage: 452 .long 0 453 .balign L1_CACHE_BYTES, 0 454 455#endif /* CONFIG_6xx */ 456 .section .text 457