1 /*-
2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/smp.h>
40
41 #include <vm/vm.h>
42 #include <vm/pmap.h>
43
44 #include <machine/smp.h>
45 #include <machine/fdt.h>
46 #include <machine/intr.h>
47
48 #define SCU_PHYSBASE 0xFFFEC000
49 #define SCU_SIZE 0x100
50
51 #define SCU_CONTROL_REG 0x00
52 #define SCU_CONTROL_ENABLE (1 << 0)
53 #define SCU_CONFIG_REG 0x04
54 #define SCU_CONFIG_REG_NCPU_MASK 0x03
55 #define SCU_CPUPOWER_REG 0x08
56 #define SCU_INV_TAGS_REG 0x0c
57 #define SCU_DIAG_CONTROL 0x30
58 #define SCU_DIAG_DISABLE_MIGBIT (1 << 0)
59 #define SCU_FILTER_START_REG 0x40
60 #define SCU_FILTER_END_REG 0x44
61 #define SCU_SECURE_ACCESS_REG 0x50
62 #define SCU_NONSECURE_ACCESS_REG 0x54
63
64 #define RSTMGR_PHYSBASE 0xFFD05000
65 #define RSTMGR_SIZE 0x100
66 #define MPUMODRST 0x10
67 #define MPUMODRST_CPU1 (1 << 1)
68
69 #define RAM_PHYSBASE 0x0
70 #define RAM_SIZE 0x1000
71
72 extern char *mpentry_addr;
73 static void socfpga_trampoline(void);
74
75 static void
socfpga_trampoline(void)76 socfpga_trampoline(void)
77 {
78
79 __asm __volatile(
80 "ldr pc, 1f\n"
81 ".globl mpentry_addr\n"
82 "mpentry_addr:\n"
83 "1: .space 4\n");
84 }
85
86 void
platform_mp_init_secondary(void)87 platform_mp_init_secondary(void)
88 {
89
90 intr_pic_init_secondary();
91 }
92
93 void
platform_mp_setmaxid(void)94 platform_mp_setmaxid(void)
95 {
96 int hwcpu, ncpu;
97
98 /* If we've already set this don't bother to do it again. */
99 if (mp_ncpus != 0)
100 return;
101
102 hwcpu = 2;
103
104 ncpu = hwcpu;
105 TUNABLE_INT_FETCH("hw.ncpu", &ncpu);
106 if (ncpu < 1 || ncpu > hwcpu)
107 ncpu = hwcpu;
108
109 mp_ncpus = ncpu;
110 mp_maxid = ncpu - 1;
111 }
112
113 int
platform_mp_probe(void)114 platform_mp_probe(void)
115 {
116
117 if (mp_ncpus == 0)
118 platform_mp_setmaxid();
119
120 return (mp_ncpus > 1);
121 }
122
123 void
platform_mp_start_ap(void)124 platform_mp_start_ap(void)
125 {
126 bus_space_handle_t scu, rst, ram;
127 int reg;
128
129 if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE,
130 SCU_SIZE, 0, &scu) != 0)
131 panic("Couldn't map the SCU\n");
132 if (bus_space_map(fdtbus_bs_tag, RSTMGR_PHYSBASE,
133 RSTMGR_SIZE, 0, &rst) != 0)
134 panic("Couldn't map the reset manager (RSTMGR)\n");
135 if (bus_space_map(fdtbus_bs_tag, RAM_PHYSBASE,
136 RAM_SIZE, 0, &ram) != 0)
137 panic("Couldn't map the first physram page\n");
138
139 /* Invalidate SCU cache tags */
140 bus_space_write_4(fdtbus_bs_tag, scu,
141 SCU_INV_TAGS_REG, 0x0000ffff);
142
143 /*
144 * Erratum ARM/MP: 764369 (problems with cache maintenance).
145 * Setting the "disable-migratory bit" in the undocumented SCU
146 * Diagnostic Control Register helps work around the problem.
147 */
148 reg = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL);
149 reg |= (SCU_DIAG_DISABLE_MIGBIT);
150 bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, reg);
151
152 /* Put CPU1 to reset state */
153 bus_space_write_4(fdtbus_bs_tag, rst, MPUMODRST, MPUMODRST_CPU1);
154
155 /* Enable the SCU, then clean the cache on this core */
156 reg = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
157 reg |= (SCU_CONTROL_ENABLE);
158 bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, reg);
159
160 /* Set up trampoline code */
161 mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry);
162 bus_space_write_region_4(fdtbus_bs_tag, ram, 0,
163 (uint32_t *)&socfpga_trampoline, 8);
164
165 cpu_idcache_wbinv_all();
166 cpu_l2cache_wbinv_all();
167
168 /* Put CPU1 out from reset */
169 bus_space_write_4(fdtbus_bs_tag, rst, MPUMODRST, 0);
170
171 armv7_sev();
172
173 bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
174 bus_space_unmap(fdtbus_bs_tag, rst, RSTMGR_SIZE);
175 bus_space_unmap(fdtbus_bs_tag, ram, RAM_SIZE);
176 }
177
178 void
platform_ipi_send(cpuset_t cpus,u_int ipi)179 platform_ipi_send(cpuset_t cpus, u_int ipi)
180 {
181
182 pic_ipi_send(cpus, ipi);
183 }
184