linux/arch/arm/mach-ux500/platsmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2002 ARM Ltd.
   4 * Copyright (C) 2008 STMicroelctronics.
   5 * Copyright (C) 2009 ST-Ericsson.
   6 * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
   7 *
   8 * This file is based on arm realview platform
   9 */
  10#include <linux/init.h>
  11#include <linux/errno.h>
  12#include <linux/delay.h>
  13#include <linux/device.h>
  14#include <linux/smp.h>
  15#include <linux/io.h>
  16#include <linux/of.h>
  17#include <linux/of_address.h>
  18
  19#include <asm/cacheflush.h>
  20#include <asm/smp_plat.h>
  21#include <asm/smp_scu.h>
  22
  23#include "db8500-regs.h"
  24
  25/* Magic triggers in backup RAM */
  26#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4
  27#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0
  28
  29static void __iomem *backupram;
  30
  31static void __init ux500_smp_prepare_cpus(unsigned int max_cpus)
  32{
  33        struct device_node *np;
  34        static void __iomem *scu_base;
  35        unsigned int ncores;
  36        int i;
  37
  38        np = of_find_compatible_node(NULL, NULL, "ste,dbx500-backupram");
  39        if (!np) {
  40                pr_err("No backupram base address\n");
  41                return;
  42        }
  43        backupram = of_iomap(np, 0);
  44        of_node_put(np);
  45        if (!backupram) {
  46                pr_err("No backupram remap\n");
  47                return;
  48        }
  49
  50        np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
  51        if (!np) {
  52                pr_err("No SCU base address\n");
  53                return;
  54        }
  55        scu_base = of_iomap(np, 0);
  56        of_node_put(np);
  57        if (!scu_base) {
  58                pr_err("No SCU remap\n");
  59                return;
  60        }
  61
  62        scu_enable(scu_base);
  63        ncores = scu_get_core_count(scu_base);
  64        for (i = 0; i < ncores; i++)
  65                set_cpu_possible(i, true);
  66        iounmap(scu_base);
  67}
  68
  69static int ux500_boot_secondary(unsigned int cpu, struct task_struct *idle)
  70{
  71        /*
  72         * write the address of secondary startup into the backup ram register
  73         * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the
  74         * backup ram register at offset 0x1FF0, which is what boot rom code
  75         * is waiting for. This will wake up the secondary core from WFE.
  76         */
  77        writel(__pa_symbol(secondary_startup),
  78               backupram + UX500_CPU1_JUMPADDR_OFFSET);
  79        writel(0xA1FEED01,
  80               backupram + UX500_CPU1_WAKEMAGIC_OFFSET);
  81
  82        /* make sure write buffer is drained */
  83        mb();
  84        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  85        return 0;
  86}
  87
  88#ifdef CONFIG_HOTPLUG_CPU
  89void ux500_cpu_die(unsigned int cpu)
  90{
  91        wfi();
  92}
  93#endif
  94
  95static const struct smp_operations ux500_smp_ops __initconst = {
  96        .smp_prepare_cpus       = ux500_smp_prepare_cpus,
  97        .smp_boot_secondary     = ux500_boot_secondary,
  98#ifdef CONFIG_HOTPLUG_CPU
  99        .cpu_die                = ux500_cpu_die,
 100#endif
 101};
 102CPU_METHOD_OF_DECLARE(ux500_smp, "ste,dbx500-smp", &ux500_smp_ops);
 103