^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/arch/arm/mach-axxia/platsmp.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2012 LSI Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /* Syscon register offsets for releasing cores from reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define SC_CRIT_WRITE_KEY 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define SC_RST_CPU_HOLD 0x1010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Write the kernel entry point for secondary CPUs to the specified address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static void write_release_addr(u32 release_phys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u32 *virt = (u32 *) phys_to_virt(release_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) writel_relaxed(__pa_symbol(secondary_startup), virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Make sure this store is visible to other CPUs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) smp_wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) __cpuc_flush_dcache_area(virt, sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct device_node *syscon_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) void __iomem *syscon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) syscon_np = of_find_compatible_node(NULL, NULL, "lsi,axxia-syscon");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!syscon_np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) syscon = of_iomap(syscon_np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (!syscon)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) tmp = readl(syscon + SC_RST_CPU_HOLD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) writel(0xab, syscon + SC_CRIT_WRITE_KEY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) tmp &= ~(1 << cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) writel(tmp, syscon + SC_RST_CPU_HOLD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static void __init axxia_smp_prepare_cpus(unsigned int max_cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int cpu_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * Initialise the present map, which describes the set of CPUs actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * populated at the present time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) for_each_possible_cpu(cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u32 release_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) np = of_get_cpu_node(cpu, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (of_property_read_u32(np, "cpu-release-addr", &release_phys))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (cpu_count < max_cpus) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) set_cpu_present(cpu, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) cpu_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (release_phys != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) write_release_addr(release_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static const struct smp_operations axxia_smp_ops __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .smp_prepare_cpus = axxia_smp_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .smp_boot_secondary = axxia_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) CPU_METHOD_OF_DECLARE(axxia_smp, "lsi,syscon-release", &axxia_smp_ops);