mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-27 07:01:24 +00:00
f5a2425919
The 7610 and related parts have an L2IP bit in the L2CR that is monitored to signal when the L2 cache invalidate is complete whereas the 7450 and related parts utilize L2I for this purpose. However, the current code does not account for this difference. Additionally the 86xx L2 cache invalidate code used an "andi" instruction where an "andis" instruction should have been used. This patch addresses both of these bugs. Signed-off-by: Travis Wheatley <travis.wheatley@freescale.com> Acked-By: Jon Loeliger <jdl@freescale.com>
374 lines
7.2 KiB
ArmAsm
374 lines
7.2 KiB
ArmAsm
#include <config.h>
|
|
#include <mpc86xx.h>
|
|
#include <version.h>
|
|
|
|
#include <ppc_asm.tmpl>
|
|
#include <ppc_defs.h>
|
|
|
|
#include <asm/cache.h>
|
|
#include <asm/mmu.h>
|
|
|
|
#ifndef CACHE_LINE_SIZE
|
|
# define CACHE_LINE_SIZE L1_CACHE_BYTES
|
|
#endif
|
|
|
|
#if CACHE_LINE_SIZE == 128
|
|
#define LG_CACHE_LINE_SIZE 7
|
|
#elif CACHE_LINE_SIZE == 32
|
|
#define LG_CACHE_LINE_SIZE 5
|
|
#elif CACHE_LINE_SIZE == 16
|
|
#define LG_CACHE_LINE_SIZE 4
|
|
#elif CACHE_LINE_SIZE == 8
|
|
#define LG_CACHE_LINE_SIZE 3
|
|
#else
|
|
# error "Invalid cache line size!"
|
|
#endif
|
|
|
|
/*
|
|
* Most of this code is taken from 74xx_7xx/cache.S
|
|
* and then cleaned up a bit
|
|
*/
|
|
|
|
/*
|
|
* Invalidate L1 instruction cache.
|
|
*/
|
|
_GLOBAL(invalidate_l1_instruction_cache)
|
|
/* use invalidate-all bit in HID0 */
|
|
mfspr r3,HID0
|
|
ori r3,r3,HID0_ICFI
|
|
mtspr HID0,r3
|
|
isync
|
|
blr
|
|
|
|
/*
|
|
* Invalidate L1 data cache.
|
|
*/
|
|
_GLOBAL(invalidate_l1_data_cache)
|
|
mfspr r3,HID0
|
|
ori r3,r3,HID0_DCFI
|
|
mtspr HID0,r3
|
|
isync
|
|
blr
|
|
|
|
/*
|
|
* Flush data cache.
|
|
*/
|
|
_GLOBAL(flush_data_cache)
|
|
lis r3,0
|
|
lis r5,CACHE_LINE_SIZE
|
|
flush:
|
|
cmp 0,1,r3,r5
|
|
bge done
|
|
lwz r5,0(r3)
|
|
lis r5,CACHE_LINE_SIZE
|
|
addi r3,r3,0x4
|
|
b flush
|
|
done:
|
|
blr
|
|
/*
|
|
* Write any modified data cache blocks out to memory
|
|
* and invalidate the corresponding instruction cache blocks.
|
|
* This is a no-op on the 601.
|
|
*
|
|
* flush_icache_range(unsigned long start, unsigned long stop)
|
|
*/
|
|
_GLOBAL(flush_icache_range)
|
|
li r5,CACHE_LINE_SIZE-1
|
|
andc r3,r3,r5
|
|
subf r4,r3,r4
|
|
add r4,r4,r5
|
|
srwi. r4,r4,LG_CACHE_LINE_SIZE
|
|
beqlr
|
|
mtctr r4
|
|
mr r6,r3
|
|
1: dcbst 0,r3
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
sync /* wait for dcbst's to get to ram */
|
|
mtctr r4
|
|
2: icbi 0,r6
|
|
addi r6,r6,CACHE_LINE_SIZE
|
|
bdnz 2b
|
|
sync /* additional sync needed on g4 */
|
|
isync
|
|
blr
|
|
/*
|
|
* Write any modified data cache blocks out to memory.
|
|
* Does not invalidate the corresponding cache lines (especially for
|
|
* any corresponding instruction cache).
|
|
*
|
|
* clean_dcache_range(unsigned long start, unsigned long stop)
|
|
*/
|
|
_GLOBAL(clean_dcache_range)
|
|
li r5,CACHE_LINE_SIZE-1
|
|
andc r3,r3,r5 /* align r3 down to cache line */
|
|
subf r4,r3,r4 /* r4 = offset of stop from start of cache line */
|
|
add r4,r4,r5 /* r4 += cache_line_size-1 */
|
|
srwi. r4,r4,LG_CACHE_LINE_SIZE /* r4 = number of cache lines to flush */
|
|
beqlr /* if r4 == 0 return */
|
|
mtctr r4 /* ctr = r4 */
|
|
|
|
sync
|
|
1: dcbst 0,r3
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
sync /* wait for dcbst's to get to ram */
|
|
blr
|
|
|
|
/*
|
|
* Write any modified data cache blocks out to memory
|
|
* and invalidate the corresponding instruction cache blocks.
|
|
*
|
|
* flush_dcache_range(unsigned long start, unsigned long stop)
|
|
*/
|
|
_GLOBAL(flush_dcache_range)
|
|
li r5,CACHE_LINE_SIZE-1
|
|
andc r3,r3,r5
|
|
subf r4,r3,r4
|
|
add r4,r4,r5
|
|
srwi. r4,r4,LG_CACHE_LINE_SIZE
|
|
beqlr
|
|
mtctr r4
|
|
|
|
sync
|
|
1: dcbf 0,r3
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
sync /* wait for dcbf's to get to ram */
|
|
blr
|
|
|
|
/*
|
|
* Like above, but invalidate the D-cache. This is used by the 8xx
|
|
* to invalidate the cache so the PPC core doesn't get stale data
|
|
* from the CPM (no cache snooping here :-).
|
|
*
|
|
* invalidate_dcache_range(unsigned long start, unsigned long stop)
|
|
*/
|
|
_GLOBAL(invalidate_dcache_range)
|
|
li r5,CACHE_LINE_SIZE-1
|
|
andc r3,r3,r5
|
|
subf r4,r3,r4
|
|
add r4,r4,r5
|
|
srwi. r4,r4,LG_CACHE_LINE_SIZE
|
|
beqlr
|
|
mtctr r4
|
|
|
|
sync
|
|
1: dcbi 0,r3
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
sync /* wait for dcbi's to get to ram */
|
|
blr
|
|
|
|
/*
|
|
* Flush a particular page from the data cache to RAM.
|
|
* Note: this is necessary because the instruction cache does *not*
|
|
* snoop from the data cache.
|
|
*
|
|
* void __flush_page_to_ram(void *page)
|
|
*/
|
|
_GLOBAL(__flush_page_to_ram)
|
|
rlwinm r3,r3,0,0,19 /* Get page base address */
|
|
li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
|
|
mtctr r4
|
|
mr r6,r3
|
|
0: dcbst 0,r3 /* Write line to ram */
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 0b
|
|
sync
|
|
mtctr r4
|
|
1: icbi 0,r6
|
|
addi r6,r6,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
sync
|
|
isync
|
|
blr
|
|
|
|
/*
|
|
* Flush a particular page from the instruction cache.
|
|
* Note: this is necessary because the instruction cache does *not*
|
|
* snoop from the data cache.
|
|
*
|
|
* void __flush_icache_page(void *page)
|
|
*/
|
|
_GLOBAL(__flush_icache_page)
|
|
li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
|
|
mtctr r4
|
|
1: icbi 0,r3
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
sync
|
|
isync
|
|
blr
|
|
|
|
/*
|
|
* Clear a page using the dcbz instruction, which doesn't cause any
|
|
* memory traffic (except to write out any cache lines which get
|
|
* displaced). This only works on cacheable memory.
|
|
*/
|
|
_GLOBAL(clear_page)
|
|
li r0,4096/CACHE_LINE_SIZE
|
|
mtctr r0
|
|
1: dcbz 0,r3
|
|
addi r3,r3,CACHE_LINE_SIZE
|
|
bdnz 1b
|
|
blr
|
|
|
|
/*
|
|
* Enable L1 Instruction cache
|
|
*/
|
|
_GLOBAL(icache_enable)
|
|
mfspr r3, HID0
|
|
li r5, HID0_ICFI|HID0_ILOCK
|
|
andc r3, r3, r5
|
|
ori r3, r3, HID0_ICE
|
|
ori r5, r3, HID0_ICFI
|
|
mtspr HID0, r5
|
|
mtspr HID0, r3
|
|
isync
|
|
blr
|
|
|
|
/*
|
|
* Disable L1 Instruction cache
|
|
*/
|
|
_GLOBAL(icache_disable)
|
|
mfspr r3, HID0
|
|
li r5, 0
|
|
ori r5, r5, HID0_ICE
|
|
andc r3, r3, r5
|
|
mtspr HID0, r3
|
|
isync
|
|
blr
|
|
|
|
/*
|
|
* Is instruction cache enabled?
|
|
*/
|
|
_GLOBAL(icache_status)
|
|
mfspr r3, HID0
|
|
andi. r3, r3, HID0_ICE
|
|
blr
|
|
|
|
|
|
_GLOBAL(l1dcache_enable)
|
|
mfspr r3, HID0
|
|
li r5, HID0_DCFI|HID0_DLOCK
|
|
andc r3, r3, r5
|
|
mtspr HID0, r3 /* no invalidate, unlock */
|
|
ori r3, r3, HID0_DCE
|
|
ori r5, r3, HID0_DCFI
|
|
mtspr HID0, r5 /* enable + invalidate */
|
|
mtspr HID0, r3 /* enable */
|
|
sync
|
|
blr
|
|
|
|
/*
|
|
* Enable data cache(s) - L1 and optionally L2
|
|
* Calls l2cache_enable. LR saved in r5
|
|
*/
|
|
_GLOBAL(dcache_enable)
|
|
mfspr r3, HID0
|
|
li r5, HID0_DCFI|HID0_DLOCK
|
|
andc r3, r3, r5
|
|
mtspr HID0, r3 /* no invalidate, unlock */
|
|
ori r3, r3, HID0_DCE
|
|
ori r5, r3, HID0_DCFI
|
|
mtspr HID0, r5 /* enable + invalidate */
|
|
mtspr HID0, r3 /* enable */
|
|
sync
|
|
#ifdef CFG_L2
|
|
mflr r5
|
|
bl l2cache_enable /* uses r3 and r4 */
|
|
sync
|
|
mtlr r5
|
|
#endif
|
|
blr
|
|
|
|
|
|
/*
|
|
* Disable data cache(s) - L1 and optionally L2
|
|
* Calls flush_data_cache and l2cache_disable_no_flush.
|
|
* LR saved in r4
|
|
*/
|
|
_GLOBAL(dcache_disable)
|
|
mflr r4 /* save link register */
|
|
bl flush_data_cache /* uses r3 and r5 */
|
|
sync
|
|
mfspr r3, HID0
|
|
li r5, HID0_DCFI|HID0_DLOCK
|
|
andc r3, r3, r5
|
|
mtspr HID0, r3 /* no invalidate, unlock */
|
|
li r5, HID0_DCE|HID0_DCFI
|
|
andc r3, r3, r5 /* no enable, no invalidate */
|
|
mtspr HID0, r3
|
|
sync
|
|
#ifdef CFG_L2
|
|
bl l2cache_disable_no_flush /* uses r3 */
|
|
#endif
|
|
mtlr r4 /* restore link register */
|
|
blr
|
|
|
|
/*
|
|
* Is data cache enabled?
|
|
*/
|
|
_GLOBAL(dcache_status)
|
|
mfspr r3, HID0
|
|
andi. r3, r3, HID0_DCE
|
|
blr
|
|
|
|
/*
|
|
* Invalidate L2 cache using L2I, assume L2 is enabled
|
|
*/
|
|
_GLOBAL(l2cache_invalidate)
|
|
mfspr r3, l2cr
|
|
rlwinm. r3, r3, 0, 0, 0
|
|
beq 1f
|
|
|
|
mfspr r3, l2cr
|
|
rlwinm r3, r3, 0, 1, 31
|
|
|
|
#ifdef CONFIG_ALTIVEC
|
|
dssall
|
|
#endif
|
|
sync
|
|
mtspr l2cr, r3
|
|
sync
|
|
1: mfspr r3, l2cr
|
|
oris r3, r3, L2CR_L2I@h
|
|
mtspr l2cr, r3
|
|
|
|
invl2:
|
|
mfspr r3, l2cr
|
|
andis. r3, r3, L2CR_L2I@h
|
|
bne invl2
|
|
blr
|
|
|
|
/*
|
|
* Enable L2 cache
|
|
* Calls l2cache_invalidate. LR is saved in r4
|
|
*/
|
|
_GLOBAL(l2cache_enable)
|
|
mflr r4 /* save link register */
|
|
bl l2cache_invalidate /* uses r3 */
|
|
sync
|
|
lis r3, L2_ENABLE@h
|
|
ori r3, r3, L2_ENABLE@l
|
|
mtspr l2cr, r3
|
|
isync
|
|
mtlr r4 /* restore link register */
|
|
blr
|
|
|
|
/*
|
|
* Disable L2 cache
|
|
* Calls flush_data_cache. LR is saved in r4
|
|
*/
|
|
_GLOBAL(l2cache_disable)
|
|
mflr r4 /* save link register */
|
|
bl flush_data_cache /* uses r3 and r5 */
|
|
sync
|
|
mtlr r4 /* restore link register */
|
|
l2cache_disable_no_flush: /* provide way to disable L2 w/o flushing */
|
|
lis r3, L2_INIT@h
|
|
ori r3, r3, L2_INIT@l
|
|
mtspr l2cr, r3
|
|
isync
|
|
blr
|