Loading arch/arm/mach-tegra/Makefile +2 −4 Original line number Diff line number Diff line Loading @@ -8,13 +8,13 @@ obj-y += reset.o obj-y += reset-handler.o obj-y += sleep.o obj-y += tegra.o obj-y += sleep-tegra20.o obj-y += sleep-tegra30.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o endif obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o Loading @@ -22,12 +22,10 @@ endif obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o endif obj-$(CONFIG_ARCH_TEGRA_124_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_124_SOC) += cpuidle-tegra114.o Loading arch/arm/mach-tegra/cpuidle-tegra114.c +5 −4 Original line number Diff line number Diff line Loading @@ -12,13 +12,14 @@ #include <linux/firmware/trusted_foundations.h> #include <soc/tegra/pm.h> #include <asm/cpuidle.h> #include <asm/smp_plat.h> #include <asm/suspend.h> #include <asm/psci.h> #include "cpuidle.h" #include "pm.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP Loading @@ -34,17 +35,17 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, { local_fiq_disable(); tegra_set_cpu_in_lp2(); tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); /* Do suspend by ourselves if the firmware does not implement it */ if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); cpu_pm_exit(); tegra_clear_cpu_in_lp2(); tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); Loading arch/arm/mach-tegra/cpuidle-tegra20.c +59 −52 Original line number Diff line number Diff line Loading @@ -14,10 +14,13 @@ #include <linux/tick.h> #include <linux/cpuidle.h> #include <linux/cpu_pm.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <soc/tegra/flowctrl.h> #include <soc/tegra/irq.h> #include <soc/tegra/pm.h> #include <asm/cpuidle.h> #include <asm/smp_plat.h> Loading @@ -25,13 +28,11 @@ #include "cpuidle.h" #include "iomap.h" #include "irq.h" #include "pm.h" #include "reset.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP static bool abort_flag; static atomic_t abort_flag; static atomic_t abort_barrier; static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, Loading Loading @@ -65,28 +66,8 @@ static struct cpuidle_driver tegra_idle_driver = { #ifdef CONFIG_PM_SLEEP #ifdef CONFIG_SMP static int tegra20_reset_sleeping_cpu_1(void) { int ret = 0; tegra_pen_lock(); if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE) tegra20_cpu_shutdown(1); else ret = -EINVAL; tegra_pen_unlock(); return ret; } static void tegra20_wake_cpu1_from_reset(void) { tegra_pen_lock(); tegra20_cpu_clear_resettable(); /* enable cpu clock on cpu */ tegra_enable_cpu_clock(1); Loading @@ -95,45 +76,74 @@ static void tegra20_wake_cpu1_from_reset(void) /* unhalt the cpu */ flowctrl_write_cpu_halt(1, 0); tegra_pen_unlock(); } #else static inline void tegra20_wake_cpu1_from_reset(void) { } #endif static int tegra20_reset_cpu_1(void) static void tegra20_report_cpus_state(void) { if (!cpu_online(1) || !tegra20_reset_sleeping_cpu_1()) return 0; unsigned long cpu, lcpu, csr; tegra20_wake_cpu1_from_reset(); return -EBUSY; for_each_cpu(lcpu, cpu_possible_mask) { cpu = cpu_logical_map(lcpu); csr = flowctrl_read_cpu_csr(cpu); pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n", cpu, cpu_online(lcpu), csr); } #else static inline void tegra20_wake_cpu1_from_reset(void) { } static inline int tegra20_reset_cpu_1(void) static int tegra20_wait_for_secondary_cpu_parking(void) { unsigned int retries = 3; while (retries--) { unsigned int delay_us = 10; unsigned int timeout_us = 500 * 1000 / delay_us; /* * The primary CPU0 core shall wait for the secondaries * shutdown in order to power-off CPU's cluster safely. * The timeout value depends on the current CPU frequency, * it takes about 40-150us in average and over 1000us in * a worst case scenario. */ do { if (tegra_cpu_rail_off_ready()) return 0; udelay(delay_us); } while (timeout_us--); pr_err("secondary CPU taking too long to park\n"); tegra20_report_cpus_state(); } pr_err("timed out waiting secondaries to park\n"); return -ETIMEDOUT; } #endif static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { while (tegra20_cpu_is_resettable_soon()) cpu_relax(); bool ret; if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) if (tegra20_wait_for_secondary_cpu_parking()) return false; tegra_idle_lp2_last(); ret = !tegra_pm_enter_lp2(); if (cpu_online(1)) tegra20_wake_cpu1_from_reset(); return true; return ret; } #ifdef CONFIG_SMP Loading @@ -141,9 +151,7 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); tegra20_cpu_clear_resettable(); cpu_suspend(dev->cpu, tegra_pm_park_secondary_cpu); return true; } Loading @@ -163,19 +171,20 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, bool entered_lp2 = false; if (tegra_pending_sgi()) WRITE_ONCE(abort_flag, true); atomic_set(&abort_flag, 1); cpuidle_coupled_parallel_barrier(dev, &abort_barrier); if (abort_flag) { if (atomic_read(&abort_flag)) { cpuidle_coupled_parallel_barrier(dev, &abort_barrier); abort_flag = false; /* clean flag for next coming */ /* clean flag for next coming */ atomic_set(&abort_flag, 0); return -EINTR; } local_fiq_disable(); tegra_set_cpu_in_lp2(); tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); if (dev->cpu == 0) Loading @@ -184,12 +193,10 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index); cpu_pm_exit(); tegra_clear_cpu_in_lp2(); tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); smp_rmb(); return entered_lp2 ? index : 0; } #endif Loading arch/arm/mach-tegra/cpuidle-tegra30.c +9 −18 Original line number Diff line number Diff line Loading @@ -17,12 +17,13 @@ #include <linux/kernel.h> #include <linux/module.h> #include <soc/tegra/pm.h> #include <asm/cpuidle.h> #include <asm/smp_plat.h> #include <asm/suspend.h> #include "cpuidle.h" #include "pm.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP Loading Loading @@ -68,9 +69,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, return false; } tegra_idle_lp2_last(); return true; return !tegra_pm_enter_lp2(); } #ifdef CONFIG_SMP Loading @@ -80,7 +79,7 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, { smp_wmb(); cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); return true; } Loading @@ -98,30 +97,22 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev, int index) { bool entered_lp2 = false; bool last_cpu; local_fiq_disable(); last_cpu = tegra_set_cpu_in_lp2(); tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); if (dev->cpu == 0) { if (last_cpu) entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index); if (dev->cpu == 0) entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index); else cpu_do_idle(); } else { entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index); } cpu_pm_exit(); tegra_clear_cpu_in_lp2(); tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); smp_rmb(); return (entered_lp2) ? index : 0; } #endif Loading arch/arm/mach-tegra/irq.c +2 −1 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ #include <linux/of.h> #include <linux/syscore_ops.h> #include <soc/tegra/irq.h> #include "board.h" #include "iomap.h" #include "irq.h" #define SGI_MASK 0xFFFF Loading Loading
arch/arm/mach-tegra/Makefile +2 −4 Original line number Diff line number Diff line Loading @@ -8,13 +8,13 @@ obj-y += reset.o obj-y += reset-handler.o obj-y += sleep.o obj-y += tegra.o obj-y += sleep-tegra20.o obj-y += sleep-tegra30.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o endif obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o Loading @@ -22,12 +22,10 @@ endif obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o endif obj-$(CONFIG_ARCH_TEGRA_124_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_124_SOC) += cpuidle-tegra114.o Loading
arch/arm/mach-tegra/cpuidle-tegra114.c +5 −4 Original line number Diff line number Diff line Loading @@ -12,13 +12,14 @@ #include <linux/firmware/trusted_foundations.h> #include <soc/tegra/pm.h> #include <asm/cpuidle.h> #include <asm/smp_plat.h> #include <asm/suspend.h> #include <asm/psci.h> #include "cpuidle.h" #include "pm.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP Loading @@ -34,17 +35,17 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, { local_fiq_disable(); tegra_set_cpu_in_lp2(); tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); /* Do suspend by ourselves if the firmware does not implement it */ if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); cpu_pm_exit(); tegra_clear_cpu_in_lp2(); tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); Loading
arch/arm/mach-tegra/cpuidle-tegra20.c +59 −52 Original line number Diff line number Diff line Loading @@ -14,10 +14,13 @@ #include <linux/tick.h> #include <linux/cpuidle.h> #include <linux/cpu_pm.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <soc/tegra/flowctrl.h> #include <soc/tegra/irq.h> #include <soc/tegra/pm.h> #include <asm/cpuidle.h> #include <asm/smp_plat.h> Loading @@ -25,13 +28,11 @@ #include "cpuidle.h" #include "iomap.h" #include "irq.h" #include "pm.h" #include "reset.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP static bool abort_flag; static atomic_t abort_flag; static atomic_t abort_barrier; static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, Loading Loading @@ -65,28 +66,8 @@ static struct cpuidle_driver tegra_idle_driver = { #ifdef CONFIG_PM_SLEEP #ifdef CONFIG_SMP static int tegra20_reset_sleeping_cpu_1(void) { int ret = 0; tegra_pen_lock(); if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE) tegra20_cpu_shutdown(1); else ret = -EINVAL; tegra_pen_unlock(); return ret; } static void tegra20_wake_cpu1_from_reset(void) { tegra_pen_lock(); tegra20_cpu_clear_resettable(); /* enable cpu clock on cpu */ tegra_enable_cpu_clock(1); Loading @@ -95,45 +76,74 @@ static void tegra20_wake_cpu1_from_reset(void) /* unhalt the cpu */ flowctrl_write_cpu_halt(1, 0); tegra_pen_unlock(); } #else static inline void tegra20_wake_cpu1_from_reset(void) { } #endif static int tegra20_reset_cpu_1(void) static void tegra20_report_cpus_state(void) { if (!cpu_online(1) || !tegra20_reset_sleeping_cpu_1()) return 0; unsigned long cpu, lcpu, csr; tegra20_wake_cpu1_from_reset(); return -EBUSY; for_each_cpu(lcpu, cpu_possible_mask) { cpu = cpu_logical_map(lcpu); csr = flowctrl_read_cpu_csr(cpu); pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n", cpu, cpu_online(lcpu), csr); } #else static inline void tegra20_wake_cpu1_from_reset(void) { } static inline int tegra20_reset_cpu_1(void) static int tegra20_wait_for_secondary_cpu_parking(void) { unsigned int retries = 3; while (retries--) { unsigned int delay_us = 10; unsigned int timeout_us = 500 * 1000 / delay_us; /* * The primary CPU0 core shall wait for the secondaries * shutdown in order to power-off CPU's cluster safely. * The timeout value depends on the current CPU frequency, * it takes about 40-150us in average and over 1000us in * a worst case scenario. */ do { if (tegra_cpu_rail_off_ready()) return 0; udelay(delay_us); } while (timeout_us--); pr_err("secondary CPU taking too long to park\n"); tegra20_report_cpus_state(); } pr_err("timed out waiting secondaries to park\n"); return -ETIMEDOUT; } #endif static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { while (tegra20_cpu_is_resettable_soon()) cpu_relax(); bool ret; if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) if (tegra20_wait_for_secondary_cpu_parking()) return false; tegra_idle_lp2_last(); ret = !tegra_pm_enter_lp2(); if (cpu_online(1)) tegra20_wake_cpu1_from_reset(); return true; return ret; } #ifdef CONFIG_SMP Loading @@ -141,9 +151,7 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); tegra20_cpu_clear_resettable(); cpu_suspend(dev->cpu, tegra_pm_park_secondary_cpu); return true; } Loading @@ -163,19 +171,20 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, bool entered_lp2 = false; if (tegra_pending_sgi()) WRITE_ONCE(abort_flag, true); atomic_set(&abort_flag, 1); cpuidle_coupled_parallel_barrier(dev, &abort_barrier); if (abort_flag) { if (atomic_read(&abort_flag)) { cpuidle_coupled_parallel_barrier(dev, &abort_barrier); abort_flag = false; /* clean flag for next coming */ /* clean flag for next coming */ atomic_set(&abort_flag, 0); return -EINTR; } local_fiq_disable(); tegra_set_cpu_in_lp2(); tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); if (dev->cpu == 0) Loading @@ -184,12 +193,10 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, entered_lp2 = tegra20_idle_enter_lp2_cpu_1(dev, drv, index); cpu_pm_exit(); tegra_clear_cpu_in_lp2(); tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); smp_rmb(); return entered_lp2 ? index : 0; } #endif Loading
arch/arm/mach-tegra/cpuidle-tegra30.c +9 −18 Original line number Diff line number Diff line Loading @@ -17,12 +17,13 @@ #include <linux/kernel.h> #include <linux/module.h> #include <soc/tegra/pm.h> #include <asm/cpuidle.h> #include <asm/smp_plat.h> #include <asm/suspend.h> #include "cpuidle.h" #include "pm.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP Loading Loading @@ -68,9 +69,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, return false; } tegra_idle_lp2_last(); return true; return !tegra_pm_enter_lp2(); } #ifdef CONFIG_SMP Loading @@ -80,7 +79,7 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, { smp_wmb(); cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); return true; } Loading @@ -98,30 +97,22 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev, int index) { bool entered_lp2 = false; bool last_cpu; local_fiq_disable(); last_cpu = tegra_set_cpu_in_lp2(); tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); if (dev->cpu == 0) { if (last_cpu) entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index); if (dev->cpu == 0) entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index); else cpu_do_idle(); } else { entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index); } cpu_pm_exit(); tegra_clear_cpu_in_lp2(); tegra_pm_clear_cpu_in_lp2(); local_fiq_enable(); smp_rmb(); return (entered_lp2) ? index : 0; } #endif Loading
arch/arm/mach-tegra/irq.c +2 −1 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ #include <linux/of.h> #include <linux/syscore_ops.h> #include <soc/tegra/irq.h> #include "board.h" #include "iomap.h" #include "irq.h" #define SGI_MASK 0xFFFF Loading