1167598Srrs/*-
2169382Srrs * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
3167598Srrs * All rights reserved.
4167598Srrs *
5167598Srrs * Redistribution and use in source and binary forms, with or without
6167598Srrs * modification, are permitted provided that the following conditions
7167598Srrs * are met:
8167598Srrs * 1. Redistributions of source code must retain the above copyright
9167598Srrs *    notice, this list of conditions and the following disclaimer.
10167598Srrs * 2. Redistributions in binary form must reproduce the above copyright
11167598Srrs *    notice, this list of conditions and the following disclaimer in the
12167598Srrs *    documentation and/or other materials provided with the distribution.
13167598Srrs *
14167598Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15167598Srrs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16167598Srrs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17167598Srrs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18167598Srrs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19167598Srrs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20167598Srrs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21167598Srrs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22167598Srrs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23167598Srrs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24167598Srrs */
25167598Srrs
26167598Srrs#include <sys/cdefs.h>
27167598Srrs__FBSDID("$FreeBSD$");
28167598Srrs#include <sys/param.h>
29167598Srrs#include <sys/systm.h>
30167598Srrs#include <sys/bus.h>
31167598Srrs#include <sys/kernel.h>
32167598Srrs#include <sys/lock.h>
33167598Srrs#include <sys/mutex.h>
34167598Srrs#include <sys/smp.h>
35167598Srrs
36167598Srrs#include <machine/smp.h>
37167598Srrs#include <machine/fdt.h>
38167598Srrs#include <machine/intr.h>
39167598Srrs
40167598Srrs#define	SCU_PHYSBASE			0x1013c000
41167598Srrs#define	SCU_SIZE			0x100
42167598Srrs
43167598Srrs#define	SCU_CONTROL_REG			0x00
44167598Srrs#define	SCU_CONTROL_ENABLE		(1 << 0)
45167598Srrs#define	SCU_STANDBY_EN			(1 << 5)
46167598Srrs#define	SCU_CONFIG_REG			0x04
47167598Srrs#define	SCU_CONFIG_REG_NCPU_MASK	0x03
48167598Srrs#define	SCU_CPUPOWER_REG		0x08
49167598Srrs#define	SCU_INV_TAGS_REG		0x0c
50167598Srrs
51167598Srrs#define	SCU_FILTER_START_REG		0x10
52167598Srrs#define	SCU_FILTER_END_REG		0x14
53167598Srrs#define	SCU_SECURE_ACCESS_REG		0x18
54167598Srrs#define	SCU_NONSECURE_ACCESS_REG	0x1c
55167598Srrs
56167598Srrs#define	IMEM_PHYSBASE			0x10080000
57167598Srrs#define	IMEM_SIZE			0x20
58167598Srrs
59167598Srrs#define	PMU_PHYSBASE			0x20004000
60167598Srrs#define	PMU_SIZE			0x100
61167598Srrs#define	PMU_PWRDN_CON			0x08
62167598Srrs#define	PMU_PWRDN_SCU			(1 << 4)
63167598Srrs
64167598Srrsextern char 	*mpentry_addr;
65167598Srrsstatic void 	 rk30xx_boot2(void);
66167598Srrs
67167598Srrsstatic void
68167598Srrsrk30xx_boot2(void)
69167598Srrs{
70167598Srrs
71167598Srrs	__asm __volatile(
72167598Srrs			   "ldr pc, 1f\n"
73167598Srrs			   ".globl mpentry_addr\n"
74167598Srrs			   "mpentry_addr:\n"
75167598Srrs			"1: .space 4\n");
76167598Srrs}
77167598Srrs
78167598Srrsvoid
79167598Srrsplatform_mp_init_secondary(void)
80167598Srrs{
81167598Srrs
82167598Srrs	gic_init_secondary();
83167598Srrs}
84167598Srrs
85167598Srrsvoid
86167598Srrsplatform_mp_setmaxid(void)
87167598Srrs{
88167598Srrs	bus_space_handle_t scu;
89167598Srrs	int ncpu;
90167598Srrs	uint32_t val;
91167598Srrs
92167598Srrs	if (mp_ncpus != 0)
93167598Srrs		return;
94167598Srrs
95167598Srrs	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
96167598Srrs		panic("Could not map the SCU");
97167598Srrs
98167598Srrs	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
99167598Srrs	ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
100167598Srrs	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
101167598Srrs
102167598Srrs	mp_ncpus = ncpu;
103167598Srrs	mp_maxid = ncpu - 1;
104170642Srrs}
105167598Srrs
106167598Srrsint
107167598Srrsplatform_mp_probe(void)
108167598Srrs{
109167598Srrs
110167598Srrs	if (mp_ncpus == 0)
111167598Srrs		platform_mp_setmaxid();
112167598Srrs
113167598Srrs	return (mp_ncpus > 1);
114167598Srrs}
115167598Srrs
116167598Srrsvoid
117167598Srrsplatform_mp_start_ap(void)
118167598Srrs{
119167598Srrs	bus_space_handle_t scu;
120167598Srrs	bus_space_handle_t imem;
121167598Srrs	bus_space_handle_t pmu;
122167598Srrs	uint32_t val;
123167598Srrs	int i;
124167598Srrs
125167598Srrs	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
126167598Srrs		panic("Could not map the SCU");
127167598Srrs	if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE,
128167598Srrs	    IMEM_SIZE, 0, &imem) != 0)
129167598Srrs		panic("Could not map the IMEM");
130167598Srrs	if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0)
131167598Srrs		panic("Could not map the PMU");
132167598Srrs
133167598Srrs	/*
134167598Srrs	 * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates all
135167598Srrs	 * ways on all cores 0-3. Per the ARM docs, it's harmless to write to
136167598Srrs	 * the bits for cores that are not present.
137167598Srrs	 */
138167598Srrs	bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff);
139167598Srrs
140167598Srrs	/* Make sure all cores except the first are off */
141167598Srrs	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
142167598Srrs	for (i = 1; i < mp_ncpus; i++)
143167598Srrs		val |= 1 << i;
144167598Srrs	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
145167598Srrs
146167598Srrs	/* Enable SCU power domain */
147167598Srrs	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
148167598Srrs	val &= ~PMU_PWRDN_SCU;
149167598Srrs	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
150167598Srrs
151167598Srrs	/* Enable SCU */
152167598Srrs	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
153167598Srrs	bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG,
154167598Srrs	    val | SCU_CONTROL_ENABLE);
155167598Srrs
156167598Srrs	/*
157167598Srrs	 * Cores will execute the code which resides at the start of
158167598Srrs	 * the on-chip bootram/sram after power-on. This sram region
159167598Srrs	 * should be reserved and the trampoline code that directs
160167598Srrs	 * the core to the real startup code in ram should be copied
161167598Srrs	 * into this sram region.
162167598Srrs	 *
163167598Srrs	 * First set boot function for the sram code.
164167598Srrs	 */
165167598Srrs	mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry);
166167598Srrs
167167598Srrs	/* Copy trampoline to sram, that runs during startup of the core */
168167598Srrs	bus_space_write_region_4(fdtbus_bs_tag, imem, 0,
169167598Srrs	    (uint32_t *)&rk30xx_boot2, 8);
170167598Srrs
171167598Srrs	cpu_idcache_wbinv_all();
172167598Srrs	cpu_l2cache_wbinv_all();
173167598Srrs
174167598Srrs	/* Start all cores */
175167598Srrs	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
176167598Srrs	for (i = 1; i < mp_ncpus; i++)
177167598Srrs		val &= ~(1 << i);
178167598Srrs	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
179167598Srrs
180167598Srrs	armv7_sev();
181167598Srrs
182167598Srrs	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
183167598Srrs	bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE);
184167598Srrs	bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE);
185167598Srrs}
186167598Srrs
187167598Srrsvoid
188167598Srrsplatform_ipi_send(cpuset_t cpus, u_int ipi)
189167598Srrs{
190167598Srrs
191167598Srrs	pic_ipi_send(cpus, ipi);
192167598Srrs}
193167598Srrs