![Kevin Cernekee](/assets/img/avatar_default.png)
Initial commit of BMIPS SMP support code. Smoke-tested on a variety of BMIPS4350, BMIPS4380, and BMIPS5000 platforms. Signed-off-by: Kevin Cernekee <cernekee@gmail.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2977/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
256 lines
5.4 KiB
ArmAsm
256 lines
5.4 KiB
ArmAsm
/*
|
|
* 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) 2011 by Kevin Cernekee (cernekee@gmail.com)
|
|
*
|
|
* Reset/NMI/re-entry vectors for BMIPS processors
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <asm/asm.h>
|
|
#include <asm/asmmacro.h>
|
|
#include <asm/cacheops.h>
|
|
#include <asm/regdef.h>
|
|
#include <asm/mipsregs.h>
|
|
#include <asm/stackframe.h>
|
|
#include <asm/addrspace.h>
|
|
#include <asm/hazards.h>
|
|
#include <asm/bmips.h>
|
|
|
|
.macro BARRIER
|
|
.set mips32
|
|
_ssnop
|
|
_ssnop
|
|
_ssnop
|
|
.set mips0
|
|
.endm
|
|
|
|
__CPUINIT
|
|
|
|
/***********************************************************************
|
|
* Alternate CPU1 startup vector for BMIPS4350
|
|
*
|
|
* On some systems the bootloader has already started CPU1 and configured
|
|
* it to resume execution at 0x8000_0200 (!BEV IV vector) when it is
|
|
* triggered by the SW1 interrupt. If that is the case we try to move
|
|
* it to a more convenient place: BMIPS_WARM_RESTART_VEC @ 0x8000_0380.
|
|
***********************************************************************/
|
|
|
|
LEAF(bmips_smp_movevec)
|
|
la k0, 1f
|
|
li k1, CKSEG1
|
|
or k0, k1
|
|
jr k0
|
|
|
|
1:
|
|
/* clear IV, pending IPIs */
|
|
mtc0 zero, CP0_CAUSE
|
|
|
|
/* re-enable IRQs to wait for SW1 */
|
|
li k0, ST0_IE | ST0_BEV | STATUSF_IP1
|
|
mtc0 k0, CP0_STATUS
|
|
|
|
/* set up CPU1 CBR; move BASE to 0xa000_0000 */
|
|
li k0, 0xff400000
|
|
mtc0 k0, $22, 6
|
|
li k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1
|
|
or k0, k1
|
|
li k1, 0xa0080000
|
|
sw k1, 0(k0)
|
|
|
|
/* wait here for SW1 interrupt from bmips_boot_secondary() */
|
|
wait
|
|
|
|
la k0, bmips_reset_nmi_vec
|
|
li k1, CKSEG1
|
|
or k0, k1
|
|
jr k0
|
|
END(bmips_smp_movevec)
|
|
|
|
/***********************************************************************
|
|
* Reset/NMI vector
|
|
* For BMIPS processors that can relocate their exception vectors, this
|
|
* entire function gets copied to 0x8000_0000.
|
|
***********************************************************************/
|
|
|
|
NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
|
|
.set push
|
|
.set noat
|
|
.align 4
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* if the NMI bit is clear, assume this is a CPU1 reset instead */
|
|
li k1, (1 << 19)
|
|
mfc0 k0, CP0_STATUS
|
|
and k0, k1
|
|
beqz k0, bmips_smp_entry
|
|
|
|
#if defined(CONFIG_CPU_BMIPS5000)
|
|
/* if we're not on core 0, this must be the SMP boot signal */
|
|
li k1, (3 << 25)
|
|
mfc0 k0, $22
|
|
and k0, k1
|
|
bnez k0, bmips_smp_entry
|
|
#endif
|
|
#endif /* CONFIG_SMP */
|
|
|
|
/* nope, it's just a regular NMI */
|
|
SAVE_ALL
|
|
move a0, sp
|
|
|
|
/* clear EXL, ERL, BEV so that TLB refills still work */
|
|
mfc0 k0, CP0_STATUS
|
|
li k1, ST0_ERL | ST0_EXL | ST0_BEV | ST0_IE
|
|
or k0, k1
|
|
xor k0, k1
|
|
mtc0 k0, CP0_STATUS
|
|
BARRIER
|
|
|
|
/* jump to the NMI handler function */
|
|
la k0, nmi_handler
|
|
jr k0
|
|
|
|
RESTORE_ALL
|
|
.set mips3
|
|
eret
|
|
|
|
/***********************************************************************
|
|
* CPU1 reset vector (used for the initial boot only)
|
|
* This is still part of bmips_reset_nmi_vec().
|
|
***********************************************************************/
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
bmips_smp_entry:
|
|
|
|
/* set up CP0 STATUS; enable FPU */
|
|
li k0, 0x30000000
|
|
mtc0 k0, CP0_STATUS
|
|
BARRIER
|
|
|
|
/* set local CP0 CONFIG to make kseg0 cacheable, write-back */
|
|
mfc0 k0, CP0_CONFIG
|
|
ori k0, 0x07
|
|
xori k0, 0x04
|
|
mtc0 k0, CP0_CONFIG
|
|
|
|
#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
|
|
/* initialize CPU1's local I-cache */
|
|
li k0, 0x80000000
|
|
li k1, 0x80010000
|
|
mtc0 zero, $28
|
|
mtc0 zero, $28, 1
|
|
BARRIER
|
|
|
|
1: cache Index_Store_Tag_I, 0(k0)
|
|
addiu k0, 16
|
|
bne k0, k1, 1b
|
|
#elif defined(CONFIG_CPU_BMIPS5000)
|
|
/* set exception vector base */
|
|
la k0, ebase
|
|
lw k0, 0(k0)
|
|
mtc0 k0, $15, 1
|
|
BARRIER
|
|
#endif
|
|
|
|
/* jump back to kseg0 in case we need to remap the kseg1 area */
|
|
la k0, 1f
|
|
jr k0
|
|
1:
|
|
la k0, bmips_enable_xks01
|
|
jalr k0
|
|
|
|
/* use temporary stack to set up upper memory TLB */
|
|
li sp, BMIPS_WARM_RESTART_VEC
|
|
la k0, plat_wired_tlb_setup
|
|
jalr k0
|
|
|
|
/* switch to permanent stack and continue booting */
|
|
|
|
.global bmips_secondary_reentry
|
|
bmips_secondary_reentry:
|
|
la k0, bmips_smp_boot_sp
|
|
lw sp, 0(k0)
|
|
la k0, bmips_smp_boot_gp
|
|
lw gp, 0(k0)
|
|
la k0, start_secondary
|
|
jr k0
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
.align 4
|
|
.global bmips_reset_nmi_vec_end
|
|
bmips_reset_nmi_vec_end:
|
|
|
|
END(bmips_reset_nmi_vec)
|
|
|
|
.set pop
|
|
.previous
|
|
|
|
/***********************************************************************
|
|
* CPU1 warm restart vector (used for second and subsequent boots).
|
|
* Also used for S2 standby recovery (PM).
|
|
* This entire function gets copied to (BMIPS_WARM_RESTART_VEC)
|
|
***********************************************************************/
|
|
|
|
LEAF(bmips_smp_int_vec)
|
|
|
|
.align 4
|
|
mfc0 k0, CP0_STATUS
|
|
ori k0, 0x01
|
|
xori k0, 0x01
|
|
mtc0 k0, CP0_STATUS
|
|
eret
|
|
|
|
.align 4
|
|
.global bmips_smp_int_vec_end
|
|
bmips_smp_int_vec_end:
|
|
|
|
END(bmips_smp_int_vec)
|
|
|
|
/***********************************************************************
|
|
* XKS01 support
|
|
* Certain CPUs support extending kseg0 to 1024MB.
|
|
***********************************************************************/
|
|
|
|
__CPUINIT
|
|
|
|
LEAF(bmips_enable_xks01)
|
|
|
|
#if defined(CONFIG_XKS01)
|
|
|
|
#if defined(CONFIG_CPU_BMIPS4380)
|
|
mfc0 t0, $22, 3
|
|
li t1, 0x1ff0
|
|
li t2, (1 << 12) | (1 << 9)
|
|
or t0, t1
|
|
xor t0, t1
|
|
or t0, t2
|
|
mtc0 t0, $22, 3
|
|
BARRIER
|
|
#elif defined(CONFIG_CPU_BMIPS5000)
|
|
mfc0 t0, $22, 5
|
|
li t1, 0x01ff
|
|
li t2, (1 << 8) | (1 << 5)
|
|
or t0, t1
|
|
xor t0, t1
|
|
or t0, t2
|
|
mtc0 t0, $22, 5
|
|
BARRIER
|
|
#else
|
|
|
|
#error Missing XKS01 setup
|
|
|
|
#endif
|
|
|
|
#endif /* defined(CONFIG_XKS01) */
|
|
|
|
jr ra
|
|
|
|
END(bmips_enable_xks01)
|
|
|
|
.previous
|