root/arch/arm/mach-bcm/bcm63xx_smp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scu_a9_enable
  2. bcm63138_smp_boot_secondary
  3. bcm63138_smp_prepare_cpus

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Broadcom BCM63138 DSL SoCs SMP support code
   4  *
   5  * Copyright (C) 2015, Broadcom Corporation
   6  */
   7 
   8 #include <linux/delay.h>
   9 #include <linux/init.h>
  10 #include <linux/smp.h>
  11 #include <linux/io.h>
  12 #include <linux/of.h>
  13 #include <linux/of_address.h>
  14 
  15 #include <asm/cacheflush.h>
  16 #include <asm/smp_scu.h>
  17 #include <asm/smp_plat.h>
  18 #include <asm/vfp.h>
  19 
  20 #include "bcm63xx_smp.h"
  21 
  22 /* Size of mapped Cortex A9 SCU address space */
  23 #define CORTEX_A9_SCU_SIZE      0x58
  24 
  25 /*
  26  * Enable the Cortex A9 Snoop Control Unit
  27  *
  28  * By the time this is called we already know there are multiple
  29  * cores present.  We assume we're running on a Cortex A9 processor,
  30  * so any trouble getting the base address register or getting the
  31  * SCU base is a problem.
  32  *
  33  * Return 0 if successful or an error code otherwise.
  34  */
  35 static int __init scu_a9_enable(void)
  36 {
  37         unsigned long config_base;
  38         void __iomem *scu_base;
  39         unsigned int i, ncores;
  40 
  41         if (!scu_a9_has_base()) {
  42                 pr_err("no configuration base address register!\n");
  43                 return -ENXIO;
  44         }
  45 
  46         /* Config base address register value is zero for uniprocessor */
  47         config_base = scu_a9_get_base();
  48         if (!config_base) {
  49                 pr_err("hardware reports only one core\n");
  50                 return -ENOENT;
  51         }
  52 
  53         scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
  54         if (!scu_base) {
  55                 pr_err("failed to remap config base (%lu/%u) for SCU\n",
  56                         config_base, CORTEX_A9_SCU_SIZE);
  57                 return -ENOMEM;
  58         }
  59 
  60         scu_enable(scu_base);
  61 
  62         ncores = scu_base ? scu_get_core_count(scu_base) : 1;
  63 
  64         if (ncores > nr_cpu_ids) {
  65                 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
  66                                 ncores, nr_cpu_ids);
  67                 ncores = nr_cpu_ids;
  68         }
  69 
  70         /* The BCM63138 SoC has two Cortex-A9 CPUs, CPU0 features a complete
  71          * and fully functional VFP unit that can be used, but CPU1 does not.
  72          * Since we will not be able to trap kernel-mode NEON to force
  73          * migration to CPU0, just do not advertise VFP support at all.
  74          *
  75          * This will make vfp_init bail out and do not attempt to use VFP at
  76          * all, for kernel-mode NEON, we do not want to introduce any
  77          * conditionals in hot-paths, so we just restrict the system to UP.
  78          */
  79 #ifdef CONFIG_VFP
  80         if (ncores > 1) {
  81                 pr_warn("SMP: secondary CPUs lack VFP unit, disabling VFP\n");
  82                 vfp_disable();
  83 
  84 #ifdef CONFIG_KERNEL_MODE_NEON
  85                 WARN(1, "SMP: kernel-mode NEON enabled, restricting to UP\n");
  86                 ncores = 1;
  87 #endif
  88         }
  89 #endif
  90 
  91         for (i = 0; i < ncores; i++)
  92                 set_cpu_possible(i, true);
  93 
  94         iounmap(scu_base);      /* That's the last we'll need of this */
  95 
  96         return 0;
  97 }
  98 
  99 static const struct of_device_id bcm63138_bootlut_ids[] = {
 100         { .compatible = "brcm,bcm63138-bootlut", },
 101         { /* sentinel */ },
 102 };
 103 
 104 #define BOOTLUT_RESET_VECT      0x20
 105 
 106 static int bcm63138_smp_boot_secondary(unsigned int cpu,
 107                                        struct task_struct *idle)
 108 {
 109         void __iomem *bootlut_base;
 110         struct device_node *dn;
 111         int ret = 0;
 112         u32 val;
 113 
 114         dn = of_find_matching_node(NULL, bcm63138_bootlut_ids);
 115         if (!dn) {
 116                 pr_err("SMP: unable to find bcm63138 boot LUT node\n");
 117                 return -ENODEV;
 118         }
 119 
 120         bootlut_base = of_iomap(dn, 0);
 121         of_node_put(dn);
 122 
 123         if (!bootlut_base) {
 124                 pr_err("SMP: unable to remap boot LUT base register\n");
 125                 return -ENOMEM;
 126         }
 127 
 128         /* Locate the secondary CPU node */
 129         dn = of_get_cpu_node(cpu, NULL);
 130         if (!dn) {
 131                 pr_err("SMP: failed to locate secondary CPU%d node\n", cpu);
 132                 ret = -ENODEV;
 133                 goto out;
 134         }
 135 
 136         /* Write the secondary init routine to the BootLUT reset vector */
 137         val = __pa_symbol(secondary_startup);
 138         writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
 139 
 140         /* Power up the core, will jump straight to its reset vector when we
 141          * return
 142          */
 143         ret = bcm63xx_pmb_power_on_cpu(dn);
 144         of_node_put(dn);
 145         if (ret)
 146                 goto out;
 147 out:
 148         iounmap(bootlut_base);
 149 
 150         return ret;
 151 }
 152 
 153 static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
 154 {
 155         int ret;
 156 
 157         ret = scu_a9_enable();
 158         if (ret) {
 159                 pr_warn("SMP: Cortex-A9 SCU setup failed\n");
 160                 return;
 161         }
 162 }
 163 
 164 static const struct smp_operations bcm63138_smp_ops __initconst = {
 165         .smp_prepare_cpus       = bcm63138_smp_prepare_cpus,
 166         .smp_boot_secondary     = bcm63138_smp_boot_secondary,
 167 };
 168 
 169 CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);

/* [<][>][^][v][top][bottom][index][help] */