pm_34xx.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,647 行 · 第 1/3 页

C
1,647
字号
/* * linux/arch/arm/mach-omap2/pm_34xx.c * * OMAP3 Power Management Routines * * Copyright (C) 2007 Texas Instruments, Inc. * Karthik Dasu <karthik-dp@ti.com> * * Copyright (C) 2006 Nokia Corporation * Tony Lindgren <tony@atomide.com> * * Copyright (C) 2005 Texas Instruments, Inc. * Richard Woodruff <r-woodruff2@ti.com> * * Based on pm.c for omap1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/pm.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/interrupt.h>#include <linux/sysfs.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/cpuidle.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/atomic.h>#include <asm/mach/time.h>#include <asm/mach/irq.h>#include <asm/mach-types.h>#include <linux/mm.h>#include <asm/mmu.h>#include <asm/tlbflush.h>#include <asm/arch/irqs.h>#include <asm/arch/clock.h>#include <asm/arch/sram.h>#include <asm/arch/pm.h>#include <linux/tick.h>#define SR1_ID 1#define SR2_ID 2#include "prcm-regs.h"/* * Define DEBUG_HW_SUP for extended information during 'cat /proc/pm_prepwst' */#undef DEBUG_HW_SUP#define S600M   600000000#define S550M	550000000#define S500M	500000000#define S250M	250000000#define S125M	125000000#define S19M	 19200000#define S120M	120000000#define S477M	476000000#define S381M	381000000#define S191M	190000000#define S96M	 96000000#define S166M	166000000#define S83M	 83000000#define PRCM_MPU_IRQ	0xB		/* MPU IRQ 11 */#define CORE_FCLK_MASK	0x3FF9E29 	/* Mask of all functional clocks*/					/* in core except UART */#define CORE3_FCLK_MASK		0x7	/* Mask of all functional clocks */#define USBHOST_FCLK_MASK	0x3	/* Mask of all functional clocks in USB */#define SGX_FCLK_MASK		0x2	/* Mask of all functional clocks in SGX */#define DSS_FCLK_MASK		0x7	/* Mask of all functional clocks in DSS */#define CAM_FCLK_MASK		0x1 	/* Mask of all functional clocks in CAM */#define PER_FCLK_MASK		0x17FF	/* Mask of all functional clocks in PER */					/* except UART and GPIO */#define CORE1_ICLK_VALID	0x3FFFFFF9 /*Ignore SDRC_ICLK*/#define CORE2_ICLK_VALID	0x1F#define CORE3_ICLK_VALID	0x4#define USBHOST_ICLK_VALID	0x1#define	SGX_ICLK_VALID		0x1#define DSS_ICLK_VALID		0x1#define CAM_ICLK_VALID		0x1#define PER_ICLK_VALID 		0x1#define WKUP_ICLK_VALID 	0x3E /* Ignore GPT1 ICLK as it is handled explicitly*/#define OMAP3_MAX_STATES	7#define OMAP3_STATE_C0		0 /* MPU ACTIVE + CORE ACTIVE(only WFI)*/#define OMAP3_STATE_C1 		1 /* MPU WFI + Dynamic tick + CORE ACTIVE*/#define OMAP3_STATE_C2 		2 /* MPU CSWR + CORE ACTIVE*/#define OMAP3_STATE_C3 		3 /* MPU OFF + CORE ACTIVE*/#define OMAP3_STATE_C4		4 /* MPU RET + CORE CSWR */#define OMAP3_STATE_C5		5 /* MPU OFF + CORE CSWR */#define OMAP3_STATE_C6		6 /* MPU OFF + CORE OFF */#define MAX_SUPPORTED_STATES 	5#define IOPAD_WKUP	1/* #define DEBUG_CPUIDLE 1 */#define DPRINTK(fmt, args...)int cpuidle_deepest_st = 0;/* Macro for debugging */#define RESTORE_TABLE_ENTRY 1/* * Time-out value for frame buffer (in seconds). */int fb_timeout_val = 30;u32 target_opp_no;int enable_off = 1;u32 debug_domain = DOM_CORE1;struct res_handle  *memret1;struct res_handle  *memret2;struct res_handle  *logret1;int res1_level = -1, res2_level = -1, res3_level = -1;static struct constraint_handle *vdd1_opp_co;static struct constraint_handle *vdd2_opp_co;static struct constraint_id cnstr_id1 = {	.type = RES_FREQ_CO,	.data = (void *)"vdd1_opp",};static struct constraint_id cnstr_id2 = {	.type = RES_FREQ_CO,	.data = (void *)"vdd2_opp",};/* * Time-out value for UART before cutting clock (in msecs). */#define UART_TIME_OUT	6000extern void omap_uart_save_ctx(void);extern void omap_uart_restore_ctx(void);extern void set_blank_interval(int fb_timeout_val);#define SCRATCHPAD_ROM			0x48002860#define SCRATCHPAD			0x48002910#define SCRATCHPAD_ROM_OFFSET		0x19C#define TABLE_ADDRESS_OFFSET		0x31#define TABLE_VALUE_OFFSET		0x30#define CONTROL_REG_VALUE_OFFSET	0x32struct system_power_state target_state;static u32 *scratchpad_restore_addr;static u32 restore_pointer_address;static u32 mpu_ret_cnt;static u32 mpu_off_cnt;static u32 core_ret_cnt;static u32 core_off_cnt;struct omap3_processor_cx {	u8 valid;	u8 type;	u32 sleep_latency;	u32 wakeup_latency;	u32 mpu_state;	u32 core_state;	u32 threshold;	u32 flags;};#define LAST_IDLE_STATE_ARR_SIZE 10struct idle_state {	u32 mpu_state;	u32 core_state;	u32 fclks;	u32 iclks;	u8 iva_state;};static struct idle_state last_idle_state[LAST_IDLE_STATE_ARR_SIZE];u32 arr_wrptr;struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];struct omap3_processor_cx current_cx_state;static void (*saved_idle)(void);u32 current_vdd1_opp = PRCM_VDD1_OPP3;u32 current_vdd2_opp = PRCM_VDD2_OPP3;EXPORT_SYMBOL(current_vdd1_opp);EXPORT_SYMBOL(current_vdd2_opp);EXPORT_SYMBOL(power_subsys);struct clk *p_vdd1_clk;struct clk *p_vdd2_clk;u32 vdd1_opp_no;u32 vdd2_opp_no;static unsigned long awake_time_end;struct mpu_core_vdd_state target_sleep_state;/* * Functions to save & restore core context. */extern void prcm_save_core_context(u32 target_core_state);extern void prcm_restore_core_context(u32 target_core_state);/** * store_prepwst - Store the previous power state */static void store_prepwst(void){	last_idle_state[arr_wrptr].mpu_state  = PM_PREPWSTST_MPU;	last_idle_state[arr_wrptr].core_state = PM_PREPWSTST_CORE;	if ((PM_PREPWSTST_MPU & 0x3) == 0x1)		mpu_ret_cnt++;	if ((PM_PREPWSTST_MPU & 0x3) == 0x0)		mpu_off_cnt++;	if ((PM_PREPWSTST_CORE & 0x3) == 0x1)		core_ret_cnt++;	if ((PM_PREPWSTST_CORE & 0x3) == 0x0)		core_off_cnt++;	last_idle_state[arr_wrptr].fclks =		(  (CM_FCLKEN1_CORE & CORE_FCLK_MASK)		 | (CM_FCLKEN_SGX      & SGX_FCLK_MASK)		 | (CM_FCLKEN_DSS      & DSS_FCLK_MASK)		 | (CM_FCLKEN_USBHOST  & USBHOST_FCLK_MASK)		 | (CM_FCLKEN3_CORE    & CORE3_FCLK_MASK)		 | (CM_FCLKEN_CAM      & CAM_FCLK_MASK)		 | (CM_FCLKEN_PER      & PER_FCLK_MASK));	last_idle_state[arr_wrptr].iclks =		(  (CORE1_ICLK_VALID & (CM_ICLKEN1_CORE & ~CM_AUTOIDLE1_CORE))		 | (CORE2_ICLK_VALID & (CM_ICLKEN2_CORE & ~CM_AUTOIDLE2_CORE))		 | (CORE3_ICLK_VALID   & (CM_ICLKEN3_CORE & ~CM_AUTOIDLE3_CORE))		 | (SGX_ICLK_VALID     & (CM_ICLKEN_SGX))		 | (USBHOST_ICLK_VALID & (CM_ICLKEN_USBHOST))		 | (DSS_ICLK_VALID     & (CM_ICLKEN_DSS & ~CM_AUTOIDLE_DSS))		 | (CAM_ICLK_VALID     & (CM_ICLKEN_CAM & ~CM_AUTOIDLE_CAM))		 | (PER_ICLK_VALID     & (CM_ICLKEN_PER & ~CM_AUTOIDLE_PER))		 | (WKUP_ICLK_VALID    & (CM_ICLKEN_WKUP & ~CM_AUTOIDLE_WKUP)));	prcm_get_power_domain_state(DOM_IVA2,				&(last_idle_state[arr_wrptr].iva_state));	arr_wrptr++;	if (arr_wrptr == LAST_IDLE_STATE_ARR_SIZE)		arr_wrptr = 0;}int omap_get_system_sleep_time(int ticks){	ticks -= (current_cx_state.wakeup_latency)/10000;	return ticks;}static void restore_control_register(u32 val){	__asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val));}/** * restore_table_entry - restore table entry that was modified for enabling MMU */static void restore_table_entry(void){	u32 *scratchpad_address;	u32 previous_value, control_reg_value;	u32 *address;	/* Get virtual address of SCRATCHPAD */	scratchpad_address = (u32 *) io_p2v(SCRATCHPAD);	/* Get address of entry that was modified */	address = (u32 *) *(scratchpad_address + TABLE_ADDRESS_OFFSET);	/* Get the previous value which needs to be restored */	previous_value = *(scratchpad_address + TABLE_VALUE_OFFSET);	/* Convert address to virtual address */	address = __va(address);	/* Restore table entry */	*address = previous_value;	/* Flush TLB */	flush_tlb_all();	control_reg_value = *(scratchpad_address + CONTROL_REG_VALUE_OFFSET);	/* Restore control register*/	/* This will enable caches and prediction */	restore_control_register(control_reg_value);}static void (*_omap_sram_idle)(u32 *addr, int save_state);void omap_sram_idle(void){	/* Variable to tell what needs to be saved and restored	 * in omap_sram_idle*/	/* save_state = 0 => Nothing to save and restored */	/* save_state = 1 => Only L1 and logic lost */	/* save_state = 2 => Only L2 lost */	/* save_state = 3 => L1, L2 and logic lost */	int save_state = 0;	if (!_omap_sram_idle)		return;	switch (target_state.mpu_state) {	case PRCM_MPU_ACTIVE:	case PRCM_MPU_INACTIVE:	case PRCM_MPU_CSWR_L2RET:		/* No need to save context */		save_state = 0;		break;	case PRCM_MPU_OSWR_L2RET:		/* L1 and Logic lost */		save_state = 1;		break;	case PRCM_MPU_CSWR_L2OFF:		/* Only L2 lost */		save_state = 2;		break;	case PRCM_MPU_OSWR_L2OFF:	case PRCM_MPU_OFF:		/* L1, L2 and logic lost */		save_state = 3;		break;	default:		/* Invalid state */		printk(KERN_ERR "Invalid mpu state in sram_idle\n");		return;	}	_omap_sram_idle(context_mem, save_state);	/* Restore table entry modified during MMU restoration */	if ((PM_PREPWSTST_MPU & 0x3) == 0x0)		restore_table_entry();}static int pre_uart_inactivity(void){	int driver8250_managed = 0;	if (are_driver8250_uarts_active(&driver8250_managed)) {		awake_time_end = jiffies + msecs_to_jiffies(UART_TIME_OUT);		return 0;	}	if (time_before(jiffies, awake_time_end)) {		return 0;	}	return 1;}static void post_uart_inactivity(void){	if (awake_time_end == 0)		awake_time_end = jiffies;}static int omap3_pm_prepare(suspend_state_t state){	int error = 0;	/* We cannot sleep in idle until we have resumed */	saved_idle = pm_idle;	pm_idle = NULL;	switch (state) {	case PM_SUSPEND_STANDBY:	case PM_SUSPEND_MEM:		break;	/*TODO: Need to fix this*/	/*case PM_SUSPEND_DISK:		return -ENOTSUPP;*/	default:		return -EINVAL;	}	return error;}/* Save and retore global configuration in NEON domain */static void omap3_save_neon_context(void){	/* Nothing to do here */	return;}static void omap3_restore_neon_context(void){	vfp_enable();}/** * omap3_save_per_context - Save global configuration in PER domain * * Only the GPIO save is done here. */static void omap3_save_per_context(void){	omap_gpio_save();	omap_uart_save_ctx();}/** * omap3_restore_per_context - Restore global configuration in PER domain * * Only the GPIO restore is done here. */static void omap3_restore_per_context(void){	omap_gpio_restore();	omap_uart_restore_ctx();}/* Configuration that is OS specific is done here */static void omap3_restore_core_settings(void){	prcm_lock_iva_dpll(current_vdd1_opp);	restore_sram_functions();	_omap_sram_idle = omap_sram_push(omap34xx_suspend,				omap34xx_suspend_sz);	save_scratchpad_contents();}static void memory_logic_res_seting(void){	if (res3_level == LOGIC_RET) {		if ((res1_level == MEMORY_RET) && (res2_level == MEMORY_RET))			target_state.core_state = PRCM_CORE_CSWR_MEMRET;		else if (res1_level == MEMORY_OFF && res2_level == MEMORY_RET)			target_state.core_state = PRCM_CORE_CSWR_MEM1OFF;		else if (res1_level == MEMORY_RET &&  res2_level == MEMORY_OFF)			target_state.core_state = PRCM_CORE_CSWR_MEM2OFF;		else			target_state.core_state = PRCM_CORE_CSWR_MEMOFF;	} else if (res3_level == LOGIC_OFF) {		if ((res1_level && res2_level) == MEMORY_RET)			target_state.core_state = PRCM_CORE_OSWR_MEMRET;		else if (res1_level == MEMORY_OFF && res2_level == MEMORY_RET)			target_state.core_state = PRCM_CORE_OSWR_MEM1OFF;		else if (res1_level == MEMORY_RET &&  res2_level == MEMORY_OFF)			target_state.core_state = PRCM_CORE_OSWR_MEM2OFF;		else			target_state.core_state = PRCM_CORE_OSWR_MEMOFF;	} else		DPRINTK("Current State not supported in Retention");}/** * omap3_pm_suspend */static int omap3_pm_suspend(void){	int ret;	disable_smartreflex(SR1_ID);	disable_smartreflex(SR2_ID);	local_irq_disable();	local_fiq_disable();	target_state.iva2_state = PRCM_RET;	target_state.gfx_state  = PRCM_RET;	target_state.dss_state  = PRCM_RET;	target_state.cam_state  = PRCM_RET;	target_state.per_state  = PRCM_RET;	target_state.neon_state = PRCM_RET;	target_state.usbhost_state = PRCM_RET;	target_state.mpu_state = PRCM_MPU_CSWR_L2RET;	if (target_state.neon_state == PRCM_OFF)		omap3_save_neon_context();	if (target_state.per_state == PRCM_OFF)		omap3_save_per_context();	target_state.core_state = PRCM_CORE_CSWR_MEMRET;	if (target_state.core_state == PRCM_CORE_CSWR_MEMRET) {		res1_level = resource_get_level(memret1);		res2_level = resource_get_level(memret2);		res3_level = resource_get_level(logret1);		memory_logic_res_seting();	}	if (target_state.core_state >=  PRCM_CORE_OSWR_MEMRET) {		prcm_save_core_context(target_state.core_state);		omap_uart_save_ctx();	}	omap_disable_system_timer();	ret = prcm_set_chip_power_mode(&target_state,					PRCM_WAKEUP_T2_KEYPAD |					PRCM_WAKEUP_TOUCHSCREEN);	if (ret != 0) {		printk(KERN_ERR "pm_suspend: Unable to set target state\n");	}	else {		printk(KERN_INFO "pm_suspend: Successfully set target state\n");		printk(KERN_INFO "Target MPU state: CSWR_L2RET, "				"Target CORE state: CSWR_MEMRET\n");	}	omap_enable_system_timer();	if (target_state.neon_state == PRCM_OFF)		omap3_restore_neon_context();	if (target_state.per_state == PRCM_OFF)		omap3_restore_per_context();	if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) {		prcm_restore_core_context(target_state.core_state);		omap_uart_restore_ctx();	}	if ((target_state.core_state > PRCM_CORE_CSWR_MEMRET) &&			(target_state.core_state != PRCM_CORE_OSWR_MEMRET)) {			restore_sram_functions();			_omap_sram_idle = omap_sram_push(omap34xx_suspend,					omap34xx_suspend_sz);		}	local_fiq_enable();	local_irq_enable();	enable_smartreflex(SR1_ID);	enable_smartreflex(SR2_ID);	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?