^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) * arch/arm/mach-spear13xx/platsmp.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * based upon linux/arch/arm/mach-realview/platsmp.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2012 ST Microelectronics Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/smp_scu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <mach/spear.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "generic.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* XXX spear_pen_release is cargo culted code - DO NOT COPY XXX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) volatile int spear_pen_release = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * XXX CARGO CULTED CODE - DO NOT COPY XXX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Write spear_pen_release in a way that is guaranteed to be visible to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * all observers, irrespective of whether they're taking part in coherency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * or not. This is necessary for the hotplug code to work reliably.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static void spear_write_pen_release(int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) spear_pen_release = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) smp_wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) sync_cache_w(&spear_pen_release);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static DEFINE_SPINLOCK(boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static void __iomem *scu_base = IOMEM(VA_SCU_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void spear13xx_secondary_init(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * let the primary processor know we're out of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * pen, then head off into the C entry point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) spear_write_pen_release(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * Synchronise with the boot thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) spin_lock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) spin_unlock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * set synchronisation state between this boot processor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * and the secondary one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) spin_lock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * The secondary processor is waiting to be released from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * the holding pen - release it, then wait for it to flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * that it has been released by resetting spear_pen_release.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Note that "spear_pen_release" is the hardware CPU ID, whereas
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * "cpu" is Linux's internal ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) spear_write_pen_release(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) timeout = jiffies + (1 * HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) while (time_before(jiffies, timeout)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) smp_rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (spear_pen_release == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * now the secondary core is starting up let it run its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * calibrations, then wait for it to finish
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) spin_unlock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return spear_pen_release != -1 ? -ENOSYS : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * Initialise the CPU possible map early - this describes the CPUs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * which may be present or become present in the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static void __init spear13xx_smp_init_cpus(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned int i, ncores = scu_get_core_count(scu_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (ncores > nr_cpu_ids) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ncores, nr_cpu_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ncores = nr_cpu_ids;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) for (i = 0; i < ncores; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) set_cpu_possible(i, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static void __init spear13xx_smp_prepare_cpus(unsigned int max_cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) scu_enable(scu_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * Write the address of secondary startup into the system-wide location
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * (presently it is in SRAM). The BootMonitor waits until it receives a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * soft interrupt, and then the secondary CPU branches to this address.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) __raw_writel(__pa_symbol(spear13xx_secondary_startup), SYS_LOCATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) const struct smp_operations spear13xx_smp_ops __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .smp_init_cpus = spear13xx_smp_init_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .smp_prepare_cpus = spear13xx_smp_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .smp_secondary_init = spear13xx_secondary_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .smp_boot_secondary = spear13xx_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .cpu_die = spear13xx_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) };