162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/mach-spear13xx/hotplug.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics Ltd. 662306a36Sopenharmony_ci * Deepak Sikri <deepak.sikri@st.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * based upon linux/arch/arm/mach-realview/hotplug.c 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/smp.h> 1362306a36Sopenharmony_ci#include <asm/cp15.h> 1462306a36Sopenharmony_ci#include <asm/smp_plat.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "generic.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic inline void cpu_enter_lowpower(void) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci unsigned int v; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci asm volatile( 2362306a36Sopenharmony_ci " mcr p15, 0, %1, c7, c5, 0\n" 2462306a36Sopenharmony_ci " dsb\n" 2562306a36Sopenharmony_ci /* 2662306a36Sopenharmony_ci * Turn off coherency 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci " mrc p15, 0, %0, c1, c0, 1\n" 2962306a36Sopenharmony_ci " bic %0, %0, #0x20\n" 3062306a36Sopenharmony_ci " mcr p15, 0, %0, c1, c0, 1\n" 3162306a36Sopenharmony_ci " mrc p15, 0, %0, c1, c0, 0\n" 3262306a36Sopenharmony_ci " bic %0, %0, %2\n" 3362306a36Sopenharmony_ci " mcr p15, 0, %0, c1, c0, 0\n" 3462306a36Sopenharmony_ci : "=&r" (v) 3562306a36Sopenharmony_ci : "r" (0), "Ir" (CR_C) 3662306a36Sopenharmony_ci : "cc", "memory"); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline void cpu_leave_lowpower(void) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci unsigned int v; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci asm volatile("mrc p15, 0, %0, c1, c0, 0\n" 4462306a36Sopenharmony_ci " orr %0, %0, %1\n" 4562306a36Sopenharmony_ci " mcr p15, 0, %0, c1, c0, 0\n" 4662306a36Sopenharmony_ci " mrc p15, 0, %0, c1, c0, 1\n" 4762306a36Sopenharmony_ci " orr %0, %0, #0x20\n" 4862306a36Sopenharmony_ci " mcr p15, 0, %0, c1, c0, 1\n" 4962306a36Sopenharmony_ci : "=&r" (v) 5062306a36Sopenharmony_ci : "Ir" (CR_C) 5162306a36Sopenharmony_ci : "cc"); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic inline void spear13xx_do_lowpower(unsigned int cpu, int *spurious) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci for (;;) { 5762306a36Sopenharmony_ci wfi(); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (spear_pen_release == cpu) { 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * OK, proper wakeup, we're done 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci break; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * Getting here, means that we have come out of WFI without 6862306a36Sopenharmony_ci * having been woken up - this shouldn't happen 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Just note it happening - when we're woken, we can report 7162306a36Sopenharmony_ci * its occurrence. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci (*spurious)++; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * platform-specific code to shutdown a CPU 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * Called with IRQs disabled 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_civoid spear13xx_cpu_die(unsigned int cpu) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci int spurious = 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * we're ready for shutdown now, so do it 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci cpu_enter_lowpower(); 9062306a36Sopenharmony_ci spear13xx_do_lowpower(cpu, &spurious); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * bring this CPU back into the world of cache 9462306a36Sopenharmony_ci * coherency, and then restore interrupts 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci cpu_leave_lowpower(); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (spurious) 9962306a36Sopenharmony_ci pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); 10062306a36Sopenharmony_ci} 101