ARM: tegra: Core changes for v5.7-rc1
These patches a preparatory work to move the CPU idle drivers into drivers/cpuidle. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEiOrDCAFJzPfAjcif3SOs138+s6EFAl5rtDcTHHRyZWRpbmdA bnZpZGlhLmNvbQAKCRDdI6zXfz6zoYSRD/98HactRMwJb41LlLpaUeNT/xTQk/DB k+Y0NkeiT34QE7c+UcSeDXecnipuajB3kB7kd64lSS0DI0V+KZam1qZUsMTqG7D3 ZLvzIJXykoGf19QC89nN7TnRy/jjRO8ITk/dFjj1BwSP0M1WuWlQAHNXczRyEP77 OLvViPH8YzLkDe2TH8AhbF/zCCnmW9lqCE8oJuQMdMmQo3qOLL6c/CZcxkzo3iVn rUu1uIgNXiY5fBTgl1woP7mSHgYytjAm4WouSpJRoPAodKqlaI61rb7gwbrav+rQ 2kkORNxOr5Eo36wszxxzknY18PCCjbZtNFrZyAGdmu0IePDdxMiWG2z+30OGESam qlzia0Yz82pSBBRgxVO03oTpZGh9jxdHoubIRR3UGVAttD8rdC4xjIkxjv+FbPp/ A0yVKqA5GFpftUKOKFoC056nByfH2UE1XrPoPWKuu9+ED5vKh7tC4cMEJhhUOA6N 6+pqE8FsZ0NTjxT7pvrPtvTI9lCVy8UTTWQomnd1HMxT2tJEijq1mTVPrsZISYQq +DDsww1UpblslFQwZMoGp8D9IXF3VdvmQae/0ko63XUYDw2Nz4gP7yw+mQoDoALP M9W3FE2XK3u0NsCV76nG1yjJ6CtHgMnZx+DM4VwNZ5m29XUvmdwVwcsv2lrP0TES HWpsPD3vQdatug== =nOBN -----END PGP SIGNATURE----- Merge tag 'tegra-for-5.7-arm-core' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into arm/soc ARM: tegra: Core changes for v5.7-rc1 These patches a preparatory work to move the CPU idle drivers into drivers/cpuidle. * tag 'tegra-for-5.7-arm-core' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: ARM: tegra: cpuidle: Remove unnecessary memory barrier ARM: tegra: cpuidle: Make abort_flag atomic ARM: tegra: cpuidle: Handle case where secondary CPU hangs on entering LP2 ARM: tegra: Make outer_disable() open-coded ARM: tegra: Rename some of the newly exposed PM functions ARM: tegra: Expose PM functions required for new cpuidle driver ARM: tegra: Propagate error from tegra_idle_lp2_last() ARM: tegra: Change tegra_set_cpu_in_lp2() type to void ARM: tegra: Remove pen-locking from cpuidle-tegra20 ARM: tegra: Add tegra_pm_park_secondary_cpu() ARM: tegra: Compile sleep-tegra20/30.S unconditionally Link: https://lore.kernel.org/r/20200313165848.2915133-5-thierry.reding@gmail.com Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
10996b2404
@ -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
|
||||
@ -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
|
||||
|
@ -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
|
||||
@ -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();
|
||||
|
||||
|
@ -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>
|
||||
@ -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,
|
||||
@ -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);
|
||||
|
||||
@ -95,45 +76,74 @@ static void tegra20_wake_cpu1_from_reset(void)
|
||||
|
||||
/* unhalt the cpu */
|
||||
flowctrl_write_cpu_halt(1, 0);
|
||||
|
||||
tegra_pen_unlock();
|
||||
}
|
||||
|
||||
static int tegra20_reset_cpu_1(void)
|
||||
{
|
||||
if (!cpu_online(1) || !tegra20_reset_sleeping_cpu_1())
|
||||
return 0;
|
||||
|
||||
tegra20_wake_cpu1_from_reset();
|
||||
return -EBUSY;
|
||||
}
|
||||
#else
|
||||
static inline void tegra20_wake_cpu1_from_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int tegra20_reset_cpu_1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tegra20_report_cpus_state(void)
|
||||
{
|
||||
unsigned long cpu, lcpu, csr;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
@ -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;
|
||||
}
|
||||
@ -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)
|
||||
@ -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
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
else
|
||||
cpu_do_idle();
|
||||
} else {
|
||||
if (dev->cpu == 0)
|
||||
entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index);
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -110,7 +110,7 @@ static void suspend_cpu_complex(void)
|
||||
flowctrl_cpu_suspend_enter(cpu);
|
||||
}
|
||||
|
||||
void tegra_clear_cpu_in_lp2(void)
|
||||
void tegra_pm_clear_cpu_in_lp2(void)
|
||||
{
|
||||
int phy_cpu_id = cpu_logical_map(smp_processor_id());
|
||||
u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
|
||||
@ -123,11 +123,9 @@ void tegra_clear_cpu_in_lp2(void)
|
||||
spin_unlock(&tegra_lp2_lock);
|
||||
}
|
||||
|
||||
bool tegra_set_cpu_in_lp2(void)
|
||||
void tegra_pm_set_cpu_in_lp2(void)
|
||||
{
|
||||
int phy_cpu_id = cpu_logical_map(smp_processor_id());
|
||||
bool last_cpu = false;
|
||||
cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
|
||||
u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
|
||||
|
||||
spin_lock(&tegra_lp2_lock);
|
||||
@ -135,22 +133,15 @@ bool tegra_set_cpu_in_lp2(void)
|
||||
BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
|
||||
*cpu_in_lp2 |= BIT(phy_cpu_id);
|
||||
|
||||
if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
|
||||
last_cpu = true;
|
||||
else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1)
|
||||
tegra20_cpu_set_resettable_soon();
|
||||
|
||||
spin_unlock(&tegra_lp2_lock);
|
||||
return last_cpu;
|
||||
}
|
||||
|
||||
int tegra_cpu_do_idle(void)
|
||||
{
|
||||
return cpu_do_idle();
|
||||
}
|
||||
|
||||
static int tegra_sleep_cpu(unsigned long v2p)
|
||||
{
|
||||
if (tegra_cpu_car_ops->rail_off_ready &&
|
||||
WARN_ON(!tegra_cpu_rail_off_ready()))
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* L2 cache disabling using kernel API only allowed when all
|
||||
* secondary CPU's are offline. Cache have to be disabled with
|
||||
@ -159,9 +150,10 @@ static int tegra_sleep_cpu(unsigned long v2p)
|
||||
* if any of secondary CPU's is online and this is the LP2-idle
|
||||
* code-path only for Tegra20/30.
|
||||
*/
|
||||
if (trusted_foundations_registered())
|
||||
outer_disable();
|
||||
|
||||
#ifdef CONFIG_OUTER_CACHE
|
||||
if (trusted_foundations_registered() && outer_cache.disable)
|
||||
outer_cache.disable();
|
||||
#endif
|
||||
/*
|
||||
* Note that besides of setting up CPU reset vector this firmware
|
||||
* call may also do the following, depending on the FW version:
|
||||
@ -202,14 +194,16 @@ static void tegra_pm_set(enum tegra_suspend_mode mode)
|
||||
tegra_pmc_enter_suspend_mode(mode);
|
||||
}
|
||||
|
||||
void tegra_idle_lp2_last(void)
|
||||
int tegra_pm_enter_lp2(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
tegra_pm_set(TEGRA_SUSPEND_LP2);
|
||||
|
||||
cpu_cluster_pm_enter();
|
||||
suspend_cpu_complex();
|
||||
|
||||
cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
|
||||
err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
|
||||
|
||||
/*
|
||||
* Resume L2 cache if it wasn't re-enabled early during resume,
|
||||
@ -221,6 +215,8 @@ void tegra_idle_lp2_last(void)
|
||||
|
||||
restore_cpu_complex();
|
||||
cpu_cluster_pm_exit();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
|
||||
@ -365,7 +361,7 @@ static int tegra_suspend_enter(suspend_state_t state)
|
||||
tegra_suspend_enter_lp1();
|
||||
break;
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
tegra_set_cpu_in_lp2();
|
||||
tegra_pm_set_cpu_in_lp2();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -386,7 +382,7 @@ static int tegra_suspend_enter(suspend_state_t state)
|
||||
tegra_suspend_exit_lp1();
|
||||
break;
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
tegra_clear_cpu_in_lp2();
|
||||
tegra_pm_clear_cpu_in_lp2();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -436,4 +432,18 @@ void __init tegra_init_suspend(void)
|
||||
|
||||
suspend_set_ops(&tegra_suspend_ops);
|
||||
}
|
||||
|
||||
int tegra_pm_park_secondary_cpu(unsigned long cpu)
|
||||
{
|
||||
if (cpu > 0) {
|
||||
tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS);
|
||||
|
||||
if (tegra_get_chip_id() == TEGRA20)
|
||||
tegra20_hotplug_shutdown();
|
||||
else
|
||||
tegra30_hotplug_shutdown();
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
@ -23,10 +23,6 @@ void tegra20_sleep_core_init(void);
|
||||
void tegra30_lp1_iram_hook(void);
|
||||
void tegra30_sleep_core_init(void);
|
||||
|
||||
void tegra_clear_cpu_in_lp2(void);
|
||||
bool tegra_set_cpu_in_lp2(void);
|
||||
int tegra_cpu_do_idle(void);
|
||||
void tegra_idle_lp2_last(void);
|
||||
extern void (*tegra_tear_down_cpu)(void);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -183,17 +183,6 @@ after_errata:
|
||||
bleq __die @ CPU not present (to OS)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
/* Are we on Tegra20? */
|
||||
cmp r6, #TEGRA20
|
||||
bne 1f
|
||||
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
|
||||
mov r0, #CPU_NOT_RESETTABLE
|
||||
cmp r10, #0
|
||||
strbne r0, [r12, #RESET_DATA(RESETTABLE_STATUS)]
|
||||
1:
|
||||
#endif
|
||||
|
||||
/* Waking up from LP1? */
|
||||
ldr r8, [r12, #RESET_DATA(MASK_LP1)]
|
||||
tst r8, r11 @ if in_lp1
|
||||
|
@ -16,9 +16,8 @@
|
||||
#define TEGRA_RESET_STARTUP_SECONDARY 3
|
||||
#define TEGRA_RESET_STARTUP_LP2 4
|
||||
#define TEGRA_RESET_STARTUP_LP1 5
|
||||
#define TEGRA_RESET_RESETTABLE_STATUS 6
|
||||
#define TEGRA_RESET_TF_PRESENT 7
|
||||
#define TEGRA_RESET_DATA_SIZE 8
|
||||
#define TEGRA_RESET_TF_PRESENT 6
|
||||
#define TEGRA_RESET_DATA_SIZE 7
|
||||
|
||||
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
|
||||
|
||||
@ -42,10 +41,6 @@ void __tegra_cpu_reset_handler_end(void);
|
||||
(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
|
||||
((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
|
||||
(u32)__tegra_cpu_reset_handler_start)))
|
||||
#define tegra20_cpu1_resettable_status \
|
||||
(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
|
||||
((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_RESETTABLE_STATUS] - \
|
||||
(u32)__tegra_cpu_reset_handler_start)))
|
||||
#endif
|
||||
|
||||
#define tegra_cpu_reset_handler_offset \
|
||||
|
@ -43,9 +43,6 @@
|
||||
#define APB_MISC_XM2CFGCPADCTRL2 0x8e4
|
||||
#define APB_MISC_XM2CFGDPADCTRL2 0x8e8
|
||||
|
||||
#define __tegra20_cpu1_resettable_status_offset \
|
||||
(__tegra_cpu_reset_handler_data_offset + RESET_DATA(RESETTABLE_STATUS))
|
||||
|
||||
.macro pll_enable, rd, r_car_base, pll_base
|
||||
ldr \rd, [\r_car_base, #\pll_base]
|
||||
tst \rd, #(1 << 30)
|
||||
@ -90,10 +87,6 @@ ENDPROC(tegra20_hotplug_shutdown)
|
||||
ENTRY(tegra20_cpu_shutdown)
|
||||
cmp r0, #0
|
||||
reteq lr @ must not be called for CPU 0
|
||||
mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
|
||||
ldr r2, =__tegra20_cpu1_resettable_status_offset
|
||||
mov r12, #CPU_RESETTABLE
|
||||
strb r12, [r1, r2]
|
||||
|
||||
cpu_to_halt_reg r1, r0
|
||||
ldr r3, =TEGRA_FLOW_CTRL_VIRT
|
||||
@ -116,107 +109,6 @@ ENDPROC(tegra20_cpu_shutdown)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* tegra_pen_lock
|
||||
*
|
||||
* spinlock implementation with no atomic test-and-set and no coherence
|
||||
* using Peterson's algorithm on strongly-ordered registers
|
||||
* used to synchronize a cpu waking up from wfi with entering lp2 on idle
|
||||
*
|
||||
* The reference link of Peterson's algorithm:
|
||||
* http://en.wikipedia.org/wiki/Peterson's_algorithm
|
||||
*
|
||||
* SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
|
||||
* on cpu 0:
|
||||
* r2 = flag[0] (in SCRATCH38)
|
||||
* r3 = flag[1] (in SCRATCH39)
|
||||
* on cpu1:
|
||||
* r2 = flag[1] (in SCRATCH39)
|
||||
* r3 = flag[0] (in SCRATCH38)
|
||||
*
|
||||
* must be called with MMU on
|
||||
* corrupts r0-r3, r12
|
||||
*/
|
||||
ENTRY(tegra_pen_lock)
|
||||
mov32 r3, TEGRA_PMC_VIRT
|
||||
cpu_id r0
|
||||
add r1, r3, #PMC_SCRATCH37
|
||||
cmp r0, #0
|
||||
addeq r2, r3, #PMC_SCRATCH38
|
||||
addeq r3, r3, #PMC_SCRATCH39
|
||||
addne r2, r3, #PMC_SCRATCH39
|
||||
addne r3, r3, #PMC_SCRATCH38
|
||||
|
||||
mov r12, #1
|
||||
str r12, [r2] @ flag[cpu] = 1
|
||||
dsb
|
||||
str r12, [r1] @ !turn = cpu
|
||||
1: dsb
|
||||
ldr r12, [r3]
|
||||
cmp r12, #1 @ flag[!cpu] == 1?
|
||||
ldreq r12, [r1]
|
||||
cmpeq r12, r0 @ !turn == cpu?
|
||||
beq 1b @ while !turn == cpu && flag[!cpu] == 1
|
||||
|
||||
ret lr @ locked
|
||||
ENDPROC(tegra_pen_lock)
|
||||
|
||||
ENTRY(tegra_pen_unlock)
|
||||
dsb
|
||||
mov32 r3, TEGRA_PMC_VIRT
|
||||
cpu_id r0
|
||||
cmp r0, #0
|
||||
addeq r2, r3, #PMC_SCRATCH38
|
||||
addne r2, r3, #PMC_SCRATCH39
|
||||
mov r12, #0
|
||||
str r12, [r2]
|
||||
ret lr
|
||||
ENDPROC(tegra_pen_unlock)
|
||||
|
||||
/*
|
||||
* tegra20_cpu_clear_resettable(void)
|
||||
*
|
||||
* Called to clear the "resettable soon" flag in IRAM variable when
|
||||
* it is expected that the secondary CPU will be idle soon.
|
||||
*/
|
||||
ENTRY(tegra20_cpu_clear_resettable)
|
||||
mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
|
||||
ldr r2, =__tegra20_cpu1_resettable_status_offset
|
||||
mov r12, #CPU_NOT_RESETTABLE
|
||||
strb r12, [r1, r2]
|
||||
ret lr
|
||||
ENDPROC(tegra20_cpu_clear_resettable)
|
||||
|
||||
/*
|
||||
* tegra20_cpu_set_resettable_soon(void)
|
||||
*
|
||||
* Called to set the "resettable soon" flag in IRAM variable when
|
||||
* it is expected that the secondary CPU will be idle soon.
|
||||
*/
|
||||
ENTRY(tegra20_cpu_set_resettable_soon)
|
||||
mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
|
||||
ldr r2, =__tegra20_cpu1_resettable_status_offset
|
||||
mov r12, #CPU_RESETTABLE_SOON
|
||||
strb r12, [r1, r2]
|
||||
ret lr
|
||||
ENDPROC(tegra20_cpu_set_resettable_soon)
|
||||
|
||||
/*
|
||||
* tegra20_cpu_is_resettable_soon(void)
|
||||
*
|
||||
* Returns true if the "resettable soon" flag in IRAM variable has been
|
||||
* set because it is expected that the secondary CPU will be idle soon.
|
||||
*/
|
||||
ENTRY(tegra20_cpu_is_resettable_soon)
|
||||
mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
|
||||
ldr r2, =__tegra20_cpu1_resettable_status_offset
|
||||
ldrb r12, [r1, r2]
|
||||
cmp r12, #CPU_RESETTABLE_SOON
|
||||
moveq r0, #1
|
||||
movne r0, #0
|
||||
ret lr
|
||||
ENDPROC(tegra20_cpu_is_resettable_soon)
|
||||
|
||||
/*
|
||||
* tegra20_sleep_core_finish(unsigned long v2p)
|
||||
*
|
||||
@ -242,68 +134,6 @@ ENTRY(tegra20_sleep_core_finish)
|
||||
ret r3
|
||||
ENDPROC(tegra20_sleep_core_finish)
|
||||
|
||||
/*
|
||||
* tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
|
||||
*
|
||||
* Enters WFI on secondary CPU by exiting coherency.
|
||||
*/
|
||||
ENTRY(tegra20_sleep_cpu_secondary_finish)
|
||||
stmfd sp!, {r4-r11, lr}
|
||||
|
||||
mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency
|
||||
|
||||
/* Flush and disable the L1 data cache */
|
||||
mov r0, #TEGRA_FLUSH_CACHE_LOUIS
|
||||
bl tegra_disable_clean_inv_dcache
|
||||
|
||||
mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
|
||||
ldr r4, =__tegra20_cpu1_resettable_status_offset
|
||||
mov r3, #CPU_RESETTABLE
|
||||
strb r3, [r0, r4]
|
||||
|
||||
bl tegra_cpu_do_idle
|
||||
|
||||
/*
|
||||
* cpu may be reset while in wfi, which will return through
|
||||
* tegra_resume to cpu_resume
|
||||
* or interrupt may wake wfi, which will return here
|
||||
* cpu state is unchanged - MMU is on, cache is on, coherency
|
||||
* is off, and the data cache is off
|
||||
*
|
||||
* r11 contains the original actlr
|
||||
*/
|
||||
|
||||
bl tegra_pen_lock
|
||||
|
||||
mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
|
||||
ldr r4, =__tegra20_cpu1_resettable_status_offset
|
||||
mov r3, #CPU_NOT_RESETTABLE
|
||||
strb r3, [r0, r4]
|
||||
|
||||
bl tegra_pen_unlock
|
||||
|
||||
/* Re-enable the data cache */
|
||||
mrc p15, 0, r10, c1, c0, 0
|
||||
orr r10, r10, #CR_C
|
||||
mcr p15, 0, r10, c1, c0, 0
|
||||
isb
|
||||
|
||||
mcr p15, 0, r11, c1, c0, 1 @ reenable coherency
|
||||
|
||||
/* Invalidate the TLBs & BTAC */
|
||||
mov r1, #0
|
||||
mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
|
||||
mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC
|
||||
dsb
|
||||
isb
|
||||
|
||||
/* the cpu was running with coherency disabled,
|
||||
* caches may be out of date */
|
||||
bl v7_flush_kern_cache_louis
|
||||
|
||||
ldmfd sp!, {r4 - r11, pc}
|
||||
ENDPROC(tegra20_sleep_cpu_secondary_finish)
|
||||
|
||||
/*
|
||||
* tegra20_tear_down_cpu
|
||||
*
|
||||
|
@ -265,11 +265,11 @@ ENTRY(tegra30_sleep_core_finish)
|
||||
ENDPROC(tegra30_sleep_core_finish)
|
||||
|
||||
/*
|
||||
* tegra30_sleep_cpu_secondary_finish(unsigned long v2p)
|
||||
* tegra30_pm_secondary_cpu_suspend(unsigned long unused_arg)
|
||||
*
|
||||
* Enters LP2 on secondary CPU by exiting coherency and powergating the CPU.
|
||||
*/
|
||||
ENTRY(tegra30_sleep_cpu_secondary_finish)
|
||||
ENTRY(tegra30_pm_secondary_cpu_suspend)
|
||||
mov r7, lr
|
||||
|
||||
/* Flush and disable the L1 data cache */
|
||||
@ -281,7 +281,7 @@ ENTRY(tegra30_sleep_cpu_secondary_finish)
|
||||
bl tegra30_cpu_shutdown
|
||||
mov r0, #1 @ never return here
|
||||
ret r7
|
||||
ENDPROC(tegra30_sleep_cpu_secondary_finish)
|
||||
ENDPROC(tegra30_pm_secondary_cpu_suspend)
|
||||
|
||||
/*
|
||||
* tegra30_tear_down_cpu
|
||||
|
@ -114,29 +114,14 @@
|
||||
.endm
|
||||
|
||||
#else
|
||||
void tegra_pen_lock(void);
|
||||
void tegra_pen_unlock(void);
|
||||
void tegra_resume(void);
|
||||
int tegra_sleep_cpu_finish(unsigned long);
|
||||
void tegra_disable_clean_inv_dcache(u32 flag);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void tegra20_hotplug_shutdown(void);
|
||||
void tegra30_hotplug_shutdown(void);
|
||||
#endif
|
||||
|
||||
void tegra20_cpu_shutdown(int cpu);
|
||||
int tegra20_cpu_is_resettable_soon(void);
|
||||
void tegra20_cpu_clear_resettable(void);
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
void tegra20_cpu_set_resettable_soon(void);
|
||||
#else
|
||||
static inline void tegra20_cpu_set_resettable_soon(void) {}
|
||||
#endif
|
||||
|
||||
int tegra20_sleep_cpu_secondary_finish(unsigned long);
|
||||
void tegra20_tear_down_cpu(void);
|
||||
int tegra30_sleep_cpu_secondary_finish(unsigned long);
|
||||
void tegra30_tear_down_cpu(void);
|
||||
|
||||
#endif
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include "common.h"
|
||||
#include "cpuidle.h"
|
||||
#include "iomap.h"
|
||||
#include "irq.h"
|
||||
#include "pm.h"
|
||||
#include "reset.h"
|
||||
#include "sleep.h"
|
||||
|
@ -3,9 +3,11 @@
|
||||
* Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __TEGRA_IRQ_H
|
||||
#define __TEGRA_IRQ_H
|
||||
#ifndef __SOC_TEGRA_IRQ_H
|
||||
#define __SOC_TEGRA_IRQ_H
|
||||
|
||||
#if defined(CONFIG_ARM)
|
||||
bool tegra_pending_sgi(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __SOC_TEGRA_IRQ_H */
|
@ -6,6 +6,8 @@
|
||||
#ifndef __SOC_TEGRA_PM_H__
|
||||
#define __SOC_TEGRA_PM_H__
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
enum tegra_suspend_mode {
|
||||
TEGRA_SUSPEND_NONE = 0,
|
||||
TEGRA_SUSPEND_LP2, /* CPU voltage off */
|
||||
@ -20,6 +22,12 @@ tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
|
||||
|
||||
/* low-level resume entry point */
|
||||
void tegra_resume(void);
|
||||
|
||||
int tegra30_pm_secondary_cpu_suspend(unsigned long arg);
|
||||
void tegra_pm_clear_cpu_in_lp2(void);
|
||||
void tegra_pm_set_cpu_in_lp2(void);
|
||||
int tegra_pm_enter_lp2(void);
|
||||
int tegra_pm_park_secondary_cpu(unsigned long cpu);
|
||||
#else
|
||||
static inline enum tegra_suspend_mode
|
||||
tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
|
||||
@ -30,6 +38,29 @@ tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode)
|
||||
static inline void tegra_resume(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int tegra30_pm_secondary_cpu_suspend(unsigned long arg)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline void tegra_pm_clear_cpu_in_lp2(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void tegra_pm_set_cpu_in_lp2(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int tegra_pm_enter_lp2(void)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int tegra_pm_park_secondary_cpu(unsigned long cpu)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#endif /* __SOC_TEGRA_PM_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user