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:
Arnd Bergmann 2020-03-25 20:58:56 +01:00
commit 10996b2404
15 changed files with 152 additions and 317 deletions

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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
*

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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 */

View File

@ -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__ */