*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
mfsprg r9,2 ; Get feature flags
mfmsr r0 ; Save the current MSR
+ rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
neg r10,r3 ; Number of bytes to end of page
rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
rlwinm. r10,r10,0,20,31 ; Clear excess junk and test for page bndry
mr r0,r5
li r3,0
mprNoMSRx:
+
+ mfspr r6, hid0 ; Get a copy of hid0
+
+ rlwinm. r5, r9, 0, pfNoMuMMCKb, pfNoMuMMCKb ; Check for NoMuMMCK
+ bne mprNoMuM
+ rlwinm r5, r6, 0, ice+1, ice-1 ; Turn off L1 I-Cache
+ mtspr hid0, r5
+ isync ; Wait for I-Cache off
+ rlwinm r5, r6, 0, mum+1, mum-1 ; Turn off MuM w/ I-Cache on
+ mtspr hid0, r5
+mprNoMuM:
+
;
; We need to insure that there is no more than 1 BAT register that
; can get a hit. There could be repercussions beyond the ken
; of mortal man. It is best not to tempt fate.
;
+
+; Note: we will reload these from the shadow BATs later
+
li r10,0 ; Clear a register
- mfdbatu r5,0 ; Save DBAT 0 high
- mfdbatl r6,0 ; Save DBAT 0 low
- mfdbatu r7,1 ; Save DBAT 1 high
- mfdbatu r8,2 ; Save DBAT 2 high
- mfdbatu r9,3 ; Save DBAT 3 high
sync ; Make sure all is well
mtdbatu 0,r10 ; Now the upper
sync ; Just make sure
+ dcbf 0,r12 ; Make sure we kill the cache to avoid paradoxes
+ sync
+
ori r11,r2,lo16(MASK(MSR_DR)) ; Turn on data translation
mtmsr r11 ; Do it for real
isync ; Make sure of it
sync ; Get caught up yet again
isync ; Do not go further till we are here
+ mtmsr r2 ; Turn translation back off
+ isync
+
+ mtspr hid0, r6 ; Restore HID0
+ isync
+
+ lis r10,hi16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
+ ori r10,r10,lo16(EXT(shadow_BAT)+shdDBAT) ; Get shadow address
+
+ lwz r5,0(r10) ; Pick up DBAT 0 high
+ lwz r6,4(r10) ; Pick up DBAT 0 low
+ lwz r7,8(r10) ; Pick up DBAT 1 high
+ lwz r8,16(r10) ; Pick up DBAT 2 high
+ lwz r9,24(r10) ; Pick up DBAT 3 high
+
mtdbatu 0,r5 ; Restore DBAT 0 high
mtdbatl 0,r6 ; Restore DBAT 0 low
mtdbatu 1,r7 ; Restore DBAT 1 high
LEXT(ml_phys_read_byte)
mfmsr r10 ; Save the current MSR
- rlwinm r4,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
+ rlwinm r10,r10,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r10,r10,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
+ rlwinm r4,r10,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
rlwinm r4,r4,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
mtmsr r4 ; Translation and all off
LEXT(ml_phys_read)
mfmsr r0 ; Save the current MSR
+ rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r4,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
rlwinm r4,r4,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
LEXT(ml_phys_write_byte)
mfmsr r0 ; Save the current MSR
+ rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r5,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
LEXT(ml_phys_write)
mfmsr r0 ; Save the current MSR
+ rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r5,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interruptions
rlwinm r5,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Clear translation
mr. r4,r4
beq- EXT(fake_set_interrupts_enabled)
mfmsr r5 ; Get the current MSR
+ rlwinm r5,r5,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
mr r4,r3 ; Save the old value
+ rlwinm r5,r5,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r3,r5,17,31,31 ; Set return value
rlwimi r5,r4,15,16,16 ; Insert new EE bit
andi. r8,r5,lo16(MASK(MSR_EE)) ; Interruptions
CheckPreemption:
lwz r8,PP_NEED_AST(r7)
- lwz r7,PP_CPU_DATA(r7)
li r6,AST_URGENT
lwz r8,0(r8)
- lwz r7,CPU_PREEMPTION_LEVEL(r7)
+ lwz r7,PP_PREEMPT_CNT(r7)
lis r0,HIGH_ADDR(DoPreemptCall)
and. r8,r8,r6
ori r0,r0,LOW_ADDR(DoPreemptCall)
- beq+ NoPreemption
+ beq+ NoPreemption
cmpi cr0, r7, 0
- bne+ NoPreemption
- sc
- mtmsr r5
+ mtmsr r5 ; Restore the MSR now, before we can preempt
+ bnelr+ ; Return if no premption
+ sc ; Preempt
blr
LEXT(machine_idle_ppc)
mfmsr r3 ; Get the current MSR
+ rlwinm r3,r3,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r3,r3,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r5,r3,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
mtmsr r5 ; Hold up interruptions for now
+ isync ; May have messed with fp/vec
mfsprg r12,0 ; Get the per_proc_info
mfspr r6,hid0 ; Get the current power-saving mode
mfsprg r11,2 ; Get CPU specific features
bne- yesnap ; Yeah, need to get it again...
stw r8,napStamp(r12) ; Set high order time stamp
stw r7,napStamp+4(r12) ; Set low order nap stamp
-
- bf pfL1nncb,minoflushl1 ; The L1 is coherent in nap/doze...
-;
-; 7450 does not keep L1 cache coherent across nap/sleep it must alwasy flush.
-; It does not have a L1 flush assist, so we do not test for it here.
-;
-; Note that the time stamp take above is not completely accurate for 7450
-; because we are about to flush the L1 cache and that takes a bit of time.
-;
- cror cr0_eq,pfL1ib,pfL1db ; Check for either I- or D-cache
- bf- cr0_eq,minoflushl1 ; No level 1 to flush...
- rlwinm. r0,r4,0,ice,dce ; Were either of the level 1s on?
- beq- minoflushl1 ; No, no need to flush...
-miswdl1: lwz r0,pfl1dSize(r12) ; Get the level 1 cache size
- rlwinm r2,r0,0,1,30 ; Double it
- add r0,r0,r2 ; Get 3 times cache size
- rlwinm r2,r5,0,MSR_DR_BIT+1,MSR_DR_BIT-1 ; Turn off data translation
- rlwinm r0,r0,26,6,31 ; Get 3/2 number of cache lines
- lis r3,0xFFF0 ; Dead recon ROM address for now
- mtctr r0 ; Number of lines to flush
- mtmsr r2 ; Do it
- isync
+ rlwinm. r7,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before nap?
+ beq miL2PFok
-miswfldl1a: lwz r2,0(r3) ; Flush anything else
- addi r3,r3,32 ; Next line
- bdnz miswfldl1a ; Flush the lot...
-
-miinvdl1: sync ; Make sure all flushes have been committed
- mtmsr r5 ; Put back data translation
+ mfspr r7,msscr0 ; Get currect MSSCR0 value
+ rlwinm r7,r7,0,0,l2pfes-1 ; Dissable L2 Prefetch
+ mtspr msscr0,r7 ; Updates MSSCR0 value
+ sync
isync
- mfspr r8,hid0 ; Get the HID0 bits
- li r7,lo16(icem|dcem) ; Get the cache enable bits
- andc r8,r8,r7 ; Clear cache enables
- mtspr hid0,r8 ; and turn off L1 cache
- sync ; Make sure all is done
-
- ori r8,r8,lo16(icfim|dcfim) ; Set the HID0 bits for invalidate
- sync
- isync
-
- mtspr hid0,r8 ; Start the invalidate
- sync
-
-minoflushl1:
-
+miL2PFok:
+ rlwinm. r7,r11,0,pfSlowNapb,pfSlowNapb ; Should nap at slow speed?
+ beq minoslownap
+
+ mfspr r7,hid1 ; Get current HID1 value
+ oris r7,r7,hi16(hid1psm) ; Select PLL1
+ mtspr hid1,r7 ; Update HID1 value
+
+minoslownap:
+
;
; We have to open up interruptions here because book 4 says that we should
; turn on only the POW bit and that we should have interrupts enabled
mtmsr r5 ; No talking
isync
-; No interrupts allowed after we get the savearea
-
- mfsprg r6,0 ; Get the per_proc
- mfsprg r7,1 ; Get the pending savearea
- stw r7,savedSave(r6) ; Save the savearea for when we wake up
-
deadsleep: addi r3,r3,1 ; Make analyzer happy
addi r3,r3,1
addi r3,r3,1
b deadsleep ; Die the death of 1000 joys...
#endif
- mfsprg r12,0 ; Get the per_proc_info
mfspr r4,hid0 ; Get the current power-saving mode
eqv r10,r10,r10 ; Get all foxes
mfsprg r11,2 ; Get CPU specific features
+
+ rlwinm. r5,r11,0,pfNoL2PFNapb,pfNoL2PFNapb ; Turn off L2 Prefetch before sleep?
+ beq mpsL2PFok
+
+ mfspr r5,msscr0 ; Get currect MSSCR0 value
+ rlwinm r5,r5,0,0,l2pfes-1 ; Dissable L2 Prefetch
+ mtspr msscr0,r5 ; Updates MSSCR0 value
+ sync
+ isync
+
+mpsL2PFok:
mfmsr r5 ; Get the current MSR
rlwinm r10,r10,0,1,31 ; Make 0x7FFFFFFF
rlwinm r4,r4,0,sleep+1,doze-1 ; Clear all possible power-saving modes (not DPM though)
mtmsr r5 ; Interruptions back off
isync ; Toss prefetch
- mfsprg r7,1 ; Get the pending savearea
- stw r7,savedSave(r12) ; Save the savearea for when we wake up
-
;
; We are here with translation off, interrupts off, all possible
; interruptions drained off, and a decrimenter that will not pop.
mfsprg r11,2 ; Get CPU specific features
mfmsr r7 ; Get the current MSR
rlwinm r4,r9,0,dpm+1,doze-1 ; Clear all possible power-saving modes (also disable DPM)
+ rlwinm r7,r7,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r7,r7,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwimi r11,r11,pfLClckb+1,31,31 ; Move pfLClck to another position (to keep from using non-volatile CRs)
rlwinm r5,r7,0,MSR_DR_BIT+1,MSR_IR_BIT-1 ; Turn off translation
rlwinm r5,r5,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
mfspr r8,l2cr ; Get the L2CR
lwz r3,pfl2cr(r12) ; Get the L2CR value
+ rlwinm. r0,r8,0,l2e,l2e ; Was the L2 enabled?
+ bne ciflushl2 ; Yes, force flush
+ cmplwi r8, 0 ; Was the L2 all the way off?
+ beq ciinvdl2 ; Yes, force invalidate
lis r0,hi16(l2sizm|l2clkm|l2ramm|l2ohm) ; Get confiuration bits
xor r2,r8,r3 ; Get changing bits?
ori r0,r0,lo16(l2slm|l2dfm|l2bypm) ; More config bits
and. r0,r0,r2 ; Did any change?
bne- ciinvdl2 ; Yes, just invalidate and get PLL synced...
+ciflushl2:
bf pfL2fab,ciswfl2 ; Flush not in hardware...
- mr r10,r3 ; Take a copy now
+ mr r10,r8 ; Take a copy now
bf 31,cinol2lck ; Skip if pfLClck not set...
ciswfl2:
lwz r0,pfl2Size(r12) ; Get the L2 size
- oris r2,r3,hi16(l2dom) ; Set L2 to data only mode
+ oris r2,r8,hi16(l2dom) ; Set L2 to data only mode
b ciswfl2doa ; Branch to next line...
addi r10,r10,32 ; Next line
bdnz ciswfldl2a ; Do the lot...
-ciinvdl2: rlwinm r3,r3,0,l2e+1,31 ; Clear the enable bit
+ciinvdl2: rlwinm r8,r3,0,l2e+1,31 ; Use the saved L2CR and clear the enable bit
b cinla ; Branch to next line...
.align 5
-cinlc: mtspr l2cr,r3 ; Disable L2
+cinlc: mtspr l2cr,r8 ; Disable L2
sync
isync
b ciinvl2 ; It is off, go invalidate it...
ciinvl2: sync
isync
- oris r2,r3,hi16(l2im) ; Get the invalidate flag set
+
+ cmplwi r3, 0 ; Should the L2 be all the way off?
+ beq cinol2 ; Yes, done with L2
+
+ oris r2,r8,hi16(l2im) ; Get the invalidate flag set
mtspr l2cr,r2 ; Start the invalidate
sync
rlwinm. r2,r2,0,l2ip,l2ip ; Is the invalidate still going?
bne+ ciinvdl2a ; Assume so, this will take a looong time...
sync
- mtspr l2cr,r3 ; Turn off the invalidate request
+ mtspr l2cr,r8 ; Turn off the invalidate request
cinol2:
mfspr r8,l3cr ; Get the L3CR
lwz r3,pfl3cr(r12) ; Get the L3CR value
+ rlwinm. r0,r8,0,l3e,l3e ; Was the L3 enabled?
+ bne ciflushl3 ; Yes, force flush
+ cmplwi r8, 0 ; Was the L3 all the way off?
+ beq ciinvdl3 ; Yes, force invalidate
lis r0,hi16(l3pem|l3sizm|l3dxm|l3clkm|l3spom|l3ckspm) ; Get configuration bits
xor r2,r8,r3 ; Get changing bits?
ori r0,r0,lo16(l3pspm|l3repm|l3rtm|l3cyam|l3dmemm|l3dmsizm) ; More config bits
and. r0,r0,r2 ; Did any change?
bne- ciinvdl3 ; Yes, just invalidate and get PLL synced...
+ciflushl3:
sync ; 7450 book says do this even though not needed
- mr r10,r3 ; Take a copy now
+ mr r10,r8 ; Take a copy now
bf 31,cinol3lck ; Skip if pfL23lck not set...
rlwinm. r10,r10,0,l3hwf,l3hwf ; Is the flush over?
bne+ cihwfl3 ; Nope, keep going...
-ciinvdl3: rlwinm r3,r3,0,l3e+1,31 ; Clear the enable bit
+ciinvdl3: rlwinm r8,r3,0,l3e+1,31 ; Use saved L3CR value and clear the enable bit
sync ; Make sure of life, liberty, and justice
- mtspr l3cr,r3 ; Disable L3
+ mtspr l3cr,r8 ; Disable L3
sync
- ori r3,r3,lo16(l3im) ; Get the invalidate flag set
+ cmplwi r3, 0 ; Should the L3 be all the way off?
+ beq cinol3 ; Yes, done with L3
+
+ ori r8,r8,lo16(l3im) ; Get the invalidate flag set
- mtspr l3cr,r3 ; Start the invalidate
+ mtspr l3cr,r8 ; Start the invalidate
-ciinvdl3b: mfspr r3,l3cr ; Get the L3CR
- rlwinm. r3,r3,0,l3i,l3i ; Is the invalidate still going?
+ciinvdl3b: mfspr r8,l3cr ; Get the L3CR
+ rlwinm. r8,r8,0,l3i,l3i ; Is the invalidate still going?
bne+ ciinvdl3b ; Assume so...
sync
- mfspr r3,l3pdet ; ?
- rlwimi r3,r3,28,0,23 ; ?
- oris r3,r3,0xF000 ; ?
- ori r3,r3,0x0080 ; ?
- mtspr l3pdet,r3 ; ?
+ lwz r10, pfBootConfig(r12) ; ?
+ rlwinm. r10, r10, 24, 28, 31 ; ?
+ beq ciinvdl3nopdet ; ?
+
+ mfspr r8,l3pdet ; ?
+ srw r2, r8, r10 ; ?
+ rlwimi r2, r8, 0, 24, 31 ; ?
+ subfic r10, r10, 32 ; ?
+ li r8, -1 ; ?
+ ori r2, r2, 0x0080 ; ?
+ slw r8, r8, r10 ; ?
+ or r8, r2, r8 ; ?
+ mtspr l3pdet, r8 ; ?
isync
- mfspr r3,l3cr ; Get the L3CR
- rlwinm r3,r3,0,l3clken+1,l3clken-1 ; Clear the clock enable bit
- mtspr l3cr,r3 ; Disable the clock
+ciinvdl3nopdet:
+ mfspr r8,l3cr ; Get the L3CR
+ rlwinm r8,r8,0,l3clken+1,l3clken-1 ; Clear the clock enable bit
+ mtspr l3cr,r8 ; Disable the clock
li r2,128 ; ?
ciinvdl3c: addi r2,r2,-1 ; ?
mtspr msssr0,r10 ; ?
sync
- oris r3,r3,hi16(l3em|l3clkenm) ; Turn on enable bit
- mtspr l3cr,r3 ; Enable it
+ mtspr l3cr,r3 ; Enable it as desired
sync
cinol3:
bf pfL2b,cinol2a ; No level 2 cache to enable
lwz r3,pfl2cr(r12) ; Get the L2CR value
- oris r3,r3,hi16(l2em) ; Turn on enable bit
- mtspr l2cr,r3 ; Enable it
+ cmplwi r3, 0 ; Should the L2 be all the way off?
+ beq cinol2a : Yes, done with L2
+ mtspr l2cr,r3 ; Enable it as desired
sync
;
LEXT(ml_thrm_set)
mfmsr r0 ; Get the MSR
+ rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r6,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear EE bit
mtmsr r6
+ isync
mfsprg r12,0 ; Get the per_proc blok
LEXT(ml_read_temp)
mfmsr r9 ; Save the MSR
- rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
li r5,15 ; Starting point for ranging (start at 15 so we do not overflow)
+ rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
+ rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
mfsprg r7,2 ; Get CPU specific features
mtmsr r8 ; Do not allow interruptions
mtcrf 0x40,r7 ; See if we can thermal this machine
LEXT(ml_throttle)
mfmsr r9 ; Save the MSR
+ rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
rlwinm r8,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Turn off interruptions
cmplwi r3,lo16(ictcfim>>1) ; See if we are going too far
- mtmsr r8 ; Do not allow interruptions
+ mtmsr r8 ; Do not allow interruptions
+ isync
ble+ throtok ; Throttle value is ok...
li r3,lo16(ictcfim>>1) ; Set max
blr
+/*
+ * The routine that implements cpu_number.
+ */
+
+ .align 5
+ .globl EXT(cpu_number)
+
+LEXT(cpu_number)
+
+ mfmsr r9 /* Save the old MSR */
+ rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off
+ rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off
+ rlwinm r8,r9,0,17,15 /* Clear interruptions */
+ mtmsr r8 /* Interrupts off */
+ isync
+ mfsprg r7,0 /* Get per-proc block */
+ lhz r3,PP_CPU_NUMBER(r7) /* Get CPU number */
+ mtmsr r9 /* Restore interruptions to entry */
+ blr /* Return... */
+
/*
** ml_sense_nmi()
**
blr ; Leave...
+/*
+** ml_set_processor_speed()
+**
+*/
+; Force a line boundry here
+ .align 5
+ .globl EXT(ml_set_processor_speed)
+
+LEXT(ml_set_processor_speed)
+ mfsprg r5, 0 ; Get the per_proc_info
+
+ cmpli cr0, r3, 0 ; Turn off BTIC before low speed
+ beq sps1
+ mfspr r4, hid0 ; Get the current hid0 value
+ rlwinm r4, r4, 0, btic+1, btic-1 ; Clear the BTIC bit
+ sync
+ mtspr hid0, r4 ; Set the new hid0 value
+ isync
+ sync
+
+sps1:
+ mfspr r4, hid1 ; Get the current PLL settings
+ rlwimi r4, r3, 31-hid1ps, hid1ps, hid1ps ; Copy the PLL Select bit
+ stw r4, pfHID1(r5) ; Save the new hid1 value
+ mtspr hid1, r4 ; Select desired PLL
+
+ cmpli cr0, r3, 0 ; Restore BTIC after high speed
+ bne sps2
+ lwz r4, pfHID0(r5) ; Load the hid0 value
+ sync
+ mtspr hid0, r4 ; Set the hid0 value
+ isync
+ sync
+
+sps2:
+ blr
+
+/*
+** ml_set_processor_voltage()
+**
+*/
+; Force a line boundry here
+ .align 5
+ .globl EXT(ml_set_processor_voltage)
+
+LEXT(ml_set_processor_voltage)
+ mfspr r4, hid2 ; Get HID2 value
+ rlwimi r4, r3, 31-hid2vmin, hid2vmin, hid2vmin ; Insert the voltage mode bit
+ mtspr hid2, r4 ; Set the voltage mode
+ sync ; Make sure it is done
+ blr