rk30xx_mp.c revision 266397
1/*-
2 * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: stable/10/sys/arm/rockchip/rk30xx_mp.c 266397 2014-05-18 13:05:07Z ian $");
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/bus.h>
31#include <sys/kernel.h>
32#include <sys/lock.h>
33#include <sys/mutex.h>
34#include <sys/smp.h>
35
36#include <machine/smp.h>
37#include <machine/fdt.h>
38#include <machine/intr.h>
39
40#define	SCU_PHYSBASE			0x1013c000
41#define	SCU_SIZE			0x100
42
43#define	SCU_CONTROL_REG			0x00
44#define	SCU_CONTROL_ENABLE		(1 << 0)
45#define	SCU_STANDBY_EN			(1 << 5)
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
51#define	SCU_FILTER_START_REG		0x10
52#define	SCU_FILTER_END_REG		0x14
53#define	SCU_SECURE_ACCESS_REG		0x18
54#define	SCU_NONSECURE_ACCESS_REG	0x1c
55
56#define	IMEM_PHYSBASE			0x10080000
57#define	IMEM_SIZE			0x20
58
59#define	PMU_PHYSBASE			0x20004000
60#define	PMU_SIZE			0x100
61#define	PMU_PWRDN_CON			0x08
62#define	PMU_PWRDN_SCU			(1 << 4)
63
64extern char 	*mpentry_addr;
65static void 	 rk30xx_boot2(void);
66
67static void
68rk30xx_boot2(void)
69{
70
71	__asm __volatile(
72			   "ldr pc, 1f\n"
73			   ".globl mpentry_addr\n"
74			   "mpentry_addr:\n"
75			"1: .space 4\n");
76}
77
78void
79platform_mp_init_secondary(void)
80{
81
82	gic_init_secondary();
83}
84
85void
86platform_mp_setmaxid(void)
87{
88	bus_space_handle_t scu;
89	int ncpu;
90	uint32_t val;
91
92	if (mp_ncpus != 0)
93		return;
94
95	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
96		panic("Could not map the SCU");
97
98	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
99	ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
100	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
101
102	mp_ncpus = ncpu;
103	mp_maxid = ncpu - 1;
104}
105
106int
107platform_mp_probe(void)
108{
109
110	if (mp_ncpus == 0)
111		platform_mp_setmaxid();
112
113	return (mp_ncpus > 1);
114}
115
116void
117platform_mp_start_ap(void)
118{
119	bus_space_handle_t scu;
120	bus_space_handle_t imem;
121	bus_space_handle_t pmu;
122	uint32_t val;
123	int i;
124
125	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
126		panic("Could not map the SCU");
127	if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE,
128	    IMEM_SIZE, 0, &imem) != 0)
129		panic("Could not map the IMEM");
130	if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0)
131		panic("Could not map the PMU");
132
133	/*
134	 * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates all
135	 * ways on all cores 0-3. Per the ARM docs, it's harmless to write to
136	 * the bits for cores that are not present.
137	 */
138	bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff);
139
140	/* Make sure all cores except the first are off */
141	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
142	for (i = 1; i < mp_ncpus; i++)
143		val |= 1 << i;
144	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
145
146	/* Enable SCU power domain */
147	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
148	val &= ~PMU_PWRDN_SCU;
149	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
150
151	/* Enable SCU */
152	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
153	bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG,
154	    val | SCU_CONTROL_ENABLE);
155
156	/*
157	 * Cores will execute the code which resides at the start of
158	 * the on-chip bootram/sram after power-on. This sram region
159	 * should be reserved and the trampoline code that directs
160	 * the core to the real startup code in ram should be copied
161	 * into this sram region.
162	 *
163	 * First set boot function for the sram code.
164	 */
165	mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry);
166
167	/* Copy trampoline to sram, that runs during startup of the core */
168	bus_space_write_region_4(fdtbus_bs_tag, imem, 0,
169	    (uint32_t *)&rk30xx_boot2, 8);
170
171	cpu_idcache_wbinv_all();
172	cpu_l2cache_wbinv_all();
173
174	/* Start all cores */
175	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
176	for (i = 1; i < mp_ncpus; i++)
177		val &= ~(1 << i);
178	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
179
180	armv7_sev();
181
182	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
183	bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE);
184	bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE);
185}
186
187void
188platform_ipi_send(cpuset_t cpus, u_int ipi)
189{
190
191	pic_ipi_send(cpus, ipi);
192}
193