arm: tegra: Fix initial boot to LP cluster
Scott Williams [Fri, 11 Feb 2011 22:37:19 +0000 (14:37 -0800)]
Forbid cluster switch to G cluster if the G cluster doesn't exist.

Bug 791057

Original-Change-Id: I215de2581edf5fb3c1feaa00d1c6e0b52b15dc23
Reviewed-on: http://git-master/r/19302
Tested-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Original-Change-Id: Id0a7e5ad62df4d1638518fe00715aac60e4efea9

Rebase-Id: Re39a0fedb7bb0e2518cfd56d46c6565d4a6c2ef4

arch/arm/mach-tegra/cpu-tegra3.c
arch/arm/mach-tegra/platsmp.c
arch/arm/mach-tegra/pm-t3.c
arch/arm/mach-tegra/pm.h

index 209220d..9d88b41 100644 (file)
@@ -195,11 +195,15 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work)
 
 void tegra_auto_hotplug_governor(unsigned int cpu_freq)
 {
+       if (!is_g_cluster_present())
+               return;
+
        mutex_lock(&tegra_hp_lock);
 
        if (is_lp_cluster() && (cpu_freq > lpcpu_max_freq)) {
-               tegra_cluster_control(0, TEGRA_POWER_CLUSTER_G |
-                                        TEGRA_POWER_CLUSTER_IMMEDIATE);
+               if (tegra_cluster_control(0, TEGRA_POWER_CLUSTER_G |
+                                            TEGRA_POWER_CLUSTER_IMMEDIATE))
+                       goto fail;
                hp_stats_update(CONFIG_NR_CPUS, false);
                hp_stats_update(0, true);
        }
@@ -241,6 +245,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq)
                       __func__, hp_state);
                BUG();
        }
+fail:
        mutex_unlock(&tegra_hp_lock);
 }
 
index 733b4c3..87b68e1 100644 (file)
@@ -61,10 +61,6 @@ static int power_up_cpu(unsigned int cpu);
 #define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS \
        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x470)
 
-#define FUSE_SKU_DIRECT_CONFIG \
-       (IO_ADDRESS(TEGRA_FUSE_BASE) + 0x1F4)
-#define FUSE_SKU_DISABLE_ALL_CPUS      (1<<5)
-#define FUSE_SKU_NUM_DISABLED_CPUS(x)  (((x) >> 3) & 3)
 #endif
 
 extern void tegra_secondary_startup(void);
@@ -211,7 +207,7 @@ static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
        scu_enable(scu_base);
 }
 
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
 
 static bool is_cpu_powered(unsigned int cpu)
 {
index 66a4365..1d69f7f 100644 (file)
 #define CPU_CLOCK(cpu) (0x1<<(8+cpu))
 #define CPU_RESET(cpu) (0x1111ul<<(cpu))
 
-#define FLOW_CTRL_CLUSTER_CONTROL \
-       (IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x2c)
-
 void tegra_suspend_dram(bool lp0_ok, unsigned int flags);
 
-unsigned int is_lp_cluster(void)
-{
-       unsigned int reg;
-       reg = readl(FLOW_CTRL_CLUSTER_CONTROL);
-       return (reg & 1); /* 0 == G, 1 == LP*/
-}
-
 static int cluster_switch_prolog_clock(unsigned int flags)
 {
        u32 reg;
@@ -313,6 +303,10 @@ int tegra_cluster_control(unsigned int us, unsigned int flags)
        && !(flags & TEGRA_POWER_CLUSTER_FORCE))
                return -EEXIST;
 
+       if (target_cluster == TEGRA_POWER_CLUSTER_G)
+               if (!is_g_cluster_present())
+                       return -EPERM;
+
        if (flags & TEGRA_POWER_CLUSTER_IMMEDIATE)
                us = 0;
 
index 9ee5b82..f7d3055 100644 (file)
@@ -50,6 +50,14 @@ unsigned long tegra_cpu_power_off_time(void);
 #define TEGRA_POWER_CLUSTER_IMMEDIATE  0x4000  /* Immediate wake */
 #define TEGRA_POWER_CLUSTER_FORCE      0x8000  /* Force switch */
 
+#define FLOW_CTRL_CLUSTER_CONTROL \
+       (IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x2c)
+
+#define FUSE_SKU_DIRECT_CONFIG \
+       (IO_ADDRESS(TEGRA_FUSE_BASE) + 0x1F4)
+#define FUSE_SKU_DISABLE_ALL_CPUS      (1<<5)
+#define FUSE_SKU_NUM_DISABLED_CPUS(x)  (((x) >> 3) & 3)
+
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 void tegra2_lp0_suspend_init(void);
 #else
@@ -89,6 +97,8 @@ static inline int tegra_cluster_control(unsigned int us, unsigned int flags)
 { return -EPERM; }
 #define tegra_cluster_switch_prolog(flags) do {} while(0)
 #define tegra_cluster_switch_epilog(flags) do {} while(0)
+static inline bool is_g_cluster_present(void)
+{ return true; }
 static inline unsigned int is_lp_cluster(void)
 { return 0; }
 static inline unsigned long tegra_get_lpcpu_max_rate(void)
@@ -99,7 +109,19 @@ static inline unsigned long tegra_get_lpcpu_max_rate(void)
 int tegra_cluster_control(unsigned int us, unsigned int flags);
 void tegra_cluster_switch_prolog(unsigned int flags);
 void tegra_cluster_switch_epilog(unsigned int flags);
-unsigned int is_lp_cluster(void);
+static inline bool is_g_cluster_present(void)
+{
+       u32 fuse_sku = readl(FUSE_SKU_DIRECT_CONFIG);
+       if (fuse_sku & FUSE_SKU_DISABLE_ALL_CPUS)
+               return false;
+       return true;
+}
+static inline unsigned int is_lp_cluster(void)
+{
+       unsigned int reg;
+       reg = readl(FLOW_CTRL_CLUSTER_CONTROL);
+       return (reg & 1); /* 0 == G, 1 == LP*/
+}
 unsigned long tegra_get_lpcpu_max_rate(void);
 #endif