| /* | |
| * This file is subject to the terms and conditions of the GNU General Public | |
| * License. See the file "COPYING" in the main directory of this archive | |
| * for more details. | |
| * | |
| * Copyright (C) 2005 Embedded Alley Solutions, Inc | |
| */ | |
| #ifndef __ASM_MACH_KERNEL_ENTRY_INIT_H | |
| #define __ASM_MACH_KERNEL_ENTRY_INIT_H | |
| #include <asm/cacheops.h> | |
| #include <asm/addrspace.h> | |
| #define CO_CONFIGPR_VALID 0x3F1F41FF /* valid bits to write to ConfigPR */ | |
| #define HAZARD_CP0 nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; | |
| #define CACHE_OPC 0xBC000000 /* MIPS cache instruction opcode */ | |
| #define ICACHE_LINE_SIZE 32 /* Instruction cache line size bytes */ | |
| #define DCACHE_LINE_SIZE 32 /* Data cache line size in bytes */ | |
| #define ICACHE_SET_COUNT 256 /* Instruction cache set count */ | |
| #define DCACHE_SET_COUNT 128 /* Data cache set count */ | |
| #define ICACHE_SET_SIZE (ICACHE_SET_COUNT * ICACHE_LINE_SIZE) | |
| #define DCACHE_SET_SIZE (DCACHE_SET_COUNT * DCACHE_LINE_SIZE) | |
| .macro kernel_entry_setup | |
| .set push | |
| .set noreorder | |
| /* | |
| * PNX8550 entry point, when running a non compressed | |
| * kernel. When loading a zImage, the head.S code in | |
| * arch/mips/zboot/pnx8550 will init the caches and, | |
| * decompress the kernel, and branch to kernel_entry. | |
| */ | |
| cache_begin: li t0, (1<<28) | |
| mtc0 t0, CP0_STATUS /* cp0 usable */ | |
| HAZARD_CP0 | |
| mtc0 zero, CP0_CAUSE | |
| HAZARD_CP0 | |
| /* Set static virtual to phys address translation and TLB disabled */ | |
| mfc0 t0, CP0_CONFIG, 7 | |
| HAZARD_CP0 | |
| and t0,~((1<<19) | (1<<20)) /* TLB/MAP cleared */ | |
| mtc0 t0, CP0_CONFIG, 7 | |
| HAZARD_CP0 | |
| /* CPU boots with kseg0 cache algo set to 0x2 -- uncached */ | |
| init_icache | |
| nop | |
| init_dcache | |
| nop | |
| cachePr4450ICReset | |
| nop | |
| cachePr4450DCReset | |
| nop | |
| /* read ConfigPR into t0 */ | |
| mfc0 t0, CP0_CONFIG, 7 | |
| HAZARD_CP0 | |
| /* enable the TLB */ | |
| or t0, (1<<19) | |
| /* disable the ICACHE: at least 10x slower */ | |
| /* or t0, (1<<26) */ | |
| /* disable the DCACHE; CONFIG_CPU_HAS_LLSC should not be set */ | |
| /* or t0, (1<<27) */ | |
| and t0, CO_CONFIGPR_VALID | |
| /* enable TLB. */ | |
| mtc0 t0, CP0_CONFIG, 7 | |
| HAZARD_CP0 | |
| cache_end: | |
| /* Setup CMEM_0 to MMIO address space, 2MB */ | |
| lui t0, 0x1BE0 | |
| addi t0, t0, 0x3 | |
| mtc0 $8, $22, 4 | |
| nop | |
| /* Setup CMEM_1, 128MB */ | |
| lui t0, 0x1000 | |
| addi t0, t0, 0xf | |
| mtc0 $8, $22, 5 | |
| nop | |
| /* Setup CMEM_2, 32MB */ | |
| lui t0, 0x1C00 | |
| addi t0, t0, 0xb | |
| mtc0 $8, $22, 6 | |
| nop | |
| /* Setup CMEM_3, 0MB */ | |
| lui t0, 0x0 | |
| addi t0, t0, 0x0 | |
| mtc0 $8, $22, 7 | |
| nop | |
| /* Enable cache */ | |
| mfc0 t0, CP0_CONFIG | |
| HAZARD_CP0 | |
| and t0, t0, 0xFFFFFFF8 | |
| or t0, t0, 3 | |
| mtc0 t0, CP0_CONFIG | |
| HAZARD_CP0 | |
| .set pop | |
| .endm | |
| .macro init_icache | |
| .set push | |
| .set noreorder | |
| /* Get Cache Configuration */ | |
| mfc0 t3, CP0_CONFIG, 1 | |
| HAZARD_CP0 | |
| /* get cache Line size */ | |
| srl t1, t3, 19 /* C0_CONFIGPR_IL_SHIFT */ | |
| andi t1, t1, 0x7 /* C0_CONFIGPR_IL_MASK */ | |
| beq t1, zero, pr4450_instr_cache_invalidated /* if zero instruction cache is absent */ | |
| nop | |
| addiu t0, t1, 1 | |
| ori t1, zero, 1 | |
| sllv t1, t1, t0 | |
| /* get max cache Index */ | |
| srl t2, t3, 22 /* C0_CONFIGPR_IS_SHIFT */ | |
| andi t2, t2, 0x7 /* C0_CONFIGPR_IS_MASK */ | |
| addiu t0, t2, 6 | |
| ori t2, zero, 1 | |
| sllv t2, t2, t0 | |
| /* get max cache way */ | |
| srl t3, t3, 16 /* C0_CONFIGPR_IA_SHIFT */ | |
| andi t3, t3, 0x7 /* C0_CONFIGPR_IA_MASK */ | |
| addiu t3, t3, 1 | |
| /* total no of cache lines */ | |
| multu t2, t3 /* max index * max way */ | |
| mflo t2 | |
| addiu t2, t2, -1 | |
| move t0, zero | |
| pr4450_next_instruction_cache_set: | |
| cache Index_Invalidate_I, 0(t0) | |
| addu t0, t0, t1 /* add bytes in a line */ | |
| bne t2, zero, pr4450_next_instruction_cache_set | |
| addiu t2, t2, -1 /* reduce no of lines to invalidate by one */ | |
| pr4450_instr_cache_invalidated: | |
| .set pop | |
| .endm | |
| .macro init_dcache | |
| .set push | |
| .set noreorder | |
| move t1, zero | |
| /* Store Tag Information */ | |
| mtc0 zero, CP0_TAGLO, 0 | |
| HAZARD_CP0 | |
| mtc0 zero, CP0_TAGHI, 0 | |
| HAZARD_CP0 | |
| /* Cache size is 16384 = 512 lines x 32 bytes per line */ | |
| or t2, zero, (128*4)-1 /* 512 lines */ | |
| /* Invalidate all lines */ | |
| 2: | |
| cache Index_Store_Tag_D, 0(t1) | |
| addiu t2, t2, -1 | |
| bne t2, zero, 2b | |
| addiu t1, t1, 32 /* 32 bytes in a line */ | |
| .set pop | |
| .endm | |
| .macro cachePr4450ICReset | |
| .set push | |
| .set noreorder | |
| /* Save CP0 status reg on entry; */ | |
| /* disable interrupts during cache reset */ | |
| mfc0 t0, CP0_STATUS /* T0 = interrupt status on entry */ | |
| HAZARD_CP0 | |
| mtc0 zero, CP0_STATUS /* disable CPU interrupts */ | |
| HAZARD_CP0 | |
| or t1, zero, zero /* T1 = starting cache index (0) */ | |
| ori t2, zero, (256 - 1) /* T2 = inst cache set cnt - 1 */ | |
| icache_invd_loop: | |
| /* 9 == register t1 */ | |
| .word (CACHE_OPC | (9 << 21) | (Index_Invalidate_I << 16) | \ | |
| (0 * ICACHE_SET_SIZE)) /* invalidate inst cache WAY0 */ | |
| .word (CACHE_OPC | (9 << 21) | (Index_Invalidate_I << 16) | \ | |
| (1 * ICACHE_SET_SIZE)) /* invalidate inst cache WAY1 */ | |
| addiu t1, t1, ICACHE_LINE_SIZE /* T1 = next cache line index */ | |
| bne t2, zero, icache_invd_loop /* T2 = 0 if all sets invalidated */ | |
| addiu t2, t2, -1 /* decrement T2 set cnt (delay slot) */ | |
| /* Initialize the latches in the instruction cache tag */ | |
| /* that drive the way selection tri-state bus drivers, by doing a */ | |
| /* dummy load while the instruction cache is still disabled. */ | |
| /* TODO: Is this needed ? */ | |
| la t1, KSEG0 /* T1 = cached memory base address */ | |
| lw zero, 0x0000(t1) /* (dummy read of first memory word) */ | |
| mtc0 t0, CP0_STATUS /* restore interrupt status on entry */ | |
| HAZARD_CP0 | |
| .set pop | |
| .endm | |
| .macro cachePr4450DCReset | |
| .set push | |
| .set noreorder | |
| mfc0 t0, CP0_STATUS /* T0 = interrupt status on entry */ | |
| HAZARD_CP0 | |
| mtc0 zero, CP0_STATUS /* disable CPU interrupts */ | |
| HAZARD_CP0 | |
| /* Writeback/invalidate entire data cache sets/ways/lines */ | |
| or t1, zero, zero /* T1 = starting cache index (0) */ | |
| ori t2, zero, (DCACHE_SET_COUNT - 1) /* T2 = data cache set cnt - 1 */ | |
| dcache_wbinvd_loop: | |
| /* 9 == register t1 */ | |
| .word (CACHE_OPC | (9 << 21) | (Index_Writeback_Inv_D << 16) | \ | |
| (0 * DCACHE_SET_SIZE)) /* writeback/invalidate WAY0 */ | |
| .word (CACHE_OPC | (9 << 21) | (Index_Writeback_Inv_D << 16) | \ | |
| (1 * DCACHE_SET_SIZE)) /* writeback/invalidate WAY1 */ | |
| .word (CACHE_OPC | (9 << 21) | (Index_Writeback_Inv_D << 16) | \ | |
| (2 * DCACHE_SET_SIZE)) /* writeback/invalidate WAY2 */ | |
| .word (CACHE_OPC | (9 << 21) | (Index_Writeback_Inv_D << 16) | \ | |
| (3 * DCACHE_SET_SIZE)) /* writeback/invalidate WAY3 */ | |
| addiu t1, t1, DCACHE_LINE_SIZE /* T1 = next data cache line index */ | |
| bne t2, zero, dcache_wbinvd_loop /* T2 = 0 when wbinvd entire cache */ | |
| addiu t2, t2, -1 /* decrement T2 set cnt (delay slot) */ | |
| /* Initialize the latches in the data cache tag that drive the way | |
| selection tri-state bus drivers, by doing a dummy load while the | |
| data cache is still in the disabled mode. TODO: Is this needed ? */ | |
| la t1, KSEG0 /* T1 = cached memory base address */ | |
| lw zero, 0x0000(t1) /* (dummy read of first memory word) */ | |
| mtc0 t0, CP0_STATUS /* restore interrupt status on entry */ | |
| HAZARD_CP0 | |
| .set pop | |
| .endm | |
| #endif /* __ASM_MACH_KERNEL_ENTRY_INIT_H */ |