197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King/*
297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King *  linux/arch/arm/mach-realview/hotplug.c
397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King *
497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King *  Copyright (C) 2002 ARM Ltd.
597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King *  All Rights Reserved
697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King *
797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King * This program is free software; you can redistribute it and/or modify
897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King * it under the terms of the GNU General Public License version 2 as
997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King * published by the Free Software Foundation.
1097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King */
1197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King#include <linux/kernel.h>
1297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King#include <linux/errno.h>
1397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King#include <linux/smp.h>
1497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
1515d07dc9c59eae51219c40253bdf920f62bb10f2Russell King#include <asm/cp15.h>
16eb50439b92b6298bf209a982f295ba9c0f7cb30bWill Deacon#include <asm/smp_plat.h>
178aa2da872a492a2196397603ed756a4c48677122Harry Fearnhamm
1897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell Kingstatic inline void cpu_enter_lowpower(void)
1997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King{
2097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	unsigned int v;
2197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
228aa2da872a492a2196397603ed756a4c48677122Harry Fearnhamm	asm volatile(
2397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mcr	p15, 0, %1, c7, c5, 0\n"
2497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mcr	p15, 0, %1, c7, c10, 4\n"
2597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	/*
2697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * Turn off coherency
2797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 */
2897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mrc	p15, 0, %0, c1, c0, 1\n"
2997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	bic	%0, %0, #0x20\n"
3097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mcr	p15, 0, %0, c1, c0, 1\n"
3197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mrc	p15, 0, %0, c1, c0, 0\n"
32e3d9c625f5e4158014e041f492b46e38ad10987eRussell King	"	bic	%0, %0, %2\n"
3397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mcr	p15, 0, %0, c1, c0, 0\n"
3497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	  : "=&r" (v)
35e3d9c625f5e4158014e041f492b46e38ad10987eRussell King	  : "r" (0), "Ir" (CR_C)
3697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	  : "cc");
3797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King}
3897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
3997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell Kingstatic inline void cpu_leave_lowpower(void)
4097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King{
4197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	unsigned int v;
4297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
4397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	asm volatile(	"mrc	p15, 0, %0, c1, c0, 0\n"
44e3d9c625f5e4158014e041f492b46e38ad10987eRussell King	"	orr	%0, %0, %1\n"
4597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mcr	p15, 0, %0, c1, c0, 0\n"
4697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mrc	p15, 0, %0, c1, c0, 1\n"
4797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	orr	%0, %0, #0x20\n"
4897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	"	mcr	p15, 0, %0, c1, c0, 1\n"
4997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	  : "=&r" (v)
50e3d9c625f5e4158014e041f492b46e38ad10987eRussell King	  : "Ir" (CR_C)
5197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	  : "cc");
5297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King}
5397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
54d4450261e546953c4a1ce8b48e29164a57c6ed33Russell Kingstatic inline void platform_do_lowpower(unsigned int cpu, int *spurious)
5597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King{
5697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	/*
5797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * there is no power-control hardware on this platform, so all
5897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * we can do is put the core into WFI; this is safe as the calling
5997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * code will have already disabled interrupts
6097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 */
6197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	for (;;) {
6297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		/*
6397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		 * here's the WFI
6497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		 */
6597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		asm(".word	0xe320f003\n"
6697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		    :
6797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		    :
6897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		    : "memory", "cc");
6997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
704a139b64703115e41e1a4e16ebf7eb93d0a0e349Will Deacon		if (pen_release == cpu_logical_map(cpu)) {
7197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King			/*
7297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King			 * OK, proper wakeup, we're done
7397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King			 */
7497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King			break;
7597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		}
7697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
7797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		/*
78d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King		 * Getting here, means that we have come out of WFI without
7997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		 * having been woken up - this shouldn't happen
8097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		 *
81d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King		 * Just note it happening - when we're woken, we can report
82d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King		 * its occurrence.
8397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King		 */
84d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King		(*spurious)++;
8597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	}
8697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King}
8797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
8897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King/*
8997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King * platform-specific code to shutdown a CPU
9097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King *
9197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King * Called with IRQs disabled
9297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King */
933695adc2fdaf3ad1881e0dd3e3422e5e141abd7dMarc Zyngiervoid __ref realview_cpu_die(unsigned int cpu)
9497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King{
95d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King	int spurious = 0;
96d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King
9797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	/*
9897a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * we're ready for shutdown now, so do it
9997a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 */
10097a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	cpu_enter_lowpower();
101d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King	platform_do_lowpower(cpu, &spurious);
10297a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King
10397a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	/*
10497a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * bring this CPU back into the world of cache
10597a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 * coherency, and then restore interrupts
10697a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	 */
10797a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King	cpu_leave_lowpower();
108d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King
109d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King	if (spurious)
110d4450261e546953c4a1ce8b48e29164a57c6ed33Russell King		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
11197a63ecff4bd06da5d8feb8c0394a4d020f2d34dRussell King}
112