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