summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sunxi
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-sunxi')
-rw-r--r--arch/arm/mach-sunxi/mc_smp.c59
1 files changed, 56 insertions, 3 deletions
diff --git a/arch/arm/mach-sunxi/mc_smp.c b/arch/arm/mach-sunxi/mc_smp.c
index fc0acfa07f74..11e46c6efb90 100644
--- a/arch/arm/mach-sunxi/mc_smp.c
+++ b/arch/arm/mach-sunxi/mc_smp.c
@@ -65,8 +65,12 @@
#define PRCM_PWR_SWITCH_REG(c, cpu) (0x140 + 0x10 * (c) + 0x4 * (cpu))
#define PRCM_CPU_SOFT_ENTRY_REG 0x164
+#define CPU0_SUPPORT_HOTPLUG_MAGIC0 0xFA50392F
+#define CPU0_SUPPORT_HOTPLUG_MAGIC1 0x790DCA3A
+
static void __iomem *cpucfg_base;
static void __iomem *prcm_base;
+static void __iomem *sram_b_smp_base;
static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster)
{
@@ -125,6 +129,17 @@ static int sunxi_cpu_power_switch_set(unsigned int cpu, unsigned int cluster,
return 0;
}
+static void sunxi_cpu0_hotplug_support_set(bool enable)
+{
+ if (enable) {
+ writel(CPU0_SUPPORT_HOTPLUG_MAGIC0, sram_b_smp_base);
+ writel(CPU0_SUPPORT_HOTPLUG_MAGIC1, sram_b_smp_base + 0x4);
+ } else {
+ writel(0x0, sram_b_smp_base);
+ writel(0x0, sram_b_smp_base + 0x4);
+ }
+}
+
static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster)
{
u32 reg;
@@ -133,6 +148,10 @@ static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster)
if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS)
return -EINVAL;
+ /* Set hotplug support magic flags for cpu0 */
+ if (cluster == 0 && cpu == 0)
+ sunxi_cpu0_hotplug_support_set(true);
+
/* assert processor power-on reset */
reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
reg &= ~PRCM_CPU_PO_RST_CTRL_CORE(cpu);
@@ -362,6 +381,13 @@ static bool sunxi_mc_smp_cluster_is_down(unsigned int cluster)
return true;
}
+static void sunxi_mc_smp_secondary_init(unsigned int cpu)
+{
+ /* Clear hotplug support magic flags for cpu0 */
+ if (cpu == 0)
+ sunxi_cpu0_hotplug_support_set(false);
+}
+
static int sunxi_mc_smp_boot_secondary(unsigned int l_cpu, struct task_struct *idle)
{
unsigned int mpidr, cpu, cluster;
@@ -572,13 +598,19 @@ out:
return !ret;
}
+static bool sunxi_mc_smp_cpu_can_disable(unsigned int __unused)
+{
+ return true;
+}
#endif
static const struct smp_operations sunxi_mc_smp_smp_ops __initconst = {
+ .smp_secondary_init = sunxi_mc_smp_secondary_init,
.smp_boot_secondary = sunxi_mc_smp_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = sunxi_mc_smp_cpu_die,
.cpu_kill = sunxi_mc_smp_cpu_kill,
+ .cpu_can_disable = sunxi_mc_smp_cpu_can_disable,
#endif
};
@@ -654,7 +686,7 @@ static int __init sunxi_mc_smp_lookback(void)
static int __init sunxi_mc_smp_init(void)
{
- struct device_node *cpucfg_node, *node;
+ struct device_node *cpucfg_node, *sram_node, *node;
struct resource res;
int ret;
@@ -702,16 +734,31 @@ static int __init sunxi_mc_smp_init(void)
goto err_put_cpucfg_node;
}
+ sram_node = of_find_compatible_node(NULL, NULL,
+ "allwinner,sun9i-a80-smp-sram");
+ if (!sram_node) {
+ ret = -ENODEV;
+ goto err_unmap_release_cpucfg;
+ }
+
+ sram_b_smp_base = of_io_request_and_map(sram_node, 0, "sunxi-mc-smp");
+ if (IS_ERR(sram_b_smp_base)) {
+ ret = PTR_ERR(sram_b_smp_base);
+ pr_err("%s: failed to map secure SRAM\n", __func__);
+ goto err_put_sram_node;
+ }
+
/* Configure CCI-400 for boot cluster */
ret = sunxi_mc_smp_lookback();
if (ret) {
pr_err("%s: failed to configure boot cluster: %d\n",
__func__, ret);
- goto err_unmap_release_cpucfg;
+ goto err_unmap_release_secure_sram;
}
- /* We don't need the CPUCFG device node anymore */
+ /* We don't need the CPUCFG and SRAM device nodes anymore */
of_node_put(cpucfg_node);
+ of_node_put(sram_node);
/* Set the hardware entry point address */
writel(__pa_symbol(sunxi_mc_smp_secondary_startup),
@@ -724,6 +771,12 @@ static int __init sunxi_mc_smp_init(void)
return 0;
+err_unmap_release_secure_sram:
+ iounmap(sram_b_smp_base);
+ of_address_to_resource(sram_node, 0, &res);
+ release_mem_region(res.start, resource_size(&res));
+err_put_sram_node:
+ of_node_put(sram_node);
err_unmap_release_cpucfg:
iounmap(cpucfg_base);
of_address_to_resource(cpucfg_node, 0, &res);