Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2010-2011 Calxeda, Inc.
0004  * Copyright 2012 Pavel Machek <pavel@denx.de>
0005  * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
0006  * Copyright (C) 2012 Altera Corporation
0007  */
0008 #include <linux/delay.h>
0009 #include <linux/init.h>
0010 #include <linux/smp.h>
0011 #include <linux/io.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 
0015 #include <asm/cacheflush.h>
0016 #include <asm/smp_scu.h>
0017 #include <asm/smp_plat.h>
0018 
0019 #include "core.h"
0020 
0021 static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
0022 {
0023     int trampoline_size = secondary_trampoline_end - secondary_trampoline;
0024 
0025     if (socfpga_cpu1start_addr) {
0026         /* This will put CPU #1 into reset. */
0027         writel(RSTMGR_MPUMODRST_CPU1,
0028                rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
0029 
0030         memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);
0031 
0032         writel(__pa_symbol(secondary_startup),
0033                sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));
0034 
0035         flush_cache_all();
0036         smp_wmb();
0037         outer_clean_range(0, trampoline_size);
0038 
0039         /* This will release CPU #1 out of reset. */
0040         writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
0041     }
0042 
0043     return 0;
0044 }
0045 
0046 static int socfpga_a10_boot_secondary(unsigned int cpu, struct task_struct *idle)
0047 {
0048     int trampoline_size = secondary_trampoline_end - secondary_trampoline;
0049 
0050     if (socfpga_cpu1start_addr) {
0051         writel(RSTMGR_MPUMODRST_CPU1, rst_manager_base_addr +
0052                SOCFPGA_A10_RSTMGR_MODMPURST);
0053         memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);
0054 
0055         writel(__pa_symbol(secondary_startup),
0056                sys_manager_base_addr + (socfpga_cpu1start_addr & 0x00000fff));
0057 
0058         flush_cache_all();
0059         smp_wmb();
0060         outer_clean_range(0, trampoline_size);
0061 
0062         /* This will release CPU #1 out of reset. */
0063         writel(0, rst_manager_base_addr + SOCFPGA_A10_RSTMGR_MODMPURST);
0064     }
0065 
0066     return 0;
0067 }
0068 
0069 static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
0070 {
0071     struct device_node *np;
0072     void __iomem *socfpga_scu_base_addr;
0073 
0074     np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
0075     if (!np) {
0076         pr_err("%s: missing scu\n", __func__);
0077         return;
0078     }
0079 
0080     socfpga_scu_base_addr = of_iomap(np, 0);
0081     if (!socfpga_scu_base_addr)
0082         return;
0083     scu_enable(socfpga_scu_base_addr);
0084 }
0085 
0086 #ifdef CONFIG_HOTPLUG_CPU
0087 /*
0088  * platform-specific code to shutdown a CPU
0089  *
0090  * Called with IRQs disabled
0091  */
0092 static void socfpga_cpu_die(unsigned int cpu)
0093 {
0094     /* Do WFI. If we wake up early, go back into WFI */
0095     while (1)
0096         cpu_do_idle();
0097 }
0098 
0099 /*
0100  * We need a dummy function so that platform_can_cpu_hotplug() knows
0101  * we support CPU hotplug. However, the function does not need to do
0102  * anything, because CPUs going offline just do WFI. We could reset
0103  * the CPUs but it would increase power consumption.
0104  */
0105 static int socfpga_cpu_kill(unsigned int cpu)
0106 {
0107     return 1;
0108 }
0109 #endif
0110 
0111 static const struct smp_operations socfpga_smp_ops __initconst = {
0112     .smp_prepare_cpus   = socfpga_smp_prepare_cpus,
0113     .smp_boot_secondary = socfpga_boot_secondary,
0114 #ifdef CONFIG_HOTPLUG_CPU
0115     .cpu_die        = socfpga_cpu_die,
0116     .cpu_kill       = socfpga_cpu_kill,
0117 #endif
0118 };
0119 
0120 static const struct smp_operations socfpga_a10_smp_ops __initconst = {
0121     .smp_prepare_cpus   = socfpga_smp_prepare_cpus,
0122     .smp_boot_secondary = socfpga_a10_boot_secondary,
0123 #ifdef CONFIG_HOTPLUG_CPU
0124     .cpu_die        = socfpga_cpu_die,
0125     .cpu_kill       = socfpga_cpu_kill,
0126 #endif
0127 };
0128 
0129 CPU_METHOD_OF_DECLARE(socfpga_smp, "altr,socfpga-smp", &socfpga_smp_ops);
0130 CPU_METHOD_OF_DECLARE(socfpga_a10_smp, "altr,socfpga-a10-smp", &socfpga_a10_smp_ops);