mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-11-01 09:13:37 +00:00 
			
		
		
		
	ARM: 5778/1: AT91: Add cpuidle support
This patch adds the support for cpuidle on AT91 SoCs, taken from the cpuidle support in mach-kirkwood. cpuidle needs sdram_selfrefresh_enable and _disable, so move their definition to a separate header file instead of duplicating the code already used in pm.c. Tested-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Albin Tonnerre <albin.tonnerre@free-electrons.com> Acked-by: Andrew Victor <linux@maxim.org.za> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									cd3abf98ae
								
							
						
					
					
						commit
						1ea60cf706
					
				
					 4 changed files with 166 additions and 58 deletions
				
			
		| 
						 | 
				
			
			@ -77,6 +77,7 @@ obj-y				+= leds.o
 | 
			
		|||
# Power Management
 | 
			
		||||
obj-$(CONFIG_PM)		+= pm.o
 | 
			
		||||
obj-$(CONFIG_AT91_SLOW_CLOCK)	+= pm_slowclock.o
 | 
			
		||||
obj-$(CONFIG_CPU_IDLE)	+= cpuidle.o
 | 
			
		||||
 | 
			
		||||
ifeq ($(CONFIG_PM_DEBUG),y)
 | 
			
		||||
CFLAGS_pm.o += -DDEBUG
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										94
									
								
								arch/arm/mach-at91/cpuidle.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								arch/arm/mach-at91/cpuidle.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
/*
 | 
			
		||||
 * based on arch/arm/mach-kirkwood/cpuidle.c
 | 
			
		||||
 *
 | 
			
		||||
 * CPU idle support for AT91 SoC
 | 
			
		||||
 *
 | 
			
		||||
 * This file is licensed under the terms of the GNU General Public
 | 
			
		||||
 * License version 2.  This program is licensed "as is" without any
 | 
			
		||||
 * warranty of any kind, whether express or implied.
 | 
			
		||||
 *
 | 
			
		||||
 * The cpu idle uses wait-for-interrupt and RAM self refresh in order
 | 
			
		||||
 * to implement two idle states -
 | 
			
		||||
 * #1 wait-for-interrupt
 | 
			
		||||
 * #2 wait-for-interrupt and RAM self refresh
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/cpuidle.h>
 | 
			
		||||
#include <asm/proc-fns.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
 | 
			
		||||
#include "pm.h"
 | 
			
		||||
 | 
			
		||||
#define AT91_MAX_STATES	2
 | 
			
		||||
 | 
			
		||||
static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device);
 | 
			
		||||
 | 
			
		||||
static struct cpuidle_driver at91_idle_driver = {
 | 
			
		||||
	.name =         "at91_idle",
 | 
			
		||||
	.owner =        THIS_MODULE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Actual code that puts the SoC in different idle states */
 | 
			
		||||
static int at91_enter_idle(struct cpuidle_device *dev,
 | 
			
		||||
			       struct cpuidle_state *state)
 | 
			
		||||
{
 | 
			
		||||
	struct timeval before, after;
 | 
			
		||||
	int idle_time;
 | 
			
		||||
	u32 saved_lpr;
 | 
			
		||||
 | 
			
		||||
	local_irq_disable();
 | 
			
		||||
	do_gettimeofday(&before);
 | 
			
		||||
	if (state == &dev->states[0])
 | 
			
		||||
		/* Wait for interrupt state */
 | 
			
		||||
		cpu_do_idle();
 | 
			
		||||
	else if (state == &dev->states[1]) {
 | 
			
		||||
		asm("b 1f; .align 5; 1:");
 | 
			
		||||
		asm("mcr p15, 0, r0, c7, c10, 4");	/* drain write buffer */
 | 
			
		||||
		saved_lpr = sdram_selfrefresh_enable();
 | 
			
		||||
		cpu_do_idle();
 | 
			
		||||
		sdram_selfrefresh_disable(saved_lpr);
 | 
			
		||||
	}
 | 
			
		||||
	do_gettimeofday(&after);
 | 
			
		||||
	local_irq_enable();
 | 
			
		||||
	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 | 
			
		||||
			(after.tv_usec - before.tv_usec);
 | 
			
		||||
	return idle_time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize CPU idle by registering the idle states */
 | 
			
		||||
static int at91_init_cpuidle(void)
 | 
			
		||||
{
 | 
			
		||||
	struct cpuidle_device *device;
 | 
			
		||||
 | 
			
		||||
	cpuidle_register_driver(&at91_idle_driver);
 | 
			
		||||
 | 
			
		||||
	device = &per_cpu(at91_cpuidle_device, smp_processor_id());
 | 
			
		||||
	device->state_count = AT91_MAX_STATES;
 | 
			
		||||
 | 
			
		||||
	/* Wait for interrupt state */
 | 
			
		||||
	device->states[0].enter = at91_enter_idle;
 | 
			
		||||
	device->states[0].exit_latency = 1;
 | 
			
		||||
	device->states[0].target_residency = 10000;
 | 
			
		||||
	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
 | 
			
		||||
	strcpy(device->states[0].name, "WFI");
 | 
			
		||||
	strcpy(device->states[0].desc, "Wait for interrupt");
 | 
			
		||||
 | 
			
		||||
	/* Wait for interrupt and RAM self refresh state */
 | 
			
		||||
	device->states[1].enter = at91_enter_idle;
 | 
			
		||||
	device->states[1].exit_latency = 10;
 | 
			
		||||
	device->states[1].target_residency = 10000;
 | 
			
		||||
	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
 | 
			
		||||
	strcpy(device->states[1].name, "RAM_SR");
 | 
			
		||||
	strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
 | 
			
		||||
 | 
			
		||||
	if (cpuidle_register_device(device)) {
 | 
			
		||||
		printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
device_initcall(at91_init_cpuidle);
 | 
			
		||||
| 
						 | 
				
			
			@ -29,62 +29,7 @@
 | 
			
		|||
#include <mach/cpu.h>
 | 
			
		||||
 | 
			
		||||
#include "generic.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_AT91RM9200
 | 
			
		||||
#include <mach/at91rm9200_mc.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The AT91RM9200 goes into self-refresh mode with this command, and will
 | 
			
		||||
 * terminate self-refresh automatically on the next SDRAM access.
 | 
			
		||||
 */
 | 
			
		||||
#define sdram_selfrefresh_enable()	at91_sys_write(AT91_SDRAMC_SRR, 1)
 | 
			
		||||
#define sdram_selfrefresh_disable()	do {} while (0)
 | 
			
		||||
 | 
			
		||||
#elif defined(CONFIG_ARCH_AT91CAP9)
 | 
			
		||||
#include <mach/at91cap9_ddrsdr.h>
 | 
			
		||||
 | 
			
		||||
static u32 saved_lpr;
 | 
			
		||||
 | 
			
		||||
static inline void sdram_selfrefresh_enable(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 lpr;
 | 
			
		||||
 | 
			
		||||
	saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR);
 | 
			
		||||
 | 
			
		||||
	lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
 | 
			
		||||
	at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define sdram_selfrefresh_disable()	at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
#include <mach/at91sam9_sdramc.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_AT91SAM9263
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
 | 
			
		||||
 * handle those cases both here and in the Suspend-To-RAM support.
 | 
			
		||||
 */
 | 
			
		||||
#define	AT91_SDRAMC	AT91_SDRAMC0
 | 
			
		||||
#warning Assuming EB1 SDRAM controller is *NOT* used
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static u32 saved_lpr;
 | 
			
		||||
 | 
			
		||||
static inline void sdram_selfrefresh_enable(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 lpr;
 | 
			
		||||
 | 
			
		||||
	saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
 | 
			
		||||
 | 
			
		||||
	lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
 | 
			
		||||
	at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define sdram_selfrefresh_disable()	at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "pm.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Show the reason for the previous system reset.
 | 
			
		||||
| 
						 | 
				
			
			@ -260,6 +205,7 @@ extern u32 at91_slow_clock_sz;
 | 
			
		|||
 | 
			
		||||
static int at91_pm_enter(suspend_state_t state)
 | 
			
		||||
{
 | 
			
		||||
	u32 saved_lpr;
 | 
			
		||||
	at91_gpio_suspend();
 | 
			
		||||
	at91_irq_suspend();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -315,9 +261,9 @@ static int at91_pm_enter(suspend_state_t state)
 | 
			
		|||
			 */
 | 
			
		||||
			asm("b 1f; .align 5; 1:");
 | 
			
		||||
			asm("mcr p15, 0, r0, c7, c10, 4");	/* drain write buffer */
 | 
			
		||||
			sdram_selfrefresh_enable();
 | 
			
		||||
			saved_lpr = sdram_selfrefresh_enable();
 | 
			
		||||
			asm("mcr p15, 0, r0, c7, c0, 4");	/* wait for interrupt */
 | 
			
		||||
			sdram_selfrefresh_disable();
 | 
			
		||||
			sdram_selfrefresh_disable(saved_lpr);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case PM_SUSPEND_ON:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										67
									
								
								arch/arm/mach-at91/pm.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								arch/arm/mach-at91/pm.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
#ifdef CONFIG_ARCH_AT91RM9200
 | 
			
		||||
#include <mach/at91rm9200_mc.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The AT91RM9200 goes into self-refresh mode with this command, and will
 | 
			
		||||
 * terminate self-refresh automatically on the next SDRAM access.
 | 
			
		||||
 *
 | 
			
		||||
 * Self-refresh mode is exited as soon as a memory access is made, but we don't
 | 
			
		||||
 * know for sure when that happens. However, we need to restore the low-power
 | 
			
		||||
 * mode if it was enabled before going idle. Restoring low-power mode while
 | 
			
		||||
 * still in self-refresh is "not recommended", but seems to work.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static inline u32 sdram_selfrefresh_enable(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
 | 
			
		||||
 | 
			
		||||
	at91_sys_write(AT91_SDRAMC_LPR, 0);
 | 
			
		||||
	at91_sys_write(AT91_SDRAMC_SRR, 1);
 | 
			
		||||
	return saved_lpr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define sdram_selfrefresh_disable(saved_lpr)	at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
 | 
			
		||||
 | 
			
		||||
#elif defined(CONFIG_ARCH_AT91CAP9)
 | 
			
		||||
#include <mach/at91cap9_ddrsdr.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static inline u32 sdram_selfrefresh_enable(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 saved_lpr, lpr;
 | 
			
		||||
 | 
			
		||||
	saved_lpr = at91_sys_read(AT91_DDRSDRC_LPR);
 | 
			
		||||
 | 
			
		||||
	lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
 | 
			
		||||
	at91_sys_write(AT91_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
 | 
			
		||||
	return saved_lpr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define sdram_selfrefresh_disable(saved_lpr)	at91_sys_write(AT91_DDRSDRC_LPR, saved_lpr)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
#include <mach/at91sam9_sdramc.h>
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_AT91SAM9263
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
 | 
			
		||||
 * handle those cases both here and in the Suspend-To-RAM support.
 | 
			
		||||
 */
 | 
			
		||||
#define	AT91_SDRAMC	AT91_SDRAMC0
 | 
			
		||||
#warning Assuming EB1 SDRAM controller is *NOT* used
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline u32 sdram_selfrefresh_enable(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 saved_lpr, lpr;
 | 
			
		||||
 | 
			
		||||
	saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
 | 
			
		||||
 | 
			
		||||
	lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
 | 
			
		||||
	at91_sys_write(AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
 | 
			
		||||
	return saved_lpr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define sdram_selfrefresh_disable(saved_lpr)	at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue