2 * Copyright 2015 John Wehle <john@feith.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 * Amlogic aml8726 multiprocessor support.
30 * Some processors require powering on which involves poking registers
31 * on the aobus and cbus ... it's expected that these locations are set
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).
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42 #include <sys/param.h>
43 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/resource.h>
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>
62 #include <dev/fdt/fdt_common.h>
63 #include <dev/ofw/ofw_bus.h>
64 #include <dev/ofw/ofw_bus_subr.h>
66 #include <arm/amlogic/aml8726/aml8726_soc.h>
68 static const char *scu_compatible[] = {
74 static const char *scu_errata_764369[] = {
79 static const char *cpucfg_compatible[] = {
80 "amlogic,aml8726-cpuconfig",
85 boolean_t errata_764369;
87 struct resource scu_res;
89 struct resource cpucfg_res;
90 struct resource aobus_res;
91 struct resource cbus_res;
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
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
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)
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)
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)
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)
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)
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)
144 #define SCU_WRITE_4(reg, value) bus_write_4(&aml8726_smp.scu_res, \
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))
150 #define CPUCONF_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cpucfg_res, \
152 #define CPUCONF_READ_4(reg) bus_read_4(&aml8726_smp.cpucfg_res, \
154 #define CPUCONF_BARRIER(reg) bus_barrier(&aml8726_smp.cpucfg_res, \
155 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
157 #define AOBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.aobus_res, \
159 #define AOBUS_READ_4(reg) bus_read_4(&aml8726_smp.aobus_res, \
161 #define AOBUS_BARRIER(reg) bus_barrier(&aml8726_smp.aobus_res, \
162 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
164 #define CBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cbus_res, \
166 #define CBUS_READ_4(reg) bus_read_4(&aml8726_smp.cbus_res, \
168 #define CBUS_BARRIER(reg) bus_barrier(&aml8726_smp.cbus_res, \
169 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
172 find_node_for_device(const char *device, const char **compatible)
178 * Try to access the node directly i.e. through /aliases/.
181 if ((node = OF_finddevice(device)) != 0)
182 for (i = 0; compatible[i]; i++)
183 if (fdt_is_compatible_strict(node, compatible[i]))
187 * Find the node the long way.
190 for (i = 0; compatible[i]; i++) {
191 if ((node = OF_finddevice("/soc")) == 0)
194 if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0)
203 alloc_resource_for_node(phandle_t node, struct resource *res, u_long *size)
209 if ((err = fdt_get_range(OF_parent(node), 0, &pbase, &psize)) != 0 ||
210 (err = fdt_regsize(node, &start, size)) != 0)
215 memset(res, 0, sizeof(*res));
217 res->r_bustag = fdtbus_bs_tag;
219 err = bus_space_map(res->r_bustag, start, *size, 0, &res->r_bushandle);
226 power_on_cpu(int cpu)
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).
240 switch (aml8726_soc_hw_rev) {
241 case AML_SOC_HW_REV_M8:
242 case AML_SOC_HW_REV_M8B:
244 * Set the SCU power status for the CPU to normal mode.
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);
251 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
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
258 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG);
259 value &= ~(AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK <<
261 AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value);
262 AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG);
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);
275 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
277 * Release RAM pull-down.
279 value = AOBUS_READ_4(AML_M8B_CPU_PWR_MEM_PD0_REG);
280 value &= ~((uint32_t)AML_M8B_CPU_PWR_MEM_PD0_CPU1 >>
282 AOBUS_WRITE_4(AML_M8B_CPU_PWR_MEM_PD0_REG, value);
283 AOBUS_BARRIER(AML_M8B_CPU_PWR_MEM_PD0_REG);
289 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG);
290 value &= ~(AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK <<
292 AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL1_REG, value);
293 AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL1_REG);
297 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
299 * Wait for power on confirmation.
302 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG);
303 value &= AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 <<
312 * Release peripheral clamp.
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);
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);
327 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) {
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).
335 SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr);
336 SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG);
346 platform_mp_init_secondary(void)
350 * Consider modifying the timer driver to support
351 * per-cpu timers and then enabling the timer for
355 intr_pic_init_secondary();
360 platform_mp_setmaxid(void)
365 phandle_t cpucfg_node;
375 * Is the hardware necessary for SMP present?
378 if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0)
381 if ((cpucfg_node = find_node_for_device("cpuconfig",
382 cpucfg_compatible)) == 0)
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");
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");
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.
400 aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag;
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);
407 panic("Could not allocate resource for AOBUS");
409 aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag;
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);
416 panic("Could not allocate resource for CBUS");
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;
426 * Read the number of CPUs present.
428 value = SCU_READ_4(AML_SCU_CONFIG_REG);
429 ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1;
438 platform_mp_probe(void)
442 platform_mp_setmaxid();
444 return (mp_ncpus > 1);
449 platform_mp_start_ap(void)
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.
464 SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff);
466 if (aml8726_smp.errata_764369) {
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.
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);
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.
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();
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);
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).
509 value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG);
511 for (i = 1; i < mp_ncpus; i++)
513 CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value);
514 CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG);
516 /* Wakeup the now enabled APs */
520 * Free the resources which are not needed after startup.
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,
531 bus_space_unmap(aml8726_smp.cbus_res.r_bustag,
532 aml8726_smp.cbus_res.r_bushandle,
534 memset(&aml8726_smp, 0, sizeof(aml8726_smp));
538 platform_ipi_send(cpuset_t cpus, u_int ipi)
541 pic_ipi_send(cpus, ipi);
545 * Stub drivers for cosmetic purposes.
547 struct aml8726_scu_softc {
552 aml8726_scu_probe(device_t dev)
556 for (i = 0; scu_compatible[i]; i++)
557 if (ofw_bus_is_compatible(dev, scu_compatible[i]))
560 if (!scu_compatible[i])
563 device_set_desc(dev, "ARM Snoop Control Unit");
565 return (BUS_PROBE_DEFAULT);
569 aml8726_scu_attach(device_t dev)
571 struct aml8726_scu_softc *sc = device_get_softc(dev);
579 aml8726_scu_detach(device_t dev)
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),
594 static driver_t aml8726_scu_driver = {
597 sizeof(struct aml8726_scu_softc),
600 static devclass_t aml8726_scu_devclass;
602 EARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass,
603 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);
605 struct aml8726_cpucfg_softc {
610 aml8726_cpucfg_probe(device_t dev)
614 for (i = 0; cpucfg_compatible[i]; i++)
615 if (ofw_bus_is_compatible(dev, cpucfg_compatible[i]))
618 if (!cpucfg_compatible[i])
621 device_set_desc(dev, "Amlogic CPU Config");
623 return (BUS_PROBE_DEFAULT);
627 aml8726_cpucfg_attach(device_t dev)
629 struct aml8726_cpucfg_softc *sc = device_get_softc(dev);
637 aml8726_cpucfg_detach(device_t dev)
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),
652 static driver_t aml8726_cpucfg_driver = {
654 aml8726_cpucfg_methods,
655 sizeof(struct aml8726_cpucfg_softc),
658 static devclass_t aml8726_cpucfg_devclass;
660 EARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver,
661 aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);