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

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

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp