--- zzzz-none-000/linux-3.10.107/arch/arm/mach-tegra/cpuidle-tegra20.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/arm/mach-tegra/cpuidle-tegra20.c 2021-02-04 17:41:59.000000000 +0000 @@ -19,23 +19,23 @@ * more details. */ -#include -#include +#include +#include #include #include -#include -#include +#include +#include #include -#include -#include #include +#include -#include "pm.h" -#include "sleep.h" +#include "flowctrl.h" #include "iomap.h" #include "irq.h" -#include "flowctrl.h" +#include "pm.h" +#include "reset.h" +#include "sleep.h" #ifdef CONFIG_PM_SLEEP static bool abort_flag; @@ -59,8 +59,7 @@ .exit_latency = 5000, .target_residency = 10000, .power_usage = 0, - .flags = CPUIDLE_FLAG_TIME_VALID | - CPUIDLE_FLAG_COUPLED, + .flags = CPUIDLE_FLAG_COUPLED, .name = "powered-down", .desc = "CPU power gated", }, @@ -72,15 +71,13 @@ #ifdef CONFIG_PM_SLEEP #ifdef CONFIG_SMP -static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); - static int tegra20_reset_sleeping_cpu_1(void) { int ret = 0; tegra_pen_lock(); - if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE) + if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE) tegra20_cpu_shutdown(1); else ret = -EINVAL; @@ -137,11 +134,11 @@ if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) return false; - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); + tick_broadcast_enter(); tegra_idle_lp2_last(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); + tick_broadcast_exit(); if (cpu_online(1)) tegra20_wake_cpu1_from_reset(); @@ -154,13 +151,13 @@ struct cpuidle_driver *drv, int index) { - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); + tick_broadcast_enter(); cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); tegra20_cpu_clear_resettable(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); + tick_broadcast_exit(); return true; } @@ -177,7 +174,6 @@ struct cpuidle_driver *drv, int index) { - u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; if (tegra_pending_sgi()) @@ -193,16 +189,16 @@ local_fiq_disable(); - tegra_set_cpu_in_lp2(cpu); + tegra_set_cpu_in_lp2(); cpu_pm_enter(); - if (cpu == 0) + if (dev->cpu == 0) entered_lp2 = tegra20_cpu_cluster_power_down(dev, drv, index); else entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index); cpu_pm_exit(); - tegra_clear_cpu_in_lp2(cpu); + tegra_clear_cpu_in_lp2(); local_fiq_enable(); @@ -212,10 +208,19 @@ } #endif +/* + * Tegra20 HW appears to have a bug such that PCIe device interrupts, whether + * they are legacy IRQs or MSI, are lost when LP2 is enabled. To work around + * this, simply disable LP2 if the PCI driver and DT node are both enabled. + */ +void tegra20_cpuidle_pcie_irqs_in_use(void) +{ + pr_info_once( + "Disabling cpuidle LP2 state, since PCIe IRQs are in use\n"); + tegra_idle_driver.states[1].disabled = true; +} + int __init tegra20_cpuidle_init(void) { -#ifdef CONFIG_PM_SLEEP - tegra_tear_down_cpu = tegra20_tear_down_cpu; -#endif return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); }