static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) { int i; if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) scu_enable(scu_base_addr()); /* * Write the address of secondary startup into the * system-wide flags register. The boot monitor waits * until it receives a soft interrupt, and then the * secondary CPU branches to this address. * * Try using firmware operation first and fall back to * boot register if it fails. */ for (i = 1; i < max_cpus; ++i) { unsigned long phys_cpu; unsigned long boot_addr; phys_cpu = cpu_logical_map(i); boot_addr = virt_to_phys(exynos4_secondary_startup); if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr)) __raw_writel(boot_addr, cpu_boot_reg(phys_cpu)); } }
static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) { int i; exynos_sysram_init(); if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) scu_enable(scu_base_addr()); /* * Write the address of secondary startup into the * system-wide flags register. The boot monitor waits * until it receives a soft interrupt, and then the * secondary CPU branches to this address. * * Try using firmware operation first and fall back to * boot register if it fails. */ for (i = 1; i < max_cpus; ++i) { unsigned long boot_addr; u32 mpidr; u32 core_id; int ret; mpidr = cpu_logical_map(i); core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); boot_addr = virt_to_phys(exynos4_secondary_startup); ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); if (ret && ret != -ENOSYS) break; if (ret == -ENOSYS) { void __iomem *boot_reg = cpu_boot_reg(core_id); if (IS_ERR(boot_reg)) break; __raw_writel(boot_addr, cpu_boot_reg(core_id)); } } }
static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) { int i; if (!(soc_is_exynos5250() || soc_is_exynos5440())) scu_enable(scu_base_addr()); /* * Write the address of secondary startup into the * system-wide flags register. The boot monitor waits * until it receives a soft interrupt, and then the * secondary CPU branches to this address. */ for (i = 1; i < max_cpus; ++i) __raw_writel(virt_to_phys(exynos4_secondary_startup), cpu_boot_reg(cpu_logical_map(i))); }
static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; unsigned long phys_cpu = cpu_logical_map(cpu); /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * 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(phys_cpu); if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) { __raw_writel(S5P_CORE_LOCAL_PWR_EN, S5P_ARM_CORE1_CONFIGURATION); timeout = 10; /* wait max 10 ms until cpu1 is on */ while ((__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) { if (timeout-- == 0) break; mdelay(1); } if (timeout == 0) { printk(KERN_ERR "cpu1 power enable failed"); spin_unlock(&boot_lock); return -ETIMEDOUT; } } /* * 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)) { unsigned long boot_addr; smp_rmb(); boot_addr = virt_to_phys(exynos4_secondary_startup); /* * Try to set boot address using firmware first * and fall back to boot register if it fails. */ if (call_firmware_op(set_cpu_boot_addr, phys_cpu, boot_addr)) __raw_writel(boot_addr, cpu_boot_reg(phys_cpu)); call_firmware_op(cpu_boot, phys_cpu); arch_send_wakeup_ipi_mask(cpumask_of(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; }
static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) { unsigned long timeout; u32 mpidr = cpu_logical_map(cpu); u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); int ret = -ENOSYS; /* * Set synchronisation state between this boot processor * and the secondary one */ spin_lock(&boot_lock); /* * 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 core ID, whereas * "cpu" is Linux's internal ID. */ write_pen_release(core_id); if (!soc_is_exynos5440() && !exynos_cpu_power_state(core_id)) { exynos_cpu_power_up(core_id); timeout = 10; /* wait max 10 ms until cpu1 is on */ while (exynos_cpu_power_state(core_id) != S5P_CORE_LOCAL_PWR_EN) { if (timeout-- == 0) break; mdelay(1); } if (timeout == 0) { printk(KERN_ERR "cpu1 power enable failed"); spin_unlock(&boot_lock); return -ETIMEDOUT; } } /* * 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)) { unsigned long boot_addr; smp_rmb(); boot_addr = virt_to_phys(exynos4_secondary_startup); /* * Try to set boot address using firmware first * and fall back to boot register if it fails. */ ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); if (ret && ret != -ENOSYS) goto fail; if (ret == -ENOSYS) { void __iomem *boot_reg = cpu_boot_reg(core_id); if (IS_ERR(boot_reg)) { ret = PTR_ERR(boot_reg); goto fail; } __raw_writel(boot_addr, cpu_boot_reg(core_id)); } call_firmware_op(cpu_boot, core_id); arch_send_wakeup_ipi_mask(cpumask_of(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 */ fail: spin_unlock(&boot_lock); return pen_release != -1 ? ret : 0; }