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