Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2014 Marvell Technology Group Ltd.
0004  *
0005  * Antoine Ténart <antoine.tenart@free-electrons.com>
0006  */
0007 
0008 #include <linux/io.h>
0009 #include <linux/delay.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 
0013 #include <asm/cacheflush.h>
0014 #include <asm/cp15.h>
0015 #include <asm/memory.h>
0016 #include <asm/smp_plat.h>
0017 #include <asm/smp_scu.h>
0018 
0019 /*
0020  * There are two reset registers, one with self-clearing (SC)
0021  * reset and one with non-self-clearing reset (NON_SC).
0022  */
0023 #define CPU_RESET_SC        0x00
0024 #define CPU_RESET_NON_SC    0x20
0025 
0026 #define RESET_VECT      0x00
0027 #define SW_RESET_ADDR       0x94
0028 
0029 extern u32 boot_inst;
0030 
0031 static void __iomem *cpu_ctrl;
0032 
0033 static inline void berlin_perform_reset_cpu(unsigned int cpu)
0034 {
0035     u32 val;
0036 
0037     val = readl(cpu_ctrl + CPU_RESET_NON_SC);
0038     val &= ~BIT(cpu_logical_map(cpu));
0039     writel(val, cpu_ctrl + CPU_RESET_NON_SC);
0040     val |= BIT(cpu_logical_map(cpu));
0041     writel(val, cpu_ctrl + CPU_RESET_NON_SC);
0042 }
0043 
0044 static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
0045 {
0046     if (!cpu_ctrl)
0047         return -EFAULT;
0048 
0049     /*
0050      * Reset the CPU, making it to execute the instruction in the reset
0051      * exception vector.
0052      */
0053     berlin_perform_reset_cpu(cpu);
0054 
0055     return 0;
0056 }
0057 
0058 static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
0059 {
0060     struct device_node *np;
0061     void __iomem *scu_base;
0062     void __iomem *vectors_base;
0063 
0064     np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
0065     scu_base = of_iomap(np, 0);
0066     of_node_put(np);
0067     if (!scu_base)
0068         return;
0069 
0070     np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl");
0071     cpu_ctrl = of_iomap(np, 0);
0072     of_node_put(np);
0073     if (!cpu_ctrl)
0074         goto unmap_scu;
0075 
0076     vectors_base = ioremap(VECTORS_BASE, SZ_32K);
0077     if (!vectors_base)
0078         goto unmap_scu;
0079 
0080     scu_enable(scu_base);
0081 
0082     /*
0083      * Write the first instruction the CPU will execute after being reset
0084      * in the reset exception vector.
0085      */
0086     writel(boot_inst, vectors_base + RESET_VECT);
0087 
0088     /*
0089      * Write the secondary startup address into the SW reset address
0090      * vector. This is used by boot_inst.
0091      */
0092     writel(__pa_symbol(secondary_startup), vectors_base + SW_RESET_ADDR);
0093 
0094     iounmap(vectors_base);
0095 unmap_scu:
0096     iounmap(scu_base);
0097 }
0098 
0099 #ifdef CONFIG_HOTPLUG_CPU
0100 static void berlin_cpu_die(unsigned int cpu)
0101 {
0102     v7_exit_coherency_flush(louis);
0103     while (1)
0104         cpu_do_idle();
0105 }
0106 
0107 static int berlin_cpu_kill(unsigned int cpu)
0108 {
0109     u32 val;
0110 
0111     val = readl(cpu_ctrl + CPU_RESET_NON_SC);
0112     val &= ~BIT(cpu_logical_map(cpu));
0113     writel(val, cpu_ctrl + CPU_RESET_NON_SC);
0114 
0115     return 1;
0116 }
0117 #endif
0118 
0119 static const struct smp_operations berlin_smp_ops __initconst = {
0120     .smp_prepare_cpus   = berlin_smp_prepare_cpus,
0121     .smp_boot_secondary = berlin_boot_secondary,
0122 #ifdef CONFIG_HOTPLUG_CPU
0123     .cpu_die        = berlin_cpu_die,
0124     .cpu_kill       = berlin_cpu_kill,
0125 #endif
0126 };
0127 CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);