~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-bcm/bcm63xx_smp.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
146 out:
147         iounmap(bootlut_base);
148 
149         return ret;
150 }
151 
152 static void __init bcm63138_smp_prepare_cpus(unsigned int max_cpus)
153 {
154         int ret;
155 
156         ret = scu_a9_enable();
157         if (ret) {
158                 pr_warn("SMP: Cortex-A9 SCU setup failed\n");
159                 return;
160         }
161 }
162 
163 static const struct smp_operations bcm63138_smp_ops __initconst = {
164         .smp_prepare_cpus       = bcm63138_smp_prepare_cpus,
165         .smp_boot_secondary     = bcm63138_smp_boot_secondary,
166 };
167 
168 CPU_METHOD_OF_DECLARE(bcm63138_smp, "brcm,bcm63138", &bcm63138_smp_ops);
169 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php