/** * omap3_enter_idle_bm - Checks for any bus activity * @dev: cpuidle device * @state: The target state to be programmed * * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This * function checks for any pending activity and then programs the * device to the specified or a safer state. */ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *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()) { BUG_ON(!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; /* 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; 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; }
/* * This sets pwrdm state (other than mpu & core. Currently only ON & * RET are supported. */ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) { u32 cur_state; int sleep_switch = 0; int ret = 0; if (pwrdm == NULL || IS_ERR(pwrdm)) return -EINVAL; while (!(pwrdm->pwrsts & (1 << state))) { if (state == PWRDM_POWER_OFF) return ret; state--; } cur_state = pwrdm_read_next_pwrst(pwrdm); if (cur_state == state) return ret; if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { if ((pwrdm_read_pwrst(pwrdm) > state) && (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { sleep_switch = LOWPOWERSTATE_SWITCH; } else { clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); sleep_switch = FORCEWAKEUP_SWITCH; } } ret = pwrdm_set_next_pwrst(pwrdm, state); if (ret) { printk(KERN_ERR "Unable to set state of powerdomain: %s\n", pwrdm->name); goto err; } switch (sleep_switch) { case FORCEWAKEUP_SWITCH: if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO) clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); else clkdm_sleep(pwrdm->pwrdm_clkdms[0]); break; case LOWPOWERSTATE_SWITCH: pwrdm_set_lowpwrstchange(pwrdm); break; default: return ret; } pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); err: return ret; }
/* * This sets pwrdm state (other than mpu & core. Currently only ON & * RET are supported. */ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) { u32 cur_state; int sleep_switch = -1; int ret = 0; int hwsup = 0; if (pwrdm == NULL || IS_ERR(pwrdm)) return -EINVAL; while (!(pwrdm->pwrsts & (1 << state))) { if (state == PWRDM_POWER_OFF) return ret; state--; } cur_state = pwrdm_read_next_pwrst(pwrdm); if (cur_state == state) return ret; if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { if ((pwrdm_read_pwrst(pwrdm) > state) && (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { sleep_switch = LOWPOWERSTATE_SWITCH; } else { hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); sleep_switch = FORCEWAKEUP_SWITCH; } } ret = pwrdm_set_next_pwrst(pwrdm, state); if (ret) { pr_err("%s: unable to set state of powerdomain: %s\n", __func__, pwrdm->name); goto err; } switch (sleep_switch) { case FORCEWAKEUP_SWITCH: if (hwsup) clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); else clkdm_sleep(pwrdm->pwrdm_clkdms[0]); break; case LOWPOWERSTATE_SWITCH: pwrdm_set_lowpwrstchange(pwrdm); break; default: return ret; } pwrdm_state_switch(pwrdm); err: return ret; }
/** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device * @state: The target state to be programmed * * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; u32 saved_mpu_state; current_cx_state = *cx; /* Used to keep track of the total time in idle */ getnstimeofday(&ts_preidle); local_irq_disable(); local_fiq_disable(); if (!enable_off_mode) { if (mpu_state < PWRDM_POWER_RET) mpu_state = PWRDM_POWER_RET; if (core_state < PWRDM_POWER_RET) core_state = PWRDM_POWER_RET; } if (omap_irq_pending() || need_resched()) goto return_sleep_time; saved_mpu_state = pwrdm_read_next_pwrst(mpu_pd); pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state); if (cx->type == OMAP3_STATE_C1) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); } /* Execute ARM wfi */ omap_sram_idle(); if (cx->type == OMAP3_STATE_C1) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); } pwrdm_set_next_pwrst(mpu_pd, saved_mpu_state); return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); local_irq_enable(); local_fiq_enable(); return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
/* * This sets pwrdm state (other than mpu & core. Currently only ON & * RET are supported. */ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) { u8 curr_pwrst, next_pwrst; int sleep_switch = -1, ret = 0, hwsup = 0; if (!pwrdm || IS_ERR(pwrdm)) return -EINVAL; while (!(pwrdm->pwrsts & (1 << pwrst))) { if (pwrst == PWRDM_POWER_OFF) return ret; pwrst--; } next_pwrst = pwrdm_read_next_pwrst(pwrdm); if (next_pwrst == pwrst) return ret; curr_pwrst = pwrdm_read_pwrst(pwrdm); if (curr_pwrst < PWRDM_POWER_ON) { if ((curr_pwrst > pwrst) && (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { sleep_switch = LOWPOWERSTATE_SWITCH; } else { hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); sleep_switch = FORCEWAKEUP_SWITCH; } } ret = pwrdm_set_next_pwrst(pwrdm, pwrst); if (ret) pr_err("%s: unable to set power state of powerdomain: %s\n", __func__, pwrdm->name); switch (sleep_switch) { case FORCEWAKEUP_SWITCH: if (hwsup) clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); else clkdm_sleep(pwrdm->pwrdm_clkdms[0]); break; case LOWPOWERSTATE_SWITCH: pwrdm_set_lowpwrstchange(pwrdm); pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); break; } return ret; }
/* * This sets pwrdm state (other than mpu & core. Currently only ON & * RET are supported. Function is assuming that clkdm doesn't have * hw_sup mode enabled. */ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state) { u32 cur_state; int sleep_switch = 0; int ret = 0; if (pwrdm == NULL || IS_ERR(pwrdm)) return -EINVAL; while (!(pwrdm->pwrsts & (1 << state))) { if (state == PWRDM_POWER_OFF) return ret; state--; } cur_state = pwrdm_read_next_pwrst(pwrdm); if (cur_state == state) return ret; if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); sleep_switch = 1; pwrdm_wait_transition(pwrdm); } ret = pwrdm_set_next_pwrst(pwrdm, state); if (ret) { printk(KERN_ERR "Unable to set state of powerdomain: %s\n", pwrdm->name); goto err; } if (sleep_switch) { omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); } err: return ret; }
/* * FIXME: This function should be called before entering off-mode after * OMAP3 secure services have been accessed. Currently it is only called * once during boot sequence, but this works as we are not using secure * services. */ static void omap3_save_secure_ram_context(void) { u32 ret; int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); if (omap_type() != OMAP2_DEVICE_TYPE_GP) { /* * MPU next state must be set to POWER_ON temporarily, * otherwise the WFI executed inside the ROM code * will hang the system. */ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); ret = _omap_save_secure_sram((u32 *) __pa(omap3_secure_ram_storage)); pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state); /* Following is for error tracking, it should not happen */ if (ret) { printk(KERN_ERR "save_secure_sram() returns %08x\n", ret); while (1) ; } } }
/* * OMAP4 MPUSS Low Power Entry Function * * The purpose of this function is to manage low power programming * of OMAP4 MPUSS subsystem * Paramenters: * cpu : CPU ID * power_state: Targetted Low power state. * * MPUSS Low power states * The basic rule is that the MPUSS power domain must be at the higher or * equal power state (state that consume more power) than the higher of the * two CPUs. For example, it is illegal for system power to be OFF, while * the power of one or both of the CPU is DORMANT. When an illegal state is * entered, then the hardware behavior is unpredictable. * * MPUSS state for the context save * save_state = * 0 - Nothing lost and no need to save: MPUSS INACTIVE * 1 - CPUx L1 and logic lost: MPUSS CSWR * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF */ void omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { unsigned int save_state, wakeup_cpu; if (cpu > NR_CPUS) return; /* * Low power state not supported on ES1.0 silicon */ if (omap_rev() == OMAP4430_REV_ES1_0) { wmb(); do_wfi(); return; } switch (power_state) { case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: save_state = 0; break; case PWRDM_POWER_OFF: save_state = 1; setup_wakeup_routine(cpu); save_local_timers(cpu); break; case PWRDM_POWER_RET: /* * CPUx CSWR is invalid hardware state. Additionally * CPUx OSWR doesn't give any gain vs CPUxOFF and * hence not supported */ default: /* Invalid state */ pr_debug("Invalid CPU low power state\n"); return; } /* * MPUSS book keeping should be executed by master * CPU only which is the last CPU to go down */ if (cpu) goto cpu_prepare; /* * Check MPUSS next state and save GIC if needed * GIC lost during MPU OFF and OSWR */ pwrdm_clear_all_prev_pwrst(mpuss_pd); if (omap4_device_off_read_next_state() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) { /* FIXME: Check if this can be optimised */ save_secure_all(); save_ivahd_tesla_regs(); save_l3instr_regs(); save_state = 3; goto cpu_prepare; } switch (pwrdm_read_next_pwrst(mpuss_pd)) { case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: /* No need to save MPUSS context */ break; case PWRDM_POWER_RET: /* MPUSS OSWR, logic lost */ if (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF) { if (omap_type() != OMAP2_DEVICE_TYPE_GP) { save_gic_wakeupgen_secure(); save_l3instr_regs(); } else { save_gic(); omap4_wakeupgen_save(); } save_state = 2; } break; case PWRDM_POWER_OFF: /* MPUSS OFF */ if (omap_type() != OMAP2_DEVICE_TYPE_GP) { save_secure_ram(); save_gic_wakeupgen_secure(); save_ivahd_tesla_regs(); save_l3instr_regs(); } else { save_gic(); omap4_wakeupgen_save(); } save_state = 3; break; default: /* Fall through */ ; } /* * Program the CPU targeted state */ cpu_prepare: clear_cpu_prev_pwrst(cpu); if (cpu) pwrdm_set_next_pwrst(cpu1_pwrdm, power_state); else pwrdm_set_next_pwrst(cpu0_pwrdm, power_state); scu_pwrst_prepare(cpu, power_state); /* * Call low level routine to enter to * targeted power state */ __omap4_cpu_suspend(cpu, save_state); wakeup_cpu = hard_smp_processor_id(); /* * Restore the CPUx and mpuss power state to ON otherwise * CPUx power domain can transitions to programmed low power * state while doing WFI outside the low powe code. On HS devices, * CPUx can do WFI outside idle thread which can result in * power domain domain transition if the previous state was * programmed to OFF/RET. */ if (wakeup_cpu) { pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON); } else { pwrdm_set_next_pwrst(cpu0_pwrdm, PWRDM_POWER_ON); pwrdm_set_next_pwrst(mpuss_pd, PWRDM_POWER_ON); } /* * Check the CPUx previous power state */ if (read_cpu_prev_pwrst(wakeup_cpu) == PWRDM_POWER_OFF) { cpu_init(); restore_mmu_table_entry(); restore_local_timers(wakeup_cpu); } /* * Check MPUSS previous power state and enable * GIC if needed. */ switch (pwrdm_read_prev_pwrst(mpuss_pd)) { case PWRDM_POWER_ON: /* No need to restore */ break; case PWRDM_POWER_RET: /* FIXME: * if (pwrdm_read_prev_logic_pwrst(mpuss_pd) == PWRDM_POWER_OFF) */ if (omap_readl(0x4a306324) == PWRDM_POWER_OFF) break; case PWRDM_POWER_OFF: /* * Enable GIC distributor */ if (!wakeup_cpu) { if ((omap_type() == OMAP2_DEVICE_TYPE_GP) && omap4_device_off_read_prev_state()) { restore_gic(); omap4_wakeupgen_restore(); } enable_gic_distributor(); if (omap_type() != OMAP2_DEVICE_TYPE_GP) { restore_ivahd_tesla_regs(); restore_l3instr_regs(); } } /* * Enable GIC cpu inrterface */ enable_gic_cpu_interface(); break; default: ; } }
/** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device * @state: The target state to be programmed * * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 core_next_state, per_next_state = 0, per_saved_state = 0; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; current_cx_state = *cx; /* Used to keep track of the total time in idle */ getnstimeofday(&ts_preidle); local_irq_disable(); local_fiq_disable(); pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state); /* * Don't allow PER to go to OFF in idle state * transitions. * This is a tempory fix for display flashing issue * which occurs when off mode is enabled */ per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); if (per_next_state == PWRDM_POWER_OFF) per_next_state = PWRDM_POWER_RET; /* Are we changing PER target state? */ if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); if (omap_irq_pending() || need_resched()) goto return_sleep_time; if (cx->type == OMAP3_STATE_C1) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); } /* Execute ARM wfi */ omap_sram_idle(); if (cx->type == OMAP3_STATE_C1) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); } return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); /* Restore original PER state if it was modified */ if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_saved_state); local_irq_enable(); local_fiq_enable(); return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
/** * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function * The purpose of this function is to manage low power programming * of OMAP4 MPUSS subsystem * @cpu : CPU ID * @power_state: Low power state. * * MPUSS states for the context save: * save_state = * 0 - Nothing lost and no need to save: MPUSS INACTIVE * 1 - CPUx L1 and logic lost: MPUSS CSWR * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR * 3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF */ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { unsigned int save_state = 0; unsigned int wakeup_cpu; if (omap_rev() == OMAP4430_REV_ES1_0) return -ENXIO; switch (power_state) { case PWRDM_POWER_ON: case PWRDM_POWER_INACTIVE: save_state = 0; break; case PWRDM_POWER_OFF: save_state = 1; break; case PWRDM_POWER_RET: default: /* * CPUx CSWR is invalid hardware state. Also CPUx OSWR * doesn't make much scense, since logic is lost and $L1 * needs to be cleaned because of coherency. This makes * CPUx OSWR equivalent to CPUX OFF and hence not supported */ WARN_ON(1); return -ENXIO; } pwrdm_pre_transition(NULL); /* * Check MPUSS next state and save interrupt controller if needed. * In MPUSS OSWR or device OFF, interrupt controller contest is lost. */ mpuss_clear_prev_logic_pwrst(); if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) && (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) save_state = 2; cpu_clear_prev_logic_pwrst(cpu); set_cpu_next_pwrst(cpu, power_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); scu_pwrst_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); /* * Call low level function with targeted low power state. */ cpu_suspend(save_state, omap4_finish_suspend); /* * Restore the CPUx power state to ON otherwise CPUx * power domain can transitions to programmed low power * state while doing WFI outside the low powe code. On * secure devices, CPUx does WFI which can result in * domain transition */ wakeup_cpu = smp_processor_id(); set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); pwrdm_post_transition(NULL); return 0; }
/** * power_domain_test - Test the power domain APIs * * Test the power domain APIs for all power domains * */ void power_domain_test() { int bank, i; int val = -EINVAL; static struct powerdomain *p, *pwrdm; for (i = 0; powerdomains_omap[i] != NULL; i++) { p = powerdomains_omap[i]; pwrdm = pwrdm_lookup(p->name); if (pwrdm) printk(KERN_INFO "PWR DM No%d = %s\n", i, pwrdm->name); else printk(KERN_INFO "PWR DM %s not supported\n", p->name); } /* i starts from 1 as gfx_pwrdm not supported in ES3.1.1 */ for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_add_clkdm(p = powerdomains_omap[i], &dummy_clkdm); if (val == 0) printk(KERN_INFO "Clock Domain Registered for %s\n", p->name); else if (val == -EINVAL) printk(KERN_ERR "Clock Domain Register FAILED!!! for" " %s\n", p->name); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_del_clkdm(p = powerdomains_omap[i], &dummy_clkdm); if (val == 0) printk(KERN_INFO "Clock Domain Unregistered for %s\n", p->name); else if (val == -EINVAL) printk(KERN_ERR "Clock Domain Unregister FAILED!!! for" " %s\n", p->name); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_get_mem_bank_count(p = powerdomains_omap[i]); printk(KERN_INFO "Bnk Cnt for %s = %d\n", p->name, val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_read_logic_pwrst(p = powerdomains_omap[i]); printk(KERN_INFO "PwrState of %s = %d\n", p->name, val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_set_logic_retst(p = powerdomains_omap[i], PWRDM_POWER_OFF); if (val == 0) printk(KERN_INFO "Logic RET State OFF for %s Set\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "OFF State not supported for %s\n", p->name); else printk(KERN_ERR "Set Logic RET State OFF FAILED!!!" " with value %d\n", val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_set_logic_retst(p = powerdomains_omap[i], PWRDM_POWER_RET); if (val == 0) printk(KERN_INFO "Logic RET State RET for %s Set\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "RET State not supported for %s\n", p->name); else printk(KERN_ERR "Logic RET State RET FAILED!!!" " with value %d\n", val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_read_pwrst(p = powerdomains_omap[i]); printk(KERN_INFO "PwrState of %s = %d\n", p->name, val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_set_next_pwrst(p = powerdomains_omap[i], PWRDM_POWER_OFF); if (val == 0) printk(KERN_INFO "Next PWRST for %s Set to OFF\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "OFF not supported for %s\n", p->name); else printk(KERN_ERR "Next PWRST Set to OFF FAILED!!!" " with value %d\n", val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_set_next_pwrst(p = powerdomains_omap[i], PWRDM_POWER_RET); if (val == 0) printk(KERN_INFO "Next PWRST for %s Set to RET\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "RET not supported for %s\n", p->name); else printk(KERN_ERR "Next PWRST Set to RET FAILED!!!" " with value %d\n", val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_set_next_pwrst(p = powerdomains_omap[i], PWRDM_POWER_ON); if (val == 0) printk(KERN_INFO "Next PWRST for %s Set to ON\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "ON not supported for %s\n", p->name); else printk(KERN_ERR "Next PWRST Set to ON FAILED!!!" " with value %d\n", val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_read_next_pwrst(p = powerdomains_omap[i]); printk(KERN_INFO "Next Power State of %s = %d\n", p->name, val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { val = pwrdm_read_pwrst(p = powerdomains_omap[i]); printk(KERN_INFO "Current Power State of %s = %d\n", p->name, val); } for (i = 1; powerdomains_omap[i] != NULL; i++) { for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) { val = pwrdm_set_mem_onst(p = powerdomains_omap[i], bank, PWRDM_POWER_OFF); if (val == 0) printk(KERN_INFO "Memory ON State OFF for %s" " Set\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "OFF State not supported" " for %s\n", p->name); else if (val == -EEXIST) printk(KERN_ERR "Memory Bank %d not present" " for %s\n", bank, p->name); else printk(KERN_ERR "Memory ON State OFF FAILED!!!" " with value %d\n", val); } } for (i = 1; powerdomains_omap[i] != NULL; i++) { for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) { val = pwrdm_set_mem_onst(p = powerdomains_omap[i], bank, PWRDM_POWER_RET); if (val == 0) printk(KERN_INFO "Memory ON State RET for %s" " Set\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "RET State not supported" " for %s\n", p->name); else if (val == -EEXIST) printk(KERN_ERR "Memory Bank %d not present" " for %s\n", bank, p->name); else printk(KERN_ERR "Memory ON State RET FAILED!!!" " with value %d\n", val); } } for (i = 1; powerdomains_omap[i] != NULL; i++) { for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) { val = pwrdm_set_mem_retst(p = powerdomains_omap[i], bank, PWRDM_POWER_OFF); if (val == 0) printk(KERN_INFO "Memory RET State OFF for" " %s Set\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "OFF State not supported for" " %s\n", p->name); else if (val == -EEXIST) printk(KERN_ERR "Memory Bank %d not present" " for %s\n", bank, p->name); else printk(KERN_ERR "Memory ON State OFF FAILED!!!" " with value %d\n", val); } } for (i = 1; powerdomains_omap[i] != NULL; i++) { for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) { val = pwrdm_set_mem_retst(p = powerdomains_omap[i], bank, PWRDM_POWER_RET); if (val == 0) printk(KERN_INFO "Memory RET State RET for" " %s Set\n", p->name); else if (val == -EINVAL) printk(KERN_INFO "RET State not supported for" " %s\n", p->name); else if (val == -EEXIST) printk(KERN_ERR "Memory Bank %d not present" " for %s\n", bank, p->name); else printk(KERN_ERR "MEM PWRST Set FAILED!!!" " with value %d\n", val); } } for (i = 1; powerdomains_omap[i] != NULL; i++) { for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) { val = pwrdm_read_mem_pwrst(p = powerdomains_omap[i], bank); if (val == -EEXIST) printk(KERN_ERR "Memory Bank %d not present" " for %s\n", bank, p->name); else if (val == -EINVAL) printk(KERN_ERR "MEM PWRST Read FAILED!!!" " with value %d\n", val); else printk(KERN_INFO "MEM PWRST for bank %d of" " %s = %d\n", bank, p->name, val); } } }
static int pwrdm_get_idle_state(struct powerdomain *pwrdm) { if (pwrdm_can_idle(pwrdm)) return pwrdm_read_next_pwrst(pwrdm); return PWRDM_POWER_ON; }
/** * omap3_enter_idle_bm - Checks for any bus activity * @dev: cpuidle device * @state: The target state to be programmed * * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This * function checks for any pending activity and then programs the * device to the specified or a safer state. */ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; u32 per_state = PWRDM_POWER_RET; u32 saved_per_state = PWRDM_POWER_RET; u32 cam_state, usb_state, iva2_state; u32 sgx_state, dss_state, new_core_state; struct omap3_processor_cx *cx; int ret; if (state->flags & CPUIDLE_FLAG_CHECK_BM) { if (omap3_idle_bm_check()) { BUG_ON(!dev->safe_state); new_state = dev->safe_state; goto select_state; } cx = cpuidle_get_statedata(state); new_core_state = cx->core_state; /* Check if CORE is active, if yes, fallback to inactive */ if (!pwrdm_can_idle(core_pd)) new_core_state = PWRDM_POWER_INACTIVE; /* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. */ cam_state = pwrdm_get_idle_state(cam_pd); if (cam_state == PWRDM_POWER_ON) { new_state = dev->safe_state; goto select_state; } /* * Check if PER can idle or not. If we are not likely * to idle, deny PER off. This prevents unnecessary * context save/restore. */ saved_per_state = pwrdm_read_next_pwrst(per_pd); per_state = saved_per_state; if (pwrdm_can_idle(per_pd)) { /* * Prevent PER off if CORE is active as this * would disable PER wakeups completely */ if (per_state == PWRDM_POWER_OFF && new_core_state > PWRDM_POWER_RET) per_state = PWRDM_POWER_RET; } else if (saved_per_state == PWRDM_POWER_OFF) per_state = PWRDM_POWER_RET; /* * If we are attempting CORE off, check if any other * powerdomains are at retention or higher. CORE off causes * chipwide reset which would reset these domains also. */ if (new_core_state == PWRDM_POWER_OFF) { dss_state = pwrdm_get_idle_state(dss_pd); iva2_state = pwrdm_get_idle_state(iva2_pd); sgx_state = pwrdm_get_idle_state(sgx_pd); usb_state = pwrdm_get_idle_state(usb_pd); if (cam_state > PWRDM_POWER_OFF || dss_state > PWRDM_POWER_OFF || iva2_state > PWRDM_POWER_OFF || per_state > PWRDM_POWER_OFF || sgx_state > PWRDM_POWER_OFF || usb_state > PWRDM_POWER_OFF) new_core_state = PWRDM_POWER_RET; } /* Fallback to new target core state */ while (cx->core_state < new_core_state) { state--; cx = cpuidle_get_statedata(state); } new_state = state; /* Are we changing PER target state? */ if (per_state != saved_per_state) pwrdm_set_next_pwrst(per_pd, per_state); } select_state: dev->last_state = new_state; ret = omap3_enter_idle(dev, new_state); /* Restore potentially tampered PER state */ if (per_state != saved_per_state) pwrdm_set_next_pwrst(per_pd, saved_per_state); return ret; }