1/*-
2 * Copyright (c) 2005 Peter Grehan
3 * Copyright (c) 2009 Nathan Whitehorn
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/arm/arm/platform.c 331893 2018-04-02 23:19:07Z gonzo $");
31
32/*
33 * Dispatch platform calls to the appropriate platform implementation
34 * through a previously registered kernel object.
35 */
36
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/kernel.h>
40#include <sys/lock.h>
41#include <sys/ktr.h>
42#include <sys/mutex.h>
43#include <sys/rman.h>
44#include <sys/systm.h>
45#include <sys/smp.h>
46#include <sys/sysctl.h>
47#include <sys/types.h>
48
49#include <vm/vm.h>
50#include <vm/vm_page.h>
51
52#include <machine/bus_dma.h>
53#include <machine/cpu.h>
54#include <machine/intr.h>
55#include <machine/machdep.h>
56#include <machine/md_var.h>
57#include <machine/platform.h>
58#include <machine/platformvar.h>
59#include <machine/smp.h>
60
61#include "platform_if.h"
62
63static platform_def_t	*plat_def_impl;
64static platform_t	plat_obj;
65static struct kobj_ops	plat_kernel_kops;
66static struct platform_kobj	plat_kernel_obj;
67
68static char plat_name[64];
69SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, plat_name, 0,
70    "Platform currently in use");
71
72/*
73 * Platform install routines. Highest priority wins, using the same
74 * algorithm as bus attachment.
75 */
76SET_DECLARE(platform_set, platform_def_t);
77
78#ifdef MULTIDELAY
79static delay_func platform_delay;
80#endif
81
82void
83platform_probe_and_attach(void)
84{
85	platform_def_t	**platpp, *platp;
86	int		prio, best_prio;
87
88	plat_obj = &plat_kernel_obj;
89	best_prio = 0;
90
91	/*
92	 * We are unable to use TUNABLE_STR as the read will happen
93	 * well after this function has returned.
94	 */
95	TUNABLE_STR_FETCH("hw.platform", plat_name, sizeof(plat_name));
96
97	/*
98	 * Try to locate the best platform kobj
99	 */
100	SET_FOREACH(platpp, platform_set) {
101		platp = *platpp;
102
103		/*
104		 * Take care of compiling the selected class, and
105		 * then statically initialise the MMU object
106		 */
107		kobj_class_compile_static((kobj_class_t)platp,
108		    &plat_kernel_kops);
109		kobj_init_static((kobj_t)plat_obj, (kobj_class_t)platp);
110
111		plat_obj->cls = platp;
112
113		prio = PLATFORM_PROBE(plat_obj);
114
115		/* Check for errors */
116		if (prio > 0)
117			continue;
118
119		/*
120		 * Check if this module was specifically requested through
121		 * the loader tunable we provide.
122		 */
123		if (strcmp(platp->name,plat_name) == 0) {
124			plat_def_impl = platp;
125			break;
126		}
127
128		/* Otherwise, see if it is better than our current best */
129		if (plat_def_impl == NULL || prio > best_prio) {
130			best_prio = prio;
131			plat_def_impl = platp;
132		}
133
134		/*
135		 * We can't free the KOBJ, since it is static. Reset the ops
136		 * member of this class so that we can come back later.
137		 */
138		platp->ops = NULL;
139	}
140
141	if (plat_def_impl == NULL)
142		panic("No platform module found!");
143
144	/*
145	 * Recompile to make sure we ended with the
146	 * correct one, and then attach.
147	 */
148
149	kobj_class_compile_static((kobj_class_t)plat_def_impl,
150	    &plat_kernel_kops);
151	kobj_init_static((kobj_t)plat_obj, (kobj_class_t)plat_def_impl);
152
153	strlcpy(plat_name, plat_def_impl->name, sizeof(plat_name));
154
155#ifdef MULTIDELAY
156	/* Set a default delay function */
157	arm_set_delay(platform_delay, NULL);
158#endif
159
160	PLATFORM_ATTACH(plat_obj);
161}
162
163int
164platform_devmap_init(void)
165{
166
167	return PLATFORM_DEVMAP_INIT(plat_obj);
168}
169
170vm_offset_t
171platform_lastaddr(void)
172{
173
174	return PLATFORM_LASTADDR(plat_obj);
175}
176
177void
178platform_gpio_init(void)
179{
180
181	PLATFORM_GPIO_INIT(plat_obj);
182}
183
184void
185platform_late_init(void)
186{
187
188	PLATFORM_LATE_INIT(plat_obj);
189}
190
191void
192cpu_reset(void)
193{
194
195	PLATFORM_CPU_RESET(plat_obj);
196
197	printf("cpu_reset failed");
198
199	intr_disable();
200	while(1) {
201		cpu_sleep(0);
202	}
203}
204
205#ifdef MULTIDELAY
206static void
207platform_delay(int usec, void *arg __unused)
208{
209	int counts;
210
211	for (; usec > 0; usec--)
212		for (counts = plat_obj->cls->delay_count; counts > 0; counts--)
213			/*
214			 * Prevent the compiler from optimizing
215			 * out the loop
216			 */
217			cpufunc_nullop();
218}
219#endif
220
221#if defined(SMP) && defined(PLATFORM_SMP)
222void
223platform_mp_setmaxid(void)
224{
225	int ncpu;
226
227	PLATFORM_MP_SETMAXID(plat_obj);
228
229	if (TUNABLE_INT_FETCH("hw.ncpu", &ncpu)) {
230		if (ncpu >= 1 && ncpu <= mp_ncpus) {
231			mp_ncpus = ncpu;
232			mp_maxid = ncpu - 1;
233		}
234	}
235}
236
237void
238platform_mp_start_ap(void)
239{
240
241	PLATFORM_MP_START_AP(plat_obj);
242}
243#endif
244