exynos_platform.c revision 1.16 1 /* $NetBSD: exynos_platform.c,v 1.16 2018/09/14 11:58:38 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2017 Jared D. McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "opt_arm_debug.h"
30 #include "opt_exynos.h"
31 #include "opt_multiprocessor.h"
32 #include "opt_fdt_arm.h"
33
34 #include "ukbd.h"
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: exynos_platform.c,v 1.16 2018/09/14 11:58:38 skrll Exp $");
38
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/cpu.h>
42 #include <sys/device.h>
43 #include <sys/termios.h>
44
45 #include <dev/fdt/fdtvar.h>
46
47 #include <uvm/uvm_extern.h>
48
49 #include <machine/bootconfig.h>
50 #include <arm/cpufunc.h>
51
52 #include <arm/samsung/exynos_reg.h>
53 #include <arm/samsung/exynos_var.h>
54 #include <arm/samsung/mct_var.h>
55 #include <arm/samsung/sscom_reg.h>
56
57 #include <evbarm/exynos/platform.h>
58
59 #include <arm/fdt/arm_fdtvar.h>
60
61 void exynos_platform_early_putchar(char);
62
63 #define EXYNOS5_SWRESET_REG 0x10040400
64
65 #define EXYNOS_IOPHYSTOVIRT(a) \
66 ((vaddr_t)(((a) - EXYNOS_CORE_PBASE) + EXYNOS_CORE_VBASE))
67
68 #define EXYNOS5800_PMU_BASE 0x10040000
69 #define EXYNOS5800_PMU_SIZE 0x20000
70 #define EXYNOS5800_PMU_CORE_CONFIG(n) (0x2000 + 0x80 * (n))
71 #define EXYNOS5800_PMU_CORE_STATUS(n) (0x2004 + 0x80 * (n))
72 #define EXYNOS5800_PMU_CORE_POWER_EN 0x3
73 #define EXYNOS5800_SYSRAM_BASE 0x0207301c
74 #define EXYNOS5800_SYSRAM_SIZE 0x4
75
76 static void
77 exynos5800_mp_bootstrap(void)
78 {
79 #if defined(MULTIPROCESSOR)
80 extern void cortex_mpstart(void);
81 bus_space_tag_t bst = &armv7_generic_bs_tag;
82 bus_space_handle_t pmu_bsh, sysram_bsh;
83 uint32_t val, started = 0;
84 int n;
85
86 arm_cpu_max = 1 + __SHIFTOUT(armreg_l2ctrl_read(), L2CTRL_NUMCPU);
87
88 bus_space_map(bst, EXYNOS5800_PMU_BASE, EXYNOS5800_PMU_SIZE, 0, &pmu_bsh);
89 bus_space_map(bst, EXYNOS5800_SYSRAM_BASE, EXYNOS5800_SYSRAM_SIZE, 0, &sysram_bsh);
90
91 bus_space_write_4(bst, sysram_bsh, 0, (uint32_t)cortex_mpstart);
92 bus_space_barrier(bst, sysram_bsh, 0, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
93
94 for (n = 1; n < arm_cpu_max; n++) {
95 bus_space_write_4(bst, pmu_bsh, EXYNOS5800_PMU_CORE_CONFIG(n),
96 EXYNOS5800_PMU_CORE_POWER_EN);
97 for (u_int i = 0x01000000; i > 0; i--) {
98 val = bus_space_read_4(bst, pmu_bsh, EXYNOS5800_PMU_CORE_STATUS(n));
99 if ((val & EXYNOS5800_PMU_CORE_POWER_EN) == EXYNOS5800_PMU_CORE_POWER_EN) {
100 started |= __BIT(n);
101 break;
102 }
103 }
104 }
105
106 for (u_int i = 0x10000000; i > 0; i--) {
107 arm_dmb();
108 if (arm_cpu_hatched == started)
109 break;
110 }
111
112 bus_space_unmap(bst, sysram_bsh, EXYNOS5800_SYSRAM_SIZE);
113 bus_space_unmap(bst, pmu_bsh, EXYNOS5800_PMU_SIZE);
114 #endif
115 }
116
117 static struct of_compat_data mp_compat_data[] = {
118 { "samsung,exynos5800", (uintptr_t)exynos5800_mp_bootstrap },
119 { NULL }
120 };
121
122 static void
123 exynos_platform_bootstrap(void)
124 {
125
126 exynos_bootstrap();
127
128 void (*mp_bootstrap)(void) = NULL;
129 const struct of_compat_data *cd = of_search_compatible(OF_finddevice("/"), mp_compat_data);
130 if (cd)
131 mp_bootstrap = (void (*)(void))cd->data;
132
133 if (mp_bootstrap)
134 mp_bootstrap();
135 }
136
137 static void
138 exynos_platform_init_attach_args(struct fdt_attach_args *faa)
139 {
140 extern struct bus_space armv7_generic_bs_tag;
141 extern struct bus_space armv7_generic_a4x_bs_tag;
142 extern struct arm32_bus_dma_tag arm_generic_dma_tag;
143
144 faa->faa_bst = &armv7_generic_bs_tag;
145 faa->faa_a4x_bst = &armv7_generic_a4x_bs_tag;
146 faa->faa_dmat = &arm_generic_dma_tag;
147 }
148
149
150 void
151 exynos_platform_early_putchar(char c)
152 {
153 #ifdef CONSADDR
154 #define CONSADDR_VA (CONSADDR - EXYNOS_CORE_PBASE + EXYNOS_CORE_VBASE)
155
156 volatile uint32_t *uartaddr = cpu_earlydevice_va_p() ?
157 (volatile uint32_t *)CONSADDR_VA :
158 (volatile uint32_t *)CONSADDR;
159
160 while ((uartaddr[SSCOM_UFSTAT / 4] & UFSTAT_TXFULL) != 0)
161 ;
162
163 uartaddr[SSCOM_UTXH / 4] = c;
164 #endif
165 }
166
167 static void
168 exynos_platform_device_register(device_t self, void *aux)
169 {
170 exynos_device_register(self, aux);
171 }
172
173 static void
174 exynos5_platform_reset(void)
175 {
176 bus_space_tag_t bst = &armv7_generic_bs_tag;
177 bus_space_handle_t bsh;
178
179 bus_space_map(bst, EXYNOS5_SWRESET_REG, 4, 0, &bsh);
180 bus_space_write_4(bst, bsh, 0, 1);
181 }
182
183 static u_int
184 exynos_platform_uart_freq(void)
185 {
186 return EXYNOS_UART_FREQ;
187 }
188
189
190 #if defined(SOC_EXYNOS4)
191 static const struct pmap_devmap *
192 exynos4_platform_devmap(void)
193 {
194 static const struct pmap_devmap devmap[] = {
195 DEVMAP_ENTRY(EXYNOS_CORE_VBASE,
196 EXYNOS_CORE_PBASE,
197 EXYNOS4_CORE_SIZE),
198 DEVMAP_ENTRY(EXYNOS4_AUDIOCORE_VBASE,
199 EXYNOS4_AUDIOCORE_PBASE,
200 EXYNOS4_AUDIOCORE_SIZE),
201 DEVMAP_ENTRY_END
202 };
203
204 return devmap;
205 }
206
207 static const struct arm_platform exynos4_platform = {
208 .ap_devmap = exynos4_platform_devmap,
209 .ap_bootstrap = exynos_platform_bootstrap,
210 .ap_init_attach_args = exynos_platform_init_attach_args,
211 .ap_early_putchar = exynos_platform_early_putchar,
212 .ap_device_register = exynos_platform_device_register,
213 .ap_reset = exynos5_platform_reset,
214 .ap_delay = mct_delay,
215 .ap_uart_freq = exynos_platform_uart_freq,
216 };
217
218 ARM_PLATFORM(exynos4, "samsung,exynos4", &exynos4_platform);
219 #endif
220
221
222 #if defined(SOC_EXYNOS5)
223 static const struct pmap_devmap *
224 exynos5_platform_devmap(void)
225 {
226 static const struct pmap_devmap devmap[] = {
227 DEVMAP_ENTRY(EXYNOS_CORE_VBASE,
228 EXYNOS_CORE_PBASE,
229 EXYNOS5_CORE_SIZE),
230 DEVMAP_ENTRY(EXYNOS5_AUDIOCORE_VBASE,
231 EXYNOS5_AUDIOCORE_PBASE,
232 EXYNOS5_AUDIOCORE_SIZE),
233 DEVMAP_ENTRY(EXYNOS5_SYSRAM_VBASE,
234 EXYNOS5_SYSRAM_PBASE,
235 EXYNOS5_SYSRAM_SIZE),
236 DEVMAP_ENTRY_END
237 };
238
239 return devmap;
240 }
241
242 static const struct arm_platform exynos5_platform = {
243 .ap_devmap = exynos5_platform_devmap,
244 .ap_bootstrap = exynos_platform_bootstrap,
245 .ap_init_attach_args = exynos_platform_init_attach_args,
246 .ap_early_putchar = exynos_platform_early_putchar,
247 .ap_device_register = exynos_platform_device_register,
248 .ap_reset = exynos5_platform_reset,
249 .ap_delay = mct_delay,
250 .ap_uart_freq = exynos_platform_uart_freq,
251 };
252
253 ARM_PLATFORM(exynos5, "samsung,exynos5", &exynos5_platform);
254 #endif
255