struct tegra210_pm_data {
bool cc4_no_retention;
bool cc3_no_hvc;
+ bool cc6_allow;
/* Idle state index array */
int idle_state_idx[IDLE_STATE_MAX];
};
static int proc_idle_state_enter(int cpu, int idle_state)
{
u32 ctrl;
-
ctrl = 0xffffffff;
if (t210_pm_data.cc4_no_retention)
flowctrl_write_cc4_ctrl(cpu, ctrl);
+ if (idle_state == t210_pm_data.idle_state_idx[CC6_IDX] &&
+ !t210_pm_data.cc6_allow)
+ return -ENODEV;
+
return 0;
}
static int __init tegra210_cpuidle_init(void)
{
+ struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+ struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+ int i;
+
if (tegra_get_chip_id() != TEGRA210)
goto out;
platform_driver_register(&tegra210_cpuidle_driver);
debugfs_init();
+
+ /*
+ * Disable CC6 during boot. They can be enabled later using the
+ * fast_cluster_enable knobs from userspace.
+ */
+ for (i = drv->safe_state_index + 1; i < drv->state_count; i++)
+ if (i == t210_pm_data.idle_state_idx[CC6_IDX])
+ drv->states[i].disabled = true;
+
+ t210_pm_data.cc6_allow = true;
+
out:
return 0;
}
/* Disable CC4 until DFLL clk is ready */
t210_pm_data.cc4_no_retention = true;
+ /*
+ * CC6 also needs to be disabled until DFLL clk is ready, but there is
+ * no explicit hook that notifies when the DFLL init is complete. The
+ * cluster states can be disabled in the arm cpuidle driver which may
+ * not be ready here. Use this flag until the tegra_cpuidle driver
+ * disables the arm cpuidle driver's states during late_init.
+ */
+ t210_pm_data.cc6_allow = false;
+
t210_pm_data.idle_state_idx[C7_IDX] =
tegra_of_idle_state_idx_from_name("c7");
t210_pm_data.idle_state_idx[CC6_IDX] =
tegra210_cpu_pm_register_notifier(&tegra210_cpu_pm_nb);
register_cpu_notifier(&tegra210_cpu_nb);
register_syscore_ops(&bpmp_sc7_suspend_ops);
-
out:
return 0;
}