xref: /freebsd-11-stable/sys/arm/rockchip/rk30xx_mp.c (revision b4db52d05a32de05aecc7e44ccaa4a7ae30baef8)
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$");
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 <vm/vm.h>
37 #include <vm/pmap.h>
38 
39 #include <machine/cpu.h>
40 #include <machine/smp.h>
41 #include <machine/fdt.h>
42 #include <machine/intr.h>
43 
44 #define	SCU_PHYSBASE			0x1013c000
45 #define	SCU_SIZE			0x100
46 
47 #define	SCU_CONTROL_REG			0x00
48 #define	SCU_CONTROL_ENABLE		(1 << 0)
49 #define	SCU_STANDBY_EN			(1 << 5)
50 #define	SCU_CONFIG_REG			0x04
51 #define	SCU_CONFIG_REG_NCPU_MASK	0x03
52 #define	SCU_CPUPOWER_REG		0x08
53 #define	SCU_INV_TAGS_REG		0x0c
54 
55 #define	SCU_FILTER_START_REG		0x10
56 #define	SCU_FILTER_END_REG		0x14
57 #define	SCU_SECURE_ACCESS_REG		0x18
58 #define	SCU_NONSECURE_ACCESS_REG	0x1c
59 
60 #define	IMEM_PHYSBASE			0x10080000
61 #define	IMEM_SIZE			0x20
62 
63 #define	PMU_PHYSBASE			0x20004000
64 #define	PMU_SIZE			0x100
65 #define	PMU_PWRDN_CON			0x08
66 #define	PMU_PWRDN_SCU			(1 << 4)
67 
68 extern char 	*mpentry_addr;
69 static void 	 rk30xx_boot2(void);
70 
71 static void
rk30xx_boot2(void)72 rk30xx_boot2(void)
73 {
74 
75 	__asm __volatile(
76 			   "ldr pc, 1f\n"
77 			   ".globl mpentry_addr\n"
78 			   "mpentry_addr:\n"
79 			"1: .space 4\n");
80 }
81 
82 void
platform_mp_setmaxid(void)83 platform_mp_setmaxid(void)
84 {
85 	bus_space_handle_t scu;
86 	int ncpu;
87 	uint32_t val;
88 
89 	if (mp_ncpus != 0)
90 		return;
91 
92 	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
93 		panic("Could not map the SCU");
94 
95 	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
96 	ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
97 	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
98 
99 	mp_ncpus = ncpu;
100 	mp_maxid = ncpu - 1;
101 }
102 
103 void
platform_mp_start_ap(void)104 platform_mp_start_ap(void)
105 {
106 	bus_space_handle_t scu;
107 	bus_space_handle_t imem;
108 	bus_space_handle_t pmu;
109 	uint32_t val;
110 	int i;
111 
112 	if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
113 		panic("Could not map the SCU");
114 	if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE,
115 	    IMEM_SIZE, 0, &imem) != 0)
116 		panic("Could not map the IMEM");
117 	if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0)
118 		panic("Could not map the PMU");
119 
120 	/*
121 	 * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates all
122 	 * ways on all cores 0-3. Per the ARM docs, it's harmless to write to
123 	 * the bits for cores that are not present.
124 	 */
125 	bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff);
126 
127 	/* Make sure all cores except the first are off */
128 	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
129 	for (i = 1; i < mp_ncpus; i++)
130 		val |= 1 << i;
131 	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
132 
133 	/* Enable SCU power domain */
134 	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
135 	val &= ~PMU_PWRDN_SCU;
136 	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
137 
138 	/* Enable SCU */
139 	val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
140 	bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG,
141 	    val | SCU_CONTROL_ENABLE);
142 
143 	/*
144 	 * Cores will execute the code which resides at the start of
145 	 * the on-chip bootram/sram after power-on. This sram region
146 	 * should be reserved and the trampoline code that directs
147 	 * the core to the real startup code in ram should be copied
148 	 * into this sram region.
149 	 *
150 	 * First set boot function for the sram code.
151 	 */
152 	mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry);
153 
154 	/* Copy trampoline to sram, that runs during startup of the core */
155 	bus_space_write_region_4(fdtbus_bs_tag, imem, 0,
156 	    (uint32_t *)&rk30xx_boot2, 8);
157 
158 	dcache_wbinv_poc_all();
159 
160 	/* Start all cores */
161 	val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON);
162 	for (i = 1; i < mp_ncpus; i++)
163 		val &= ~(1 << i);
164 	bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val);
165 
166 	dsb();
167 	sev();
168 
169 	bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
170 	bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE);
171 	bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE);
172 }
173