Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | // SPDX-License-Identifier: GPL-2.0 /* * SH-X3 SMP * * Copyright (C) 2007 - 2010 Paul Mundt * Copyright (C) 2007 Magnus Damm */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/cpumask.h> #include <linux/smp.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/cpu.h> #include <asm/sections.h> #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) #define STBCR_MSTP 0x00000001 #define STBCR_RESET 0x00000002 #define STBCR_SLEEP 0x00000004 #define STBCR_LTSLP 0x80000000 static irqreturn_t ipi_interrupt_handler(int irq, void *arg) { unsigned int message = (unsigned int)(long)arg; unsigned int cpu = hard_smp_processor_id(); unsigned int offs = 4 * cpu; unsigned int x; x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ x &= (1 << (message << 2)); __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ smp_message_recv(message); return IRQ_HANDLED; } static void shx3_smp_setup(void) { unsigned int cpu = 0; int i, num; init_cpu_possible(cpumask_of(cpu)); /* Enable light sleep for the boot CPU */ __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu)); __cpu_number_map[0] = 0; __cpu_logical_map[0] = 0; /* * Do this stupidly for now.. we don't have an easy way to probe * for the total number of cores. */ for (i = 1, num = 0; i < NR_CPUS; i++) { set_cpu_possible(i, true); __cpu_number_map[i] = ++num; __cpu_logical_map[num] = i; } printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); } static void shx3_prepare_cpus(unsigned int max_cpus) { int i; BUILD_BUG_ON(SMP_MSG_NR >= 8); for (i = 0; i < SMP_MSG_NR; i++) if (request_irq(104 + i, ipi_interrupt_handler, IRQF_PERCPU, "IPI", (void *)(long)i)) pr_err("Failed to request irq %d\n", i); for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); } static void shx3_start_cpu(unsigned int cpu, unsigned long entry_point) { if (__in_29bit_mode()) __raw_writel(entry_point, RESET_REG(cpu)); else __raw_writel(virt_to_phys(entry_point), RESET_REG(cpu)); if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) __raw_writel(STBCR_MSTP, STBCR_REG(cpu)); while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) cpu_relax(); /* Start up secondary processor by sending a reset */ __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu)); } static unsigned int shx3_smp_processor_id(void) { return __raw_readl(0xff000048); /* CPIDR */ } static void shx3_send_ipi(unsigned int cpu, unsigned int message) { unsigned long addr = 0xfe410070 + (cpu * 4); BUG_ON(cpu >= 4); __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ } static void shx3_update_boot_vector(unsigned int cpu) { __raw_writel(STBCR_MSTP, STBCR_REG(cpu)); while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) cpu_relax(); __raw_writel(STBCR_RESET, STBCR_REG(cpu)); } static int shx3_cpu_prepare(unsigned int cpu) { shx3_update_boot_vector(cpu); return 0; } static int register_shx3_cpu_notifier(void) { cpuhp_setup_state_nocalls(CPUHP_SH_SH3X_PREPARE, "sh/shx3:prepare", shx3_cpu_prepare, NULL); return 0; } late_initcall(register_shx3_cpu_notifier); struct plat_smp_ops shx3_smp_ops = { .smp_setup = shx3_smp_setup, .prepare_cpus = shx3_prepare_cpus, .start_cpu = shx3_start_cpu, .smp_processor_id = shx3_smp_processor_id, .send_ipi = shx3_send_ipi, .cpu_die = native_cpu_die, .cpu_disable = native_cpu_disable, .play_dead = native_play_dead, }; |