]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/amlogic/aml8726/aml8726_mp.c
Update ELF Tool Chain to upstream rev 3400
[FreeBSD/FreeBSD.git] / sys / arm / amlogic / aml8726 / aml8726_mp.c
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$");
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
68 static const char *scu_compatible[] = {
69         "arm,cortex-a5-scu",
70         "arm,cortex-a9-scu",
71         NULL
72 };
73
74 static const char *scu_errata_764369[] = {
75         "arm,cortex-a9-scu",
76         NULL
77 };
78
79 static const char *cpucfg_compatible[] = {
80         "amlogic,aml8726-cpuconfig",
81         NULL
82 };
83
84 static 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
171 static phandle_t
172 find_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
202 static int
203 alloc_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
225 static void
226 power_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
344
345 void
346 platform_mp_init_secondary(void)
347 {
348
349         /*
350          * Consider modifying the timer driver to support
351          * per-cpu timers and then enabling the timer for
352          * each AP.
353          */
354
355          intr_pic_init_secondary();
356 }
357
358
359 void
360 platform_mp_setmaxid(void)
361 {
362         int err;
363         int i;
364         int ncpu;
365         phandle_t cpucfg_node;
366         phandle_t scu_node;
367         uint32_t value;
368
369         if (mp_ncpus != 0)
370                 return;
371
372         ncpu = 1;
373
374         /*
375          * Is the hardware necessary for SMP present?
376          */
377
378         if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0)
379                 goto moveon;
380
381         if ((cpucfg_node = find_node_for_device("cpuconfig",
382             cpucfg_compatible)) == 0)
383                 goto moveon;
384
385         if (alloc_resource_for_node(scu_node, &aml8726_smp.scu_res,
386             &aml8726_smp.scu_size) != 0)
387                 panic("Could not allocate resource for SCU");
388
389         if (alloc_resource_for_node(cpucfg_node, &aml8726_smp.cpucfg_res,
390             &aml8726_smp.cpucfg_size) != 0)
391                 panic("Could not allocate resource for CPUCONFIG");
392
393
394         /*
395          * Strictly speaking the aobus and cbus may not be required in
396          * order to start an AP (it depends on the processor), however
397          * always mapping them in simplifies the code.
398          */
399
400         aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag;
401
402         err = bus_space_map(aml8726_smp.aobus_res.r_bustag,
403             AML_SOC_AOBUS_BASE_ADDR, 0x100000,
404             0, &aml8726_smp.aobus_res.r_bushandle);
405
406         if (err)
407                 panic("Could not allocate resource for AOBUS");
408
409         aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag;
410
411         err = bus_space_map(aml8726_smp.cbus_res.r_bustag,
412             AML_SOC_CBUS_BASE_ADDR, 0x100000,
413             0, &aml8726_smp.cbus_res.r_bushandle);
414
415         if (err)
416                 panic("Could not allocate resource for CBUS");
417
418         aml8726_smp.errata_764369 = false;
419         for (i = 0; scu_errata_764369[i]; i++)
420                 if (fdt_is_compatible_strict(scu_node, scu_errata_764369[i])) {
421                         aml8726_smp.errata_764369 = true;
422                         break;
423                 }
424
425         /*
426          * Read the number of CPUs present.
427          */
428         value = SCU_READ_4(AML_SCU_CONFIG_REG);
429         ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1;
430
431 moveon:
432         mp_ncpus = ncpu;
433         mp_maxid = ncpu - 1;
434 }
435
436
437 int
438 platform_mp_probe(void)
439 {
440
441         if (mp_ncpus == 0)
442                 platform_mp_setmaxid();
443
444         return (mp_ncpus > 1);
445 }
446
447
448 void
449 platform_mp_start_ap(void)
450 {
451         int i;
452         uint32_t reg;
453         uint32_t value;
454         vm_paddr_t paddr;
455
456         if (mp_ncpus < 2)
457                 return;
458
459         /*
460          * Invalidate SCU cache tags.  The 0x0000ffff constant invalidates
461          * all ways on all cores 0-3.  Per the ARM docs, it's harmless to
462          * write to the bits for cores that are not present.
463          */
464         SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff);
465
466         if (aml8726_smp.errata_764369) {
467                 /*
468                  * Erratum ARM/MP: 764369 (problems with cache maintenance).
469                  * Setting the "disable-migratory bit" in the undocumented SCU
470                  * Diagnostic Control Register helps work around the problem.
471                  */
472                 value = SCU_READ_4(AML_SCU_DIAG_CONTROL_REG);
473                 value |= AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT;
474                 SCU_WRITE_4(AML_SCU_DIAG_CONTROL_REG, value);
475         }
476
477         /*
478          * Enable the SCU, then clean the cache on this core.  After these
479          * two operations the cache tag ram in the SCU is coherent with
480          * the contents of the cache on this core.  The other cores aren't
481          * running yet so their caches can't contain valid data yet, however
482          * we've initialized their SCU tag ram above, so they will be
483          * coherent from startup.
484          */
485         value = SCU_READ_4(AML_SCU_CONTROL_REG);
486         value |= AML_SCU_CONTROL_ENABLE;
487         SCU_WRITE_4(AML_SCU_CONTROL_REG, value);
488         SCU_BARRIER(AML_SCU_CONTROL_REG);
489         dcache_wbinv_poc_all();
490
491         /* Set the boot address and power on each AP. */
492         paddr = pmap_kextract((vm_offset_t)mpentry);
493         for (i = 1; i < mp_ncpus; i++) {
494                 reg = AML_CPUCONF_CPU1_ADDR_REG + ((i - 1) * 4);
495                 CPUCONF_WRITE_4(reg, paddr);
496                 CPUCONF_BARRIER(reg);
497
498                 power_on_cpu(i);
499         }
500
501         /*
502          * Enable the APs.
503          *
504          * The Amlogic Linux platform code sets the lsb for some reason
505          * in addition to the enable bit for each AP so we follow suit
506          * (the lsb may be the enable bit for the BP, though in that case
507          * it should already be set since it's currently running).
508          */
509         value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG);
510         value |= 1;
511         for (i = 1; i < mp_ncpus; i++)
512                 value |= (1 << i);
513         CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value);
514         CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG);
515
516         /* Wakeup the now enabled APs */
517         armv7_sev();
518
519         /*
520          * Free the resources which are not needed after startup.
521          */
522         bus_space_unmap(aml8726_smp.scu_res.r_bustag,
523             aml8726_smp.scu_res.r_bushandle,
524             aml8726_smp.scu_size);
525         bus_space_unmap(aml8726_smp.cpucfg_res.r_bustag,
526             aml8726_smp.cpucfg_res.r_bushandle,
527             aml8726_smp.cpucfg_size);
528         bus_space_unmap(aml8726_smp.aobus_res.r_bustag,
529             aml8726_smp.aobus_res.r_bushandle,
530             0x100000);
531         bus_space_unmap(aml8726_smp.cbus_res.r_bustag,
532             aml8726_smp.cbus_res.r_bushandle,
533             0x100000);
534         memset(&aml8726_smp, 0, sizeof(aml8726_smp));
535 }
536
537 void
538 platform_ipi_send(cpuset_t cpus, u_int ipi)
539 {
540
541         pic_ipi_send(cpus, ipi);
542 }
543
544 /*
545  * Stub drivers for cosmetic purposes.
546  */
547 struct aml8726_scu_softc {
548         device_t        dev;
549 };
550
551 static int
552 aml8726_scu_probe(device_t dev)
553 {
554         int i;
555
556         for (i = 0; scu_compatible[i]; i++)
557                 if (ofw_bus_is_compatible(dev, scu_compatible[i]))
558                         break;
559
560         if (!scu_compatible[i])
561                 return (ENXIO);
562
563         device_set_desc(dev, "ARM Snoop Control Unit");
564
565         return (BUS_PROBE_DEFAULT);
566 }
567
568 static int
569 aml8726_scu_attach(device_t dev)
570 {
571         struct aml8726_scu_softc *sc = device_get_softc(dev);
572
573         sc->dev = dev;
574
575         return (0);
576 }
577
578 static int
579 aml8726_scu_detach(device_t dev)
580 {
581
582         return (0);
583 }
584
585 static device_method_t aml8726_scu_methods[] = {
586         /* Device interface */
587         DEVMETHOD(device_probe,         aml8726_scu_probe),
588         DEVMETHOD(device_attach,        aml8726_scu_attach),
589         DEVMETHOD(device_detach,        aml8726_scu_detach),
590
591         DEVMETHOD_END
592 };
593
594 static driver_t aml8726_scu_driver = {
595         "scu",
596         aml8726_scu_methods,
597         sizeof(struct aml8726_scu_softc),
598 };
599
600 static devclass_t aml8726_scu_devclass;
601
602 EARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass,
603     0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);
604
605 struct aml8726_cpucfg_softc {
606         device_t        dev;
607 };
608
609 static int
610 aml8726_cpucfg_probe(device_t dev)
611 {
612         int i;
613
614         for (i = 0; cpucfg_compatible[i]; i++)
615                 if (ofw_bus_is_compatible(dev, cpucfg_compatible[i]))
616                         break;
617
618         if (!cpucfg_compatible[i])
619                 return (ENXIO);
620
621         device_set_desc(dev, "Amlogic CPU Config");
622
623         return (BUS_PROBE_DEFAULT);
624 }
625
626 static int
627 aml8726_cpucfg_attach(device_t dev)
628 {
629         struct aml8726_cpucfg_softc *sc = device_get_softc(dev);
630
631         sc->dev = dev;
632
633         return (0);
634 }
635
636 static int
637 aml8726_cpucfg_detach(device_t dev)
638 {
639
640         return (0);
641 }
642
643 static device_method_t aml8726_cpucfg_methods[] = {
644         /* Device interface */
645         DEVMETHOD(device_probe,         aml8726_cpucfg_probe),
646         DEVMETHOD(device_attach,        aml8726_cpucfg_attach),
647         DEVMETHOD(device_detach,        aml8726_cpucfg_detach),
648
649         DEVMETHOD_END
650 };
651
652 static driver_t aml8726_cpucfg_driver = {
653         "cpuconfig",
654         aml8726_cpucfg_methods,
655         sizeof(struct aml8726_cpucfg_softc),
656 };
657
658 static devclass_t aml8726_cpucfg_devclass;
659
660 EARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver,
661     aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);