| #include <config.h> |
| #include <mpc86xx.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_dcache) |
| 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) |
| mflr r4 |
| bl invalidate_l1_instruction_cache /* uses r3 */ |
| sync |
| mtlr r4 |
| 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 CONFIG_SYS_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_dcache and l2cache_disable_no_flush. |
| * LR saved in r4 |
| */ |
| _GLOBAL(dcache_disable) |
| mflr r4 /* save link register */ |
| bl flush_dcache /* 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 CONFIG_SYS_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_dcache. LR is saved in r4 |
| */ |
| _GLOBAL(l2cache_disable) |
| mflr r4 /* save link register */ |
| bl flush_dcache /* 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 |