コード例 #1
0
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;
}
コード例 #2
0
ファイル: platsmp.c プロジェクト: Juanhulk/Adam-Kernel-GS4
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;
}