static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Clear the APU power control register for this cpu */ pm_client_wakeup(proc); /* enable coherency */ plat_arm_interconnect_enter_coherency(); }
static int zynqmp_pwr_domain_on(u_register_t mpidr) { unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); const struct pm_proc *proc; VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); if (cpu_id == -1) return PSCI_E_INTERN_FAIL; proc = pm_get_proc(cpu_id); /* Send request to PMU to wake up selected APU CPU core */ pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_BLOCKING); return PSCI_E_SUCCESS; }
/** * pm_self_suspend() - PM call for processor to suspend itself * @nid Node id of the processor or subsystem * @latency Requested maximum wakeup latency (not supported) * @state Requested state (not supported) * @address Resume address * * This is a blocking call, it will return only once PMU has responded. * On a wakeup, resume address will be automatically set by PMU. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_self_suspend(enum pm_node_id nid, unsigned int latency, unsigned int state, uintptr_t address) { uint32_t payload[PAYLOAD_ARG_CNT]; unsigned int cpuid = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpuid); /* * Do client specific suspend operations * (e.g. set powerdown request bit) */ pm_client_suspend(proc); /* Send request to the PMU */ PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency, state, address, (address >> 32)); return pm_ipi_send_sync(proc, payload, NULL); }
static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Send request to PMU to suspend this core */ pm_self_suspend(proc->node_id, MAX_LATENCY, 0, zynqmp_sec_entry); /* APU is to be turned off */ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { /* Power down L2 cache */ pm_set_requirement(NODE_L2, 0, 0, REQ_ACK_NO); /* Send request for OCM retention state */ set_ocm_retention(); /* disable coherency */ plat_arm_interconnect_exit_coherency(); } }
static void zynqmp_pwr_domain_off(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); /* * Send request to PMU to power down the appropriate APU CPU * core. * According to PSCI specification, CPU_off function does not * have resume address and CPU core can only be woken up * invoking CPU_on function, during which resume address will * be set. */ pm_self_suspend(proc->node_id, MAX_LATENCY, 0, 0); }
static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state) { unsigned int state; unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ? PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE; /* Send request to PMU to suspend this core */ pm_self_suspend(proc->node_id, MAX_LATENCY, state, zynqmp_sec_entry); /* APU is to be turned off */ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { /* disable coherency */ plat_arm_interconnect_exit_coherency(); } }