xref: /freebsd/sys/arm/freescale/imx/imx6_mp.c (revision 2b15cb3d0922bd70ea592f0da9b4a5b167f4d53f)
1 /*-
2  * Copyright (c) 2014 Juergen Weiss <weiss@uni-mainz.de>
3  * Copyright (c) 2014 Ian Lepore <ian@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.h>
34 #include <sys/mutex.h>
35 #include <sys/smp.h>
36 
37 #include <machine/smp.h>
38 #include <machine/fdt.h>
39 #include <machine/intr.h>
40 
41 #define	SCU_PHYSBASE			0x00a00000
42 #define	SCU_SIZE			0x00001000
43 
44 #define	SCU_CONTROL_REG			0x00
45 #define	  SCU_CONTROL_ENABLE		  (1 << 0)
46 #define	SCU_CONFIG_REG			0x04
47 #define	  SCU_CONFIG_REG_NCPU_MASK	  0x03
48 #define	SCU_CPUPOWER_REG		0x08
49 #define	SCU_INV_TAGS_REG		0x0c
50 #define	SCU_DIAG_CONTROL		0x30
51 #define	  SCU_DIAG_DISABLE_MIGBIT	  (1 << 0)
52 #define	SCU_FILTER_START_REG		0x40
53 #define	SCU_FILTER_END_REG		0x44
54 #define	SCU_SECURE_ACCESS_REG		0x50
55 #define	SCU_NONSECURE_ACCESS_REG	0x54
56 
57 #define	SRC_PHYSBASE			0x020d8000
58 #define SRC_SIZE			0x4000
59 #define	SRC_CONTROL_REG			0x00
60 #define	SRC_CONTROL_C1ENA_SHIFT		  22	/* Bit for Core 1 enable */
61 #define	SRC_CONTROL_C1RST_SHIFT		  14	/* Bit for Core 1 reset */
62 #define	SRC_GPR0_C1FUNC			0x20	/* Register for Core 1 entry func */
63 #define	SRC_GPR1_C1ARG			0x24	/* Register for Core 1 entry arg */
64 
65 void
66 platform_mp_init_secondary(void)
67 {
68 
69 	arm_init_secondary_ic();
70 }
71 
72 void
73 platform_mp_setmaxid(void)
74 {
75 	bus_space_handle_t scu;
76 	int hwcpu, ncpu;
77 	uint32_t val;
78 
79 	/* If we've already set the global vars don't bother to do it again. */
80 	if (mp_ncpus != 0)
81 		return;
82 
83 	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
84 		panic("Couldn't map the SCU\n");
85 	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
86 	hwcpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
87 	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
88 
89 	ncpu = hwcpu;
90 	TUNABLE_INT_FETCH("hw.ncpu", &ncpu);
91 	if (ncpu < 1 || ncpu > hwcpu)
92 		ncpu = hwcpu;
93 
94 	mp_ncpus = ncpu;
95 	mp_maxid = ncpu - 1;
96 }
97 
98 int
99 platform_mp_probe(void)
100 {
101 
102 	/* I think platform_mp_setmaxid must get called first, but be safe. */
103 	if (mp_ncpus == 0)
104 		platform_mp_setmaxid();
105 
106 	return (mp_ncpus > 1);
107 }
108 
109 void
110 platform_mp_start_ap(void)
111 {
112 	bus_space_handle_t scu;
113 	bus_space_handle_t src;
114 
115 	uint32_t val;
116 	int i;
117 
118 	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
119 		panic("Couldn't map the SCU\n");
120 	if (bus_space_map(fdtbus_bs_tag, SRC_PHYSBASE, SRC_SIZE, 0, &src) != 0)
121 		panic("Couldn't map the system reset controller (SRC)\n");
122 
123 	/*
124 	 * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates all
125 	 * ways on all cores 0-3.  Per the ARM docs, it's harmless to write to
126 	 * the bits for cores that are not present.
127 	 */
128 	bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff);
129 
130 	/*
131 	 * Erratum ARM/MP: 764369 (problems with cache maintenance).
132 	 * Setting the "disable-migratory bit" in the undocumented SCU
133 	 * Diagnostic Control Register helps work around the problem.
134 	 */
135 	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL);
136 	bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL,
137 	    val | SCU_DIAG_DISABLE_MIGBIT);
138 
139 	/*
140 	 * Enable the SCU, then clean the cache on this core.  After these two
141 	 * operations the cache tag ram in the SCU is coherent with the contents
142 	 * of the cache on this core.  The other cores aren't running yet so
143 	 * their caches can't contain valid data yet, but we've initialized
144 	 * their SCU tag ram above, so they will be coherent from startup.
145 	 */
146 	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
147 	bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG,
148 	    val | SCU_CONTROL_ENABLE);
149 	cpu_idcache_wbinv_all();
150 
151 	/*
152 	 * For each AP core, set the entry point address and argument registers,
153 	 * and set the core-enable and core-reset bits in the control register.
154 	 */
155 	val = bus_space_read_4(fdtbus_bs_tag, src, SRC_CONTROL_REG);
156 	for (i=1; i < mp_ncpus; i++) {
157 		bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR0_C1FUNC + 8*i,
158 		    pmap_kextract((vm_offset_t)mpentry));
159 		bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR1_C1ARG  + 8*i, 0);
160 
161 		val |= ((1 << (SRC_CONTROL_C1ENA_SHIFT - 1 + i )) |
162 		    ( 1 << (SRC_CONTROL_C1RST_SHIFT - 1 + i)));
163 
164 	}
165 	bus_space_write_4(fdtbus_bs_tag, src, SRC_CONTROL_REG, val);
166 
167 	armv7_sev();
168 
169 	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
170 	bus_space_unmap(fdtbus_bs_tag, src, SRC_SIZE);
171 }
172 
173 void
174 platform_ipi_send(cpuset_t cpus, u_int ipi)
175 {
176 
177 	pic_ipi_send(cpus, ipi);
178 }
179