296 lines
6.3 KiB
ArmAsm
296 lines
6.3 KiB
ArmAsm
/*
|
|
* arch/ppc/boot/common/util.S
|
|
*
|
|
* Useful bootup functions, which are more easily done in asm than C.
|
|
*
|
|
* NOTE: Be very very careful about the registers you use here.
|
|
* We don't follow any ABI calling convention among the
|
|
* assembler functions that call each other, especially early
|
|
* in the initialization. Please preserve at least r3 and r4
|
|
* for these early functions, as they often contain information
|
|
* passed from boot roms into the C decompress function.
|
|
*
|
|
* Author: Tom Rini
|
|
* trini@mvista.com
|
|
* Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
|
|
*
|
|
* 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
|
|
* the terms of the GNU General Public License version 2. This program
|
|
* is licensed "as is" without any warranty of any kind, whether express
|
|
* or implied.
|
|
*/
|
|
|
|
#include <asm/processor.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/ppc_asm.h>
|
|
|
|
|
|
.text
|
|
|
|
#ifdef CONFIG_6xx
|
|
.globl disable_6xx_mmu
|
|
disable_6xx_mmu:
|
|
/* Establish default MSR value, exception prefix 0xFFF.
|
|
* If necessary, this function must fix up the LR if we
|
|
* return to a different address space once the MMU is
|
|
* disabled.
|
|
*/
|
|
li r8,MSR_IP|MSR_FP
|
|
mtmsr r8
|
|
isync
|
|
|
|
/* Test for a 601 */
|
|
mfpvr r10
|
|
srwi r10,r10,16
|
|
cmpwi 0,r10,1 /* 601 ? */
|
|
beq .clearbats_601
|
|
|
|
/* Clear BATs */
|
|
li r8,0
|
|
mtspr SPRN_DBAT0U,r8
|
|
mtspr SPRN_DBAT0L,r8
|
|
mtspr SPRN_DBAT1U,r8
|
|
mtspr SPRN_DBAT1L,r8
|
|
mtspr SPRN_DBAT2U,r8
|
|
mtspr SPRN_DBAT2L,r8
|
|
mtspr SPRN_DBAT3U,r8
|
|
mtspr SPRN_DBAT3L,r8
|
|
.clearbats_601:
|
|
mtspr SPRN_IBAT0U,r8
|
|
mtspr SPRN_IBAT0L,r8
|
|
mtspr SPRN_IBAT1U,r8
|
|
mtspr SPRN_IBAT1L,r8
|
|
mtspr SPRN_IBAT2U,r8
|
|
mtspr SPRN_IBAT2L,r8
|
|
mtspr SPRN_IBAT3U,r8
|
|
mtspr SPRN_IBAT3L,r8
|
|
isync
|
|
sync
|
|
sync
|
|
|
|
/* Set segment registers */
|
|
li r8,16 /* load up segment register values */
|
|
mtctr r8 /* for context 0 */
|
|
lis r8,0x2000 /* Ku = 1, VSID = 0 */
|
|
li r10,0
|
|
3: mtsrin r8,r10
|
|
addi r8,r8,0x111 /* increment VSID */
|
|
addis r10,r10,0x1000 /* address of next segment */
|
|
bdnz 3b
|
|
blr
|
|
|
|
.globl disable_6xx_l1cache
|
|
disable_6xx_l1cache:
|
|
/* Enable, invalidate and then disable the L1 icache/dcache. */
|
|
li r8,0
|
|
ori r8,r8,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
|
|
mfspr r11,SPRN_HID0
|
|
or r11,r11,r8
|
|
andc r10,r11,r8
|
|
isync
|
|
mtspr SPRN_HID0,r8
|
|
sync
|
|
isync
|
|
mtspr SPRN_HID0,r10
|
|
sync
|
|
isync
|
|
blr
|
|
#endif
|
|
|
|
.globl _setup_L2CR
|
|
_setup_L2CR:
|
|
/*
|
|
* We should be skipping this section on CPUs where this results in an
|
|
* illegal instruction. If not, please send trini@kernel.crashing.org
|
|
* the PVR of your CPU.
|
|
*/
|
|
/* Invalidate/disable L2 cache */
|
|
sync
|
|
isync
|
|
mfspr r8,SPRN_L2CR
|
|
rlwinm r8,r8,0,1,31
|
|
oris r8,r8,L2CR_L2I@h
|
|
sync
|
|
isync
|
|
mtspr SPRN_L2CR,r8
|
|
sync
|
|
isync
|
|
|
|
/* Wait for the invalidation to complete */
|
|
mfspr r8,SPRN_PVR
|
|
srwi r8,r8,16
|
|
cmplwi cr0,r8,0x8000 /* 7450 */
|
|
cmplwi cr1,r8,0x8001 /* 7455 */
|
|
cmplwi cr2,r8,0x8002 /* 7457 */
|
|
cror 4*cr0+eq,4*cr0+eq,4*cr1+eq /* Now test if any are true. */
|
|
cror 4*cr0+eq,4*cr0+eq,4*cr2+eq
|
|
bne 2f
|
|
|
|
1: mfspr r8,SPRN_L2CR /* On 745x, poll L2I bit (bit 10) */
|
|
rlwinm. r9,r8,0,10,10
|
|
bne 1b
|
|
b 3f
|
|
|
|
2: mfspr r8,SPRN_L2CR /* On 75x & 74[01]0, poll L2IP bit (bit 31) */
|
|
rlwinm. r9,r8,0,31,31
|
|
bne 2b
|
|
|
|
3: rlwinm r8,r8,0,11,9 /* Turn off L2I bit */
|
|
sync
|
|
isync
|
|
mtspr SPRN_L2CR,r8
|
|
sync
|
|
isync
|
|
blr
|
|
|
|
.globl _setup_L3CR
|
|
_setup_L3CR:
|
|
/* Invalidate/disable L3 cache */
|
|
sync
|
|
isync
|
|
mfspr r8,SPRN_L3CR
|
|
rlwinm r8,r8,0,1,31
|
|
ori r8,r8,L3CR_L3I@l
|
|
sync
|
|
isync
|
|
mtspr SPRN_L3CR,r8
|
|
sync
|
|
isync
|
|
|
|
/* Wait for the invalidation to complete */
|
|
1: mfspr r8,SPRN_L3CR
|
|
rlwinm. r9,r8,0,21,21
|
|
bne 1b
|
|
|
|
rlwinm r8,r8,0,22,20 /* Turn off L3I bit */
|
|
sync
|
|
isync
|
|
mtspr SPRN_L3CR,r8
|
|
sync
|
|
isync
|
|
blr
|
|
|
|
|
|
/* udelay (on non-601 processors) needs to know the period of the
|
|
* timebase in nanoseconds. This used to be hardcoded to be 60ns
|
|
* (period of 66MHz/4). Now a variable is used that is initialized to
|
|
* 60 for backward compatibility, but it can be overridden as necessary
|
|
* with code something like this:
|
|
* extern unsigned long timebase_period_ns;
|
|
* timebase_period_ns = 1000000000 / bd->bi_tbfreq;
|
|
*/
|
|
.data
|
|
.globl timebase_period_ns
|
|
timebase_period_ns:
|
|
.long 60
|
|
|
|
.text
|
|
/*
|
|
* Delay for a number of microseconds
|
|
*/
|
|
.globl udelay
|
|
udelay:
|
|
mfspr r4,SPRN_PVR
|
|
srwi r4,r4,16
|
|
cmpwi 0,r4,1 /* 601 ? */
|
|
bne .udelay_not_601
|
|
00: li r0,86 /* Instructions / microsecond? */
|
|
mtctr r0
|
|
10: addi r0,r0,0 /* NOP */
|
|
bdnz 10b
|
|
subic. r3,r3,1
|
|
bne 00b
|
|
blr
|
|
|
|
.udelay_not_601:
|
|
mulli r4,r3,1000 /* nanoseconds */
|
|
/* Change r4 to be the number of ticks using:
|
|
* (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
|
|
* timebase_period_ns defaults to 60 (16.6MHz) */
|
|
lis r5,timebase_period_ns@ha
|
|
lwz r5,timebase_period_ns@l(r5)
|
|
add r4,r4,r5
|
|
addi r4,r4,-1
|
|
divw r4,r4,r5 /* BUS ticks */
|
|
1: mftbu r5
|
|
mftb r6
|
|
mftbu r7
|
|
cmpw 0,r5,r7
|
|
bne 1b /* Get [synced] base time */
|
|
addc r9,r6,r4 /* Compute end time */
|
|
addze r8,r5
|
|
2: mftbu r5
|
|
cmpw 0,r5,r8
|
|
blt 2b
|
|
bgt 3f
|
|
mftb r6
|
|
cmpw 0,r6,r9
|
|
blt 2b
|
|
3: blr
|
|
|
|
.section ".relocate_code","xa"
|
|
/*
|
|
* Flush and enable instruction cache
|
|
* First, flush the data cache in case it was enabled and may be
|
|
* holding instructions for copy back.
|
|
*/
|
|
.globl flush_instruction_cache
|
|
flush_instruction_cache:
|
|
mflr r6
|
|
bl flush_data_cache
|
|
|
|
#ifdef CONFIG_8xx
|
|
lis r3, IDC_INVALL@h
|
|
mtspr SPRN_IC_CST, r3
|
|
lis r3, IDC_ENABLE@h
|
|
mtspr SPRN_IC_CST, r3
|
|
lis r3, IDC_DISABLE@h
|
|
mtspr SPRN_DC_CST, r3
|
|
#elif CONFIG_4xx
|
|
lis r3,start@h # r9 = &_start
|
|
lis r4,_etext@ha
|
|
addi r4,r4,_etext@l # r8 = &_etext
|
|
1: dcbf r0,r3 # Flush the data cache
|
|
icbi r0,r3 # Invalidate the instruction cache
|
|
addi r3,r3,0x10 # Increment by one cache line
|
|
cmplw cr0,r3,r4 # Are we at the end yet?
|
|
blt 1b # No, keep flushing and invalidating
|
|
#else
|
|
/* Enable, invalidate and then disable the L1 icache/dcache. */
|
|
li r3,0
|
|
ori r3,r3,(HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
|
|
mfspr r4,SPRN_HID0
|
|
or r5,r4,r3
|
|
isync
|
|
mtspr SPRN_HID0,r5
|
|
sync
|
|
isync
|
|
ori r5,r4,HID0_ICE /* Enable cache */
|
|
mtspr SPRN_HID0,r5
|
|
sync
|
|
isync
|
|
#endif
|
|
mtlr r6
|
|
blr
|
|
|
|
#define NUM_CACHE_LINES 128*8
|
|
#define cache_flush_buffer 0x1000
|
|
|
|
/*
|
|
* Flush data cache
|
|
* Do this by just reading lots of stuff into the cache.
|
|
*/
|
|
.globl flush_data_cache
|
|
flush_data_cache:
|
|
lis r3,cache_flush_buffer@h
|
|
ori r3,r3,cache_flush_buffer@l
|
|
li r4,NUM_CACHE_LINES
|
|
mtctr r4
|
|
00: lwz r4,0(r3)
|
|
addi r3,r3,L1_CACHE_BYTES /* Next line, please */
|
|
bdnz 00b
|
|
10: blr
|
|
|
|
.previous
|
|
|