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