Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2015 Linus Walleij
0004  */
0005 #include <linux/smp.h>
0006 #include <linux/io.h>
0007 #include <linux/of.h>
0008 #include <linux/of_address.h>
0009 #include <linux/regmap.h>
0010 #include <linux/mfd/syscon.h>
0011 
0012 #include <asm/cacheflush.h>
0013 #include <asm/smp_plat.h>
0014 #include <asm/smp_scu.h>
0015 
0016 #include "platsmp.h"
0017 
0018 #define REALVIEW_SYS_FLAGSSET_OFFSET    0x30
0019 
0020 static const struct of_device_id realview_scu_match[] = {
0021     { .compatible = "arm,arm11mp-scu", },
0022     { .compatible = "arm,cortex-a9-scu", },
0023     { .compatible = "arm,cortex-a5-scu", },
0024     { }
0025 };
0026 
0027 static const struct of_device_id realview_syscon_match[] = {
0028         { .compatible = "arm,core-module-integrator", },
0029         { .compatible = "arm,realview-eb-syscon", },
0030         { .compatible = "arm,realview-pb11mp-syscon", },
0031         { .compatible = "arm,realview-pbx-syscon", },
0032         { },
0033 };
0034 
0035 static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
0036 {
0037     struct device_node *np;
0038     void __iomem *scu_base;
0039     struct regmap *map;
0040     unsigned int ncores;
0041     int i;
0042 
0043     np = of_find_matching_node(NULL, realview_scu_match);
0044     if (!np) {
0045         pr_err("PLATSMP: No SCU base address\n");
0046         return;
0047     }
0048     scu_base = of_iomap(np, 0);
0049     of_node_put(np);
0050     if (!scu_base) {
0051         pr_err("PLATSMP: No SCU remap\n");
0052         return;
0053     }
0054 
0055     scu_enable(scu_base);
0056     ncores = scu_get_core_count(scu_base);
0057     pr_info("SCU: %d cores detected\n", ncores);
0058     for (i = 0; i < ncores; i++)
0059         set_cpu_possible(i, true);
0060     iounmap(scu_base);
0061 
0062     /* The syscon contains the magic SMP start address registers */
0063     np = of_find_matching_node(NULL, realview_syscon_match);
0064     if (!np) {
0065         pr_err("PLATSMP: No syscon match\n");
0066         return;
0067     }
0068     map = syscon_node_to_regmap(np);
0069     if (IS_ERR(map)) {
0070         pr_err("PLATSMP: No syscon regmap\n");
0071         return;
0072     }
0073     /* Put the boot address in this magic register */
0074     regmap_write(map, REALVIEW_SYS_FLAGSSET_OFFSET,
0075              __pa_symbol(versatile_secondary_startup));
0076 }
0077 
0078 #ifdef CONFIG_HOTPLUG_CPU
0079 static void realview_cpu_die(unsigned int cpu)
0080 {
0081     return versatile_immitation_cpu_die(cpu, 0x20);
0082 }
0083 #endif
0084 
0085 static const struct smp_operations realview_dt_smp_ops __initconst = {
0086     .smp_prepare_cpus   = realview_smp_prepare_cpus,
0087     .smp_secondary_init = versatile_secondary_init,
0088     .smp_boot_secondary = versatile_boot_secondary,
0089 #ifdef CONFIG_HOTPLUG_CPU
0090     .cpu_die        = realview_cpu_die,
0091 #endif
0092 };
0093 CPU_METHOD_OF_DECLARE(realview_smp, "arm,realview-smp", &realview_dt_smp_ops);