1265739Sganbold/*-
2265739Sganbold * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
3265739Sganbold * All rights reserved.
4265739Sganbold *
5265739Sganbold * Redistribution and use in source and binary forms, with or without
6265739Sganbold * modification, are permitted provided that the following conditions
7265739Sganbold * are met:
8265739Sganbold * 1. Redistributions of source code must retain the above copyright
9265739Sganbold *    notice, this list of conditions and the following disclaimer.
10265739Sganbold * 2. Redistributions in binary form must reproduce the above copyright
11265739Sganbold *    notice, this list of conditions and the following disclaimer in the
12265739Sganbold *    documentation and/or other materials provided with the distribution.
13265739Sganbold *
14265739Sganbold * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15265739Sganbold * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16265739Sganbold * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17265739Sganbold * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18265739Sganbold * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19265739Sganbold * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20265739Sganbold * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21265739Sganbold * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22265739Sganbold * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23265739Sganbold * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24265739Sganbold */
25265739Sganbold
26265739Sganbold#include <sys/cdefs.h>
27265739Sganbold__FBSDID("$FreeBSD$");
28265739Sganbold#include <sys/param.h>
29265739Sganbold#include <sys/systm.h>
30265739Sganbold#include <sys/bus.h>
31265739Sganbold#include <sys/kernel.h>
32265739Sganbold#include <sys/lock.h>
33265739Sganbold#include <sys/mutex.h>
34265739Sganbold#include <sys/smp.h>
35265739Sganbold
36265739Sganbold#include <machine/smp.h>
37265739Sganbold#include <machine/fdt.h>
38265739Sganbold#include <machine/intr.h>
39265739Sganbold
40265739Sganbold#define	SCU_PHYSBASE			0x1013c000
41265739Sganbold#define	SCU_SIZE			0x100
42265739Sganbold
43265739Sganbold#define	SCU_CONTROL_REG			0x00
44265739Sganbold#define	SCU_CONTROL_ENABLE		(1 << 0)
45265739Sganbold#define	SCU_STANDBY_EN			(1 << 5)
46265739Sganbold#define	SCU_CONFIG_REG			0x04
47265739Sganbold#define	SCU_CONFIG_REG_NCPU_MASK	0x03
48265739Sganbold#define	SCU_CPUPOWER_REG		0x08
49265739Sganbold#define	SCU_INV_TAGS_REG		0x0c
50265739Sganbold
51265739Sganbold#define	SCU_FILTER_START_REG		0x10
52265739Sganbold#define	SCU_FILTER_END_REG		0x14
53265739Sganbold#define	SCU_SECURE_ACCESS_REG		0x18
54265739Sganbold#define	SCU_NONSECURE_ACCESS_REG	0x1c
55265739Sganbold
56265739Sganbold#define	IMEM_PHYSBASE			0x10080000
57265739Sganbold#define	IMEM_SIZE			0x20
58265739Sganbold
59265739Sganbold#define	PMU_PHYSBASE			0x20004000
60265739Sganbold#define	PMU_SIZE			0x100
61265739Sganbold#define	PMU_PWRDN_CON			0x08
62265739Sganbold#define	PMU_PWRDN_SCU			(1 << 4)
63265739Sganbold
64265739Sganboldextern char 	*mpentry_addr;
65265739Sganboldstatic void 	 rk30xx_boot2(void);
66265739Sganbold
67265739Sganboldstatic void
68265739Sganboldrk30xx_boot2(void)
69265739Sganbold{
70265739Sganbold
71265739Sganbold	__asm __volatile(
72265739Sganbold			   "ldr pc, 1f\n"
73265739Sganbold			   ".globl mpentry_addr\n"
74265739Sganbold			   "mpentry_addr:\n"
75265739Sganbold			"1: .space 4\n");
76265739Sganbold}
77265739Sganbold
78265739Sganboldvoid
79265739Sganboldplatform_mp_init_secondary(void)
80265739Sganbold{
81265739Sganbold
82265739Sganbold	gic_init_secondary();
83265739Sganbold}
84265739Sganbold
85265739Sganboldvoid
86265739Sganboldplatform_mp_setmaxid(void)
87265739Sganbold{
88265739Sganbold	bus_space_handle_t scu;
89265739Sganbold	int ncpu;
90265739Sganbold	uint32_t val;
91265739Sganbold
92265739Sganbold	if (mp_ncpus != 0)
93265739Sganbold		return;
94265739Sganbold
95265739Sganbold	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
96265739Sganbold		panic("Could not map the SCU");
97265739Sganbold
98265739Sganbold	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
99265739Sganbold	ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
100265739Sganbold	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
101265739Sganbold
102265739Sganbold	mp_ncpus = ncpu;
103265739Sganbold	mp_maxid = ncpu - 1;
104265739Sganbold}
105265739Sganbold
106265739Sganboldint
107265739Sganboldplatform_mp_probe(void)
108265739Sganbold{
109265739Sganbold
110265739Sganbold	if (mp_ncpus == 0)
111265739Sganbold		platform_mp_setmaxid();
112265739Sganbold
113265739Sganbold	return (mp_ncpus > 1);
114265739Sganbold}
115265739Sganbold
116265739Sganboldvoid
117265739Sganboldplatform_mp_start_ap(void)
118265739Sganbold{
119265739Sganbold	bus_space_handle_t scu;
120265739Sganbold	bus_space_handle_t imem;
121265739Sganbold	bus_space_handle_t pmu;
122265739Sganbold	uint32_t val;
123265739Sganbold	int i;
124265739Sganbold
125265739Sganbold	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
126265739Sganbold		panic("Could not map the SCU");
127265739Sganbold	if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE,
128265739Sganbold	    IMEM_SIZE, 0, &imem) != 0)
129265739Sganbold		panic("Could not map the IMEM");
130265739Sganbold	if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0)
131265739Sganbold		panic("Could not map the PMU");
132265739Sganbold
133265739Sganbold	/*
134265739Sganbold	 * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates all
135265739Sganbold	 * ways on all cores 0-3. Per the ARM docs, it's harmless to write to
136265739Sganbold	 * the bits for cores that are not present.
137265739Sganbold	 */
138265739Sganbold	bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff);
139265739Sganbold
140265739Sganbold	/* Make sure all cores except the first are off */
141265739Sganbold	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
142265739Sganbold	for (i = 1; i < mp_ncpus; i++)
143265739Sganbold		val |= 1 << i;
144265739Sganbold	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
145265739Sganbold
146265739Sganbold	/* Enable SCU power domain */
147265739Sganbold	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
148265739Sganbold	val &= ~PMU_PWRDN_SCU;
149265739Sganbold	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
150265739Sganbold
151265739Sganbold	/* Enable SCU */
152265739Sganbold	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
153265739Sganbold	bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG,
154265739Sganbold	    val | SCU_CONTROL_ENABLE);
155265739Sganbold
156265739Sganbold	/*
157265739Sganbold	 * Cores will execute the code which resides at the start of
158265739Sganbold	 * the on-chip bootram/sram after power-on. This sram region
159265739Sganbold	 * should be reserved and the trampoline code that directs
160265739Sganbold	 * the core to the real startup code in ram should be copied
161265739Sganbold	 * into this sram region.
162265739Sganbold	 *
163265739Sganbold	 * First set boot function for the sram code.
164265739Sganbold	 */
165265739Sganbold	mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry);
166265739Sganbold
167265739Sganbold	/* Copy trampoline to sram, that runs during startup of the core */
168265739Sganbold	bus_space_write_region_4(fdtbus_bs_tag, imem, 0,
169265739Sganbold	    (uint32_t *)&rk30xx_boot2, 8);
170265739Sganbold
171265739Sganbold	cpu_idcache_wbinv_all();
172265739Sganbold	cpu_l2cache_wbinv_all();
173265739Sganbold
174265739Sganbold	/* Start all cores */
175265739Sganbold	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
176265739Sganbold	for (i = 1; i < mp_ncpus; i++)
177265739Sganbold		val &= ~(1 << i);
178265739Sganbold	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
179265739Sganbold
180265739Sganbold	armv7_sev();
181265739Sganbold
182265739Sganbold	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
183265739Sganbold	bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE);
184265739Sganbold	bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE);
185265739Sganbold}
186265739Sganbold
187265739Sganboldvoid
188265739Sganboldplatform_ipi_send(cpuset_t cpus, u_int ipi)
189265739Sganbold{
190265739Sganbold
191265739Sganbold	pic_ipi_send(cpus, ipi);
192265739Sganbold}
193