^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) * Copyright (C) 2002 ARM Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This hotplug implementation is _specific_ to the situation found on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * ARM development platforms where there is _no_ possibility of actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * taking a CPU offline, resetting it, or otherwise. Real platforms must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * NOT copy this code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^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/cp15.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <plat/platsmp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static inline void versatile_immitation_enter_lowpower(unsigned int actrl_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned int v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) "mcr p15, 0, %1, c7, c5, 0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) " mcr p15, 0, %1, c7, c10, 4\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * Turn off coherency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) " mrc p15, 0, %0, c1, c0, 1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) " bic %0, %0, %3\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) " mcr p15, 0, %0, c1, c0, 1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) " mrc p15, 0, %0, c1, c0, 0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) " bic %0, %0, %2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) " mcr p15, 0, %0, c1, c0, 0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) : "=&r" (v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) : "r" (0), "Ir" (CR_C), "Ir" (actrl_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) : "cc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static inline void versatile_immitation_leave_lowpower(unsigned int actrl_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned int v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) "mrc p15, 0, %0, c1, c0, 0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) " orr %0, %0, %1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) " mcr p15, 0, %0, c1, c0, 0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) " mrc p15, 0, %0, c1, c0, 1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) " orr %0, %0, %2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) " mcr p15, 0, %0, c1, c0, 1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) : "=&r" (v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) : "Ir" (CR_C), "Ir" (actrl_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) : "cc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static inline void versatile_immitation_do_lowpower(unsigned int cpu, int *spurious)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * there is no power-control hardware on this platform, so all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * we can do is put the core into WFI; this is safe as the calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * code will have already disabled interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * This code should not be used outside Versatile platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) wfi();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (versatile_cpu_release == cpu_logical_map(cpu)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * OK, proper wakeup, we're done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^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) * Getting here, means that we have come out of WFI without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * having been woken up - this shouldn't happen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * Just note it happening - when we're woken, we can report
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * its occurrence.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) (*spurious)++;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * platform-specific code to shutdown a CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * This code supports immitation-style CPU hotplug for Versatile/Realview/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * Versatile Express platforms that are unable to do real CPU hotplug.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int spurious = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) versatile_immitation_enter_lowpower(actrl_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) versatile_immitation_do_lowpower(cpu, &spurious);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) versatile_immitation_leave_lowpower(actrl_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (spurious)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }