static int psci_afflvl2_off(unsigned long mpidr, aff_map_node *system_node) { int rc = PSCI_E_SUCCESS; unsigned int plat_state; /* Cannot go beyond this level */ assert(system_node->level == MPIDR_AFFLVL2); /* State management: Decrement the system reference count */ psci_set_state(system_node, PSCI_STATE_OFF); /* * Keep the physical state of the system handy to decide what * action needs to be taken */ plat_state = psci_get_phys_state(system_node); /* No arch. and generic bookeeping to do here currently */ /* * Plat. Management : Allow the platform to do its bookeeping * at this affinity level */ if (psci_plat_pm_ops->affinst_off) rc = psci_plat_pm_ops->affinst_off(mpidr, system_node->level, plat_state); return rc; }
/******************************************************************************* * This function is passed an array of pointers to affinity level nodes in the * topology tree for an mpidr and the state which each node should transition * to. It updates the state of each node between the specified affinity levels. ******************************************************************************/ void psci_do_afflvl_state_mgmt(uint32_t start_afflvl, uint32_t end_afflvl, aff_map_node_t *mpidr_nodes[], uint32_t state) { uint32_t level; for (level = start_afflvl; level <= end_afflvl; level++) { if (mpidr_nodes[level] == NULL) continue; psci_set_state(mpidr_nodes[level], state); } }
static int psci_afflvl1_off(unsigned long mpidr, aff_map_node *cluster_node) { int rc = PSCI_E_SUCCESS; unsigned int plat_state; /* Sanity check the cluster level */ assert(cluster_node->level == MPIDR_AFFLVL1); /* State management: Decrement the cluster reference count */ psci_set_state(cluster_node, PSCI_STATE_OFF); /* * Keep the physical state of this cluster handy to decide * what action needs to be taken */ plat_state = psci_get_phys_state(cluster_node); /* * Arch. Management. Flush all levels of caches to PoC if * the cluster is to be shutdown */ if (plat_state == PSCI_STATE_OFF) dcsw_op_all(DCCISW); /* * Plat. Management. Allow the platform to do its cluster * specific bookeeping e.g. turn off interconnect coherency, * program the power controller etc. */ if (psci_plat_pm_ops->affinst_off) rc = psci_plat_pm_ops->affinst_off(mpidr, cluster_node->level, plat_state); return rc; }
/******************************************************************************* * The next three functions implement a handler for each supported affinity * level which is called when that affinity level is turned off. ******************************************************************************/ static int psci_afflvl0_off(unsigned long mpidr, aff_map_node *cpu_node) { unsigned int index, plat_state; int rc = PSCI_E_SUCCESS; unsigned long sctlr; assert(cpu_node->level == MPIDR_AFFLVL0); /* State management: mark this cpu as turned off */ psci_set_state(cpu_node, PSCI_STATE_OFF); /* * Generic management: Get the index for clearing any lingering re-entry * information and allow the secure world to switch itself off */ /* * Call the cpu off handler registered by the Secure Payload Dispatcher * to let it do any bookeeping. Assume that the SPD always reports an * E_DENIED error if SP refuse to power down */ if (psci_spd_pm && psci_spd_pm->svc_off) { rc = psci_spd_pm->svc_off(0); if (rc) return rc; } index = cpu_node->data; memset(&psci_ns_entry_info[index], 0, sizeof(psci_ns_entry_info[index])); /* * Arch. management. Perform the necessary steps to flush all * cpu caches. * * TODO: This power down sequence varies across cpus so it needs to be * abstracted out on the basis of the MIDR like in cpu_reset_handler(). * Do the bare minimal for the time being. Fix this before porting to * Cortex models. */ sctlr = read_sctlr_el3(); sctlr &= ~SCTLR_C_BIT; write_sctlr_el3(sctlr); /* * CAUTION: This flush to the level of unification makes an assumption * about the cache hierarchy at affinity level 0 (cpu) in the platform. * Ideally the platform should tell psci which levels to flush to exit * coherency. */ dcsw_op_louis(DCCISW); /* * Plat. management: Perform platform specific actions to turn this * cpu off e.g. exit cpu coherency, program the power controller etc. */ if (psci_plat_pm_ops->affinst_off) { /* Get the current physical state of this cpu */ plat_state = psci_get_phys_state(cpu_node); rc = psci_plat_pm_ops->affinst_off(mpidr, cpu_node->level, plat_state); } return rc; }