//#*********************************************************************** // // // // // Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file // contains copyrighted material. Use of this file is restricted // by the provisions of a Motorola Software License Agreement. // // Copyright 1993 International Buisness Machines Corporation. // All Rights Reserved. // // This file contains copyrighted material. Use of this file is // restricted by the provisions of a Motorola/IBM Joint Software // License Agreement. // // File Name: // PXSTALL.S // // Functions: // KeStallExecutionProcessor // HalpCalibrateStall // // History: // 21-Sep-1993 Steve Johns // Original Version // 24-Dec-1993 Peter Johnston // Adapted to 601 HAL in an attempt to avoid having different // versions if at all possible. Original was designed for both // 601 and 603 but had some 601 difficulties. // 17-Jan-1994 Steve Johns // Changed to treat 601 vs PowerPC time base differences more // transparently. // //#*********************************************************************** /* * Copyright (c) 1995 FirePower Systems, Inc. * DO NOT DISTRIBUTE without permission * * $RCSfile: pxstall.s $ * $Revision: 1.6 $ * $Date: 1996/01/11 07:13:48 $ * $Locker: $ */ #include "kxppc.h" #define ERRATA603 TRUE #define RTCU 4 #define RTCL 5 #define CMOS_INDEX 0x70 #define CMOS_DATA 0x71 #define RTC_SECOND 0x80 .extern HalpPerformanceFrequency .extern HalpIoControlBase .extern ..HalpDivide // // Register Definitions // .set Microsecs, r.3 .set TimerLo , r.6 // MUST be same as defined in PXCLKSUP.S .set TimerHi , r.7 // MUST be same as defined in PXCLKSUP.S .set EndTimerLo, r.3 .set EndTimerHi, r.4 .set Temp , r.8 .set Temp2 , r.9 .set IO_Base , r.10 //#*********************************************************************** // // Synopsis: // VOID KeStallExecutionProcessor( // ULONG Microseconds) // // Purpose: // This function stalls the execution at least the specified number // of microseconds, but not substantially longer. // // Returns: // Nothing. // // Global Variables Referenced: // HalpPerformanceFrequency //#*********************************************************************** SPECIAL_ENTRY(KeStallExecutionProcessor) mflr r.0 // Save Link Register PROLOGUE_END(KeStallExecutionProcessor) cmpli 0,0,Microsecs,0 // if (Microseconds == 0) beqlr- // return; bl ..HalpGetTimerRoutine // Get appropriate timer routine // // Read START time // bctrl // ReadPerformanceCounter(); // // Get PerformanceCounter frequency // lwz Temp,[toc]HalpPerformanceFrequency(r.toc) lwz Temp,0(Temp) // // Compute: (Microseconds * PerformanceFrequency) / 1,000,000 // mulhwu. EndTimerHi,Microsecs,Temp mullw EndTimerLo,Microsecs,Temp LWI (r.5, 1000000) bl ..HalpDivide // // Account for software overhead // .set Overhead, 30 cmpwi r.3, Overhead ble SkipOverhead addi r.3, r.3, -Overhead // Reduce delay SkipOverhead: // // Add delay to start time // addc EndTimerLo, TimerLo, r.3 addze EndTimerHi, TimerHi // // while (ReadPerformanceCounter() < EndTimer); // StallLoop: bctrl // ReadPerformanceCounter(); cmpl 0,0,TimerHi,EndTimerHi // Is TimerHi >= EndTimerHi ? blt- StallLoop // No bgt+ StallExit // Yes cmpl 0,0,TimerLo,EndTimerLo // Is TimerLo >= EndTimerLo ? blt StallLoop // Branch if not StallExit: mtlr r.0 // Restore Link Register SPECIAL_EXIT(KeStallExecutionProcessor) // // This routine is the ReadPerformanceCounter routine for the 601 processor. // The 601 RTC counts discontinuously (1 is added to RTCU when the value in // RTCL passes 999,999,999). This routine converts the RTC count to a // continuous 64-bit count by calculating: // // ((RTC.HighPart * 1,000,000,000) + RTC.LowPart) / 128 // // LEAF_ENTRY (ReadRTC) mfspr TimerHi,RTCU // Read the RTC registers coherently mfspr TimerLo,RTCL mfspr Temp,RTCU cmpl 0,0,TimerHi,Temp bne- ..ReadRTC lis Temp,(1000000000 >> 16) // RTC.HighPart * 1,000,000 ori Temp,Temp,(1000000000 & 0xFFFF) mullw Temp2,Temp,TimerHi mulhwu Temp,Temp,TimerHi addc TimerLo,Temp2,TimerLo // + RTC.LowPart addze TimerHi,Temp // // Each tick increments the RTC by 128, so let's divide that out. // mr Temp,TimerHi // Divide 64-bit value by 128 rlwinm TimerLo,TimerLo,32-7,7,31 rlwinm TimerHi,TimerHi,32-7,7,31 rlwimi TimerLo,Temp,32-7,0,6 LEAF_EXIT (ReadRTC) // // This routine is the ReadPerformanceCounter routine for PowerPC // architectures (not the 601). // LEAF_ENTRY (ReadTB) mftbu TimerHi // Read the TB registers coherently mftb TimerLo #if ERRATA603 mftb TimerLo mftb TimerLo mftb TimerLo #endif mftbu Temp cmpl 0,0,Temp,TimerHi bne- ..ReadTB LEAF_EXIT (ReadTB) // // Returns in the Count Register the entry point for the routine // that reads the appropriate Performance Counter (ReadRTC or ReadTB). // // Called from KeQueryPerformanceCounter and KeStallExecutionProcessor // LEAF_ENTRY (HalpGetTimerRoutine) mfpvr Temp // Read Processor Version Register rlwinm Temp,Temp,16,16,31 cmpli 0,0,Temp,1 // Are we running on an MPC601 ? lwz Temp,[toc]ReadTB(r.toc) bne+ GetEntryPoint // Branch if not lwz Temp,[toc]ReadRTC(r.toc) GetEntryPoint: lwz Temp,0(Temp) // Get addr to ReadRTC or ReadTB mtctr Temp LEAF_EXIT (HalpGetTimerRoutine) // // Returns the number of performance counter ticks/second. // // The DECREMENTER is clocked at the same rate as the PowerPC Time Base (TB) // and the POWER RTC. The POWER RTC is supposed to be clocked at 7.8125 MHz, // but on early prototypes of the Sandalfoot platform, this is not true). // In either case, to keep the calibration routine simple and generic, we // will determine the DECREMENTER clock rate by counting ticks for exactly // 1 second (as measured against the CMOS RealTimeClock). We then use that // value in the KeStallExecutionProcessor() and KeQueryPerformanceCounter() // LEAF_ENTRY(HalpCalibrateTB) // Get base address of ISA I/O space so we can talk to the CMOS RTC lwz IO_Base,[toc]HalpIoControlBase(r.toc) lwz IO_Base,0(IO_Base) li r.3,RTC_SECOND // Read seconds from CMOS RTC stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index eieio lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data WaitForTick1: li r.3,RTC_SECOND // Read seconds from CMOS RTC stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index eieio lbz r.3,CMOS_DATA(IO_Base) // Read CMOS data cmpl 0,0,r.3,r.4 // Loop until it changes beq+ WaitForTick1 li r.4,-1 // Start the decrementer at max. count mtdec r.4 #if ERRATA603 isync #endif WaitForTick2: li r.4,RTC_SECOND // Read seconds from CMOS RTC stb r.4,CMOS_INDEX(IO_Base) // Write CMOS index eieio lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data cmpl 0,0,r.3,r.4 beq+ WaitForTick2 mfdec r.3 // Read the decrementer neg r.3,r.3 // Compute delta ticks mfpvr Temp // Read Processor Version Register rlwinm Temp,Temp,16,16,31 cmpli 0,0,Temp,1 // if (CPU != 601) bnelr // return(r.3); // // On the 601, the DECREMENTER decrements every ns, so the 7 LSBs are // not implemented. // rlwinm r.3,r.3,32-7,7,31 // Divide count by 128 LEAF_EXIT(HalpCalibrateTB) LEAF_ENTRY(HalpCalibrateTBPStack) #define NVRAM_INDEX_LO 0x74 #define NVRAM_INDEX_HI 0x75 #define NVRAM_DATA 0x77 #define RTC_OFFSET 0x1ff8 #define RTC_CONTROL 0x0 // *BJ* Fix later. #undef RTC_SECOND #define RTC_SECOND 0x1 #define RTC_MINUTE 0x2 #define SYNCHRONIZE \ lwz Temp,[toc]HalpIoControlBase(r.toc);\ stw Temp,[toc]HalpIoControlBase(r.toc);\ nop;\ sync // Get base address of ISA I/O space so we can talk to the CMOS RTC lwz IO_Base,[toc]HalpIoControlBase(r.toc) lwz IO_Base,0(IO_Base) li r.3,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC stb r.3,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo rlwinm r.3,r.3,32-8,24,31 // Shift > 8 and mask 0xff stb r.3,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi SYNCHRONIZE lbz r.3,NVRAM_DATA(IO_Base) // Read CMOS data WaitForTick0.Ps: li r.4,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC stb r.4,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo rlwinm r.4,r.4,32-8,24,31 // Shift > 8 and mask 0xff stb r.4,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi SYNCHRONIZE lbz r.4,NVRAM_DATA(IO_Base) // Read CMOS data cmpl 0,0,r.3,r.4 // Loop until it changes beq+ WaitForTick0.Ps WaitForTick1.Ps: li r.3,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC stb r.3,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo rlwinm r.3,r.3,32-8,24,31 // Shift > 8 and mask 0xff stb r.3,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi SYNCHRONIZE lbz r.3,NVRAM_DATA(IO_Base) // Read CMOS data cmpl 0,0,r.3,r.4 // Loop until it changes beq+ WaitForTick1.Ps li r.4,-1 // Start the decrementer at max. count mtdec r.4 #if ERRATA603 isync #endif WaitForTick2.Ps: li r.4,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC stb r.4,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo rlwinm r.4,r.4,32-8,24,31 // Shift > 8 and mask 0xff stb r.4,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi SYNCHRONIZE lbz r.4,NVRAM_DATA(IO_Base) // Read CMOS data cmpl 0,0,r.3,r.4 beq+ WaitForTick2.Ps mfdec r.3 // Read the decrementer neg r.3,r.3 // Compute delta ticks mfpvr Temp // Read Processor Version Register rlwinm Temp,Temp,16,16,31 cmpli 0,0,Temp,1 // if (CPU != 601) bnelr // return(r.3); // // On the 601, the DECREMENTER decrements every ns, so the 7 LSBs are // not implemented. // rlwinm r.3,r.3,32-7,7,31 // Divide count by 128 LEAF_EXIT(HalpCalibrateTBPStack)