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/*
31 * Dispatch platform calls to the appropriate platform implementation
32 * through a previously registered kernel object.
33 */
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/kernel.h>
38#include <sys/lock.h>
39#include <sys/ktr.h>
40#include <sys/mutex.h>
41#include <sys/rman.h>
42#include <sys/systm.h>
43#include <sys/smp.h>
44#include <sys/sysctl.h>
45#include <sys/types.h>
46
47#include <vm/vm.h>
48#include <vm/vm_page.h>
49
50#include <machine/bus_dma.h>
51#include <machine/cpu.h>
52#include <machine/intr.h>
53#include <machine/machdep.h>
54#include <machine/md_var.h>
55#include <machine/platform.h>
56#include <machine/platformvar.h>
57#include <machine/smp.h>
58
59#include "platform_if.h"
60
61static platform_def_t	*plat_def_impl;
62static platform_t	plat_obj;
63static struct kobj_ops	plat_kernel_kops;
64static struct platform_kobj	plat_kernel_obj;
65
66static char plat_name[64];
67SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, plat_name, 0,
68    "Platform currently in use");
69
70/*
71 * Platform install routines. Highest priority wins, using the same
72 * algorithm as bus attachment.
73 */
74SET_DECLARE(platform_set, platform_def_t);
75
76static delay_func platform_delay;
77
78platform_t
79platform_obj(void)
80{
81
82	return (plat_obj);
83}
84
85void
86platform_probe_and_attach(void)
87{
88	platform_def_t	**platpp, *platp;
89	int		prio, best_prio;
90
91	plat_obj = &plat_kernel_obj;
92	best_prio = 0;
93
94	/*
95	 * We are unable to use TUNABLE_STR as the read will happen
96	 * well after this function has returned.
97	 */
98	TUNABLE_STR_FETCH("hw.platform", plat_name, sizeof(plat_name));
99
100	/*
101	 * Try to locate the best platform kobj
102	 */
103	SET_FOREACH(platpp, platform_set) {
104		platp = *platpp;
105
106		/*
107		 * Take care of compiling the selected class, and
108		 * then statically initialise the MMU object
109		 */
110		kobj_class_compile_static((kobj_class_t)platp,
111		    &plat_kernel_kops);
112		kobj_init_static((kobj_t)plat_obj, (kobj_class_t)platp);
113
114		plat_obj->cls = platp;
115
116		prio = PLATFORM_PROBE(plat_obj);
117
118		/* Check for errors */
119		if (prio > 0)
120			continue;
121
122		/*
123		 * Check if this module was specifically requested through
124		 * the loader tunable we provide.
125		 */
126		if (strcmp(platp->name,plat_name) == 0) {
127			plat_def_impl = platp;
128			break;
129		}
130
131		/* Otherwise, see if it is better than our current best */
132		if (plat_def_impl == NULL || prio > best_prio) {
133			best_prio = prio;
134			plat_def_impl = platp;
135		}
136
137		/*
138		 * We can't free the KOBJ, since it is static. Reset the ops
139		 * member of this class so that we can come back later.
140		 */
141		platp->ops = NULL;
142	}
143
144	if (plat_def_impl == NULL)
145		panic("No platform module found!");
146
147	/*
148	 * Recompile to make sure we ended with the
149	 * correct one, and then attach.
150	 */
151
152	kobj_class_compile_static((kobj_class_t)plat_def_impl,
153	    &plat_kernel_kops);
154	kobj_init_static((kobj_t)plat_obj, (kobj_class_t)plat_def_impl);
155
156	strlcpy(plat_name, plat_def_impl->name, sizeof(plat_name));
157
158	/* Set a default delay function */
159	arm_set_delay(platform_delay, NULL);
160
161	PLATFORM_ATTACH(plat_obj);
162}
163
164int
165platform_devmap_init(void)
166{
167
168	return PLATFORM_DEVMAP_INIT(plat_obj);
169}
170
171vm_offset_t
172platform_lastaddr(void)
173{
174
175	return PLATFORM_LASTADDR(plat_obj);
176}
177
178void
179platform_gpio_init(void)
180{
181
182	PLATFORM_GPIO_INIT(plat_obj);
183}
184
185void
186platform_late_init(void)
187{
188
189	PLATFORM_LATE_INIT(plat_obj);
190}
191
192void
193cpu_reset(void)
194{
195
196	PLATFORM_CPU_RESET(plat_obj);
197
198	printf("cpu_reset failed");
199
200	intr_disable();
201	while(1) {
202		cpu_sleep(0);
203	}
204}
205
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
220#if defined(SMP)
221void
222platform_mp_setmaxid(void)
223{
224	int ncpu;
225
226	PLATFORM_MP_SETMAXID(plat_obj);
227
228	if (TUNABLE_INT_FETCH("hw.ncpu", &ncpu)) {
229		if (ncpu >= 1 && ncpu <= mp_ncpus) {
230			mp_ncpus = ncpu;
231			mp_maxid = ncpu - 1;
232		}
233	}
234}
235
236void
237platform_mp_start_ap(void)
238{
239
240	PLATFORM_MP_START_AP(plat_obj);
241}
242#endif
243