linux/arch/arm/mach-sti/platsmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  arch/arm/mach-sti/platsmp.c
   4 *
   5 * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
   6 *              http://www.st.com
   7 *
   8 * Cloned from linux/arch/arm/mach-vexpress/platsmp.c
   9 *
  10 *  Copyright (C) 2002 ARM Ltd.
  11 *  All Rights Reserved
  12 */
  13#include <linux/init.h>
  14#include <linux/errno.h>
  15#include <linux/delay.h>
  16#include <linux/smp.h>
  17#include <linux/io.h>
  18#include <linux/of.h>
  19#include <linux/of_address.h>
  20#include <linux/memblock.h>
  21
  22#include <asm/cacheflush.h>
  23#include <asm/smp_plat.h>
  24#include <asm/smp_scu.h>
  25
  26#include "smp.h"
  27
  28static u32 __iomem *cpu_strt_ptr;
  29
  30static int sti_boot_secondary(unsigned int cpu, struct task_struct *idle)
  31{
  32        unsigned long entry_pa = __pa_symbol(secondary_startup);
  33
  34        /*
  35         * Secondary CPU is initialised and started by a U-BOOTROM firmware.
  36         * Secondary CPU is spinning and waiting for a write at cpu_strt_ptr.
  37         * Writing secondary_startup address at cpu_strt_ptr makes it to
  38         * jump directly to secondary_startup().
  39         */
  40        __raw_writel(entry_pa, cpu_strt_ptr);
  41
  42        /* wmb so that data is actually written before cache flush is done */
  43        smp_wmb();
  44        sync_cache_w(cpu_strt_ptr);
  45
  46        return 0;
  47}
  48
  49static void __init sti_smp_prepare_cpus(unsigned int max_cpus)
  50{
  51        struct device_node *np;
  52        void __iomem *scu_base;
  53        u32 release_phys;
  54        int cpu;
  55
  56        np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
  57
  58        if (np) {
  59                scu_base = of_iomap(np, 0);
  60                scu_enable(scu_base);
  61                of_node_put(np);
  62        }
  63
  64        if (max_cpus <= 1)
  65                return;
  66
  67        for_each_possible_cpu(cpu) {
  68
  69                np = of_get_cpu_node(cpu, NULL);
  70
  71                if (!np)
  72                        continue;
  73
  74                if (of_property_read_u32(np, "cpu-release-addr",
  75                                                &release_phys)) {
  76                        pr_err("CPU %d: missing or invalid cpu-release-addr "
  77                                "property\n", cpu);
  78                        continue;
  79                }
  80
  81                /*
  82                 * cpu-release-addr is usually configured in SBC DMEM but can
  83                 * also be in RAM.
  84                 */
  85
  86                if (!memblock_is_memory(release_phys))
  87                        cpu_strt_ptr =
  88                                ioremap(release_phys, sizeof(release_phys));
  89                else
  90                        cpu_strt_ptr =
  91                                (u32 __iomem *)phys_to_virt(release_phys);
  92
  93                set_cpu_possible(cpu, true);
  94        }
  95}
  96
  97const struct smp_operations sti_smp_ops __initconst = {
  98        .smp_prepare_cpus       = sti_smp_prepare_cpus,
  99        .smp_boot_secondary     = sti_boot_secondary,
 100};
 101