int 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. 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;
	}

	arm_send_ping_ipi(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;
}
static int set_enable_mask(const char *val, const struct kernel_param *kp)
{
	int rv = param_set_uint(val, kp);
	unsigned long flags;

	if (rv)
		return rv;

	spin_lock_irqsave(&enable_mask_lock, flags);

	if (!(enable_mask & ENABLE_C2)) {
		unsigned int cpuid = smp_processor_id();
		int i;
		for_each_online_cpu(i) {
			if (i == cpuid)
				continue;
			arm_send_ping_ipi(i);
		}
	}
static int exynos_power_up_cpu(unsigned int cpu)
{
	unsigned int timeout;
	unsigned int val;
	void __iomem *power_base;
#ifndef CONFIG_EXYNOS5_MP
	unsigned int cluster = (read_cpuid_mpidr() >> 8) & 0xf;
#endif
	unsigned int lpe_bits, lpe_bits_status, enabled = 0;

	power_base = cpu_boot_info[cpu].power_base;
	if (power_base == 0)
		return -EPERM;

	val = __raw_readl(power_base + 0x4);

	if (soc_is_exynos5260()) {
		if (val & 0x40000)
			enabled = 1;
		else {
			val = __raw_readl(power_base + 0x8);
			if (val & EXYNOS5_USE_SC_COUNTER) {
				val &= ~EXYNOS5_USE_SC_COUNTER;
				val |= EXYNOS5_USE_SC_FEEDBACK;
				__raw_writel(val, power_base + 0x8);
			}
			lpe_bits = 0x000F000F;
			lpe_bits_status = 0x4000F;
#ifndef CONFIG_ARM_TRUSTZONE
			__raw_writel(0, cpu_boot_info[cpu].boot_base);
#endif
		}
	} else {
		if (val & EXYNOS_CORE_LOCAL_PWR_EN)
			enabled = 1;
		else {
			lpe_bits = EXYNOS_CORE_LOCAL_PWR_EN;
			lpe_bits_status = EXYNOS_CORE_LOCAL_PWR_EN;
		}
	}

	if (!enabled) {
		__raw_writel(lpe_bits, power_base);

		/* wait max 10 ms until cpu is on */
		timeout = 10;
		while (timeout) {
			val = __raw_readl(power_base + 0x4);

			if ((val & lpe_bits) ==
			     lpe_bits_status)
				break;

			mdelay(1);
			timeout--;
		}

		if (timeout == 0) {
			printk(KERN_ERR "cpu%d power up failed", cpu);

			return -ETIMEDOUT;
		}
	}

#ifdef CONFIG_EXYNOS5_MP
	if (cpu < 4) {
#else
	if (cluster) {
#endif
		while(!__raw_readl(EXYNOS_PMU_SPARE2))
			udelay(10);

		udelay(10);

		if (soc_is_exynos5260()) {
			val = __raw_readl(power_base + 0x4);
			val |= (0xf << 8);
			__raw_writel(val, power_base + 0x4);

			pr_debug("cpu%d: SWRESEET\n", cpu);

			__raw_writel((0x1 << 1), power_base + 0xc);
		} else {
			printk(KERN_DEBUG "cpu%d: SWRESET\n", cpu);

			val = ((1 << 20) | (1 << 8)) << cpu;
			__raw_writel(val, EXYNOS_SWRESET);
		}
	}

	return 0;
}

#else
#error "exynos_power_up_cpu() does not defined"
#endif
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	unsigned long timeout;
	int ret;

	/*
	 * Set synchronisation state between this boot processor
	 * and the secondary one
	 */
	spin_lock(&boot_lock);

#ifdef CONFIG_WATCHDOG
	if (soc_is_exynos5250())
		watchdog_save();
#endif

#ifdef CONFIG_SOC_EXYNOS4415
	__raw_writel(0x0, cpu_boot_info[cpu].boot_base);
#endif

	ret = exynos_power_up_cpu(cpu);
	if (ret) {
		spin_unlock(&boot_lock);
		return ret;
	}

	/*
	 * The secondary processor is waiting to be released from
	 * the holding pen - release it, then wait for it to flag
	 * that it has been released by resetting pen_release.
	 *
	 * Note that "pen_release" is the hardware CPU ID, whereas
	 * "cpu" is Linux's internal ID.
	 */
	write_pen_release(cpu_logical_map(cpu));

	/*
	 * Send the secondary CPU a soft interrupt, thereby causing
	 * the boot monitor to read the system wide flags register,
	 * and branch to the address found there.
	 */

	timeout = jiffies + (1 * HZ);
	while (time_before(jiffies, timeout)) {
		smp_rmb();

#ifdef CONFIG_ARM_TRUSTZONE
		if (soc_is_exynos4210() || soc_is_exynos4212() ||
			soc_is_exynos5250())
			exynos_smc(SMC_CMD_CPU1BOOT, 0, 0, 0);
		else if (soc_is_exynos4412() || soc_is_exynos4415())
			exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0);
#endif
		__raw_writel(virt_to_phys(exynos4_secondary_startup),
			cpu_boot_info[cpu].boot_base);

#ifdef CONFIG_WATCHDOG
		if (soc_is_exynos5250())
			watchdog_restore();
#endif

		if (soc_is_exynos3250() || soc_is_exynos3470() ||
			soc_is_exynos5410() || soc_is_exynos5420() ||
			soc_is_exynos5260())
			dsb_sev();
		else
			arm_send_ping_ipi(cpu);

		if (pen_release == -1)
			break;

		udelay(10);
	}

	/*
	 * now the secondary core is starting up let it run its
	 * calibrations, then wait for it to finish
	 */
	spin_unlock(&boot_lock);

	return pen_release != -1 ? -ENOSYS : 0;
}
Exemple #4
0
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	unsigned long timeout;
	int ret;

	/*
	 * Set synchronisation state between this boot processor
	 * and the secondary one
	 */
	spin_lock(&boot_lock);

	watchdog_save();

	ret = exynos_power_up_cpu(cpu);
	if (ret) {
		spin_unlock(&boot_lock);
		return ret;
	}

	/*
	 * The secondary processor is waiting to be released from
	 * the holding pen - release it, then wait for it to flag
	 * that it has been released by resetting pen_release.
	 *
	 * Note that "pen_release" is the hardware CPU ID, whereas
	 * "cpu" is Linux's internal ID.
	 */
	write_pen_release(cpu_logical_map(cpu));

	/*
	 * Send the secondary CPU a soft interrupt, thereby causing
	 * the boot monitor to read the system wide flags register,
	 * and branch to the address found there.
	 */

	timeout = jiffies + (1 * HZ);
	while (time_before(jiffies, timeout)) {
		smp_rmb();

#ifdef CONFIG_ARM_TRUSTZONE
		if (!soc_is_exynos5410()) {
			if (soc_is_exynos4412())
				exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0);
			else
				exynos_smc(SMC_CMD_CPU1BOOT, 0, 0, 0);
		}
#endif
		__raw_writel(virt_to_phys(exynos4_secondary_startup),
			cpu_boot_info[cpu].boot_base);

		watchdog_restore();

		if (soc_is_exynos5410())
			dsb_sev();
		else
			arm_send_ping_ipi(cpu);

		if (pen_release == -1)
			break;

		udelay(10);
	}

	/*
	 * now the secondary core is starting up let it run its
	 * calibrations, then wait for it to finish
	 */
	spin_unlock(&boot_lock);

	return pen_release != -1 ? -ENOSYS : 0;
}