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