static int exynos5420_cpu_suspend(unsigned long arg) { /* MCPM works with HW CPU identifiers */ unsigned int mpidr = read_cpuid_mpidr(); unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); /* * Residency value passed to mcpm_cpu_suspend back-end * has to be given clear semantics. Set to 0 as a * temporary value. */ mcpm_cpu_suspend(0); } pr_info("Failed to suspend the system\n"); /* return value != 0 means failure */ return 1; }
static void mcpm_cpu_die(unsigned int cpu) { unsigned int mpidr, pcpu, pcluster; mpidr = read_cpuid_mpidr(); pcpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); pcluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); mcpm_set_entry_vector(pcpu, pcluster, NULL); mcpm_cpu_power_down(); }
static int notrace mcpm_powerdown_finisher(unsigned long arg) { u32 mpidr = read_cpuid_mpidr(); u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); u32 this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); mcpm_set_entry_vector(cpu, this_cluster, cpu_resume); mcpm_cpu_suspend(arg); return 1; }
static int notrace bl_powerdown_finisher(unsigned long arg) { unsigned int mpidr = read_cpuid_mpidr(); unsigned int cluster = (mpidr >> 8) & 0xf; unsigned int cpu = mpidr & 0xf; mcpm_set_entry_vector(cpu, cluster, cpu_resume); mcpm_cpu_suspend(0); /* 0 should be replaced with better value here */ return 1; }
static int mcpm_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned int pcpu, pcluster, ret; extern void secondary_startup(void); cpu_to_pcpu(cpu, &pcpu, &pcluster); pr_debug("%s: logical CPU %d is physical CPU %d cluster %d\n", __func__, cpu, pcpu, pcluster); mcpm_set_entry_vector(pcpu, pcluster, NULL); ret = mcpm_cpu_power_up(pcpu, pcluster); if (ret) return ret; mcpm_set_entry_vector(pcpu, pcluster, secondary_startup); arch_send_wakeup_ipi_mask(cpumask_of(cpu)); dsb_sev(); return 0; }
/* * notrace prevents trace shims from getting inserted where they * should not. Global jumps and ldrex/strex must not be inserted * in power down sequences where caches and MMU may be turned off. */ static int notrace sunxi_powerdown_c2_finisher(unsigned long flg) { /* MCPM works with HW CPU identifiers */ unsigned int mpidr = read_cpuid_mpidr(); unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); bool last_man = false; struct sunxi_enter_idle_para sunxi_idle_para; mcpm_set_entry_vector(cpu, cluster, cpu_resume); arch_spin_lock(&sun8i_mcpm_lock); sun8i_cpu_use_count[cluster][cpu]--; /* check is the last-man, and set flg */ sun8i_cluster_use_count[cluster]--; if (sun8i_cluster_use_count[cluster] == 0) { writel(1, CLUSTER_CPUX_FLG(cluster, cpu)); last_man = true; } arch_spin_unlock(&sun8i_mcpm_lock); /* call cpus to power off */ sunxi_idle_para.flags = (unsigned long)mpidr | flg; sunxi_idle_para.resume_addr = (void *)(virt_to_phys(mcpm_entry_point)); arisc_enter_cpuidle(NULL, NULL, &sunxi_idle_para); if (last_man) { int t = 0; /* wait for cpus received this message and respond, * for reconfirm is this cpu the man really, then clear flg */ while (1) { udelay(2); if (readl(CLUSTER_CPUS_FLG(cluster, cpu)) == 2) { writel(0, CLUSTER_CPUX_FLG(cluster, cpu)); break; /* last_man is true */ } else if (readl(CLUSTER_CPUS_FLG(cluster, cpu)) == 3) { writel(0, CLUSTER_CPUX_FLG(cluster, cpu)); goto out; /* last_man is false */ } if(++t > 5000) { printk(KERN_WARNING "cpu%didle time out!\n", \ cluster * 4 + cpu); t = 0; } } sunxi_idle_cluster_die(cluster); } out: sunxi_idle_cpu_die(); /* return value != 0 means failure */ return 1; }
static int __cpuinit mcpm_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned int mpidr, pcpu, pcluster, ret; extern void secondary_startup(void); mpidr = cpu_logical_map(cpu); pcpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); pcluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); pr_debug("%s: logical CPU %d is physical CPU %d cluster %d\n", __func__, cpu, pcpu, pcluster); mcpm_set_entry_vector(pcpu, pcluster, NULL); ret = mcpm_cpu_power_up(pcpu, pcluster); if (ret) return ret; mcpm_set_entry_vector(pcpu, pcluster, secondary_startup); arch_send_wakeup_ipi_mask(cpumask_of(cpu)); dsb_sev(); return 0; }
/* * notrace prevents trace shims from getting inserted where they * should not. Global jumps and ldrex/strex must not be inserted * in power down sequences where caches and MMU may be turned off. */ static int notrace bl_powerdown_finisher(unsigned long arg) { /* MCPM works with HW CPU identifiers */ unsigned int mpidr = read_cpuid_mpidr(); unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); mcpm_set_entry_vector(cpu, cluster, cpu_resume); /* * Residency value passed to mcpm_cpu_suspend back-end * has to be given clear semantics. Set to 0 as a * temporary value. */ mcpm_cpu_suspend(0); /* return value != 0 means failure */ return 1; }
static int exynos5420_cpu_suspend(unsigned long arg) { /* MCPM works with HW CPU identifiers */ unsigned int mpidr = read_cpuid_mpidr(); unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); writel_relaxed(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); mcpm_cpu_suspend(); } pr_info("Failed to suspend the system\n"); /* return value != 0 means failure */ return 1; }
static int __init nocache_trampoline(unsigned long _arg) { void (*cache_disable)(void) = (void *)_arg; unsigned int mpidr = read_cpuid_mpidr(); unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); phys_reset_t phys_reset; mcpm_set_entry_vector(cpu, cluster, cpu_resume); setup_mm_for_reboot(); __mcpm_cpu_going_down(cpu, cluster); BUG_ON(!__mcpm_outbound_enter_critical(cpu, cluster)); cache_disable(); __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); __mcpm_cpu_down(cpu, cluster); phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset); phys_reset(virt_to_phys(mcpm_entry_point)); BUG(); }