platsmp.c (527c465a3c8716d93201ae34b7fc52679610596d) | platsmp.c (c00def71efd919e8ae835a25f4f4c80a4b2d36d3) |
---|---|
1/* 2 * Copyright (C) 2002 ARM Ltd. 3 * Copyright (C) 2008 STMicroelctronics. 4 * Copyright (C) 2009 ST-Ericsson. 5 * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 6 * 7 * This file is based on arm realview platform 8 * --- 14 unchanged lines hidden (view full) --- 23#include <asm/smp_plat.h> 24#include <asm/smp_scu.h> 25 26#include "setup.h" 27 28#include "db8500-regs.h" 29#include "id.h" 30 | 1/* 2 * Copyright (C) 2002 ARM Ltd. 3 * Copyright (C) 2008 STMicroelctronics. 4 * Copyright (C) 2009 ST-Ericsson. 5 * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> 6 * 7 * This file is based on arm realview platform 8 * --- 14 unchanged lines hidden (view full) --- 23#include <asm/smp_plat.h> 24#include <asm/smp_scu.h> 25 26#include "setup.h" 27 28#include "db8500-regs.h" 29#include "id.h" 30 |
31static void __iomem *scu_base; 32static void __iomem *backupram; | 31/* Magic triggers in backup RAM */ 32#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 33#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 |
33 | 34 |
34/* This is called from headsmp.S to wakeup the secondary core */ 35extern void u8500_secondary_startup(void); 36 37/* 38 * Write pen_release in a way that is guaranteed to be visible to all 39 * observers, irrespective of whether they're taking part in coherency 40 * or not. This is necessary for the hotplug code to work reliably. 41 */ 42static void write_pen_release(int val) | 35static void wakeup_secondary(void) |
43{ | 36{ |
44 pen_release = val; 45 smp_wmb(); 46 sync_cache_w(&pen_release); 47} | 37 struct device_node *np; 38 static void __iomem *backupram; |
48 | 39 |
49static DEFINE_SPINLOCK(boot_lock); 50 51static void ux500_secondary_init(unsigned int cpu) 52{ 53 /* 54 * let the primary processor know we're out of the 55 * pen, then head off into the C entry point 56 */ 57 write_pen_release(-1); 58 59 /* 60 * Synchronise with the boot thread. 61 */ 62 spin_lock(&boot_lock); 63 spin_unlock(&boot_lock); 64} 65 66static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) 67{ 68 unsigned long timeout; 69 70 /* 71 * set synchronisation state between this boot processor 72 * and the secondary one 73 */ 74 spin_lock(&boot_lock); 75 76 /* 77 * The secondary processor is waiting to be released from 78 * the holding pen - release it, then wait for it to flag 79 * that it has been released by resetting pen_release. 80 */ 81 write_pen_release(cpu_logical_map(cpu)); 82 83 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 84 85 timeout = jiffies + (1 * HZ); 86 while (time_before(jiffies, timeout)) { 87 if (pen_release == -1) 88 break; | 40 np = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram"); 41 if (!np) { 42 pr_err("No backupram base address\n"); 43 return; |
89 } | 44 } |
45 backupram = of_iomap(np, 0); 46 of_node_put(np); 47 if (!backupram) { 48 pr_err("No backupram remap\n"); 49 return; 50 } |
|
90 91 /* | 51 52 /* |
92 * now the secondary core is starting up let it run its 93 * calibrations, then wait for it to finish 94 */ 95 spin_unlock(&boot_lock); 96 97 return pen_release != -1 ? -ENOSYS : 0; 98} 99 100static void __init wakeup_secondary(void) 101{ 102 /* | |
103 * write the address of secondary startup into the backup ram register 104 * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 105 * backup ram register at offset 0x1FF0, which is what boot rom code | 53 * write the address of secondary startup into the backup ram register 54 * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the 55 * backup ram register at offset 0x1FF0, which is what boot rom code |
106 * is waiting for. This would wake up the secondary core from WFE | 56 * is waiting for. This will wake up the secondary core from WFE. |
107 */ | 57 */ |
108#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 109 __raw_writel(virt_to_phys(u8500_secondary_startup), 110 backupram + UX500_CPU1_JUMPADDR_OFFSET); | 58 writel(virt_to_phys(secondary_startup), 59 backupram + UX500_CPU1_JUMPADDR_OFFSET); 60 writel(0xA1FEED01, 61 backupram + UX500_CPU1_WAKEMAGIC_OFFSET); |
111 | 62 |
112#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 113 __raw_writel(0xA1FEED01, 114 backupram + UX500_CPU1_WAKEMAGIC_OFFSET); 115 | |
116 /* make sure write buffer is drained */ 117 mb(); | 63 /* make sure write buffer is drained */ 64 mb(); |
65 iounmap(backupram); |
|
118} 119 | 66} 67 |
120/* 121 * Initialise the CPU possible map early - this describes the CPUs 122 * which may be present or become present in the system. 123 */ 124static void __init ux500_smp_init_cpus(void) | 68static void __init ux500_smp_prepare_cpus(unsigned int max_cpus) |
125{ | 69{ |
126 unsigned int i, ncores; | |
127 struct device_node *np; | 70 struct device_node *np; |
71 static void __iomem *scu_base; 72 unsigned int ncores; 73 int i; |
|
128 129 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); | 74 75 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); |
76 if (!np) { 77 pr_err("No SCU base address\n"); 78 return; 79 } |
|
130 scu_base = of_iomap(np, 0); 131 of_node_put(np); | 80 scu_base = of_iomap(np, 0); 81 of_node_put(np); |
132 if (!scu_base) | 82 if (!scu_base) { 83 pr_err("No SCU remap\n"); |
133 return; | 84 return; |
134 backupram = ioremap(U8500_BACKUPRAM0_BASE, SZ_8K); 135 ncores = scu_get_core_count(scu_base); 136 137 /* sanity check */ 138 if (ncores > nr_cpu_ids) { 139 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 140 ncores, nr_cpu_ids); 141 ncores = nr_cpu_ids; | |
142 } 143 | 85 } 86 |
87 scu_enable(scu_base); 88 ncores = scu_get_core_count(scu_base); |
|
144 for (i = 0; i < ncores; i++) 145 set_cpu_possible(i, true); | 89 for (i = 0; i < ncores; i++) 90 set_cpu_possible(i, true); |
91 iounmap(scu_base); |
|
146} 147 | 92} 93 |
148static void __init ux500_smp_prepare_cpus(unsigned int max_cpus) | 94static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle) |
149{ | 95{ |
150 scu_enable(scu_base); | |
151 wakeup_secondary(); | 96 wakeup_secondary(); |
97 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 98 return 0; |
|
152} 153 154struct smp_operations ux500_smp_ops __initdata = { | 99} 100 101struct smp_operations ux500_smp_ops __initdata = { |
155 .smp_init_cpus = ux500_smp_init_cpus, | |
156 .smp_prepare_cpus = ux500_smp_prepare_cpus, | 102 .smp_prepare_cpus = ux500_smp_prepare_cpus, |
157 .smp_secondary_init = ux500_secondary_init, | |
158 .smp_boot_secondary = ux500_boot_secondary, 159#ifdef CONFIG_HOTPLUG_CPU 160 .cpu_die = ux500_cpu_die, 161#endif 162}; | 103 .smp_boot_secondary = ux500_boot_secondary, 104#ifdef CONFIG_HOTPLUG_CPU 105 .cpu_die = ux500_cpu_die, 106#endif 107}; |
108CPU_METHOD_OF_DECLARE(ux500_smp, "ste,dbx500-smp", &ux500_smp_ops); |
|