1 /* 2 * SH-X3 SMP 3 * 4 * Copyright (C) 2007 - 2008 Paul Mundt 5 * Copyright (C) 2007 Magnus Damm 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file "COPYING" in the main directory of this archive 9 * for more details. 10 */ 11 #include <linux/init.h> 12 #include <linux/cpumask.h> 13 #include <linux/smp.h> 14 #include <linux/interrupt.h> 15 #include <linux/io.h> 16 17 static irqreturn_t ipi_interrupt_handler(int irq, void *arg) 18 { 19 unsigned int message = (unsigned int)(long)arg; 20 unsigned int cpu = hard_smp_processor_id(); 21 unsigned int offs = 4 * cpu; 22 unsigned int x; 23 24 x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ 25 x &= (1 << (message << 2)); 26 ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ 27 28 smp_message_recv(message); 29 30 return IRQ_HANDLED; 31 } 32 33 void __init plat_smp_setup(void) 34 { 35 unsigned int cpu = 0; 36 int i, num; 37 38 cpus_clear(cpu_possible_map); 39 cpu_set(cpu, cpu_possible_map); 40 41 __cpu_number_map[0] = 0; 42 __cpu_logical_map[0] = 0; 43 44 /* 45 * Do this stupidly for now.. we don't have an easy way to probe 46 * for the total number of cores. 47 */ 48 for (i = 1, num = 0; i < NR_CPUS; i++) { 49 cpu_set(i, cpu_possible_map); 50 __cpu_number_map[i] = ++num; 51 __cpu_logical_map[num] = i; 52 } 53 54 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); 55 } 56 57 void __init plat_prepare_cpus(unsigned int max_cpus) 58 { 59 int i; 60 61 BUILD_BUG_ON(SMP_MSG_NR >= 8); 62 63 for (i = 0; i < SMP_MSG_NR; i++) 64 request_irq(104 + i, ipi_interrupt_handler, IRQF_DISABLED, 65 "IPI", (void *)(long)i); 66 } 67 68 #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) 69 #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) 70 71 #define STBCR_MSTP 0x00000001 72 #define STBCR_RESET 0x00000002 73 #define STBCR_LTSLP 0x80000000 74 75 #define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP) 76 77 void plat_start_cpu(unsigned int cpu, unsigned long entry_point) 78 { 79 ctrl_outl(entry_point, RESET_REG(cpu)); 80 81 if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 82 ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); 83 84 while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 85 cpu_relax(); 86 87 /* Start up secondary processor by sending a reset */ 88 ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); 89 } 90 91 int plat_smp_processor_id(void) 92 { 93 return ctrl_inl(0xff000048); /* CPIDR */ 94 } 95 96 void plat_send_ipi(unsigned int cpu, unsigned int message) 97 { 98 unsigned long addr = 0xfe410070 + (cpu * 4); 99 100 BUG_ON(cpu >= 4); 101 102 ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ 103 } 104