/** * next_valid_state - Find next valid C-state * @dev: cpuidle device * @state: Currently selected C-state * * If the current state is valid, it is returned back to the caller. * Else, this function searches for a lower c-state which is still * valid. * * A state is valid if the 'valid' field is enabled and * if it satisfies the enable_off_mode condition. */ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, struct cpuidle_state *curr) { struct cpuidle_state *next = NULL; struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); u32 mpu_deepest_state = PWRDM_POWER_RET; u32 core_deepest_state = PWRDM_POWER_RET; if (off_mode_enabled) { mpu_deepest_state = PWRDM_POWER_OFF; /* * Erratum i583: valable for ES rev < Es1.2 on 3630. * CORE OFF mode is not supported in a stable form, restrict * instead the CORE state to RET. */ if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) core_deepest_state = PWRDM_POWER_OFF; } /* Check if current state is valid */ if ((cx->valid) && (cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { return curr; } else { int idx = OMAP3_NUM_STATES - 1; /* Reach the current state starting at highest C-state */ for (; idx >= 0; idx--) { if (&dev->states[idx] == curr) { next = &dev->states[idx]; break; } } /* Should never hit this condition */ WARN_ON(next == NULL); /* * Drop to next valid state. * Start search from the next (lower) state. */ idx--; for (; idx >= 0; idx--) { cx = cpuidle_get_statedata(&dev->states[idx]); if ((cx->valid) && (cx->mpu_state >= mpu_deepest_state) && (cx->core_state >= core_deepest_state)) { next = &dev->states[idx]; break; } } /* * C1 is always valid. * So, no need to check for 'next==NULL' outside this loop. */ } return next; }
/** * omap3_idle_init - Init routine for OMAP3 idle * * Registers the OMAP3 specific cpuidle driver to the cpuidle * framework with the valid set of states. */ int __init omap3_idle_init(void) { struct cpuidle_device *dev; struct omap3_idle_statedata *cx; mpu_pd = pwrdm_lookup("mpu_pwrdm"); core_pd = pwrdm_lookup("core_pwrdm"); per_pd = pwrdm_lookup("per_pwrdm"); cam_pd = pwrdm_lookup("cam_pwrdm"); cpuidle_register_driver(&omap3_idle_driver); dev = &per_cpu(omap3_idle_dev, smp_processor_id()); /* C1 . MPU WFI + Core active */ cx = _fill_cstate(dev, 0, "MPU ON + CORE ON"); (&dev->states[0])->enter = omap3_enter_idle; dev->safe_state = &dev->states[0]; cx->valid = 1; /* C1 is always valid */ cx->mpu_state = PWRDM_POWER_ON; cx->core_state = PWRDM_POWER_ON; /* C2 . MPU WFI + Core inactive */ cx = _fill_cstate(dev, 1, "MPU ON + CORE ON"); cx->mpu_state = PWRDM_POWER_ON; cx->core_state = PWRDM_POWER_ON; /* C3 . MPU CSWR + Core inactive */ cx = _fill_cstate(dev, 2, "MPU RET + CORE ON"); cx->mpu_state = PWRDM_POWER_RET; cx->core_state = PWRDM_POWER_ON; /* C4 . MPU OFF + Core inactive */ cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON"); cx->mpu_state = PWRDM_POWER_OFF; cx->core_state = PWRDM_POWER_ON; /* C5 . MPU RET + Core RET */ cx = _fill_cstate(dev, 4, "MPU RET + CORE RET"); cx->mpu_state = PWRDM_POWER_RET; cx->core_state = PWRDM_POWER_RET; /* C6 . MPU OFF + Core RET */ cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET"); cx->mpu_state = PWRDM_POWER_OFF; cx->core_state = PWRDM_POWER_RET; /* C7 . MPU OFF + Core OFF */ cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF"); /* * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot * enable OFF mode in a stable form for previous revisions. * We disable C7 state as a result. */ if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) { cx->valid = 0; pr_warn("%s: core off state C7 disabled due to i583\n", __func__); } cx->mpu_state = PWRDM_POWER_OFF; cx->core_state = PWRDM_POWER_OFF; dev->state_count = OMAP3_NUM_STATES; if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", __func__); return -EIO; } return 0; }
/* omap3_init_power_states - Initialises the OMAP3 specific C states. * * Below is the desciption of each C state. * C1 . MPU WFI + Core active * C2 . MPU WFI + Core inactive * C3 . MPU CSWR + Core inactive * C4 . MPU OFF + Core inactive * C5 . MPU CSWR + Core CSWR * C6 . MPU OFF + Core CSWR * C7 . MPU OFF + Core OFF */ void omap_init_power_states(void) { /* C1 . MPU WFI + Core active */ omap3_power_states[OMAP3_STATE_C1].valid = cpuidle_params_table[OMAP3_STATE_C1].valid; omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1; omap3_power_states[OMAP3_STATE_C1].sleep_latency = cpuidle_params_table[OMAP3_STATE_C1].sleep_latency; omap3_power_states[OMAP3_STATE_C1].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C1].wake_latency; omap3_power_states[OMAP3_STATE_C1].threshold = cpuidle_params_table[OMAP3_STATE_C1].threshold; omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID; /* C2 . MPU WFI + Core inactive */ omap3_power_states[OMAP3_STATE_C2].valid = cpuidle_params_table[OMAP3_STATE_C2].valid; omap3_power_states[OMAP3_STATE_C2].type = OMAP3_STATE_C2; omap3_power_states[OMAP3_STATE_C2].sleep_latency = cpuidle_params_table[OMAP3_STATE_C2].sleep_latency; omap3_power_states[OMAP3_STATE_C2].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[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].core_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; /* C3 . MPU CSWR + Core inactive */ omap3_power_states[OMAP3_STATE_C3].valid = cpuidle_params_table[OMAP3_STATE_C3].valid; omap3_power_states[OMAP3_STATE_C3].type = OMAP3_STATE_C3; omap3_power_states[OMAP3_STATE_C3].sleep_latency = cpuidle_params_table[OMAP3_STATE_C3].sleep_latency; omap3_power_states[OMAP3_STATE_C3].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C3].wake_latency; omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; /* C4 . MPU OFF + Core inactive */ omap3_power_states[OMAP3_STATE_C4].valid = cpuidle_params_table[OMAP3_STATE_C4].valid; omap3_power_states[OMAP3_STATE_C4].type = OMAP3_STATE_C4; omap3_power_states[OMAP3_STATE_C4].sleep_latency = cpuidle_params_table[OMAP3_STATE_C4].sleep_latency; omap3_power_states[OMAP3_STATE_C4].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C4].wake_latency; omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; /* C5 . MPU CSWR + Core CSWR*/ omap3_power_states[OMAP3_STATE_C5].valid = cpuidle_params_table[OMAP3_STATE_C5].valid; omap3_power_states[OMAP3_STATE_C5].type = OMAP3_STATE_C5; omap3_power_states[OMAP3_STATE_C5].sleep_latency = cpuidle_params_table[OMAP3_STATE_C5].sleep_latency; omap3_power_states[OMAP3_STATE_C5].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C5].wake_latency; omap3_power_states[OMAP3_STATE_C5].threshold = cpuidle_params_table[OMAP3_STATE_C5].threshold; omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_RET; omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET; omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; /* C6 . MPU OFF + Core CSWR */ omap3_power_states[OMAP3_STATE_C6].valid = cpuidle_params_table[OMAP3_STATE_C6].valid; omap3_power_states[OMAP3_STATE_C6].type = OMAP3_STATE_C6; omap3_power_states[OMAP3_STATE_C6].sleep_latency = cpuidle_params_table[OMAP3_STATE_C6].sleep_latency; omap3_power_states[OMAP3_STATE_C6].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C6].wake_latency; omap3_power_states[OMAP3_STATE_C6].threshold = cpuidle_params_table[OMAP3_STATE_C6].threshold; omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF; omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET; omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; /* C7 . MPU OFF + Core OFF */ omap3_power_states[OMAP3_STATE_C7].valid = cpuidle_params_table[OMAP3_STATE_C7].valid; omap3_power_states[OMAP3_STATE_C7].type = OMAP3_STATE_C7; omap3_power_states[OMAP3_STATE_C7].sleep_latency = cpuidle_params_table[OMAP3_STATE_C7].sleep_latency; omap3_power_states[OMAP3_STATE_C7].wakeup_latency = cpuidle_params_table[OMAP3_STATE_C7].wake_latency; omap3_power_states[OMAP3_STATE_C7].threshold = cpuidle_params_table[OMAP3_STATE_C7].threshold; omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_OFF; omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF; omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; /* * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot * enable OFF mode in a stable form for previous revisions. * we disable C7 state as a result. */ if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) { omap3_power_states[OMAP3_STATE_C7].valid = 0; cpuidle_params_table[OMAP3_STATE_C7].valid = 0; pr_warn("%s: core off state C7 disabled due to i583\n", __func__); } }