Commit fc455787 authored by Kevin Cernekee's avatar Kevin Cernekee Committed by Ralf Baechle

MIPS: BMIPS: Introduce helper function to change the reset vector

This will need to be called from a few different places, and the logic
is starting to get a bit hairy (with the need for IPIs, CPU bug
workarounds, and hazards).
Signed-off-by: default avatarKevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: mbizon@freebox.fr
Cc: jogo@openwrt.org
Cc: jfraser@broadcom.com
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8158/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent bdb2e05c
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <asm/bmips.h> #include <asm/bmips.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/barrier.h> #include <asm/barrier.h>
#include <asm/cpu-features.h>
static int __maybe_unused max_cpus = 1; static int __maybe_unused max_cpus = 1;
...@@ -43,6 +44,9 @@ int bmips_smp_enabled = 1; ...@@ -43,6 +44,9 @@ int bmips_smp_enabled = 1;
int bmips_cpu_offset; int bmips_cpu_offset;
cpumask_t bmips_booted_mask; cpumask_t bmips_booted_mask;
#define RESET_FROM_KSEG0 0x80080800
#define RESET_FROM_KSEG1 0xa0080800
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */ /* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */
...@@ -463,10 +467,61 @@ static inline void bmips_nmi_handler_setup(void) ...@@ -463,10 +467,61 @@ static inline void bmips_nmi_handler_setup(void)
&bmips_smp_int_vec_end); &bmips_smp_int_vec_end);
} }
struct reset_vec_info {
int cpu;
u32 val;
};
static void bmips_set_reset_vec_remote(void *vinfo)
{
struct reset_vec_info *info = vinfo;
int shift = info->cpu & 0x01 ? 16 : 0;
u32 mask = ~(0xffff << shift), val = info->val >> 16;
preempt_disable();
if (smp_processor_id() > 0) {
smp_call_function_single(0, &bmips_set_reset_vec_remote,
info, 1);
} else {
if (info->cpu & 0x02) {
/* BMIPS5200 "should" use mask/shift, but it's buggy */
bmips_write_zscm_reg(0xa0, (val << 16) | val);
bmips_read_zscm_reg(0xa0);
} else {
write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) |
(val << shift));
}
}
preempt_enable();
}
static void bmips_set_reset_vec(int cpu, u32 val)
{
struct reset_vec_info info;
if (current_cpu_type() == CPU_BMIPS5000) {
/* this needs to run from CPU0 (which is always online) */
info.cpu = cpu;
info.val = val;
bmips_set_reset_vec_remote(&info);
} else {
void __iomem *cbr = BMIPS_GET_CBR();
if (cpu == 0)
__raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
else {
if (current_cpu_type() != CPU_BMIPS4380)
return;
__raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
}
}
__sync();
back_to_back_c0_hazard();
}
void bmips_ebase_setup(void) void bmips_ebase_setup(void)
{ {
unsigned long new_ebase = ebase; unsigned long new_ebase = ebase;
void __iomem __maybe_unused *cbr;
BUG_ON(ebase != CKSEG0); BUG_ON(ebase != CKSEG0);
...@@ -492,9 +547,7 @@ void bmips_ebase_setup(void) ...@@ -492,9 +547,7 @@ void bmips_ebase_setup(void)
* 0x8000_0400: normal vectors * 0x8000_0400: normal vectors
*/ */
new_ebase = 0x80000400; new_ebase = 0x80000400;
cbr = BMIPS_GET_CBR(); bmips_set_reset_vec(0, RESET_FROM_KSEG0);
__raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
__raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
break; break;
case CPU_BMIPS5000: case CPU_BMIPS5000:
/* /*
...@@ -502,10 +555,8 @@ void bmips_ebase_setup(void) ...@@ -502,10 +555,8 @@ void bmips_ebase_setup(void)
* 0x8000_1000: normal vectors * 0x8000_1000: normal vectors
*/ */
new_ebase = 0x80001000; new_ebase = 0x80001000;
write_c0_brcm_bootvec(0xa0088008); bmips_set_reset_vec(0, RESET_FROM_KSEG0);
write_c0_ebase(new_ebase); write_c0_ebase(new_ebase);
if (max_cpus > 2)
bmips_write_zscm_reg(0xa0, 0xa008a008);
break; break;
default: default:
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment