summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/platsmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/platsmp.c')
-rw-r--r--arch/arm/mach-tegra/platsmp.c141
1 files changed, 80 insertions, 61 deletions
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 582810c96fc2..eadc1a8ea7f1 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -25,9 +25,14 @@
#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
+#include <mach/clk.h>
#include <mach/iomap.h>
#include <mach/powergate.h>
+#include "fuse.h"
+#include "flowctrl.h"
+#include "reset.h"
+
#include "pm.h"
#include "clock.h"
#include "reset.h"
@@ -38,6 +43,7 @@ bool tegra_all_cpus_booted;
static DECLARE_BITMAP(tegra_cpu_init_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const tegra_cpu_init_mask = to_cpumask(tegra_cpu_init_bits);
#define tegra_cpu_init_map (*(cpumask_t *)tegra_cpu_init_mask)
+static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
@@ -45,6 +51,11 @@ const struct cpumask *const tegra_cpu_init_mask = to_cpumask(tegra_cpu_init_bits
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
+#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
+ (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
+
+#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
+#define CPU_RESET(cpu) (0x1111ul<<(cpu))
#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
#define CPU_RESET(cpu) (0x1111ul<<(cpu))
@@ -109,79 +120,73 @@ static bool is_cpu_powered(unsigned int cpu)
}
#endif
-static int power_up_cpu(unsigned int cpu)
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+ gic_secondary_init(0);
+
+ cpumask_set_cpu(cpu, to_cpumask(tegra_cpu_init_bits));
+ if (!tegra_all_cpus_booted)
+ if (cpumask_equal(tegra_cpu_init_mask, cpu_present_mask))
+ tegra_all_cpus_booted = true;
+}
+
+static int tegra20_power_up_cpu(unsigned int cpu)
{
u32 reg;
- int ret = 0;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+
+ /* Enable the CPU clock. */
+ reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ barrier();
+ reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+
+ /* Clear flow controller CSR. */
+ flowctrl_write_cpu_csr(cpu, 0);
+
+ return 0;
+}
+
+static int tegra30_power_up_cpu(unsigned int cpu)
+{
+ u32 reg;
+ int ret, pwrgateid;
unsigned long timeout;
BUG_ON(cpu == smp_processor_id());
BUG_ON(is_lp_cluster());
- /* If this cpu has booted this function is entered after
- * CPU has been already un-gated by flow controller. Wait
- * for confirmation that cpu is powered and remove clamps.
- * On first boot entry do not wait - go to direct ungate.
- */
- if (cpu_isset(cpu, tegra_cpu_init_map)) {
- timeout = jiffies + 5;
- do {
- if (is_cpu_powered(cpu))
- goto remove_clamps;
- udelay(10);
- } while (time_before(jiffies, timeout));
- }
+ pwrgateid = tegra_cpu_powergate_id(cpu);
+ if (pwrgateid < 0)
+ return pwrgateid;
- /* First boot or Flow controller did not work as expected. Try to
- directly toggle power gates. Error if direct power on also fails. */
- if (!is_cpu_powered(cpu)) {
- ret = tegra_unpowergate_partition(TEGRA_CPU_POWERGATE_ID(cpu));
+ /* If this is the first boot, toggle powergates directly. */
+ if (!tegra_powergate_is_powered(pwrgateid)) {
+ ret = tegra_powergate_power_on(pwrgateid);
if (ret)
- goto fail;
+ return ret;
/* Wait for the power to come up. */
timeout = jiffies + 10*HZ;
-
- do {
- if (is_cpu_powered(cpu))
- goto remove_clamps;
+ while (tegra_powergate_is_powered(pwrgateid)) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
udelay(10);
- } while (time_before(jiffies, timeout));
- ret = -ETIMEDOUT;
- goto fail;
+ }
}
-remove_clamps:
/* CPU partition is powered. Enable the CPU clock. */
writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
udelay(10);
/* Remove I/O clamps. */
- ret = tegra_powergate_remove_clamping(TEGRA_CPU_POWERGATE_ID(cpu));
+ ret = tegra_powergate_remove_clamping(pwrgateid);
udelay(10);
-fail:
-#else
- /* Enable the CPU clock. */
- reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- barrier();
- reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-#endif
- /* Clear flow controller CSR. */
- flowctrl_writel(0, FLOW_CTRL_CPU_CSR(cpu));
- return ret;
-}
-void __cpuinit platform_secondary_init(unsigned int cpu)
-{
- gic_secondary_init(0);
+ /* Clear flow controller CSR. */
+ flowctrl_write_cpu_csr(cpu, 0);
- cpumask_set_cpu(cpu, to_cpumask(tegra_cpu_init_bits));
- if (!tegra_all_cpus_booted)
- if (cpumask_equal(tegra_cpu_init_mask, cpu_present_mask))
- tegra_all_cpus_booted = true;
+ return 0;
}
int boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -218,21 +223,36 @@ int boot_secondary(unsigned int cpu, struct task_struct *idle)
smp_wmb();
- /* Force the CPU into reset. The CPU must remain in reset when the
- flow controller state is cleared (which will cause the flow
- controller to stop driving reset if the CPU has been power-gated
- via the flow controller). This will have no effect on first boot
- of the CPU since it should already be in reset. */
+ /*
+ * Force the CPU into reset. The CPU must remain in reset when the
+ * flow controller state is cleared (which will cause the flow
+ * controller to stop driving reset if the CPU has been power-gated
+ * via the flow controller). This will have no effect on first boot
+ * of the CPU since it should already be in reset.
+ */
writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
dmb();
- /* Unhalt the CPU. If the flow controller was used to power-gate the
- CPU this will cause the flow controller to stop driving reset.
- The CPU will remain in reset because the clock and reset block
- is now driving reset. */
- flowctrl_writel(0, FLOW_CTRL_HALT_CPU(cpu));
+ /*
+ * Unhalt the CPU. If the flow controller was used to power-gate the
+ * CPU this will cause the flow controller to stop driving reset.
+ * The CPU will remain in reset because the clock and reset block
+ * is now driving reset.
+ */
+ flowctrl_write_cpu_halt(cpu, 0);
+
+ switch (tegra_chip_id) {
+ case TEGRA20:
+ status = tegra20_power_up_cpu(cpu);
+ break;
+ case TEGRA30:
+ status = tegra30_power_up_cpu(cpu);
+ break;
+ default:
+ status = -EINVAL;
+ break;
+ }
- status = power_up_cpu(cpu);
if (status)
goto done;
@@ -276,7 +296,6 @@ void __init smp_init_cpus(void)
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
-
/* Always mark the boot CPU as initialized. */
cpumask_set_cpu(0, to_cpumask(tegra_cpu_init_bits));