Path: blob/master/arch/powerpc/platforms/powermac/sleep.S
10818 views
/*1* This file contains sleep low-level functions for PowerBook G3.2* Copyright (C) 1999 Benjamin Herrenschmidt ([email protected])3* and Paul Mackerras ([email protected]).4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*10*/1112#include <asm/processor.h>13#include <asm/page.h>14#include <asm/ppc_asm.h>15#include <asm/cputable.h>16#include <asm/cache.h>17#include <asm/thread_info.h>18#include <asm/asm-offsets.h>19#include <asm/mmu.h>2021#define MAGIC 0x4c617273 /* 'Lars' */2223/*24* Structure for storing CPU registers on the stack.25*/26#define SL_SP 027#define SL_PC 428#define SL_MSR 829#define SL_SDR1 0xc30#define SL_SPRG0 0x10 /* 4 sprg's */31#define SL_DBAT0 0x2032#define SL_IBAT0 0x2833#define SL_DBAT1 0x3034#define SL_IBAT1 0x3835#define SL_DBAT2 0x4036#define SL_IBAT2 0x4837#define SL_DBAT3 0x5038#define SL_IBAT3 0x5839#define SL_TB 0x6040#define SL_R2 0x6841#define SL_CR 0x6c42#define SL_R12 0x70 /* r12 to r31 */43#define SL_SIZE (SL_R12 + 80)4445.section .text46.align 54748#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC) || \49(defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32))5051/* This gets called by via-pmu.c late during the sleep process.52* The PMU was already send the sleep command and will shut us down53* soon. We need to save all that is needed and setup the wakeup54* vector that will be called by the ROM on wakeup55*/56_GLOBAL(low_sleep_handler)57#ifndef CONFIG_6xx58blr59#else60mflr r061stw r0,4(r1)62stwu r1,-SL_SIZE(r1)63mfcr r064stw r0,SL_CR(r1)65stw r2,SL_R2(r1)66stmw r12,SL_R12(r1)6768/* Save MSR & SDR1 */69mfmsr r470stw r4,SL_MSR(r1)71mfsdr1 r472stw r4,SL_SDR1(r1)7374/* Get a stable timebase and save it */751: mftbu r476stw r4,SL_TB(r1)77mftb r578stw r5,SL_TB+4(r1)79mftbu r380cmpw r3,r481bne 1b8283/* Save SPRGs */84mfsprg r4,085stw r4,SL_SPRG0(r1)86mfsprg r4,187stw r4,SL_SPRG0+4(r1)88mfsprg r4,289stw r4,SL_SPRG0+8(r1)90mfsprg r4,391stw r4,SL_SPRG0+12(r1)9293/* Save BATs */94mfdbatu r4,095stw r4,SL_DBAT0(r1)96mfdbatl r4,097stw r4,SL_DBAT0+4(r1)98mfdbatu r4,199stw r4,SL_DBAT1(r1)100mfdbatl r4,1101stw r4,SL_DBAT1+4(r1)102mfdbatu r4,2103stw r4,SL_DBAT2(r1)104mfdbatl r4,2105stw r4,SL_DBAT2+4(r1)106mfdbatu r4,3107stw r4,SL_DBAT3(r1)108mfdbatl r4,3109stw r4,SL_DBAT3+4(r1)110mfibatu r4,0111stw r4,SL_IBAT0(r1)112mfibatl r4,0113stw r4,SL_IBAT0+4(r1)114mfibatu r4,1115stw r4,SL_IBAT1(r1)116mfibatl r4,1117stw r4,SL_IBAT1+4(r1)118mfibatu r4,2119stw r4,SL_IBAT2(r1)120mfibatl r4,2121stw r4,SL_IBAT2+4(r1)122mfibatu r4,3123stw r4,SL_IBAT3(r1)124mfibatl r4,3125stw r4,SL_IBAT3+4(r1)126127/* Backup various CPU config stuffs */128bl __save_cpu_setup129130/* The ROM can wake us up via 2 different vectors:131* - On wallstreet & lombard, we must write a magic132* value 'Lars' at address 4 and a pointer to a133* memory location containing the PC to resume from134* at address 0.135* - On Core99, we must store the wakeup vector at136* address 0x80 and eventually it's parameters137* at address 0x84. I've have some trouble with those138* parameters however and I no longer use them.139*/140lis r5,grackle_wake_up@ha141addi r5,r5,grackle_wake_up@l142tophys(r5,r5)143stw r5,SL_PC(r1)144lis r4,KERNELBASE@h145tophys(r5,r1)146addi r5,r5,SL_PC147lis r6,MAGIC@ha148addi r6,r6,MAGIC@l149stw r5,0(r4)150stw r6,4(r4)151/* Setup stuffs at 0x80-0x84 for Core99 */152lis r3,core99_wake_up@ha153addi r3,r3,core99_wake_up@l154tophys(r3,r3)155stw r3,0x80(r4)156stw r5,0x84(r4)157/* Store a pointer to our backup storage into158* a kernel global159*/160lis r3,sleep_storage@ha161addi r3,r3,sleep_storage@l162stw r5,0(r3)163164.globl low_cpu_die165low_cpu_die:166/* Flush & disable all caches */167bl flush_disable_caches168169/* Turn off data relocation. */170mfmsr r3 /* Save MSR in r7 */171rlwinm r3,r3,0,28,26 /* Turn off DR bit */172sync173mtmsr r3174isync175176BEGIN_FTR_SECTION177/* Flush any pending L2 data prefetches to work around HW bug */178sync179lis r3,0xfff0180lwz r0,0(r3) /* perform cache-inhibited load to ROM */181sync /* (caches are disabled at this point) */182END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)183184/*185* Set the HID0 and MSR for sleep.186*/187mfspr r2,SPRN_HID0188rlwinm r2,r2,0,10,7 /* clear doze, nap */189oris r2,r2,HID0_SLEEP@h190sync191isync192mtspr SPRN_HID0,r2193sync194195/* This loop puts us back to sleep in case we have a spurrious196* wakeup so that the host bridge properly stays asleep. The197* CPU will be turned off, either after a known time (about 1198* second) on wallstreet & lombard, or as soon as the CPU enters199* SLEEP mode on core99200*/201mfmsr r2202oris r2,r2,MSR_POW@h2031: sync204mtmsr r2205isync206b 1b207208/*209* Here is the resume code.210*/211212213/*214* Core99 machines resume here215* r4 has the physical address of SL_PC(sp) (unused)216*/217_GLOBAL(core99_wake_up)218/* Make sure HID0 no longer contains any sleep bit and that data cache219* is disabled220*/221mfspr r3,SPRN_HID0222rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */223rlwinm 3,r3,0,18,15 /* clear DCE, ICE */224mtspr SPRN_HID0,r3225sync226isync227228/* sanitize MSR */229mfmsr r3230ori r3,r3,MSR_EE|MSR_IP231xori r3,r3,MSR_EE|MSR_IP232sync233isync234mtmsr r3235sync236isync237238/* Recover sleep storage */239lis r3,sleep_storage@ha240addi r3,r3,sleep_storage@l241tophys(r3,r3)242lwz r1,0(r3)243244/* Pass thru to older resume code ... */245/*246* Here is the resume code for older machines.247* r1 has the physical address of SL_PC(sp).248*/249250grackle_wake_up:251252/* Restore the kernel's segment registers before253* we do any r1 memory access as we are not sure they254* are in a sane state above the first 256Mb region255*/256li r0,16 /* load up segment register values */257mtctr r0 /* for context 0 */258lis r3,0x2000 /* Ku = 1, VSID = 0 */259li r4,02603: mtsrin r3,r4261addi r3,r3,0x111 /* increment VSID */262addis r4,r4,0x1000 /* address of next segment */263bdnz 3b264sync265isync266267subi r1,r1,SL_PC268269/* Restore various CPU config stuffs */270bl __restore_cpu_setup271272/* Make sure all FPRs have been initialized */273bl reloc_offset274bl __init_fpu_registers275276/* Invalidate & enable L1 cache, we don't care about277* whatever the ROM may have tried to write to memory278*/279bl __inval_enable_L1280281/* Restore the BATs, and SDR1. Then we can turn on the MMU. */282lwz r4,SL_SDR1(r1)283mtsdr1 r4284lwz r4,SL_SPRG0(r1)285mtsprg 0,r4286lwz r4,SL_SPRG0+4(r1)287mtsprg 1,r4288lwz r4,SL_SPRG0+8(r1)289mtsprg 2,r4290lwz r4,SL_SPRG0+12(r1)291mtsprg 3,r4292293lwz r4,SL_DBAT0(r1)294mtdbatu 0,r4295lwz r4,SL_DBAT0+4(r1)296mtdbatl 0,r4297lwz r4,SL_DBAT1(r1)298mtdbatu 1,r4299lwz r4,SL_DBAT1+4(r1)300mtdbatl 1,r4301lwz r4,SL_DBAT2(r1)302mtdbatu 2,r4303lwz r4,SL_DBAT2+4(r1)304mtdbatl 2,r4305lwz r4,SL_DBAT3(r1)306mtdbatu 3,r4307lwz r4,SL_DBAT3+4(r1)308mtdbatl 3,r4309lwz r4,SL_IBAT0(r1)310mtibatu 0,r4311lwz r4,SL_IBAT0+4(r1)312mtibatl 0,r4313lwz r4,SL_IBAT1(r1)314mtibatu 1,r4315lwz r4,SL_IBAT1+4(r1)316mtibatl 1,r4317lwz r4,SL_IBAT2(r1)318mtibatu 2,r4319lwz r4,SL_IBAT2+4(r1)320mtibatl 2,r4321lwz r4,SL_IBAT3(r1)322mtibatu 3,r4323lwz r4,SL_IBAT3+4(r1)324mtibatl 3,r4325326BEGIN_MMU_FTR_SECTION327li r4,0328mtspr SPRN_DBAT4U,r4329mtspr SPRN_DBAT4L,r4330mtspr SPRN_DBAT5U,r4331mtspr SPRN_DBAT5L,r4332mtspr SPRN_DBAT6U,r4333mtspr SPRN_DBAT6L,r4334mtspr SPRN_DBAT7U,r4335mtspr SPRN_DBAT7L,r4336mtspr SPRN_IBAT4U,r4337mtspr SPRN_IBAT4L,r4338mtspr SPRN_IBAT5U,r4339mtspr SPRN_IBAT5L,r4340mtspr SPRN_IBAT6U,r4341mtspr SPRN_IBAT6L,r4342mtspr SPRN_IBAT7U,r4343mtspr SPRN_IBAT7L,r4344END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)345346/* Flush all TLBs */347lis r4,0x10003481: addic. r4,r4,-0x1000349tlbie r4350blt 1b351sync352353/* restore the MSR and turn on the MMU */354lwz r3,SL_MSR(r1)355bl turn_on_mmu356357/* get back the stack pointer */358tovirt(r1,r1)359360/* Restore TB */361li r3,0362mttbl r3363lwz r3,SL_TB(r1)364lwz r4,SL_TB+4(r1)365mttbu r3366mttbl r4367368/* Restore the callee-saved registers and return */369lwz r0,SL_CR(r1)370mtcr r0371lwz r2,SL_R2(r1)372lmw r12,SL_R12(r1)373addi r1,r1,SL_SIZE374lwz r0,4(r1)375mtlr r0376blr377378turn_on_mmu:379mflr r4380tovirt(r4,r4)381mtsrr0 r4382mtsrr1 r3383sync384isync385rfi386387#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */388389.section .data390.balign L1_CACHE_BYTES391sleep_storage:392.long 0393.balign L1_CACHE_BYTES, 0394395#endif /* CONFIG_6xx */396.section .text397398399