This source file includes following definitions.
- scu_a9_enable
- bcm63138_smp_boot_secondary
- bcm63138_smp_prepare_cpus
1
2
3
4
5
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
23 #define CORTEX_A9_SCU_SIZE 0x58
24
25
26
27
28
29
30
31
32
33
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
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
71
72
73
74
75
76
77
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);
95
96 return 0;
97 }
98
99 static const struct of_device_id bcm63138_bootlut_ids[] = {
100 { .compatible = "brcm,bcm63138-bootlut", },
101 { },
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
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
137 val = __pa_symbol(secondary_startup);
138 writel_relaxed(val, bootlut_base + BOOTLUT_RESET_VECT);
139
140
141
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);