^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * SMP support for BMIPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched/hotplug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/sched/task_stack.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/bug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/kexec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <asm/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/bootinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/tlbflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/mipsregs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/bmips.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/barrier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <asm/cpu-features.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int __maybe_unused max_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* these may be configured by the platform code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int bmips_smp_enabled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int bmips_cpu_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) cpumask_t bmips_booted_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned long bmips_tp1_irqs = IE_IRQ1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define RESET_FROM_KSEG0 0x80080800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define RESET_FROM_KSEG1 0xa0080800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static void bmips_set_reset_vec(int cpu, u32 val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned long bmips_smp_boot_sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned long bmips_smp_boot_gp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void bmips43xx_send_ipi_single(int cpu, unsigned int action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static void bmips5000_send_ipi_single(int cpu, unsigned int action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* SW interrupts 0,1 are used for interprocessor signaling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define IPI0_IRQ (MIPS_CPU_IRQ_BASE + 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define IPI1_IRQ (MIPS_CPU_IRQ_BASE + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define CPUNUM(cpu, shift) (((cpu) + bmips_cpu_offset) << (shift))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define ACTION_CLR_IPI(cpu, ipi) (0x2000 | CPUNUM(cpu, 9) | ((ipi) << 8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define ACTION_SET_IPI(cpu, ipi) (0x3000 | CPUNUM(cpu, 9) | ((ipi) << 8))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define ACTION_BOOT_THREAD(cpu) (0x08 | CPUNUM(cpu, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static void __init bmips_smp_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int i, cpu = 1, boot_cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int cpu_hw_intr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) case CPU_BMIPS4350:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* arbitration priority */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) clear_c0_brcm_cmt_ctrl(0x30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* NBK and weak order flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) set_c0_brcm_config_0(0x30000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Find out if we are running on TP0 or TP1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * thread
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (boot_cpu == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) cpu_hw_intr = 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) cpu_hw_intr = 0x1d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) change_c0_brcm_cmt_intr(0xf8018000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) (cpu_hw_intr << 27) | (0x03 << 15));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* single core, 2 threads (2 pipelines) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) max_cpus = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* enable raceless SW interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) set_c0_brcm_config(0x03 << 22);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) change_c0_brcm_mode(0x1f << 27, 0x02 << 27);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* N cores, 2 threads per core */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* clear any pending SW interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) for (i = 0; i < max_cpus; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) write_c0_brcm_action(ACTION_CLR_IPI(i, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) write_c0_brcm_action(ACTION_CLR_IPI(i, 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) max_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!bmips_smp_enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) max_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* this can be overridden by the BSP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (!board_ebase_setup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) board_ebase_setup = &bmips_ebase_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) __cpu_number_map[boot_cpu] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) __cpu_logical_map[0] = boot_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) for (i = 0; i < max_cpus; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (i != boot_cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) __cpu_number_map[i] = cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) __cpu_logical_map[cpu] = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) cpu++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) set_cpu_possible(i, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) set_cpu_present(i, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * IPI IRQ setup - runs on CPU0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void bmips_prepare_cpus(unsigned int max_cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) irqreturn_t (*bmips_ipi_interrupt)(int irq, void *dev_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case CPU_BMIPS4350:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) bmips_ipi_interrupt = bmips43xx_ipi_interrupt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) bmips_ipi_interrupt = bmips5000_ipi_interrupt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (request_irq(IPI0_IRQ, bmips_ipi_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) panic("Can't request IPI0 interrupt");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (request_irq(IPI1_IRQ, bmips_ipi_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) panic("Can't request IPI1 interrupt");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * Tell the hardware to boot CPUx - runs on CPU0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int bmips_boot_secondary(int cpu, struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) bmips_smp_boot_sp = __KSTK_TOS(idle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) bmips_smp_boot_gp = (unsigned long)task_thread_info(idle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * Initial boot sequence for secondary CPU:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * bmips_reset_nmi_vec @ a000_0000 ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * bmips_smp_entry ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * plat_wired_tlb_setup (cached function call; optional) ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * start_secondary (cached jump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * Warm restart sequence:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * play_dead WAIT loop ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * bmips_smp_int_vec @ BMIPS_WARM_RESTART_VEC ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * eret to play_dead ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * bmips_secondary_reentry ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * start_secondary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) pr_info("SMP: Booting CPU%d...\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (cpumask_test_cpu(cpu, &bmips_booted_mask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /* kseg1 might not exist if this CPU enabled XKS01 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) bmips_set_reset_vec(cpu, RESET_FROM_KSEG0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case CPU_BMIPS4350:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) bmips43xx_send_ipi_single(cpu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) bmips5000_send_ipi_single(cpu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) bmips_set_reset_vec(cpu, RESET_FROM_KSEG1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) case CPU_BMIPS4350:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /* Reset slave TP1 if booting from TP0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (cpu_logical_map(cpu) == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) set_c0_brcm_cmt_ctrl(0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cpumask_set_cpu(cpu, &bmips_booted_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) * Early setup - runs on secondary CPU after cache probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static void bmips_init_secondary(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) bmips_cpu_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) case CPU_BMIPS4350:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) cpu_set_core(¤t_cpu_data, (read_c0_brcm_config() >> 25) & 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * Late setup - runs on secondary CPU before entering the idle loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void bmips_smp_finish(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) pr_info("SMP: CPU%d is running\n", smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) /* make sure there won't be a timer interrupt for a little while */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) irq_enable_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) set_c0_status(IE_SW0 | IE_SW1 | bmips_tp1_irqs | IE_IRQ5 | ST0_IE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) irq_enable_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * BMIPS5000 raceless IPIs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * Each CPU has two inbound SW IRQs which are independent of all other CPUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * IPI0 is used for SMP_RESCHEDULE_YOURSELF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * IPI1 is used for SMP_CALL_FUNCTION
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static void bmips5000_send_ipi_single(int cpu, unsigned int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) write_c0_brcm_action(ACTION_SET_IPI(cpu, action == SMP_CALL_FUNCTION));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) int action = irq - IPI0_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), action));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (action == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) scheduler_ipi();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) generic_smp_call_function_interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) static void bmips5000_send_ipi_mask(const struct cpumask *mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) unsigned int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) for_each_cpu(i, mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) bmips5000_send_ipi_single(i, action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * BMIPS43xx racey IPIs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * We use one inbound SW IRQ for each CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * A spinlock must be held in order to keep CPUx from accidentally clearing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * an incoming IPI when it writes CP0 CAUSE to raise an IPI on CPUy. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * same spinlock is used to protect the action masks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static DEFINE_SPINLOCK(ipi_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static DEFINE_PER_CPU(int, ipi_action_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static void bmips43xx_send_ipi_single(int cpu, unsigned int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) spin_lock_irqsave(&ipi_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) set_c0_cause(cpu ? C_SW1 : C_SW0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) per_cpu(ipi_action_mask, cpu) |= action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) irq_enable_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) spin_unlock_irqrestore(&ipi_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int action, cpu = irq - IPI0_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) spin_lock_irqsave(&ipi_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) action = __this_cpu_read(ipi_action_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) per_cpu(ipi_action_mask, cpu) = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) clear_c0_cause(cpu ? C_SW1 : C_SW0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) spin_unlock_irqrestore(&ipi_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (action & SMP_RESCHEDULE_YOURSELF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) scheduler_ipi();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (action & SMP_CALL_FUNCTION)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) generic_smp_call_function_interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static void bmips43xx_send_ipi_mask(const struct cpumask *mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) unsigned int action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) for_each_cpu(i, mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) bmips43xx_send_ipi_single(i, action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static int bmips_cpu_disable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) unsigned int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (cpu == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) pr_info("SMP: CPU%d is offline\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) set_cpu_online(cpu, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) calculate_cpu_foreign_map();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) irq_cpu_offline();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) clear_c0_status(IE_IRQ5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) local_flush_tlb_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) local_flush_icache_range(0, ~0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static void bmips_cpu_die(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) void __ref play_dead(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) idle_task_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) /* flush data cache */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) _dma_cache_wback_inv(0, ~0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * Wakeup is on SW0 or SW1; disable everything else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * Use BEV !IV (BMIPS_WARM_RESTART_VEC) to avoid the regular Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * IRQ handlers; this clears ST0_IE and returns immediately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) change_c0_status(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) IE_IRQ5 | bmips_tp1_irqs | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) irq_disable_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * wait for SW interrupt from bmips_boot_secondary(), then jump
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * back to start_secondary()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) __asm__ __volatile__(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) " wait\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) " j bmips_secondary_reentry\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) #endif /* CONFIG_HOTPLUG_CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) const struct plat_smp_ops bmips43xx_smp_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) .smp_setup = bmips_smp_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) .prepare_cpus = bmips_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) .boot_secondary = bmips_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) .smp_finish = bmips_smp_finish,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) .init_secondary = bmips_init_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) .send_ipi_single = bmips43xx_send_ipi_single,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) .send_ipi_mask = bmips43xx_send_ipi_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) .cpu_disable = bmips_cpu_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) .cpu_die = bmips_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) #ifdef CONFIG_KEXEC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) const struct plat_smp_ops bmips5000_smp_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) .smp_setup = bmips_smp_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) .prepare_cpus = bmips_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) .boot_secondary = bmips_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) .smp_finish = bmips_smp_finish,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) .init_secondary = bmips_init_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) .send_ipi_single = bmips5000_send_ipi_single,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) .send_ipi_mask = bmips5000_send_ipi_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) .cpu_disable = bmips_cpu_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .cpu_die = bmips_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) #ifdef CONFIG_KEXEC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) #endif /* CONFIG_SMP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /***********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * BMIPS vector relocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * This is primarily used for SMP boot, but it is applicable to some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * UP BMIPS systems as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) ***********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) static void bmips_wr_vec(unsigned long dst, char *start, char *end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) memcpy((void *)dst, start, end - start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) dma_cache_wback(dst, end - start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) local_flush_icache_range(dst, dst + (end - start));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) instruction_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static inline void bmips_nmi_handler_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) bmips_wr_vec(BMIPS_NMI_RESET_VEC, bmips_reset_nmi_vec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) bmips_reset_nmi_vec_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) bmips_wr_vec(BMIPS_WARM_RESTART_VEC, bmips_smp_int_vec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) bmips_smp_int_vec_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) struct reset_vec_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static void bmips_set_reset_vec_remote(void *vinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) struct reset_vec_info *info = vinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) int shift = info->cpu & 0x01 ? 16 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) u32 mask = ~(0xffff << shift), val = info->val >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (smp_processor_id() > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) smp_call_function_single(0, &bmips_set_reset_vec_remote,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) info, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (info->cpu & 0x02) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* BMIPS5200 "should" use mask/shift, but it's buggy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) bmips_write_zscm_reg(0xa0, (val << 16) | val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) bmips_read_zscm_reg(0xa0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) (val << shift));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static void bmips_set_reset_vec(int cpu, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) struct reset_vec_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (current_cpu_type() == CPU_BMIPS5000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* this needs to run from CPU0 (which is always online) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) info.cpu = cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) info.val = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) bmips_set_reset_vec_remote(&info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) void __iomem *cbr = BMIPS_GET_CBR();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (cpu == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (current_cpu_type() != CPU_BMIPS4380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) __sync();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) back_to_back_c0_hazard();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) void bmips_ebase_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) unsigned long new_ebase = ebase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) BUG_ON(ebase != CKSEG0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) case CPU_BMIPS4350:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * BMIPS4350 cannot relocate the normal vectors, but it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * can relocate the BEV=1 vectors. So CPU1 starts up at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * the relocated BEV=1, IV=0 general exception vector @
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * 0xa000_0380.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) * set_uncached_handler() is used here because:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) * - CPU1 will run this from uncached space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * - None of the cacheflush functions are set up yet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) &bmips_smp_int_vec, 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) __sync();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) case CPU_BMIPS3300:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * 0x8000_0000: reset/NMI (initially in kseg1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * 0x8000_0400: normal vectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) new_ebase = 0x80000400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) bmips_set_reset_vec(0, RESET_FROM_KSEG0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * 0x8000_0000: reset/NMI (initially in kseg1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * 0x8000_1000: normal vectors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) new_ebase = 0x80001000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) bmips_set_reset_vec(0, RESET_FROM_KSEG0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) write_c0_ebase(new_ebase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) board_nmi_handler_setup = &bmips_nmi_handler_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) ebase = new_ebase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) asmlinkage void __weak plat_wired_tlb_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * Called when starting/restarting a secondary CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * Kernel stacks and other important data might only be accessible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) * once the wired entries are present.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) void bmips_cpu_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) void __iomem __maybe_unused *cbr = BMIPS_GET_CBR();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) u32 __maybe_unused cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) switch (current_cpu_type()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) case CPU_BMIPS3300:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /* Set BIU to async mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) set_c0_brcm_bus_pll(BIT(22));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) __sync();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /* put the BIU back in sync mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) clear_c0_brcm_bus_pll(BIT(22));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) /* clear BHTD to enable branch history table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) clear_c0_brcm_reset(BIT(16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /* Flush and enable RAC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) __raw_readl(cbr + BMIPS_RAC_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) __raw_writel(cfg | 0xf, cbr + BMIPS_RAC_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) __raw_readl(cbr + BMIPS_RAC_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) cfg = __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) __raw_writel(cfg | 0x0fff0000, cbr + BMIPS_RAC_ADDRESS_RANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) case CPU_BMIPS4380:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) /* CBG workaround for early BMIPS4380 CPUs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) switch (read_c0_prid()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) case 0x2a040:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) case 0x2a042:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) case 0x2a044:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) case 0x2a060:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) cfg = __raw_readl(cbr + BMIPS_L2_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) __raw_writel(cfg & ~0x07000000, cbr + BMIPS_L2_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) __raw_readl(cbr + BMIPS_L2_CONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) /* clear BHTD to enable branch history table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) clear_c0_brcm_config_0(BIT(21));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /* XI/ROTR enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) set_c0_brcm_config_0(BIT(23));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) set_c0_brcm_cmt_ctrl(BIT(15));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) case CPU_BMIPS5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* enable RDHWR, BRDHWR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) set_c0_brcm_config(BIT(17) | BIT(21));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* Disable JTB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) __asm__ __volatile__(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) " .set noreorder\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) " li $8, 0x5a455048\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) " .word 0x4088b00f\n" /* mtc0 t0, $22, 15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) " .word 0x4008b008\n" /* mfc0 t0, $22, 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) " li $9, 0x00008000\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) " or $8, $8, $9\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) " .word 0x4088b008\n" /* mtc0 t0, $22, 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) " sync\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) " li $8, 0x0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) " .word 0x4088b00f\n" /* mtc0 t0, $22, 15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) " .set reorder\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) : : : "$8", "$9");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) /* XI enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) set_c0_brcm_config(BIT(27));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) /* enable MIPS32R2 ROR instruction for XI TLB handlers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) __asm__ __volatile__(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) " li $8, 0x5a455048\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) " .word 0x4088b00f\n" /* mtc0 $8, $22, 15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) " nop; nop; nop\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) " .word 0x4008b008\n" /* mfc0 $8, $22, 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) " lui $9, 0x0100\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) " or $8, $9\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) " .word 0x4088b008\n" /* mtc0 $8, $22, 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) : : : "$8", "$9");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }