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