1 /* 2 * SH-X3 SMP 3 * 4 * Copyright (C) 2007 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 void __init plat_smp_setup(void) 18 { 19 unsigned int cpu = 0; 20 int i, num; 21 22 cpus_clear(cpu_possible_map); 23 cpu_set(cpu, cpu_possible_map); 24 25 __cpu_number_map[0] = 0; 26 __cpu_logical_map[0] = 0; 27 28 /* 29 * Do this stupidly for now.. we don't have an easy way to probe 30 * for the total number of cores. 31 */ 32 for (i = 1, num = 0; i < NR_CPUS; i++) { 33 cpu_set(i, cpu_possible_map); 34 __cpu_number_map[i] = ++num; 35 __cpu_logical_map[num] = i; 36 } 37 38 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); 39 } 40 41 void __init plat_prepare_cpus(unsigned int max_cpus) 42 { 43 } 44 45 #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) 46 #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) 47 48 #define STBCR_MSTP 0x00000001 49 #define STBCR_RESET 0x00000002 50 #define STBCR_LTSLP 0x80000000 51 52 #define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP) 53 54 void plat_start_cpu(unsigned int cpu, unsigned long entry_point) 55 { 56 ctrl_outl(entry_point, RESET_REG(cpu)); 57 58 if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 59 ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); 60 61 while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 62 ; 63 64 /* Start up secondary processor by sending a reset */ 65 ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); 66 } 67 68 int plat_smp_processor_id(void) 69 { 70 return ctrl_inl(0xff000048); /* CPIDR */ 71 } 72 73 void plat_send_ipi(unsigned int cpu, unsigned int message) 74 { 75 unsigned long addr = 0xfe410070 + (cpu * 4); 76 77 BUG_ON(cpu >= 4); 78 BUG_ON(message >= SMP_MSG_NR); 79 80 ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ 81 } 82 83 struct ipi_data { 84 void (*handler)(void *); 85 void *arg; 86 unsigned int message; 87 }; 88 89 static irqreturn_t ipi_interrupt_handler(int irq, void *arg) 90 { 91 struct ipi_data *id = arg; 92 unsigned int cpu = hard_smp_processor_id(); 93 unsigned int offs = 4 * cpu; 94 unsigned int x; 95 96 x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ 97 x &= (1 << (id->message << 2)); 98 ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ 99 100 id->handler(id->arg); 101 102 return IRQ_HANDLED; 103 } 104 105 static struct ipi_data ipi_handlers[SMP_MSG_NR]; 106 107 int plat_register_ipi_handler(unsigned int message, 108 void (*handler)(void *), void *arg) 109 { 110 struct ipi_data *id = &ipi_handlers[message]; 111 112 BUG_ON(SMP_MSG_NR >= 8); 113 BUG_ON(message >= SMP_MSG_NR); 114 115 id->handler = handler; 116 id->arg = arg; 117 id->message = message; 118 119 return request_irq(104 + message, ipi_interrupt_handler, 0, "IPI", id); 120 } 121