Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+58 −7
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <asm/bmips.h>
#include <asm/traps.h>
#include <asm/barrier.h>
#include <asm/cpu-features.h>

static int __maybe_unused max_cpus = 1;

@@ -43,6 +44,9 @@ int bmips_smp_enabled = 1;
int bmips_cpu_offset;
cpumask_t bmips_booted_mask;

#define RESET_FROM_KSEG0		0x80080800
#define RESET_FROM_KSEG1		0xa0080800

#ifdef CONFIG_SMP

/* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */
@@ -463,10 +467,61 @@ static inline void bmips_nmi_handler_setup(void)
		&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)
{
	unsigned long new_ebase = ebase;
	void __iomem __maybe_unused *cbr;

	BUG_ON(ebase != CKSEG0);

@@ -492,9 +547,7 @@ void bmips_ebase_setup(void)
		 * 0x8000_0400: normal vectors
		 */
		new_ebase = 0x80000400;
		cbr = BMIPS_GET_CBR();
		__raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
		__raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
		bmips_set_reset_vec(0, RESET_FROM_KSEG0);
		break;
	case CPU_BMIPS5000:
		/*
@@ -502,10 +555,8 @@ void bmips_ebase_setup(void)
		 * 0x8000_1000: normal vectors
		 */
		new_ebase = 0x80001000;
		write_c0_brcm_bootvec(0xa0088008);
		bmips_set_reset_vec(0, RESET_FROM_KSEG0);
		write_c0_ebase(new_ebase);
		if (max_cpus > 2)
			bmips_write_zscm_reg(0xa0, 0xa008a008);
		break;
	default:
		return;