pm_34xx.c

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

C
1,647
字号
static int omap3_pm_enter(suspend_state_t state){	int ret = 0;	switch (state) {	case PM_SUSPEND_STANDBY:	case PM_SUSPEND_MEM:		ret = omap3_pm_suspend();		break;	/*	case PM_SUSPEND_DISK:		ret = -ENOTSUPP;		break;	*/	default:		ret = -EINVAL;	}	return ret;}static int omap3_pm_valid(suspend_state_t state){	int ret = 0;	switch (state) {	case PM_SUSPEND_STANDBY:	case PM_SUSPEND_MEM:		ret = 1;		break;	default:		ret = -EINVAL;	}	return ret;}static int omap3_pm_finish(suspend_state_t state){	pm_idle = saved_idle;	return 0;}static struct pm_ops omap_pm_ops = {	.valid		= omap3_pm_valid,	.prepare	= omap3_pm_prepare,	.enter		= omap3_pm_enter,	.finish		= omap3_pm_finish,};static int omap3_idle_bm_check(void){	u32 core_dep;	u8 state;	/* Check if any modules other than debug uart and gpios are active*/	core_dep = (  (CM_FCLKEN1_CORE & CORE_FCLK_MASK)		    | (CM_FCLKEN_SGX & SGX_FCLK_MASK)		    | (CM_FCLKEN_DSS & DSS_FCLK_MASK)		    | (CM_FCLKEN_CAM & CAM_FCLK_MASK)		    | (CM_FCLKEN_PER & PER_FCLK_MASK)		    | (CM_FCLKEN_USBHOST & USBHOST_FCLK_MASK)		    | (CM_FCLKEN3_CORE & CORE3_FCLK_MASK));	/* To allow core retention during LPR scenario */	if (!lpr_enabled)		core_dep |= (CM_FCLKEN_DSS & DSS_FCLK_MASK);	DPRINTK("FCLKS: %x,%x,%x,%x,%x,%x,%x\n",		(CM_FCLKEN1_CORE & CORE_FCLK_MASK),		(CM_FCLKEN3_CORE & CORE3_FCLK_MASK),		(CM_FCLKEN_SGX & SGX_FCLK_MASK),		(CM_FCLKEN_DSS & DSS_FCLK_MASK),		(CM_FCLKEN_CAM & CAM_FCLK_MASK),		(CM_FCLKEN_PER & PER_FCLK_MASK),		(CM_FCLKEN_USBHOST & USBHOST_FCLK_MASK));	/* Check if any modules have ICLK bit enabled and interface clock */	/* autoidle disabled						 */	core_dep |= (CORE1_ICLK_VALID & (CM_ICLKEN1_CORE & ~CM_AUTOIDLE1_CORE));	/* Check for secure modules which have only ICLK */	/* Do not check for rng module.It has been ensured that	 * if rng is active cpu idle will never be entered	 */	core_dep |= (CORE2_ICLK_VALID & CM_ICLKEN2_CORE & ~4);	/* Enabling SGX ICLK will prevent CORE ret*/	core_dep |= SGX_ICLK_VALID & (CM_ICLKEN_SGX);	core_dep |= (CORE3_ICLK_VALID & (CM_ICLKEN3_CORE & ~CM_AUTOIDLE3_CORE));	core_dep |= (USBHOST_ICLK_VALID & (CM_ICLKEN_USBHOST &			~CM_AUTOIDLE_USBHOST));	core_dep |= (DSS_ICLK_VALID & (CM_ICLKEN_DSS & ~CM_AUTOIDLE_DSS));	core_dep |= (CAM_ICLK_VALID & (CM_ICLKEN_CAM & ~CM_AUTOIDLE_CAM));	core_dep |= (PER_ICLK_VALID & (CM_ICLKEN_PER & ~CM_AUTOIDLE_PER));	core_dep |= (WKUP_ICLK_VALID & (CM_ICLKEN_WKUP & ~CM_AUTOIDLE_WKUP));	DPRINTK("ICLKS: %x,%x,%x,%x%x,%x,%x\n",		(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 &			~CM_AUTOIDLE_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, &state);	DPRINTK("IVA:%d\n", state);	if (state == PRCM_ON)		core_dep |= 1;	if (core_dep)		return 1;	else		return 0;}/* Correct target state based on inactivity timer expiry, etc */static void correct_target_state(void){	switch (target_state.mpu_state) {	case PRCM_MPU_ACTIVE:	case PRCM_MPU_INACTIVE:		target_state.neon_state = PRCM_ON;		break;	case PRCM_MPU_CSWR_L2RET:	case PRCM_MPU_OSWR_L2RET:	case PRCM_MPU_CSWR_L2OFF:	case PRCM_MPU_OSWR_L2OFF:		target_state.neon_state = PRCM_RET;		break;	case PRCM_MPU_OFF:		target_state.neon_state = PRCM_OFF;		if (!enable_off) {			target_state.mpu_state = PRCM_MPU_CSWR_L2RET;			target_state.neon_state = PRCM_RET;		}		break;	}	if (target_state.core_state > PRCM_CORE_INACTIVE) {		target_state.per_state = PRCM_RET;	} else		target_state.per_state = PRCM_ON;		res1_level = resource_get_level(memret1);		res2_level = resource_get_level(memret2);		res3_level = resource_get_level(logret1);		if (target_state.core_state == PRCM_CORE_CSWR_MEMRET)			memory_logic_res_seting();}static int omap3_enter_idle(struct cpuidle_device *dev,			struct cpuidle_state *state){	struct omap3_processor_cx *cx = cpuidle_get_statedata(state);	u8 cur_per_state, cur_neon_state, pre_neon_state, pre_per_state;	unsigned long timer_32k_sleep_ticks;	u32 fclken_core, iclken_core, fclken_per, iclken_per;	u32 reprogram_ns;	int reprogram_us;	unsigned long long reprogram_cycles;	int wakeup_latency;	/* Reset previous power state registers for mpu and core*/	PM_PREPWSTST_MPU = 0xFF;	PM_PREPWSTST_CORE = 0xFF;	PM_PREPWSTST_NEON = 0xFF;	PM_PREPWSTST_PER = 0xFF;	current_cx_state = *cx;	target_state.mpu_state = cx->mpu_state;	target_state.core_state = cx->core_state;	if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) {		store_prepwst();		return 0;	}	if (cx->type == OMAP3_STATE_C0) {		omap_sram_idle();		store_prepwst();		return 0;	}	correct_target_state();	wakeup_latency = cx->wakeup_latency;	if (target_state.core_state != cx->core_state) {		/* Currently, this can happen only for core_off */		/* Adjust wakeup latency to that of core_cswr state */		/* Hard coded now and needs to be made more generic */		/* omap3_power_states[4] is CSWR for core */		wakeup_latency = omap3_power_states[4].wakeup_latency;	}	timer_32k_sleep_ticks = omap_32k_sync_timer_read();	/* Reprogram the tick timer */	reprogram_us = (s32) ktime_to_ns(tick_nohz_get_sleep_length())/1000;	if (reprogram_us > wakeup_latency) {		reprogram_us = reprogram_us - wakeup_latency;		reprogram_ns = reprogram_us * 1000;		reprogram_cycles = (unsigned long long) reprogram_ns *						div_sc(32768, NSEC_PER_SEC, 32);		reprogram_cycles >>= 32;		omap_32k_timer_start((unsigned long) reprogram_cycles);	}	/* Check for pending interrupts. If there is an interrupt, return */	if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) {		store_prepwst();		return 0;	}	prcm_get_power_domain_state(DOM_PER, &cur_per_state);	prcm_get_power_domain_state(DOM_NEON, &cur_neon_state);	fclken_core = CM_FCLKEN1_CORE;	iclken_core = CM_ICLKEN1_CORE;	fclken_per = CM_FCLKEN_PER;	iclken_per = CM_ICLKEN_PER;	/* If target state if core_off, save registers	 * before changing anything	 */	if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) {		prcm_save_registers();		omap_uart_save_ctx();	}	/* Check for pending interrupts. If there is an interrupt, return */	if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2) {		store_prepwst();		return 0;	}	/* Program MPU and NEON to target state */	if (target_state.mpu_state > PRCM_MPU_ACTIVE) {		if ((cur_neon_state == PRCM_ON) &&			(target_state.neon_state != PRCM_ON)) {			if (target_state.neon_state == PRCM_OFF)				omap3_save_neon_context();;			prcm_force_power_domain_state(DOM_NEON,				target_state.neon_state);		}		prcm_set_mpu_domain_state(target_state.mpu_state);	}	/* Check for pending interrupts. If there is an interrupt, return */	if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2)		goto restore;	/* Program CORE and PER to target state */	if ((target_state.core_state > PRCM_CORE_ACTIVE) &&			(pre_uart_inactivity())) {		if ((cur_per_state == PRCM_ON) &&				(target_state.per_state != PRCM_ON)) {			if (target_state.per_state == PRCM_OFF)				omap3_save_per_context();;			CM_FCLKEN_PER = 0;			CM_ICLKEN_PER = 0;			prcm_force_power_domain_state(DOM_PER,							target_state.per_state);		}		disable_smartreflex(SR1_ID);		disable_smartreflex(SR2_ID);		/* WORKAROUND FOR SILICON ERRATA 1.64*/		if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {			if ((CM_CLKOUT_CTRL & (0x1 << 7)) == 0x80)				CM_CLKOUT_CTRL &= ~(0x1 << 7);		}		prcm_set_core_domain_state(target_state.core_state);		/* Enable Autoidle for GPT1 explicitly - Errata 1.4 */		CM_AUTOIDLE_WKUP |= 0x1;		CM_FCLKEN1_CORE &= ~0x6000;		/* Disable HSUSB OTG ICLK explicitly*/		CM_ICLKEN1_CORE &= ~0x10;		/* Enabling IO_PAD capabilities */		PM_WKEN_WKUP |= 0x100;	}	/* Check for pending interrupts. If there is an interrupt, return */	if (INTCPS_PENDING_IRQ0 | INTCPS_PENDING_IRQ1 | INTCPS_PENDING_IRQ2)		goto restore;	omap_sram_idle();restore:	/* Disabling IO_PAD capabilities */	PM_WKEN_WKUP &= ~(0x100);	CM_FCLKEN1_CORE = fclken_core;	CM_ICLKEN1_CORE = iclken_core;	post_uart_inactivity();	if (target_state.mpu_state > PRCM_MPU_ACTIVE) {		prcm_set_mpu_domain_state(PRCM_MPU_ACTIVE);		if ((cur_neon_state == PRCM_ON) &&			(target_state.mpu_state > PRCM_MPU_INACTIVE)) {			prcm_force_power_domain_state(DOM_NEON, cur_neon_state);			prcm_get_pre_power_domain_state(DOM_NEON,					&pre_neon_state);			if (pre_neon_state == PRCM_OFF)				omap3_restore_neon_context();		}	}	if (target_state.core_state > PRCM_CORE_ACTIVE) {		prcm_set_core_domain_state(PRCM_CORE_ACTIVE);		enable_smartreflex(SR1_ID);		enable_smartreflex(SR2_ID);		if (cur_per_state == PRCM_ON) {			prcm_force_power_domain_state(DOM_PER, cur_per_state);			prcm_get_pre_power_domain_state(DOM_PER,					&pre_per_state);			CM_FCLKEN_PER = fclken_per;			CM_ICLKEN_PER = iclken_per;			if (pre_per_state == PRCM_OFF) {				omap3_restore_per_context();			}		}		if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET) {			prcm_restore_registers();			prcm_restore_core_context(target_state.core_state);			omap3_restore_core_settings();		}		/* Errata 1.4		* if the timer device gets idled which is when we		* are cutting the timer ICLK which is when we try		* to put Core to RET.		* Wait Period = 2 timer interface clock cycles +		* 1 timer functional clock cycle		* Interface clock = L4 clock. For the computation L4		* clock is assumed at 50MHz (worst case).		* Functional clock = 32KHz		* Wait Period = 2*10^-6/50 + 1/32768 = 0.000030557 = 30.557uSec		* Roundingoff the delay value to a safer 50uSec		*/		omap_udelay(GPTIMER_WAIT_DELAY);		CM_AUTOIDLE_WKUP &= ~(0x1);	}	DPRINTK("MPU state:%x,CORE state:%x\n", PM_PREPWSTST_MPU,							PM_PREPWSTST_CORE);	store_prepwst();	timer_32k_sleep_ticks = omap_32k_sync_timer_read() -							timer_32k_sleep_ticks;	if (target_state.core_state >= PRCM_CORE_OSWR_MEMRET)			omap_uart_restore_ctx();	if ((target_state.core_state > PRCM_CORE_CSWR_MEMRET) &&			(target_state.core_state != PRCM_CORE_OSWR_MEMRET)) {		restore_sram_functions(); /*restore sram data */			_omap_sram_idle = omap_sram_push(omap34xx_suspend,				omap34xx_suspend_sz);	}	return omap_32k_ticks_to_usecs(timer_32k_sleep_ticks);}static int omap3_idle_init(struct cpuidle_device *dev){	int i, count = 0;	struct omap3_processor_cx *cx;	struct cpuidle_state *state;	for (i = 0; i < OMAP3_MAX_STATES; i++) {		cx = &omap3_power_states[i];		state = &dev->states[count];		if (!cx->valid)			continue;		cpuidle_set_statedata(state, cx);		state->exit_latency = cx->sleep_latency + cx->wakeup_latency;		state->target_residency = cx->threshold;		state->flags = cx->flags;		state->enter = omap3_enter_idle;		count++;	}	if (!count)		return -EINVAL;	dev->state_count = count;	return 0;}void omap_init_power_states(void){	omap3_power_states[0].valid		= 1;	omap3_power_states[0].type		= OMAP3_STATE_C0;	omap3_power_states[0].sleep_latency	= 0;	omap3_power_states[0].wakeup_latency	= 0;	omap3_power_states[0].threshold 	= 0;	omap3_power_states[0].mpu_state		= PRCM_MPU_ACTIVE;	omap3_power_states[0].core_state	= PRCM_CORE_ACTIVE;	omap3_power_states[0].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_SHALLOW;	omap3_power_states[1].valid		= 1;	omap3_power_states[1].type		= OMAP3_STATE_C1;	omap3_power_states[1].sleep_latency	= 10;	omap3_power_states[1].wakeup_latency	= 10;	omap3_power_states[1].threshold		= 30;	omap3_power_states[1].mpu_state		= PRCM_MPU_ACTIVE;	omap3_power_states[1].core_state	= PRCM_CORE_ACTIVE;	omap3_power_states[1].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_SHALLOW;	omap3_power_states[2].valid		= 1;	omap3_power_states[2].type		= OMAP3_STATE_C2;	omap3_power_states[2].sleep_latency	= 50;	omap3_power_states[2].wakeup_latency	= 50;	omap3_power_states[2].threshold		= 300;	omap3_power_states[2].mpu_state		= PRCM_MPU_CSWR_L2RET;	omap3_power_states[2].core_state	= PRCM_CORE_ACTIVE;	omap3_power_states[2].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_BALANCED;	omap3_power_states[3].valid		= 1;	omap3_power_states[3].type		= OMAP3_STATE_C3;	omap3_power_states[3].sleep_latency	= 1500;	omap3_power_states[3].wakeup_latency	= 1800;	omap3_power_states[3].threshold		= 4000;	omap3_power_states[3].mpu_state		= PRCM_MPU_CSWR_L2RET;	omap3_power_states[3].core_state	= PRCM_CORE_ACTIVE;	omap3_power_states[3].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_BALANCED;	omap3_power_states[4].valid		= 1;	omap3_power_states[4].type		= OMAP3_STATE_C4;	omap3_power_states[4].sleep_latency	= 2500;	omap3_power_states[4].wakeup_latency	= 7500;	omap3_power_states[4].threshold		= 12000;	omap3_power_states[4].mpu_state		= PRCM_MPU_CSWR_L2RET;	omap3_power_states[4].core_state	= PRCM_CORE_CSWR_MEMRET;	omap3_power_states[4].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_BALANCED |							CPUIDLE_FLAG_CHECK_BM;	omap3_power_states[5].valid		= 1;	omap3_power_states[5].type		= OMAP3_STATE_C5;	omap3_power_states[5].sleep_latency	= 3000;	omap3_power_states[5].wakeup_latency	= 8500;	omap3_power_states[5].threshold		= 15000;	omap3_power_states[5].mpu_state		= PRCM_MPU_CSWR_L2RET;	omap3_power_states[5].core_state	= PRCM_CORE_CSWR_MEMRET;	omap3_power_states[5].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_BALANCED |							CPUIDLE_FLAG_CHECK_BM;	omap3_power_states[6].valid		= 0;	omap3_power_states[6].type		= OMAP3_STATE_C6;	omap3_power_states[6].sleep_latency	= 10000;	omap3_power_states[6].wakeup_latency	= 30000;	omap3_power_states[6].threshold		= 300000;	omap3_power_states[6].mpu_state		= PRCM_MPU_OFF;	omap3_power_states[6].core_state	= PRCM_CORE_OFF;	omap3_power_states[6].flags		= CPUIDLE_FLAG_TIME_VALID |							CPUIDLE_FLAG_DEEP |							CPUIDLE_FLAG_CHECK_BM;}struct cpuidle_driver omap3_idle_driver = {	.name		= "omap3_idle",	.init		= omap3_idle_init,	.redetect	= omap3_idle_init,	.bm_check	= omap3_idle_bm_check,	.owner		= THIS_MODULE,};/* Sysfs interface to select the system sleep state */static ssize_t omap_pm_sleep_idle_state_show(struct kset *subsys, char *buf){	return sprintf(buf, "%hu\n", cpuidle_deepest_st);}static ssize_t omap_pm_sleep_idle_state_store(struct kset *subsys,				const char *buf, size_t n){	unsigned short value;	if (sscanf(buf, "%hu", &value) != 1 ||		(value > (MAX_SUPPORTED_STATES - 1))) {		printk(KERN_ERR "idle_sleep_store: Invalid value\n");		return -EINVAL;	}	cpuidle_deepest_st = value;	return n;}static struct subsys_attribute sleep_idle_state = {	.attr = {		.name = __stringify(cpuidle_deepest_state),		.mode = 0644,		},	.show  = omap_pm_sleep_idle_state_show,	.store = omap_pm_sleep_idle_state_store,};static ssize_t omap_pm_off_show(struct kset *subsys, char *buf){	return sprintf(buf, "%hu\n", enable_off);}static ssize_t omap_pm_off_store(struct kset *subsys,				const char *buf, size_t n){	unsigned short value;	if (sscanf(buf, "%hu", &value) != 1 ||		((value != 0) && (value != 1))) {		printk(KERN_ERR "off_enable: Invalid value\n");		return -EINVAL;	}	enable_off = value;	return n;}static struct subsys_attribute off_enable = {	.attr = {		.name = __stringify(enable_mpucoreoff),		.mode = 0644,		},	.show  = omap_pm_off_show,	.store = omap_pm_off_store,};static ssize_t omap_pm_domain_show(struct kset *subsys, char *buf){	prcm_printreg(debug_domain);	return 0;}static ssize_t omap_pm_domain_store(struct kset *subsys,				const char *buf, size_t n){	unsigned short value;	if (sscanf(buf, "%hu", &value) != 1 ||		(value > PRCM_NUM_DOMAINS)		 || (value == DOM_CORE2)		 || (value == 12)) {		printk(KERN_ERR "dump_domain: Invalid value\n");		return -EINVAL;	}	debug_domain = value;	return n;}

⌨️ 快捷键说明

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