/* * platform-specific code to shutdown a CPU * Called with IRQs disabled */ void platform_cpu_die(unsigned int cpu) { unsigned int this_cpu; flush_cache_all(); dsb(); /* * we're ready for shutdown now, so do it */ if (omap_modify_auxcoreboot0(0x0, 0x200) != 0x0) pr_err("Secure clear status failed\n"); for (;;) { /* * Enter into low power state */ omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF); this_cpu = smp_processor_id(); if (omap_read_auxcoreboot0() == this_cpu) { /* * OK, proper wakeup, we're done */ break; } pr_debug("CPU%u: spurious wakeup call\n", cpu); } }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ flush_cache_all(); outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1)); omap_modify_auxcoreboot0(0x200, 0xfffffdff); smp_cross_call(cpumask_of(cpu)); set_event(); flush_cache_all(); smp_wmb(); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }
/* * platform-specific code to shutdown a CPU * Called with IRQs disabled */ void platform_cpu_die(unsigned int cpu) { flush_cache_all(); dsb(); /* * we're ready for shutdown now, so do it */ if (omap_modify_auxcoreboot0(0x0, 0x200) != 0x0) printk(KERN_CRIT "Secure clear status failed\n"); for (;;) { /* * Execute WFI */ do_wfi(); if (omap_read_auxcoreboot0() == cpu) { /* * OK, proper wakeup, we're done */ break; } pr_debug("CPU%u: spurious wakeup call\n", cpu); } }
static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) { static struct clockdomain *cpu1_clkdm; static bool booted; void __iomem *base = omap_get_wakeupgen_base(); /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ if (omap_secure_apis_support()) omap_modify_auxcoreboot0(0x200, 0xfffffdff); else __raw_writel(0x20, base + OMAP_AUX_CORE_BOOT_0); flush_cache_all(); smp_wmb(); if (!cpu1_clkdm) cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); /* * The SGI(Software Generated Interrupts) are not wakeup capable * from low power states. This is known limitation on OMAP4 and * needs to be worked around by using software forced clockdomain * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to * software force wakeup. The clockdomain is then put back to * hardware supervised mode. * More details can be found in OMAP4430 TRM - Version J * Section : * 4.3.4.2 Power States of CPU0 and CPU1 */ if (booted) { clkdm_wakeup(cpu1_clkdm); clkdm_allow_idle(cpu1_clkdm); } else { dsb_sev(); booted = true; } gic_raise_softirq(cpumask_of(cpu), 0); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }
/* * platform-specific code to shutdown a CPU * Called with IRQs disabled */ void platform_cpu_die(unsigned int cpu) { unsigned int this_cpu = hard_smp_processor_id(); struct clockdomain *cpu1_clkdm; if (cpu != this_cpu) { pr_crit("platform_cpu_die running on %u, should be %u\n", this_cpu, cpu); BUG(); } complete(&cpu_killed); flush_cache_all(); wmb(); /* * we're ready for shutdown now, so do it */ if (omap_modify_auxcoreboot0(0x0, 0x200) != 0x0) pr_err("Secure clear status failed\n"); for (;;) { /* * Enter into low power state * clear all interrupt wakeup sources */ omap4_wakeupgen_clear_all(cpu); #ifdef CONFIG_PM omap4_enter_lowpower(cpu, PWRDM_POWER_OFF); #else wmb(); do_wfi(); #endif if (omap_read_auxcoreboot0() == cpu) { /* * OK, proper wakeup, we're done */ this_cpu = hard_smp_processor_id(); omap4_wakeupgen_set_all(this_cpu); /* * Restore clock domain to HW_AUTO */ cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); omap2_clkdm_allow_idle(cpu1_clkdm); break; } pr_debug("CPU%u: spurious wakeup call\n", cpu); } }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { struct clockdomain *cpu1_clkdm; static bool booted; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ omap_modify_auxcoreboot0(0x200, 0xfffffdff); flush_cache_all(); smp_wmb(); /* * SGI isn't wakeup capable from low power states. This is * known limitation and can be worked around by using software * forced wake-up. After the wakeup, the CPU will restore it * to hw_auto. This code also gets initialised but pm init code * initialises the CPUx clockdomain to hw-auto mode */ if (booted) { cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); omap2_clkdm_wakeup(cpu1_clkdm); smp_cross_call(cpumask_of(cpu)); } else { set_event(); booted = true; } /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }
void __ref platform_cpu_die(unsigned int cpu) { unsigned int this_cpu; flush_cache_all(); dsb(); if (omap_modify_auxcoreboot0(0x0, 0x200) != 0x0) pr_err("Secure clear status failed\n"); for (;;) { omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF); this_cpu = smp_processor_id(); if (omap_read_auxcoreboot0() == this_cpu) { break; } pr_debug("CPU%u: spurious wakeup call\n", cpu); } }
static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) { static struct clockdomain *cpu1_clkdm; static bool booted; static struct powerdomain *cpu1_pwrdm; void __iomem *base = omap_get_wakeupgen_base(); /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap4_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ if (omap_secure_apis_support()) omap_modify_auxcoreboot0(0x200, 0xfffffdff); else __raw_writel(0x20, base + OMAP_AUX_CORE_BOOT_0); if (!cpu1_clkdm && !cpu1_pwrdm) { cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); cpu1_pwrdm = pwrdm_lookup("cpu1_pwrdm"); } /* * The SGI(Software Generated Interrupts) are not wakeup capable * from low power states. This is known limitation on OMAP4 and * needs to be worked around by using software forced clockdomain * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to * software force wakeup. The clockdomain is then put back to * hardware supervised mode. * More details can be found in OMAP4430 TRM - Version J * Section : * 4.3.4.2 Power States of CPU0 and CPU1 */ if (booted && cpu1_pwrdm && cpu1_clkdm) { /* * GIC distributor control register has changed between * CortexA9 r1pX and r2pX. The Control Register secure * banked version is now composed of 2 bits: * bit 0 == Secure Enable * bit 1 == Non-Secure Enable * The Non-Secure banked register has not changed * Because the ROM Code is based on the r1pX GIC, the CPU1 * GIC restoration will cause a problem to CPU0 Non-Secure SW. * The workaround must be: * 1) Before doing the CPU1 wakeup, CPU0 must disable * the GIC distributor * 2) CPU1 must re-enable the GIC distributor on * it's wakeup path. */ if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { local_irq_disable(); gic_dist_disable(); } /* * Ensure that CPU power state is set to ON to avoid CPU * powerdomain transition on wfi */ clkdm_wakeup(cpu1_clkdm); omap_set_pwrdm_state(cpu1_pwrdm, PWRDM_POWER_ON); clkdm_allow_idle(cpu1_clkdm); if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { while (gic_dist_disabled()) { udelay(1); cpu_relax(); } gic_timer_retrigger(); local_irq_enable(); } } else { dsb_sev(); booted = true; } arch_send_wakeup_ipi_mask(cpumask_of(cpu)); /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { static struct clockdomain *cpu1_clkdm; static bool booted; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * Update the AuxCoreBoot0 with boot state for secondary core. * omap_secondary_startup() routine will hold the secondary core till * the AuxCoreBoot1 register is updated with cpu state * A barrier is added to ensure that write buffer is drained */ omap_modify_auxcoreboot0(0x200, 0xfffffdff); flush_cache_all(); smp_wmb(); if (!cpu1_clkdm) cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); /* * The SGI(Software Generated Interrupts) are not wakeup capable * from low power states. This is known limitation on OMAP4 and * needs to be worked around by using software forced clockdomain * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to * software force wakeup. After the wakeup, CPU1 restores its * clockdomain hardware supervised mode. * More details can be found in OMAP4430 TRM - Version J * Section : * 4.3.4.2 Power States of CPU0 and CPU1 */ if (booted) { /* * GIC distributor control register has changed between * CortexA9 r1pX and r2pX. The Control Register secure * banked version is now composed of 2 bits: * bit 0 == Secure Enable * bit 1 == Non-Secure Enable * The Non-Secure banked register has not changed * Because the ROM Code is based on the r1pX GIC, the CPU1 * GIC restoration will cause a problem to CPU0 Non-Secure SW. * The workaround must be: * 1) Before doing the CPU1 wakeup, CPU0 must disable * the GIC distributor * 2) CPU1 must re-enable the GIC distributor on * it's wakeup path. */ if (!cpu_is_omap443x()) { local_irq_disable(); gic_dist_disable(); } clkdm_wakeup(cpu1_clkdm); if (!cpu_is_omap443x()) { while (gic_dist_disabled()) { udelay(1); cpu_relax(); } gic_timer_retrigger(); local_irq_enable(); } } else { clkdm_init_mpu1(cpu1_clkdm); dsb_sev(); booted = true; } /* * Now the secondary core is starting up let it run its * calibrations, then wait for it to finish */ spin_unlock(&boot_lock); return 0; }