linux/arch/arm/mach-axxia/platsmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/arch/arm/mach-axxia/platsmp.c
   4 *
   5 * Copyright (C) 2012 LSI Corporation
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/io.h>
  10#include <linux/smp.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <asm/cacheflush.h>
  14
  15/* Syscon register offsets for releasing cores from reset */
  16#define SC_CRIT_WRITE_KEY       0x1000
  17#define SC_RST_CPU_HOLD         0x1010
  18
  19/*
  20 * Write the kernel entry point for secondary CPUs to the specified address
  21 */
  22static void write_release_addr(u32 release_phys)
  23{
  24        u32 *virt = (u32 *) phys_to_virt(release_phys);
  25        writel_relaxed(__pa_symbol(secondary_startup), virt);
  26        /* Make sure this store is visible to other CPUs */
  27        smp_wmb();
  28        __cpuc_flush_dcache_area(virt, sizeof(u32));
  29}
  30
  31static int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
  32{
  33        struct device_node *syscon_np;
  34        void __iomem *syscon;
  35        u32 tmp;
  36
  37        syscon_np = of_find_compatible_node(NULL, NULL, "lsi,axxia-syscon");
  38        if (!syscon_np)
  39                return -ENOENT;
  40
  41        syscon = of_iomap(syscon_np, 0);
  42        if (!syscon)
  43                return -ENOMEM;
  44
  45        tmp = readl(syscon + SC_RST_CPU_HOLD);
  46        writel(0xab, syscon + SC_CRIT_WRITE_KEY);
  47        tmp &= ~(1 << cpu);
  48        writel(tmp, syscon + SC_RST_CPU_HOLD);
  49
  50        return 0;
  51}
  52
  53static void __init axxia_smp_prepare_cpus(unsigned int max_cpus)
  54{
  55        int cpu_count = 0;
  56        int cpu;
  57
  58        /*
  59         * Initialise the present map, which describes the set of CPUs actually
  60         * populated at the present time.
  61         */
  62        for_each_possible_cpu(cpu) {
  63                struct device_node *np;
  64                u32 release_phys;
  65
  66                np = of_get_cpu_node(cpu, NULL);
  67                if (!np)
  68                        continue;
  69                if (of_property_read_u32(np, "cpu-release-addr", &release_phys))
  70                        continue;
  71
  72                if (cpu_count < max_cpus) {
  73                        set_cpu_present(cpu, true);
  74                        cpu_count++;
  75                }
  76
  77                if (release_phys != 0)
  78                        write_release_addr(release_phys);
  79        }
  80}
  81
  82static const struct smp_operations axxia_smp_ops __initconst = {
  83        .smp_prepare_cpus       = axxia_smp_prepare_cpus,
  84        .smp_boot_secondary     = axxia_boot_secondary,
  85};
  86CPU_METHOD_OF_DECLARE(axxia_smp, "lsi,syscon-release", &axxia_smp_ops);
  87