1 /* 2 * SMP support for J2 processor 3 * 4 * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 */ 10 11 #include <linux/smp.h> 12 #include <linux/interrupt.h> 13 #include <linux/io.h> 14 #include <linux/of_address.h> 15 #include <linux/of_irq.h> 16 #include <asm/cmpxchg.h> 17 18 DEFINE_PER_CPU(unsigned, j2_ipi_messages); 19 20 extern u32 *sh2_cpuid_addr; 21 static u32 *j2_ipi_trigger; 22 static int j2_ipi_irq; 23 24 static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg) 25 { 26 unsigned cpu = hard_smp_processor_id(); 27 volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu); 28 unsigned messages, i; 29 30 do messages = *pmsg; 31 while (cmpxchg(pmsg, messages, 0) != messages); 32 33 if (!messages) return IRQ_NONE; 34 35 for (i=0; i<SMP_MSG_NR; i++) 36 if (messages & (1U<<i)) 37 smp_message_recv(i); 38 39 return IRQ_HANDLED; 40 } 41 42 static void j2_smp_setup(void) 43 { 44 } 45 46 static void j2_prepare_cpus(unsigned int max_cpus) 47 { 48 struct device_node *np; 49 unsigned i, max = 1; 50 51 np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller"); 52 if (!np) 53 goto out; 54 55 j2_ipi_irq = irq_of_parse_and_map(np, 0); 56 j2_ipi_trigger = of_iomap(np, 0); 57 if (!j2_ipi_irq || !j2_ipi_trigger) 58 goto out; 59 60 np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio"); 61 if (!np) 62 goto out; 63 64 sh2_cpuid_addr = of_iomap(np, 0); 65 if (!sh2_cpuid_addr) 66 goto out; 67 68 if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU, 69 "ipi", (void *)j2_ipi_interrupt_handler) != 0) 70 goto out; 71 72 max = max_cpus; 73 out: 74 /* Disable any cpus past max_cpus, or all secondaries if we didn't 75 * get the necessary resources to support SMP. */ 76 for (i=max; i<NR_CPUS; i++) { 77 set_cpu_possible(i, false); 78 set_cpu_present(i, false); 79 } 80 } 81 82 static void j2_start_cpu(unsigned int cpu, unsigned long entry_point) 83 { 84 struct device_node *np; 85 u32 regs[2]; 86 void __iomem *release, *initpc; 87 88 if (!cpu) return; 89 90 np = of_get_cpu_node(cpu, NULL); 91 if (!np) return; 92 93 if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return; 94 release = ioremap_nocache(regs[0], sizeof(u32)); 95 initpc = ioremap_nocache(regs[1], sizeof(u32)); 96 97 __raw_writel(entry_point, initpc); 98 __raw_writel(1, release); 99 100 iounmap(initpc); 101 iounmap(release); 102 103 pr_info("J2 SMP: requested start of cpu %u\n", cpu); 104 } 105 106 static unsigned int j2_smp_processor_id(void) 107 { 108 return __raw_readl(sh2_cpuid_addr); 109 } 110 111 static void j2_send_ipi(unsigned int cpu, unsigned int message) 112 { 113 volatile unsigned *pmsg; 114 unsigned old; 115 unsigned long val; 116 117 /* There is only one IPI interrupt shared by all messages, so 118 * we keep a separate interrupt flag per message type in sw. */ 119 pmsg = &per_cpu(j2_ipi_messages, cpu); 120 do old = *pmsg; 121 while (cmpxchg(pmsg, old, old|(1U<<message)) != old); 122 123 /* Generate the actual interrupt by writing to CCRn bit 28. */ 124 val = __raw_readl(j2_ipi_trigger + cpu); 125 __raw_writel(val | (1U<<28), j2_ipi_trigger + cpu); 126 } 127 128 static struct plat_smp_ops j2_smp_ops = { 129 .smp_setup = j2_smp_setup, 130 .prepare_cpus = j2_prepare_cpus, 131 .start_cpu = j2_start_cpu, 132 .smp_processor_id = j2_smp_processor_id, 133 .send_ipi = j2_send_ipi, 134 .cpu_die = native_cpu_die, 135 .cpu_disable = native_cpu_disable, 136 .play_dead = native_play_dead, 137 }; 138 139 CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops); 140