1/*-
2 * Copyright 2015 John Wehle <john@feith.com>
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 AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * Amlogic aml8726 multiprocessor support.
29 *
30 * Some processors require powering on which involves poking registers
31 * on the aobus and cbus ... it's expected that these locations are set
32 * in stone.
33 *
34 * Locking is not used as these routines should only be called by the BP
35 * during startup and should complete prior to the APs being released (the
36 * issue being to ensure that a register such as AML_SOC_CPU_CLK_CNTL_REG
37 * is not concurrently modified).
38 */
39
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: stable/11/sys/arm/amlogic/aml8726/aml8726_mp.c 307344 2016-10-15 08:27:54Z mmel $");
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/bus.h>
45#include <sys/kernel.h>
46#include <sys/module.h>
47#include <sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/resource.h>
50#include <sys/rman.h>
51#include <sys/smp.h>
52
53#include <vm/vm.h>
54#include <vm/pmap.h>
55
56#include <machine/cpu.h>
57#include <machine/bus.h>
58#include <machine/smp.h>
59#include <machine/fdt.h>
60#include <machine/intr.h>
61
62#include <dev/fdt/fdt_common.h>
63#include <dev/ofw/ofw_bus.h>
64#include <dev/ofw/ofw_bus_subr.h>
65
66#include <arm/amlogic/aml8726/aml8726_soc.h>
67
68static const char *scu_compatible[] = {
69	"arm,cortex-a5-scu",
70	"arm,cortex-a9-scu",
71	NULL
72};
73
74static const char *scu_errata_764369[] = {
75	"arm,cortex-a9-scu",
76	NULL
77};
78
79static const char *cpucfg_compatible[] = {
80	"amlogic,aml8726-cpuconfig",
81	NULL
82};
83
84static struct {
85	boolean_t errata_764369;
86	u_long scu_size;
87	struct resource scu_res;
88	u_long cpucfg_size;
89	struct resource cpucfg_res;
90	struct resource aobus_res;
91	struct resource cbus_res;
92} aml8726_smp;
93
94#define	AML_SCU_CONTROL_REG			0
95#define	AML_SCU_CONTROL_ENABLE			1
96#define	AML_SCU_CONFIG_REG			4
97#define	AML_SCU_CONFIG_NCPU_MASK		0x3
98#define	AML_SCU_CPU_PWR_STATUS_REG		8
99#define	AML_SCU_CPU_PWR_STATUS_CPU3_MASK	(3 << 24)
100#define	AML_SCU_CPU_PWR_STATUS_CPU2_MASK	(3 << 16)
101#define	AML_SCU_CPU_PWR_STATUS_CPU1_MASK	(3 << 8)
102#define	AML_SCU_CPU_PWR_STATUS_CPU0_MASK	3
103#define	AML_SCU_INV_TAGS_REG			12
104#define	AML_SCU_DIAG_CONTROL_REG		48
105#define	AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT	1
106
107#define	AML_CPUCONF_CONTROL_REG			0
108#define	AML_CPUCONF_CPU1_ADDR_REG		4
109#define	AML_CPUCONF_CPU2_ADDR_REG		8
110#define	AML_CPUCONF_CPU3_ADDR_REG		12
111
112/* aobus */
113
114#define	AML_M8_CPU_PWR_CNTL0_REG		0xe0
115#define	AML_M8B_CPU_PWR_CNTL0_MODE_CPU3_MASK	(3 << 22)
116#define	AML_M8B_CPU_PWR_CNTL0_MODE_CPU2_MASK	(3 << 20)
117#define	AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK	(3 << 18)
118
119#define	AML_M8_CPU_PWR_CNTL0_ISO_CPU3		(1 << 3)
120#define	AML_M8_CPU_PWR_CNTL0_ISO_CPU2		(1 << 2)
121#define	AML_M8_CPU_PWR_CNTL0_ISO_CPU1		(1 << 1)
122
123#define	AML_M8_CPU_PWR_CNTL1_REG		0xe4
124#define	AML_M8B_CPU_PWR_CNTL1_PWR_CPU3		(1 << 19)
125#define	AML_M8B_CPU_PWR_CNTL1_PWR_CPU2		(1 << 18)
126#define	AML_M8B_CPU_PWR_CNTL1_PWR_CPU1		(1 << 17)
127
128#define	AML_M8_CPU_PWR_CNTL1_MODE_CPU3_MASK	(3 << 8)
129#define	AML_M8_CPU_PWR_CNTL1_MODE_CPU2_MASK	(3 << 6)
130#define	AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK	(3 << 4)
131
132#define	AML_M8B_CPU_PWR_MEM_PD0_REG		0xf4
133#define	AML_M8B_CPU_PWR_MEM_PD0_CPU3		(0xf << 20)
134#define	AML_M8B_CPU_PWR_MEM_PD0_CPU2		(0xf << 24)
135#define	AML_M8B_CPU_PWR_MEM_PD0_CPU1		(0xf << 28)
136
137/* cbus */
138
139#define	AML_SOC_CPU_CLK_CNTL_REG		0x419c
140#define	AML_M8_CPU_CLK_CNTL_RESET_CPU3		(1 << 27)
141#define	AML_M8_CPU_CLK_CNTL_RESET_CPU2		(1 << 26)
142#define	AML_M8_CPU_CLK_CNTL_RESET_CPU1		(1 << 25)
143
144#define	SCU_WRITE_4(reg, value)		bus_write_4(&aml8726_smp.scu_res,    \
145    (reg), (value))
146#define	SCU_READ_4(reg)			bus_read_4(&aml8726_smp.scu_res, (reg))
147#define	SCU_BARRIER(reg)		bus_barrier(&aml8726_smp.scu_res,    \
148    (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
149
150#define	CPUCONF_WRITE_4(reg, value)	bus_write_4(&aml8726_smp.cpucfg_res, \
151    (reg), (value))
152#define	CPUCONF_READ_4(reg)		bus_read_4(&aml8726_smp.cpucfg_res,  \
153    (reg))
154#define	CPUCONF_BARRIER(reg)		bus_barrier(&aml8726_smp.cpucfg_res, \
155    (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
156
157#define	AOBUS_WRITE_4(reg, value)	bus_write_4(&aml8726_smp.aobus_res,  \
158    (reg), (value))
159#define	AOBUS_READ_4(reg)		bus_read_4(&aml8726_smp.aobus_res,   \
160    (reg))
161#define	AOBUS_BARRIER(reg)		bus_barrier(&aml8726_smp.aobus_res,  \
162    (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
163
164#define	CBUS_WRITE_4(reg, value)	bus_write_4(&aml8726_smp.cbus_res,   \
165    (reg), (value))
166#define CBUS_READ_4(reg)		bus_read_4(&aml8726_smp.cbus_res,    \
167    (reg))
168#define	CBUS_BARRIER(reg)		bus_barrier(&aml8726_smp.cbus_res,   \
169    (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
170
171static phandle_t
172find_node_for_device(const char *device, const char **compatible)
173{
174	int i;
175	phandle_t node;
176
177	/*
178	 * Try to access the node directly i.e. through /aliases/.
179	 */
180
181	if ((node = OF_finddevice(device)) != 0)
182		for (i = 0; compatible[i]; i++)
183			if (fdt_is_compatible_strict(node, compatible[i]))
184				return node;
185
186	/*
187	 * Find the node the long way.
188	 */
189
190	for (i = 0; compatible[i]; i++) {
191		if ((node = OF_finddevice("/soc")) == 0)
192			return (0);
193
194		if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0)
195			return node;
196	}
197
198	return (0);
199}
200
201
202static int
203alloc_resource_for_node(phandle_t node, struct resource *res, u_long *size)
204{
205	int err;
206	u_long pbase, psize;
207	u_long start;
208
209	if ((err = fdt_get_range(OF_parent(node), 0, &pbase, &psize)) != 0 ||
210	    (err = fdt_regsize(node, &start, size)) != 0)
211		return (err);
212
213	start += pbase;
214
215	memset(res, 0, sizeof(*res));
216
217	res->r_bustag = fdtbus_bs_tag;
218
219	err = bus_space_map(res->r_bustag, start, *size, 0, &res->r_bushandle);
220
221	return (err);
222}
223
224
225static void
226power_on_cpu(int cpu)
227{
228	uint32_t scpsr;
229	uint32_t value;
230
231	if (cpu <= 0)
232		return;
233
234	/*
235	 * Power on the CPU if the intricate details are known, otherwise
236	 * just hope for the best (it may have already be powered on by
237	 * the hardware / firmware).
238	 */
239
240	switch (aml8726_soc_hw_rev) {
241	case AML_SOC_HW_REV_M8:
242	case AML_SOC_HW_REV_M8B:
243		/*
244		 * Set the SCU power status for the CPU to normal mode.
245		 */
246		scpsr = SCU_READ_4(AML_SCU_CPU_PWR_STATUS_REG);
247		scpsr &= ~(AML_SCU_CPU_PWR_STATUS_CPU1_MASK << ((cpu - 1) * 8));
248		SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr);
249		SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG);
250
251		if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
252			/*
253			 * Reset may cause the current power status from the
254			 * actual CPU to be written to the SCU (over-writing
255			 * the value  we've just written) so set it to normal
256			 * mode as well.
257			 */
258			 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG);
259			 value &= ~(AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK <<
260			    ((cpu - 1) * 2));
261			 AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value);
262			 AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG);
263		 }
264
265		DELAY(5);
266
267		/*
268		 * Assert reset.
269		 */
270		value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG);
271		value |= AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1);
272		CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value);
273		CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG);
274
275		if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
276			/*
277			 * Release RAM pull-down.
278			 */
279			 value = AOBUS_READ_4(AML_M8B_CPU_PWR_MEM_PD0_REG);
280			 value &= ~((uint32_t)AML_M8B_CPU_PWR_MEM_PD0_CPU1 >>
281			    ((cpu - 1) * 4));
282			 AOBUS_WRITE_4(AML_M8B_CPU_PWR_MEM_PD0_REG, value);
283			 AOBUS_BARRIER(AML_M8B_CPU_PWR_MEM_PD0_REG);
284		 }
285
286		/*
287		 * Power on CPU.
288		 */
289		value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG);
290		value &= ~(AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK <<
291		    ((cpu - 1) * 2));
292		AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL1_REG, value);
293		AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL1_REG);
294
295		DELAY(10);
296
297		if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
298			/*
299			 * Wait for power on confirmation.
300			 */
301			for ( ; ; ) {
302				value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG);
303				value &= AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 <<
304				    (cpu - 1);
305				if (value)
306					break;
307				DELAY(10);
308			}
309		}
310
311		/*
312		 * Release peripheral clamp.
313		 */
314		value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG);
315		value &= ~(AML_M8_CPU_PWR_CNTL0_ISO_CPU1 << (cpu - 1));
316		AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value);
317		AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG);
318
319		/*
320		 * Release reset.
321		 */
322		value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG);
323		value &= ~(AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1));
324		CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value);
325		CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG);
326
327		if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
328			/*
329			 * The Amlogic Linux platform code sets the SCU power
330			 * status for the CPU again for some reason so we
331			 * follow suit (perhaps in case the reset caused
332			 * a stale power status from the actual CPU to be
333			 * written to the SCU).
334			 */
335			SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr);
336			SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG);
337		}
338		break;
339	default:
340		break;
341	}
342}
343
344void
345platform_mp_setmaxid(void)
346{
347	int err;
348	int i;
349	int ncpu;
350	phandle_t cpucfg_node;
351	phandle_t scu_node;
352	uint32_t value;
353
354	if (mp_ncpus != 0)
355		return;
356
357	ncpu = 1;
358
359	/*
360	 * Is the hardware necessary for SMP present?
361	 */
362
363	if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0)
364		goto moveon;
365
366	if ((cpucfg_node = find_node_for_device("cpuconfig",
367	    cpucfg_compatible)) == 0)
368		goto moveon;
369
370	if (alloc_resource_for_node(scu_node, &aml8726_smp.scu_res,
371	    &aml8726_smp.scu_size) != 0)
372		panic("Could not allocate resource for SCU");
373
374	if (alloc_resource_for_node(cpucfg_node, &aml8726_smp.cpucfg_res,
375	    &aml8726_smp.cpucfg_size) != 0)
376		panic("Could not allocate resource for CPUCONFIG");
377
378
379	/*
380	 * Strictly speaking the aobus and cbus may not be required in
381	 * order to start an AP (it depends on the processor), however
382	 * always mapping them in simplifies the code.
383	 */
384
385	aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag;
386
387	err = bus_space_map(aml8726_smp.aobus_res.r_bustag,
388	    AML_SOC_AOBUS_BASE_ADDR, 0x100000,
389	    0, &aml8726_smp.aobus_res.r_bushandle);
390
391	if (err)
392		panic("Could not allocate resource for AOBUS");
393
394	aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag;
395
396	err = bus_space_map(aml8726_smp.cbus_res.r_bustag,
397	    AML_SOC_CBUS_BASE_ADDR, 0x100000,
398	    0, &aml8726_smp.cbus_res.r_bushandle);
399
400	if (err)
401		panic("Could not allocate resource for CBUS");
402
403	aml8726_smp.errata_764369 = false;
404	for (i = 0; scu_errata_764369[i]; i++)
405		if (fdt_is_compatible_strict(scu_node, scu_errata_764369[i])) {
406			aml8726_smp.errata_764369 = true;
407			break;
408		}
409
410	/*
411	 * Read the number of CPUs present.
412	 */
413	value = SCU_READ_4(AML_SCU_CONFIG_REG);
414	ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1;
415
416moveon:
417	mp_ncpus = ncpu;
418	mp_maxid = ncpu - 1;
419}
420
421void
422platform_mp_start_ap(void)
423{
424	int i;
425	uint32_t reg;
426	uint32_t value;
427	vm_paddr_t paddr;
428
429	if (mp_ncpus < 2)
430		return;
431
432	/*
433	 * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates
434	 * all ways on all cores 0-3.  Per the ARM docs, it's harmless to
435	 * write to the bits for cores that are not present.
436	 */
437	SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff);
438
439	if (aml8726_smp.errata_764369) {
440		/*
441		 * Erratum ARM/MP: 764369 (problems with cache maintenance).
442		 * Setting the "disable-migratory bit" in the undocumented SCU
443		 * Diagnostic Control Register helps work around the problem.
444		 */
445		value = SCU_READ_4(AML_SCU_DIAG_CONTROL_REG);
446		value |= AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT;
447		SCU_WRITE_4(AML_SCU_DIAG_CONTROL_REG, value);
448	}
449
450	/*
451	 * Enable the SCU, then clean the cache on this core.  After these
452	 * two operations the cache tag ram in the SCU is coherent with
453	 * the contents of the cache on this core.  The other cores aren't
454	 * running yet so their caches can't contain valid data yet, however
455	 * we've initialized their SCU tag ram above, so they will be
456	 * coherent from startup.
457	 */
458	value = SCU_READ_4(AML_SCU_CONTROL_REG);
459	value |= AML_SCU_CONTROL_ENABLE;
460	SCU_WRITE_4(AML_SCU_CONTROL_REG, value);
461	SCU_BARRIER(AML_SCU_CONTROL_REG);
462	dcache_wbinv_poc_all();
463
464	/* Set the boot address and power on each AP. */
465	paddr = pmap_kextract((vm_offset_t)mpentry);
466	for (i = 1; i < mp_ncpus; i++) {
467		reg = AML_CPUCONF_CPU1_ADDR_REG + ((i - 1) * 4);
468		CPUCONF_WRITE_4(reg, paddr);
469		CPUCONF_BARRIER(reg);
470
471		power_on_cpu(i);
472	}
473
474	/*
475	 * Enable the APs.
476	 *
477	 * The Amlogic Linux platform code sets the lsb for some reason
478	 * in addition to the enable bit for each AP so we follow suit
479	 * (the lsb may be the enable bit for the BP, though in that case
480	 * it should already be set since it's currently running).
481	 */
482	value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG);
483	value |= 1;
484	for (i = 1; i < mp_ncpus; i++)
485		value |= (1 << i);
486	CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value);
487	CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG);
488
489	/* Wakeup the now enabled APs */
490	dsb();
491	sev();
492
493	/*
494	 * Free the resources which are not needed after startup.
495	 */
496	bus_space_unmap(aml8726_smp.scu_res.r_bustag,
497	    aml8726_smp.scu_res.r_bushandle,
498	    aml8726_smp.scu_size);
499	bus_space_unmap(aml8726_smp.cpucfg_res.r_bustag,
500	    aml8726_smp.cpucfg_res.r_bushandle,
501	    aml8726_smp.cpucfg_size);
502	bus_space_unmap(aml8726_smp.aobus_res.r_bustag,
503	    aml8726_smp.aobus_res.r_bushandle,
504	    0x100000);
505	bus_space_unmap(aml8726_smp.cbus_res.r_bustag,
506	    aml8726_smp.cbus_res.r_bushandle,
507	    0x100000);
508	memset(&aml8726_smp, 0, sizeof(aml8726_smp));
509}
510
511/*
512 * Stub drivers for cosmetic purposes.
513 */
514struct aml8726_scu_softc {
515	device_t	dev;
516};
517
518static int
519aml8726_scu_probe(device_t dev)
520{
521	int i;
522
523	for (i = 0; scu_compatible[i]; i++)
524		if (ofw_bus_is_compatible(dev, scu_compatible[i]))
525			break;
526
527	if (!scu_compatible[i])
528		return (ENXIO);
529
530	device_set_desc(dev, "ARM Snoop Control Unit");
531
532	return (BUS_PROBE_DEFAULT);
533}
534
535static int
536aml8726_scu_attach(device_t dev)
537{
538	struct aml8726_scu_softc *sc = device_get_softc(dev);
539
540	sc->dev = dev;
541
542	return (0);
543}
544
545static int
546aml8726_scu_detach(device_t dev)
547{
548
549	return (0);
550}
551
552static device_method_t aml8726_scu_methods[] = {
553	/* Device interface */
554	DEVMETHOD(device_probe,		aml8726_scu_probe),
555	DEVMETHOD(device_attach,	aml8726_scu_attach),
556	DEVMETHOD(device_detach,	aml8726_scu_detach),
557
558	DEVMETHOD_END
559};
560
561static driver_t aml8726_scu_driver = {
562	"scu",
563	aml8726_scu_methods,
564	sizeof(struct aml8726_scu_softc),
565};
566
567static devclass_t aml8726_scu_devclass;
568
569EARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass,
570    0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);
571
572struct aml8726_cpucfg_softc {
573	device_t	dev;
574};
575
576static int
577aml8726_cpucfg_probe(device_t dev)
578{
579	int i;
580
581	for (i = 0; cpucfg_compatible[i]; i++)
582		if (ofw_bus_is_compatible(dev, cpucfg_compatible[i]))
583			break;
584
585	if (!cpucfg_compatible[i])
586		return (ENXIO);
587
588	device_set_desc(dev, "Amlogic CPU Config");
589
590	return (BUS_PROBE_DEFAULT);
591}
592
593static int
594aml8726_cpucfg_attach(device_t dev)
595{
596	struct aml8726_cpucfg_softc *sc = device_get_softc(dev);
597
598	sc->dev = dev;
599
600	return (0);
601}
602
603static int
604aml8726_cpucfg_detach(device_t dev)
605{
606
607	return (0);
608}
609
610static device_method_t aml8726_cpucfg_methods[] = {
611	/* Device interface */
612	DEVMETHOD(device_probe,		aml8726_cpucfg_probe),
613	DEVMETHOD(device_attach,	aml8726_cpucfg_attach),
614	DEVMETHOD(device_detach,	aml8726_cpucfg_detach),
615
616	DEVMETHOD_END
617};
618
619static driver_t aml8726_cpucfg_driver = {
620	"cpuconfig",
621	aml8726_cpucfg_methods,
622	sizeof(struct aml8726_cpucfg_softc),
623};
624
625static devclass_t aml8726_cpucfg_devclass;
626
627EARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver,
628    aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);
629