1266301Sandrew/*-
2266301Sandrew * Copyright (c) 2005 Peter Grehan
3266301Sandrew * Copyright (c) 2009 Nathan Whitehorn
4266301Sandrew * All rights reserved.
5266301Sandrew *
6266301Sandrew * Redistribution and use in source and binary forms, with or without
7266301Sandrew * modification, are permitted provided that the following conditions
8266301Sandrew * are met:
9266301Sandrew * 1. Redistributions of source code must retain the above copyright
10266301Sandrew *    notice, this list of conditions and the following disclaimer.
11266301Sandrew * 2. Redistributions in binary form must reproduce the above copyright
12266301Sandrew *    notice, this list of conditions and the following disclaimer in the
13266301Sandrew *    documentation and/or other materials provided with the distribution.
14266301Sandrew *
15266301Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16266301Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17266301Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18266301Sandrew * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19266301Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20266301Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21266301Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22266301Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23266301Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24266301Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25266301Sandrew * SUCH DAMAGE.
26266301Sandrew *
27266301Sandrew */
28266301Sandrew
29266301Sandrew#include <sys/cdefs.h>
30266301Sandrew__FBSDID("$FreeBSD: stable/11/sys/arm/arm/platform.c 331893 2018-04-02 23:19:07Z gonzo $");
31266301Sandrew
32266301Sandrew/*
33266301Sandrew * Dispatch platform calls to the appropriate platform implementation
34266301Sandrew * through a previously registered kernel object.
35266301Sandrew */
36266301Sandrew
37266301Sandrew#include <sys/param.h>
38266301Sandrew#include <sys/bus.h>
39266301Sandrew#include <sys/kernel.h>
40266301Sandrew#include <sys/lock.h>
41266301Sandrew#include <sys/ktr.h>
42266301Sandrew#include <sys/mutex.h>
43266301Sandrew#include <sys/rman.h>
44266301Sandrew#include <sys/systm.h>
45266301Sandrew#include <sys/smp.h>
46266301Sandrew#include <sys/sysctl.h>
47266301Sandrew#include <sys/types.h>
48266301Sandrew
49266301Sandrew#include <vm/vm.h>
50266301Sandrew#include <vm/vm_page.h>
51266301Sandrew
52266301Sandrew#include <machine/bus_dma.h>
53266301Sandrew#include <machine/cpu.h>
54266301Sandrew#include <machine/intr.h>
55298854Sandrew#include <machine/machdep.h>
56266301Sandrew#include <machine/md_var.h>
57266301Sandrew#include <machine/platform.h>
58266301Sandrew#include <machine/platformvar.h>
59266301Sandrew#include <machine/smp.h>
60266301Sandrew
61266301Sandrew#include "platform_if.h"
62266301Sandrew
63266301Sandrewstatic platform_def_t	*plat_def_impl;
64266301Sandrewstatic platform_t	plat_obj;
65266301Sandrewstatic struct kobj_ops	plat_kernel_kops;
66266301Sandrewstatic struct platform_kobj	plat_kernel_obj;
67266301Sandrew
68267992Shselaskystatic char plat_name[64];
69267992ShselaskySYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, plat_name, 0,
70266301Sandrew    "Platform currently in use");
71266301Sandrew
72266301Sandrew/*
73266301Sandrew * Platform install routines. Highest priority wins, using the same
74266301Sandrew * algorithm as bus attachment.
75266301Sandrew */
76266301SandrewSET_DECLARE(platform_set, platform_def_t);
77266301Sandrew
78298854Sandrew#ifdef MULTIDELAY
79298854Sandrewstatic delay_func platform_delay;
80298854Sandrew#endif
81298854Sandrew
82266301Sandrewvoid
83266301Sandrewplatform_probe_and_attach(void)
84266301Sandrew{
85266301Sandrew	platform_def_t	**platpp, *platp;
86266301Sandrew	int		prio, best_prio;
87266301Sandrew
88266301Sandrew	plat_obj = &plat_kernel_obj;
89266301Sandrew	best_prio = 0;
90266301Sandrew
91266301Sandrew	/*
92266301Sandrew	 * We are unable to use TUNABLE_STR as the read will happen
93266301Sandrew	 * well after this function has returned.
94266301Sandrew	 */
95266301Sandrew	TUNABLE_STR_FETCH("hw.platform", plat_name, sizeof(plat_name));
96266301Sandrew
97266301Sandrew	/*
98266301Sandrew	 * Try to locate the best platform kobj
99266301Sandrew	 */
100266301Sandrew	SET_FOREACH(platpp, platform_set) {
101266301Sandrew		platp = *platpp;
102266301Sandrew
103266301Sandrew		/*
104266301Sandrew		 * Take care of compiling the selected class, and
105266301Sandrew		 * then statically initialise the MMU object
106266301Sandrew		 */
107298854Sandrew		kobj_class_compile_static((kobj_class_t)platp,
108298854Sandrew		    &plat_kernel_kops);
109298854Sandrew		kobj_init_static((kobj_t)plat_obj, (kobj_class_t)platp);
110266301Sandrew
111266301Sandrew		plat_obj->cls = platp;
112266301Sandrew
113266301Sandrew		prio = PLATFORM_PROBE(plat_obj);
114266301Sandrew
115266301Sandrew		/* Check for errors */
116266301Sandrew		if (prio > 0)
117266301Sandrew			continue;
118266301Sandrew
119266301Sandrew		/*
120266301Sandrew		 * Check if this module was specifically requested through
121266301Sandrew		 * the loader tunable we provide.
122266301Sandrew		 */
123266301Sandrew		if (strcmp(platp->name,plat_name) == 0) {
124266301Sandrew			plat_def_impl = platp;
125266301Sandrew			break;
126266301Sandrew		}
127266301Sandrew
128266301Sandrew		/* Otherwise, see if it is better than our current best */
129266301Sandrew		if (plat_def_impl == NULL || prio > best_prio) {
130266301Sandrew			best_prio = prio;
131266301Sandrew			plat_def_impl = platp;
132266301Sandrew		}
133266301Sandrew
134266301Sandrew		/*
135266301Sandrew		 * We can't free the KOBJ, since it is static. Reset the ops
136266301Sandrew		 * member of this class so that we can come back later.
137266301Sandrew		 */
138266301Sandrew		platp->ops = NULL;
139266301Sandrew	}
140266301Sandrew
141266301Sandrew	if (plat_def_impl == NULL)
142266301Sandrew		panic("No platform module found!");
143266301Sandrew
144266301Sandrew	/*
145266301Sandrew	 * Recompile to make sure we ended with the
146266301Sandrew	 * correct one, and then attach.
147266301Sandrew	 */
148266301Sandrew
149298854Sandrew	kobj_class_compile_static((kobj_class_t)plat_def_impl,
150298854Sandrew	    &plat_kernel_kops);
151298854Sandrew	kobj_init_static((kobj_t)plat_obj, (kobj_class_t)plat_def_impl);
152266301Sandrew
153298854Sandrew	strlcpy(plat_name, plat_def_impl->name, sizeof(plat_name));
154266301Sandrew
155298854Sandrew#ifdef MULTIDELAY
156298854Sandrew	/* Set a default delay function */
157298854Sandrew	arm_set_delay(platform_delay, NULL);
158298854Sandrew#endif
159298854Sandrew
160266301Sandrew	PLATFORM_ATTACH(plat_obj);
161266301Sandrew}
162266301Sandrew
163266301Sandrewint
164266301Sandrewplatform_devmap_init(void)
165266301Sandrew{
166266301Sandrew
167266301Sandrew	return PLATFORM_DEVMAP_INIT(plat_obj);
168266301Sandrew}
169266301Sandrew
170266301Sandrewvm_offset_t
171266301Sandrewplatform_lastaddr(void)
172266301Sandrew{
173266301Sandrew
174266301Sandrew	return PLATFORM_LASTADDR(plat_obj);
175266301Sandrew}
176266301Sandrew
177266301Sandrewvoid
178266301Sandrewplatform_gpio_init(void)
179266301Sandrew{
180266301Sandrew
181266301Sandrew	PLATFORM_GPIO_INIT(plat_obj);
182266301Sandrew}
183266301Sandrew
184266301Sandrewvoid
185266301Sandrewplatform_late_init(void)
186266301Sandrew{
187266301Sandrew
188266301Sandrew	PLATFORM_LATE_INIT(plat_obj);
189266301Sandrew}
190266301Sandrew
191331893Sgonzovoid
192331893Sgonzocpu_reset(void)
193331893Sgonzo{
194331893Sgonzo
195331893Sgonzo	PLATFORM_CPU_RESET(plat_obj);
196331893Sgonzo
197331893Sgonzo	printf("cpu_reset failed");
198331893Sgonzo
199331893Sgonzo	intr_disable();
200331893Sgonzo	while(1) {
201331893Sgonzo		cpu_sleep(0);
202331893Sgonzo	}
203331893Sgonzo}
204331893Sgonzo
205298854Sandrew#ifdef MULTIDELAY
206298854Sandrewstatic void
207298854Sandrewplatform_delay(int usec, void *arg __unused)
208298854Sandrew{
209298854Sandrew	int counts;
210298854Sandrew
211298854Sandrew	for (; usec > 0; usec--)
212298854Sandrew		for (counts = plat_obj->cls->delay_count; counts > 0; counts--)
213298854Sandrew			/*
214298854Sandrew			 * Prevent the compiler from optimizing
215298854Sandrew			 * out the loop
216298854Sandrew			 */
217298854Sandrew			cpufunc_nullop();
218298854Sandrew}
219298854Sandrew#endif
220298854Sandrew
221296158Sandrew#if defined(SMP) && defined(PLATFORM_SMP)
222296158Sandrewvoid
223296158Sandrewplatform_mp_setmaxid(void)
224296158Sandrew{
225299383Smanu	int ncpu;
226296158Sandrew
227296158Sandrew	PLATFORM_MP_SETMAXID(plat_obj);
228299383Smanu
229299383Smanu	if (TUNABLE_INT_FETCH("hw.ncpu", &ncpu)) {
230299383Smanu		if (ncpu >= 1 && ncpu <= mp_ncpus) {
231299383Smanu			mp_ncpus = ncpu;
232299383Smanu			mp_maxid = ncpu - 1;
233299383Smanu		}
234299383Smanu	}
235296158Sandrew}
236296158Sandrew
237296158Sandrewvoid
238296158Sandrewplatform_mp_start_ap(void)
239296158Sandrew{
240296158Sandrew
241296158Sandrew	PLATFORM_MP_START_AP(plat_obj);
242296158Sandrew}
243296158Sandrew#endif
244