OMAP3: PM: move device-specific special cases from PM core into CPUidle
In an effort to simplify the core idle path, move any device-specific special case handling from the core PM idle path into the CPUidle pre-idle checking path. This keeps the core, interrupts-disabled idle path streamlined and independent of any device-specific handling, and also allows CPUidle to do the checking only for certain C-states as needed. This patch has the device checks in place for all states with the CHECK_BM flag, namely all states >= C2. This patch was inspired by a similar patch written by Tero Kristo as part of a larger series to add INACTIVE state support. NOTE: This is a baby-step towards decoupling device idle (or system idle) from CPU idle. Eventually, CPUidle should only manage the CPU, and device/system idle should be managed elsewhere. Cc: Tero Kristo <tero.kristo@nokia.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
This commit is contained in:
		
					parent
					
						
							
								6cdee91257
							
						
					
				
			
			
				commit
				
					
						e7410cf783
					
				
			
		
					 2 changed files with 56 additions and 16 deletions
				
			
		|  | @ -60,7 +60,8 @@ struct omap3_processor_cx { | ||||||
| 
 | 
 | ||||||
| struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; | struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; | ||||||
| struct omap3_processor_cx current_cx_state; | struct omap3_processor_cx current_cx_state; | ||||||
| struct powerdomain *mpu_pd, *core_pd; | struct powerdomain *mpu_pd, *core_pd, *per_pd; | ||||||
|  | struct powerdomain *cam_pd; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * The latencies/thresholds for various C states have |  * The latencies/thresholds for various C states have | ||||||
|  | @ -233,14 +234,62 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | ||||||
| 			       struct cpuidle_state *state) | 			       struct cpuidle_state *state) | ||||||
| { | { | ||||||
| 	struct cpuidle_state *new_state = next_valid_state(dev, state); | 	struct cpuidle_state *new_state = next_valid_state(dev, state); | ||||||
|  | 	u32 core_next_state, per_next_state = 0, per_saved_state = 0; | ||||||
|  | 	u32 cam_state; | ||||||
|  | 	struct omap3_processor_cx *cx; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { | 	if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { | ||||||
| 		BUG_ON(!dev->safe_state); | 		BUG_ON(!dev->safe_state); | ||||||
| 		new_state = dev->safe_state; | 		new_state = dev->safe_state; | ||||||
|  | 		goto select_state; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	cx = cpuidle_get_statedata(state); | ||||||
|  | 	core_next_state = cx->core_state; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * FIXME: we currently manage device-specific idle states | ||||||
|  | 	 *        for PER and CORE in combination with CPU-specific | ||||||
|  | 	 *        idle states.  This is wrong, and device-specific | ||||||
|  | 	 *        idle managment needs to be separated out into  | ||||||
|  | 	 *        its own code. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Prevent idle completely if CAM is active. | ||||||
|  | 	 * CAM does not have wakeup capability in OMAP3. | ||||||
|  | 	 */ | ||||||
|  | 	cam_state = pwrdm_read_pwrst(cam_pd); | ||||||
|  | 	if (cam_state == PWRDM_POWER_ON) { | ||||||
|  | 		new_state = dev->safe_state; | ||||||
|  | 		goto select_state; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Prevent PER off if CORE is not in retention or off as this | ||||||
|  | 	 * would disable PER wakeups completely. | ||||||
|  | 	 */ | ||||||
|  | 	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | ||||||
|  | 	if ((per_next_state == PWRDM_POWER_OFF) && | ||||||
|  | 	    (core_next_state > PWRDM_POWER_RET)) { | ||||||
|  | 		per_next_state = PWRDM_POWER_RET; | ||||||
|  | 		pwrdm_set_next_pwrst(per_pd, per_next_state); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Are we changing PER target state? */ | ||||||
|  | 	if (per_next_state != per_saved_state) | ||||||
|  | 		pwrdm_set_next_pwrst(per_pd, per_next_state); | ||||||
|  | 
 | ||||||
|  | select_state: | ||||||
| 	dev->last_state = new_state; | 	dev->last_state = new_state; | ||||||
| 	return omap3_enter_idle(dev, new_state); | 	ret = omap3_enter_idle(dev, new_state); | ||||||
|  | 
 | ||||||
|  | 	/* Restore original PER state if it was modified */ | ||||||
|  | 	if (per_next_state != per_saved_state) | ||||||
|  | 		pwrdm_set_next_pwrst(per_pd, per_saved_state); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); | DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); | ||||||
|  | @ -328,7 +377,8 @@ void omap_init_power_states(void) | ||||||
| 			cpuidle_params_table[OMAP3_STATE_C2].threshold; | 			cpuidle_params_table[OMAP3_STATE_C2].threshold; | ||||||
| 	omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; | 	omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; | ||||||
| 	omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; | 	omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; | ||||||
| 	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; | 	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID | | ||||||
|  | 				CPUIDLE_FLAG_CHECK_BM; | ||||||
| 
 | 
 | ||||||
| 	/* C3 . MPU CSWR + Core inactive */ | 	/* C3 . MPU CSWR + Core inactive */ | ||||||
| 	omap3_power_states[OMAP3_STATE_C3].valid = | 	omap3_power_states[OMAP3_STATE_C3].valid = | ||||||
|  | @ -426,6 +476,8 @@ int __init omap3_idle_init(void) | ||||||
| 
 | 
 | ||||||
| 	mpu_pd = pwrdm_lookup("mpu_pwrdm"); | 	mpu_pd = pwrdm_lookup("mpu_pwrdm"); | ||||||
| 	core_pd = pwrdm_lookup("core_pwrdm"); | 	core_pd = pwrdm_lookup("core_pwrdm"); | ||||||
|  | 	per_pd = pwrdm_lookup("per_pwrdm"); | ||||||
|  | 	cam_pd = pwrdm_lookup("cam_pwrdm"); | ||||||
| 
 | 
 | ||||||
| 	omap_init_power_states(); | 	omap_init_power_states(); | ||||||
| 	cpuidle_register_driver(&omap3_idle_driver); | 	cpuidle_register_driver(&omap3_idle_driver); | ||||||
|  |  | ||||||
|  | @ -346,7 +346,6 @@ void omap_sram_idle(void) | ||||||
| 	int core_next_state = PWRDM_POWER_ON; | 	int core_next_state = PWRDM_POWER_ON; | ||||||
| 	int core_prev_state, per_prev_state; | 	int core_prev_state, per_prev_state; | ||||||
| 	u32 sdrc_pwr = 0; | 	u32 sdrc_pwr = 0; | ||||||
| 	int per_state_modified = 0; |  | ||||||
| 
 | 
 | ||||||
| 	if (!_omap_sram_idle) | 	if (!_omap_sram_idle) | ||||||
| 		return; | 		return; | ||||||
|  | @ -391,18 +390,9 @@ void omap_sram_idle(void) | ||||||
| 	if (per_next_state < PWRDM_POWER_ON) { | 	if (per_next_state < PWRDM_POWER_ON) { | ||||||
| 		omap_uart_prepare_idle(2); | 		omap_uart_prepare_idle(2); | ||||||
| 		omap2_gpio_prepare_for_idle(per_next_state); | 		omap2_gpio_prepare_for_idle(per_next_state); | ||||||
| 		if (per_next_state == PWRDM_POWER_OFF) { | 		if (per_next_state == PWRDM_POWER_OFF) | ||||||
| 			if (core_next_state == PWRDM_POWER_ON) { |  | ||||||
| 				per_next_state = PWRDM_POWER_RET; |  | ||||||
| 				pwrdm_set_next_pwrst(per_pwrdm, per_next_state); |  | ||||||
| 				per_state_modified = 1; |  | ||||||
| 			} else |  | ||||||
| 				omap3_per_save_context(); | 				omap3_per_save_context(); | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) |  | ||||||
| 		omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]); |  | ||||||
| 
 | 
 | ||||||
| 	/* CORE */ | 	/* CORE */ | ||||||
| 	if (core_next_state < PWRDM_POWER_ON) { | 	if (core_next_state < PWRDM_POWER_ON) { | ||||||
|  | @ -470,8 +460,6 @@ void omap_sram_idle(void) | ||||||
| 		if (per_prev_state == PWRDM_POWER_OFF) | 		if (per_prev_state == PWRDM_POWER_OFF) | ||||||
| 			omap3_per_restore_context(); | 			omap3_per_restore_context(); | ||||||
| 		omap_uart_resume_idle(2); | 		omap_uart_resume_idle(2); | ||||||
| 		if (per_state_modified) |  | ||||||
| 			pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Disable IO-PAD and IO-CHAIN wakeup */ | 	/* Disable IO-PAD and IO-CHAIN wakeup */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Kevin Hilman
				Kevin Hilman