| /* | |
| * 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-2008 Cavium Networks, Inc | |
| */ | |
| #ifndef __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H | |
| #define __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H | |
| #define CP0_CVMCTL_REG $9, 7 | |
| #define CP0_CVMMEMCTL_REG $11,7 | |
| #define CP0_PRID_REG $15, 0 | |
| #define CP0_DCACHE_ERR_REG $27, 1 | |
| #define CP0_PRID_OCTEON_PASS1 0x000d0000 | |
| #define CP0_PRID_OCTEON_CN30XX 0x000d0200 | |
| .macro kernel_entry_setup | |
| # Registers set by bootloader: | |
| # (only 32 bits set by bootloader, all addresses are physical | |
| # addresses, and need to have the appropriate memory region set | |
| # by the kernel | |
| # a0 = argc | |
| # a1 = argv (kseg0 compat addr) | |
| # a2 = 1 if init core, zero otherwise | |
| # a3 = address of boot descriptor block | |
| .set push | |
| .set arch=octeon | |
| # Read the cavium mem control register | |
| dmfc0 v0, CP0_CVMMEMCTL_REG | |
| # Clear the lower 6 bits, the CVMSEG size | |
| dins v0, $0, 0, 6 | |
| ori v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE | |
| dmtc0 v0, CP0_CVMMEMCTL_REG # Write the cavium mem control register | |
| dmfc0 v0, CP0_CVMCTL_REG # Read the cavium control register | |
| # Disable unaligned load/store support but leave HW fixup enabled | |
| # Needed for octeon specific memcpy | |
| or v0, v0, 0x5001 | |
| xor v0, v0, 0x1001 | |
| # First clear off CvmCtl[IPPCI] bit and move the performance | |
| # counters interrupt to IRQ 6 | |
| dli v1, ~(7 << 7) | |
| and v0, v0, v1 | |
| ori v0, v0, (6 << 7) | |
| mfc0 v1, CP0_PRID_REG | |
| and t1, v1, 0xfff8 | |
| xor t1, t1, 0x9000 # 63-P1 | |
| beqz t1, 4f | |
| and t1, v1, 0xfff8 | |
| xor t1, t1, 0x9008 # 63-P2 | |
| beqz t1, 4f | |
| and t1, v1, 0xfff8 | |
| xor t1, t1, 0x9100 # 68-P1 | |
| beqz t1, 4f | |
| and t1, v1, 0xff00 | |
| xor t1, t1, 0x9200 # 66-PX | |
| bnez t1, 5f # Skip WAR for others. | |
| and t1, v1, 0x00ff | |
| slti t1, t1, 2 # 66-P1.2 and later good. | |
| beqz t1, 5f | |
| 4: # core-16057 work around | |
| or v0, v0, 0x2000 # Set IPREF bit. | |
| 5: # No core-16057 work around | |
| # Write the cavium control register | |
| dmtc0 v0, CP0_CVMCTL_REG | |
| sync | |
| # Flush dcache after config change | |
| cache 9, 0($0) | |
| # Zero all of CVMSEG to make sure parity is correct | |
| dli v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE | |
| dsll v0, 7 | |
| beqz v0, 2f | |
| 1: dsubu v0, 8 | |
| sd $0, -32768(v0) | |
| bnez v0, 1b | |
| 2: | |
| mfc0 v0, CP0_PRID_REG | |
| bbit0 v0, 15, 1f | |
| # OCTEON II or better have bit 15 set. Clear the error bits. | |
| and t1, v0, 0xff00 | |
| dli v0, 0x9500 | |
| bge t1, v0, 1f # OCTEON III has no DCACHE_ERR_REG COP0 | |
| dli v0, 0x27 | |
| dmtc0 v0, CP0_DCACHE_ERR_REG | |
| 1: | |
| # Get my core id | |
| rdhwr v0, $0 | |
| # Jump the master to kernel_entry | |
| bne a2, zero, octeon_main_processor | |
| nop | |
| #ifdef CONFIG_SMP | |
| # | |
| # All cores other than the master need to wait here for SMP bootstrap | |
| # to begin | |
| # | |
| # This is the variable where the next core to boot os stored | |
| PTR_LA t0, octeon_processor_boot | |
| octeon_spin_wait_boot: | |
| # Get the core id of the next to be booted | |
| LONG_L t1, (t0) | |
| # Keep looping if it isn't me | |
| bne t1, v0, octeon_spin_wait_boot | |
| nop | |
| # Get my GP from the global variable | |
| PTR_LA t0, octeon_processor_gp | |
| LONG_L gp, (t0) | |
| # Get my SP from the global variable | |
| PTR_LA t0, octeon_processor_sp | |
| LONG_L sp, (t0) | |
| # Set the SP global variable to zero so the master knows we've started | |
| LONG_S zero, (t0) | |
| #ifdef __OCTEON__ | |
| syncw | |
| syncw | |
| #else | |
| sync | |
| #endif | |
| # Jump to the normal Linux SMP entry point | |
| j smp_bootstrap | |
| nop | |
| #else /* CONFIG_SMP */ | |
| # | |
| # Someone tried to boot SMP with a non SMP kernel. All extra cores | |
| # will halt here. | |
| # | |
| octeon_wait_forever: | |
| wait | |
| b octeon_wait_forever | |
| nop | |
| #endif /* CONFIG_SMP */ | |
| octeon_main_processor: | |
| .set pop | |
| .endm | |
| /* | |
| * Do SMP slave processor setup necessary before we can safely execute C code. | |
| */ | |
| .macro smp_slave_setup | |
| .endm | |
| #endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */ |