^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * plat smp support for CSR Marco dual-core SMP SoCs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
^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/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/delay.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/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/mach/map.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/smp_plat.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 <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/cputype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static void __iomem *clk_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static DEFINE_SPINLOCK(boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* XXX prima2_pen_release is cargo culted code - DO NOT COPY XXX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) volatile int prima2_pen_release = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static void sirfsoc_secondary_init(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * let the primary processor know we're out of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * pen, then head off into the C entry point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) prima2_pen_release = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) smp_wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * Synchronise with the boot thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) spin_lock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) spin_unlock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static const struct of_device_id clk_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { .compatible = "sirf,atlas7-clkc" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {},
^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) static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) np = of_find_matching_node(NULL, clk_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) clk_base = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (!clk_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * write the address of secondary startup into the clkc register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * at offset 0x2bC, then write the magic number 0x3CAF5D62 to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * clkc register at offset 0x2b8, which is what boot rom code is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * waiting for. This would wake up the secondary core from WFE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2bc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) __raw_writel(__pa_symbol(sirfsoc_secondary_startup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) clk_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x2b8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) __raw_writel(0x3CAF5D62,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) clk_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* make sure write buffer is drained */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) spin_lock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * The secondary processor is waiting to be released from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * the holding pen - release it, then wait for it to flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * that it has been released by resetting prima2_pen_release.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * Note that "prima2_pen_release" is the hardware CPU ID, whereas
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * "cpu" is Linux's internal ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) prima2_pen_release = cpu_logical_map(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) sync_cache_w(&prima2_pen_release);
^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) * Send the secondary CPU SEV, thereby causing the boot monitor to read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * the JUMPADDR and WAKEMAGIC, and branch to the address found there.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) dsb_sev();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) timeout = jiffies + (1 * HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) while (time_before(jiffies, timeout)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) smp_rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (prima2_pen_release == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) udelay(10);
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * now the secondary core is starting up let it run its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * calibrations, then wait for it to finish
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) spin_unlock(&boot_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return prima2_pen_release != -1 ? -ENOSYS : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) const struct smp_operations sirfsoc_smp_ops __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .smp_secondary_init = sirfsoc_secondary_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .smp_boot_secondary = sirfsoc_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .cpu_die = sirfsoc_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };