linux/arch/arm/mach-imx/platsmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2011 Freescale Semiconductor, Inc.
   4 * Copyright 2011 Linaro Ltd.
   5 */
   6
   7#include <linux/init.h>
   8#include <linux/of_address.h>
   9#include <linux/of.h>
  10#include <linux/smp.h>
  11
  12#include <asm/cacheflush.h>
  13#include <asm/page.h>
  14#include <asm/smp_scu.h>
  15#include <asm/mach/map.h>
  16
  17#include "common.h"
  18#include "hardware.h"
  19
  20u32 g_diag_reg;
  21static void __iomem *scu_base;
  22
  23static struct map_desc scu_io_desc __initdata = {
  24        /* .virtual and .pfn are run-time assigned */
  25        .length         = SZ_4K,
  26        .type           = MT_DEVICE,
  27};
  28
  29void __init imx_scu_map_io(void)
  30{
  31        unsigned long base;
  32
  33        /* Get SCU base */
  34        asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
  35
  36        scu_io_desc.virtual = IMX_IO_P2V(base);
  37        scu_io_desc.pfn = __phys_to_pfn(base);
  38        iotable_init(&scu_io_desc, 1);
  39
  40        scu_base = IMX_IO_ADDRESS(base);
  41}
  42
  43static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle)
  44{
  45        imx_set_cpu_jump(cpu, v7_secondary_startup);
  46        imx_enable_cpu(cpu, true);
  47        return 0;
  48}
  49
  50/*
  51 * Initialise the CPU possible map early - this describes the CPUs
  52 * which may be present or become present in the system.
  53 */
  54static void __init imx_smp_init_cpus(void)
  55{
  56        int i, ncores;
  57
  58        ncores = scu_get_core_count(scu_base);
  59
  60        for (i = ncores; i < NR_CPUS; i++)
  61                set_cpu_possible(i, false);
  62}
  63
  64void imx_smp_prepare(void)
  65{
  66        scu_enable(scu_base);
  67}
  68
  69static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
  70{
  71        imx_smp_prepare();
  72
  73        /*
  74         * The diagnostic register holds the errata bits.  Mostly bootloader
  75         * does not bring up secondary cores, so that when errata bits are set
  76         * in bootloader, they are set only for boot cpu.  But on a SMP
  77         * configuration, it should be equally done on every single core.
  78         * Read the register from boot cpu here, and will replicate it into
  79         * secondary cores when booting them.
  80         */
  81        asm("mrc p15, 0, %0, c15, c0, 1" : "=r" (g_diag_reg) : : "cc");
  82        sync_cache_w(&g_diag_reg);
  83}
  84
  85const struct smp_operations imx_smp_ops __initconst = {
  86        .smp_init_cpus          = imx_smp_init_cpus,
  87        .smp_prepare_cpus       = imx_smp_prepare_cpus,
  88        .smp_boot_secondary     = imx_boot_secondary,
  89#ifdef CONFIG_HOTPLUG_CPU
  90        .cpu_die                = imx_cpu_die,
  91        .cpu_kill               = imx_cpu_kill,
  92#endif
  93};
  94
  95#define DCFG_CCSR_SCRATCHRW1    0x200
  96
  97static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
  98{
  99        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 100
 101        return 0;
 102}
 103
 104static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
 105{
 106        struct device_node *np;
 107        void __iomem *dcfg_base;
 108        unsigned long paddr;
 109
 110        np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
 111        dcfg_base = of_iomap(np, 0);
 112        of_node_put(np);
 113        BUG_ON(!dcfg_base);
 114
 115        paddr = __pa_symbol(secondary_startup);
 116        writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1);
 117
 118        iounmap(dcfg_base);
 119}
 120
 121const struct smp_operations ls1021a_smp_ops __initconst = {
 122        .smp_prepare_cpus       = ls1021a_smp_prepare_cpus,
 123        .smp_boot_secondary     = ls1021a_boot_secondary,
 124};
 125