ARM: EXYNOS: add exynos_get_boot_addr() helper
[deliverable/linux.git] / arch / arm / mach-exynos / platsmp.c
index ebd135bb0995611517c1bce6d3b70deeeee37de4..449edd1121e4d85a15b5e5e8ff40804407b480f5 100644 (file)
 
 extern void exynos4_secondary_startup(void);
 
-/*
- * Set or clear the USE_DELAYED_RESET_ASSERTION option, set on Exynos4 SoCs
- * during hot-(un)plugging CPUx.
- *
- * The feature can be cleared safely during first boot of secondary CPU.
- *
- * Exynos4 SoCs require setting USE_DELAYED_RESET_ASSERTION during powering
- * down a CPU so the CPU idle clock down feature could properly detect global
- * idle state when CPUx is off.
- */
-static void exynos_set_delayed_reset_assertion(u32 core_id, bool enable)
-{
-       if (soc_is_exynos4()) {
-               unsigned int tmp;
-
-               tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id));
-               if (enable)
-                       tmp |= S5P_USE_DELAYED_RESET_ASSERTION;
-               else
-                       tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION);
-               pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id));
-       }
-}
-
 #ifdef CONFIG_HOTPLUG_CPU
 static inline void cpu_leave_lowpower(u32 core_id)
 {
@@ -73,8 +49,6 @@ static inline void cpu_leave_lowpower(u32 core_id)
          : "=&r" (v)
          : "Ir" (CR_C), "Ir" (0x40)
          : "cc");
-
-        exynos_set_delayed_reset_assertion(core_id, false);
 }
 
 static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
@@ -87,14 +61,6 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
                /* Turn the CPU off on next WFI instruction. */
                exynos_cpu_power_down(core_id);
 
-               /*
-                * Exynos4 SoCs require setting
-                * USE_DELAYED_RESET_ASSERTION so the CPU idle
-                * clock down feature could properly detect
-                * global idle state when CPUx is off.
-                */
-               exynos_set_delayed_reset_assertion(core_id, true);
-
                wfi();
 
                if (pen_release == core_id) {
@@ -244,7 +210,6 @@ static void exynos_core_restart(u32 core_id)
        val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG;
        pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id));
 
-       pr_info("CPU%u: Software reset\n", core_id);
        pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET);
 }
 
@@ -282,6 +247,56 @@ static void exynos_secondary_init(unsigned int cpu)
        spin_unlock(&boot_lock);
 }
 
+static int exynos_set_boot_addr(u32 core_id, unsigned long boot_addr)
+{
+       int ret;
+
+       /*
+        * 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, boot_reg);
+               ret = 0;
+       }
+fail:
+       return ret;
+}
+
+static int exynos_get_boot_addr(u32 core_id, unsigned long *boot_addr)
+{
+       int ret;
+
+       /*
+        * Try to get boot address using firmware first
+        * and fall back to boot register if it fails.
+        */
+       ret = call_firmware_op(get_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;
+               }
+               *boot_addr = __raw_readl(boot_reg);
+               ret = 0;
+       }
+fail:
+       return ret;
+}
+
 static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
        unsigned long timeout;
@@ -341,22 +356,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 
                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)
+               ret = exynos_set_boot_addr(core_id, boot_addr);
+               if (ret)
                        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, boot_reg);
-               }
 
                call_firmware_op(cpu_boot, core_id);
 
@@ -371,8 +373,8 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
                udelay(10);
        }
 
-       /* No harm if this is called during first boot of secondary CPU */
-       exynos_set_delayed_reset_assertion(core_id, false);
+       if (pen_release != -1)
+               ret = -ETIMEDOUT;
 
        /*
         * now the secondary core is starting up let it run its
@@ -420,6 +422,8 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
 
        exynos_sysram_init();
 
+       exynos_set_delayed_reset_assertion(true);
+
        if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
                scu_enable(scu_base_addr());
 
@@ -442,16 +446,9 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
                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)
+               ret = exynos_set_boot_addr(core_id, boot_addr);
+               if (ret)
                        break;
-               if (ret == -ENOSYS) {
-                       void __iomem *boot_reg = cpu_boot_reg(core_id);
-
-                       if (IS_ERR(boot_reg))
-                               break;
-                       __raw_writel(boot_addr, boot_reg);
-               }
        }
 }
 
This page took 0.034919 seconds and 5 git commands to generate.