forked from Minki/linux
ARM: tegra: core SoC support enhancements
This branch contains fixes and enhancement for core Tegra Soc support: * CPU hotplug support for Tegra114. * Some preliminary work on Tegra114 CPU sleep modes. * Minor fix for EMC table DT parsing. This branch is based on v3.10-rc1. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRu0QvAAoJEMzrak5tbycx/HcP/2TJLW7POi9J1oaSFRbe0dZY JowaiIVv6Bd9EyIisp6vMECVqNeOUbx1aZx/GRnQ8pjOCZnmf4WZO7RyUmJW7B+j gzaIqYECkVVXDJR6YVwXeB3ajRDl4FGTDysD5zLlOZfaKAGwPWgEDDqP5TZVTIBU qp3E9ImEVf7EZCvrlvC9m81LpYqQ+zx77hsPqoP8d/7v1K+2poiAI+BK7Zl5EUsQ uQVEe3q9zaY2adFNz8yhIBqhVIQt5XC9sTOGAlCtxA8IcSu43LPnEMi5G5CAJSzQ YeP/xiC6ZVfM6GjE8kDGKyfy6jm8GXHkd4+xLxP3oFu+WtaMkZ3LsKSRE6zwuPGp pCaAZjedgv3+DG6hDSs8NBnDa67jbYZQMw5RQquDK3rEsslWBDewDobJ7tyn9zXl QCSxLUNg3yt8Qhc+HJR9LSkMb9MifLvBwo0D0RXgQ89vcJWWpIJ8u+a+cTTksSR/ 4xehmeQdIfOE/AWsutLm6UUvv0dA8PBLn3guM91E1ErnlpjUYZYXb2jKDu45K8Ba uiQAr3j1jIbW58fOuKIYpGaMO78Pv2Y11sCaxwoTwpDzCsffVIsRx6YgrncP8SiY mz40TDK7GExTvMLbwty3XnQhLNsQBO13hBZeMa/ZlZkIIBvlZXgg25SS6pHK+xVC R3xCWuQ8j+j1zr41KMus =osxB -----END PGP SIGNATURE----- Merge tag 'tegra-for-3.11-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra into next/soc From Stephen Warren: ARM: tegra: core SoC support enhancements This branch contains fixes and enhancement for core Tegra Soc support: * CPU hotplug support for Tegra114. * Some preliminary work on Tegra114 CPU sleep modes. * Minor fix for EMC table DT parsing. * tag 'tegra-for-3.11-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra: ARM: tegra: don't pass CPU ID to tegra_{set,clear}_cpu_in_lp2 ARM: tegra: cpuidle: using IS_ENABLED for multi SoCs management in init func ARM: tegra: hook tegra_tear_down_cpu function in the PM suspend init function ARM: tegra: cpuidle: move the init function behind the suspend init function ARM: tegra: remove ifdef in the tegra_resume ARM: tegra: add cpu_disable for hotplug ARM: tegra114: add CPU hotplug support clk: tegra114: implement wait_for_reset and disable_clock for tegra_cpu_car_ops ARM: tegra114: add power up sequence for warm boot CPU ARM: tegra: make tegra_resume can work for Tegra114 ARM: tegra: skip SCU and PL310 code when CPU is not Cortex-A9 ARM: tegra: add an assembly marco to check Tegra SoC ID ARM: tegra: emc: correction of ram-code parsing from dt Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
7bf1541225
@ -30,6 +30,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
obj-$(CONFIG_TEGRA_PCI) += pcie.o
|
||||
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o
|
||||
ifeq ($(CONFIG_CPU_IDLE),y)
|
||||
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o
|
||||
endif
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "board.h"
|
||||
#include "common.h"
|
||||
#include "cpuidle.h"
|
||||
#include "fuse.h"
|
||||
#include "iomap.h"
|
||||
#include "irq.h"
|
||||
@ -108,5 +109,6 @@ void __init tegra_init_early(void)
|
||||
void __init tegra_init_late(void)
|
||||
{
|
||||
tegra_init_suspend();
|
||||
tegra_cpuidle_init();
|
||||
tegra_powergate_debugfs_init();
|
||||
}
|
||||
|
@ -2,3 +2,4 @@ extern struct smp_operations tegra_smp_ops;
|
||||
|
||||
extern int tegra_cpu_kill(unsigned int cpu);
|
||||
extern void tegra_cpu_die(unsigned int cpu);
|
||||
extern int tegra_cpu_disable(unsigned int cpu);
|
||||
|
@ -177,7 +177,6 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
|
||||
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 +192,16 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
|
||||
|
||||
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();
|
||||
|
||||
@ -214,8 +213,5 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -114,16 +114,15 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
|
||||
bool entered_lp2 = false;
|
||||
bool last_cpu;
|
||||
|
||||
local_fiq_disable();
|
||||
|
||||
last_cpu = tegra_set_cpu_in_lp2(cpu);
|
||||
last_cpu = tegra_set_cpu_in_lp2();
|
||||
cpu_pm_enter();
|
||||
|
||||
if (cpu == 0) {
|
||||
if (dev->cpu == 0) {
|
||||
if (last_cpu)
|
||||
entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv,
|
||||
index);
|
||||
@ -134,7 +133,7 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
|
||||
}
|
||||
|
||||
cpu_pm_exit();
|
||||
tegra_clear_cpu_in_lp2(cpu);
|
||||
tegra_clear_cpu_in_lp2();
|
||||
|
||||
local_fiq_enable();
|
||||
|
||||
@ -146,8 +145,5 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
|
||||
|
||||
int __init tegra30_cpuidle_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
tegra_tear_down_cpu = tegra30_tear_down_cpu;
|
||||
#endif
|
||||
return cpuidle_register(&tegra_idle_driver, NULL);
|
||||
}
|
||||
|
@ -27,25 +27,20 @@
|
||||
#include "fuse.h"
|
||||
#include "cpuidle.h"
|
||||
|
||||
static int __init tegra_cpuidle_init(void)
|
||||
void __init tegra_cpuidle_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (tegra_chip_id) {
|
||||
case TEGRA20:
|
||||
ret = tegra20_cpuidle_init();
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
|
||||
tegra20_cpuidle_init();
|
||||
break;
|
||||
case TEGRA30:
|
||||
ret = tegra30_cpuidle_init();
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC))
|
||||
tegra30_cpuidle_init();
|
||||
break;
|
||||
case TEGRA114:
|
||||
ret = tegra114_cpuidle_init();
|
||||
break;
|
||||
default:
|
||||
ret = -ENODEV;
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC))
|
||||
tegra114_cpuidle_init();
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
device_initcall(tegra_cpuidle_init);
|
||||
|
@ -17,22 +17,13 @@
|
||||
#ifndef __MACH_TEGRA_CPUIDLE_H
|
||||
#define __MACH_TEGRA_CPUIDLE_H
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
#ifdef CONFIG_CPU_IDLE
|
||||
int tegra20_cpuidle_init(void);
|
||||
#else
|
||||
static inline int tegra20_cpuidle_init(void) { return -ENODEV; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
int tegra30_cpuidle_init(void);
|
||||
#else
|
||||
static inline int tegra30_cpuidle_init(void) { return -ENODEV; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_114_SOC
|
||||
int tegra114_cpuidle_init(void);
|
||||
void tegra_cpuidle_init(void);
|
||||
#else
|
||||
static inline int tegra114_cpuidle_init(void) { return -ENODEV; }
|
||||
static inline void tegra_cpuidle_init(void) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define FLOW_CTRL_WAITEVENT (2 << 29)
|
||||
#define FLOW_CTRL_WAIT_FOR_INTERRUPT (4 << 29)
|
||||
#define FLOW_CTRL_JTAG_RESUME (1 << 28)
|
||||
#define FLOW_CTRL_SCLK_RESUME (1 << 27)
|
||||
#define FLOW_CTRL_HALT_CPU_IRQ (1 << 10)
|
||||
#define FLOW_CTRL_HALT_CPU_FIQ (1 << 8)
|
||||
#define FLOW_CTRL_CPU0_CSR 0x8
|
||||
|
@ -19,16 +19,6 @@
|
||||
#ifndef __MACH_TEGRA_FUSE_H
|
||||
#define __MACH_TEGRA_FUSE_H
|
||||
|
||||
enum tegra_revision {
|
||||
TEGRA_REVISION_UNKNOWN = 0,
|
||||
TEGRA_REVISION_A01,
|
||||
TEGRA_REVISION_A02,
|
||||
TEGRA_REVISION_A03,
|
||||
TEGRA_REVISION_A03p,
|
||||
TEGRA_REVISION_A04,
|
||||
TEGRA_REVISION_MAX,
|
||||
};
|
||||
|
||||
#define SKU_ID_T20 8
|
||||
#define SKU_ID_T25SE 20
|
||||
#define SKU_ID_AP25 23
|
||||
@ -40,6 +30,17 @@ enum tegra_revision {
|
||||
#define TEGRA30 0x30
|
||||
#define TEGRA114 0x35
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
enum tegra_revision {
|
||||
TEGRA_REVISION_UNKNOWN = 0,
|
||||
TEGRA_REVISION_A01,
|
||||
TEGRA_REVISION_A02,
|
||||
TEGRA_REVISION_A03,
|
||||
TEGRA_REVISION_A03p,
|
||||
TEGRA_REVISION_A04,
|
||||
TEGRA_REVISION_MAX,
|
||||
};
|
||||
|
||||
extern int tegra_sku_id;
|
||||
extern int tegra_cpu_process_id;
|
||||
extern int tegra_core_process_id;
|
||||
@ -72,5 +73,6 @@ void tegra114_init_speedo_data(void);
|
||||
#else
|
||||
static inline void tegra114_init_speedo_data(void) {}
|
||||
#endif
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif
|
||||
|
@ -46,6 +46,17 @@ void __ref tegra_cpu_die(unsigned int cpu)
|
||||
BUG();
|
||||
}
|
||||
|
||||
int tegra_cpu_disable(unsigned int cpu)
|
||||
{
|
||||
switch (tegra_chip_id) {
|
||||
case TEGRA20:
|
||||
case TEGRA30:
|
||||
return cpu == 0 ? -EPERM : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void __init tegra_hotplug_init(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
|
||||
@ -55,4 +66,6 @@ void __init tegra_hotplug_init(void)
|
||||
tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
|
||||
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
|
||||
tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
|
||||
}
|
||||
|
@ -140,8 +140,31 @@ remove_clamps:
|
||||
|
||||
static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
cpu = cpu_logical_map(cpu);
|
||||
return tegra_pmc_cpu_power_on(cpu);
|
||||
|
||||
if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) {
|
||||
/*
|
||||
* Warm boot flow
|
||||
* The flow controller in charge of the power state and
|
||||
* control for each CPU.
|
||||
*/
|
||||
/* set SCLK as event trigger for flow controller */
|
||||
flowctrl_write_cpu_csr(cpu, 1);
|
||||
flowctrl_write_cpu_halt(cpu,
|
||||
FLOW_CTRL_WAITEVENT | FLOW_CTRL_SCLK_RESUME);
|
||||
} else {
|
||||
/*
|
||||
* Cold boot flow
|
||||
* The CPU is powered up by toggling PMC directly. It will
|
||||
* also initial power state in flow controller. After that,
|
||||
* the CPU's power state is maintained by flow controller.
|
||||
*/
|
||||
ret = tegra_pmc_cpu_power_on(cpu);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __cpuinit tegra_boot_secondary(unsigned int cpu,
|
||||
@ -173,5 +196,6 @@ struct smp_operations tegra_smp_ops __initdata = {
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_kill = tegra_cpu_kill,
|
||||
.cpu_die = tegra_cpu_die,
|
||||
.cpu_disable = tegra_cpu_disable,
|
||||
#endif
|
||||
};
|
||||
|
@ -44,6 +44,20 @@
|
||||
static DEFINE_SPINLOCK(tegra_lp2_lock);
|
||||
void (*tegra_tear_down_cpu)(void);
|
||||
|
||||
static void tegra_tear_down_cpu_init(void)
|
||||
{
|
||||
switch (tegra_chip_id) {
|
||||
case TEGRA20:
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
|
||||
tegra_tear_down_cpu = tegra20_tear_down_cpu;
|
||||
break;
|
||||
case TEGRA30:
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC))
|
||||
tegra_tear_down_cpu = tegra30_tear_down_cpu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* restore_cpu_complex
|
||||
*
|
||||
@ -91,8 +105,9 @@ static void suspend_cpu_complex(void)
|
||||
flowctrl_cpu_suspend_enter(cpu);
|
||||
}
|
||||
|
||||
void tegra_clear_cpu_in_lp2(int phy_cpu_id)
|
||||
void tegra_clear_cpu_in_lp2(void)
|
||||
{
|
||||
int phy_cpu_id = cpu_logical_map(smp_processor_id());
|
||||
u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
|
||||
|
||||
spin_lock(&tegra_lp2_lock);
|
||||
@ -103,8 +118,9 @@ void tegra_clear_cpu_in_lp2(int phy_cpu_id)
|
||||
spin_unlock(&tegra_lp2_lock);
|
||||
}
|
||||
|
||||
bool tegra_set_cpu_in_lp2(int phy_cpu_id)
|
||||
bool tegra_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;
|
||||
@ -192,7 +208,7 @@ static int __cpuinit tegra_suspend_enter(suspend_state_t state)
|
||||
suspend_cpu_complex();
|
||||
switch (mode) {
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
tegra_set_cpu_in_lp2(0);
|
||||
tegra_set_cpu_in_lp2();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -202,7 +218,7 @@ static int __cpuinit tegra_suspend_enter(suspend_state_t state)
|
||||
|
||||
switch (mode) {
|
||||
case TEGRA_SUSPEND_LP2:
|
||||
tegra_clear_cpu_in_lp2(0);
|
||||
tegra_clear_cpu_in_lp2();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -224,6 +240,7 @@ void __init tegra_init_suspend(void)
|
||||
if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
|
||||
return;
|
||||
|
||||
tegra_tear_down_cpu_init();
|
||||
tegra_pmc_suspend_init();
|
||||
|
||||
suspend_set_ops(&tegra_suspend_ops);
|
||||
|
@ -28,8 +28,8 @@ extern unsigned long l2x0_saved_regs_addr;
|
||||
void save_cpu_arch_register(void);
|
||||
void restore_cpu_arch_register(void);
|
||||
|
||||
void tegra_clear_cpu_in_lp2(int phy_cpu_id);
|
||||
bool tegra_set_cpu_in_lp2(int phy_cpu_id);
|
||||
void tegra_clear_cpu_in_lp2(void);
|
||||
bool tegra_set_cpu_in_lp2(void);
|
||||
|
||||
void tegra_idle_lp2_last(void);
|
||||
extern void (*tegra_tear_down_cpu)(void);
|
||||
|
@ -22,11 +22,11 @@
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
||||
#include "flowctrl.h"
|
||||
#include "fuse.h"
|
||||
#include "iomap.h"
|
||||
#include "reset.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#define APB_MISC_GP_HIDREV 0x804
|
||||
#define PMC_SCRATCH41 0x140
|
||||
|
||||
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
|
||||
@ -38,34 +38,40 @@
|
||||
* CPU boot vector when restarting the a CPU following
|
||||
* an LP2 transition. Also branched to by LP0 and LP1 resume after
|
||||
* re-enabling sdram.
|
||||
*
|
||||
* r6: SoC ID
|
||||
*/
|
||||
ENTRY(tegra_resume)
|
||||
bl v7_invalidate_l1
|
||||
|
||||
cpu_id r0
|
||||
tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
|
||||
cmp r6, #TEGRA114
|
||||
beq no_cpu0_chk
|
||||
|
||||
cmp r0, #0 @ CPU0?
|
||||
THUMB( it ne )
|
||||
bne cpu_resume @ no
|
||||
no_cpu0_chk:
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
/* Are we on Tegra20? */
|
||||
mov32 r6, TEGRA_APB_MISC_BASE
|
||||
ldr r0, [r6, #APB_MISC_GP_HIDREV]
|
||||
and r0, r0, #0xff00
|
||||
cmp r0, #(0x20 << 8)
|
||||
cmp r6, #TEGRA20
|
||||
beq 1f @ Yes
|
||||
/* Clear the flow controller flags for this CPU. */
|
||||
mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
|
||||
ldr r1, [r2]
|
||||
cpu_to_csr_reg r1, r0
|
||||
mov32 r2, TEGRA_FLOW_CTRL_BASE
|
||||
ldr r1, [r2, r1]
|
||||
/* Clear event & intr flag */
|
||||
orr r1, r1, \
|
||||
#FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
|
||||
movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
|
||||
movw r0, #0x3FFD @ enable, cluster_switch, immed, bitmaps
|
||||
@ & ext flags for CPU power mgnt
|
||||
bic r1, r1, r0
|
||||
str r1, [r2]
|
||||
1:
|
||||
#endif
|
||||
|
||||
check_cpu_part_num 0xc09, r8, r9
|
||||
bne not_ca9
|
||||
#ifdef CONFIG_HAVE_ARM_SCU
|
||||
/* enable SCU */
|
||||
mov32 r0, TEGRA_ARM_PERIF_BASE
|
||||
@ -76,6 +82,7 @@ ENTRY(tegra_resume)
|
||||
|
||||
/* L2 cache resume & re-enable */
|
||||
l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
|
||||
not_ca9:
|
||||
|
||||
b cpu_resume
|
||||
ENDPROC(tegra_resume)
|
||||
@ -98,7 +105,7 @@ ENTRY(__tegra_cpu_reset_handler_start)
|
||||
* Register usage within the reset handler:
|
||||
*
|
||||
* Others: scratch
|
||||
* R6 = SoC ID << 8
|
||||
* R6 = SoC ID
|
||||
* R7 = CPU present (to the OS) mask
|
||||
* R8 = CPU in LP1 state mask
|
||||
* R9 = CPU in LP2 state mask
|
||||
@ -115,12 +122,10 @@ ENTRY(__tegra_cpu_reset_handler)
|
||||
|
||||
cpsid aif, 0x13 @ SVC mode, interrupts disabled
|
||||
|
||||
mov32 r6, TEGRA_APB_MISC_BASE
|
||||
ldr r6, [r6, #APB_MISC_GP_HIDREV]
|
||||
and r6, r6, #0xff00
|
||||
tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
t20_check:
|
||||
cmp r6, #(0x20 << 8)
|
||||
cmp r6, #TEGRA20
|
||||
bne after_t20_check
|
||||
t20_errata:
|
||||
# Tegra20 is a Cortex-A9 r1p1
|
||||
@ -136,7 +141,7 @@ after_t20_check:
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
|
||||
t30_check:
|
||||
cmp r6, #(0x30 << 8)
|
||||
cmp r6, #TEGRA30
|
||||
bne after_t30_check
|
||||
t30_errata:
|
||||
# Tegra30 is a Cortex-A9 r2p9
|
||||
@ -163,7 +168,7 @@ after_errata:
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
/* Are we on Tegra20? */
|
||||
cmp r6, #(0x20 << 8)
|
||||
cmp r6, #TEGRA20
|
||||
bne 1f
|
||||
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
|
||||
mov32 r5, TEGRA_PMC_BASE
|
||||
@ -186,11 +191,14 @@ __is_not_lp2:
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* Can only be secondary boot (initial or hotplug) but CPU 0
|
||||
* cannot be here.
|
||||
* Can only be secondary boot (initial or hotplug)
|
||||
* CPU0 can't be here for Tegra20/30
|
||||
*/
|
||||
cmp r6, #TEGRA114
|
||||
beq __no_cpu0_chk
|
||||
cmp r10, #0
|
||||
bleq __die @ CPU0 cannot be here
|
||||
__no_cpu0_chk:
|
||||
ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
|
||||
cmp lr, #0
|
||||
bleq __die @ no secondary startup handler
|
||||
@ -210,10 +218,7 @@ __die:
|
||||
mov32 r7, TEGRA_CLK_RESET_BASE
|
||||
|
||||
/* Are we on Tegra20? */
|
||||
mov32 r6, TEGRA_APB_MISC_BASE
|
||||
ldr r0, [r6, #APB_MISC_GP_HIDREV]
|
||||
and r0, r0, #0xff00
|
||||
cmp r0, #(0x20 << 8)
|
||||
cmp r6, #TEGRA20
|
||||
bne 1f
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <asm/assembler.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
#include "fuse.h"
|
||||
#include "sleep.h"
|
||||
#include "flowctrl.h"
|
||||
|
||||
@ -43,14 +44,19 @@ ENDPROC(tegra30_hotplug_shutdown)
|
||||
*
|
||||
* Puts the current CPU in wait-for-event mode on the flow controller
|
||||
* and powergates it -- flags (in R0) indicate the request type.
|
||||
* Must never be called for CPU 0.
|
||||
*
|
||||
* corrupts r0-r4, r12
|
||||
* r10 = SoC ID
|
||||
* corrupts r0-r4, r10-r12
|
||||
*/
|
||||
ENTRY(tegra30_cpu_shutdown)
|
||||
cpu_id r3
|
||||
tegra_get_soc_id TEGRA_APB_MISC_VIRT, r10
|
||||
cmp r10, #TEGRA30
|
||||
bne _no_cpu0_chk @ It's not Tegra30
|
||||
|
||||
cmp r3, #0
|
||||
moveq pc, lr @ Must never be called for CPU 0
|
||||
_no_cpu0_chk:
|
||||
|
||||
ldr r12, =TEGRA_FLOW_CTRL_VIRT
|
||||
cpu_to_csr_reg r1, r3
|
||||
@ -65,7 +71,9 @@ ENTRY(tegra30_cpu_shutdown)
|
||||
movw r12, \
|
||||
FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
|
||||
FLOW_CTRL_CSR_ENABLE
|
||||
mov r4, #(1 << 4)
|
||||
cmp r10, #TEGRA30
|
||||
moveq r4, #(1 << 4) @ wfe bitmap
|
||||
movne r4, #(1 << 8) @ wfi bitmap
|
||||
ARM( orr r12, r12, r4, lsl r3 )
|
||||
THUMB( lsl r4, r4, r3 )
|
||||
THUMB( orr r12, r12, r4 )
|
||||
@ -79,9 +87,20 @@ delay_1:
|
||||
cpsid a @ disable imprecise aborts.
|
||||
ldr r3, [r1] @ read CSR
|
||||
str r3, [r1] @ clear CSR
|
||||
|
||||
tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
|
||||
beq flow_ctrl_setting_for_lp2
|
||||
|
||||
/* flow controller set up for hotplug */
|
||||
mov r3, #FLOW_CTRL_WAITEVENT @ For hotplug
|
||||
b flow_ctrl_done
|
||||
flow_ctrl_setting_for_lp2:
|
||||
/* flow controller set up for LP2 */
|
||||
cmp r10, #TEGRA30
|
||||
moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2
|
||||
movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug
|
||||
movne r3, #FLOW_CTRL_WAITEVENT
|
||||
flow_ctrl_done:
|
||||
cmp r10, #TEGRA30
|
||||
str r3, [r2]
|
||||
ldr r0, [r2]
|
||||
b wfe_war
|
||||
@ -89,7 +108,8 @@ delay_1:
|
||||
__cpu_reset_again:
|
||||
dsb
|
||||
.align 5
|
||||
wfe @ CPU should be power gated here
|
||||
wfeeq @ CPU should be power gated here
|
||||
wfine
|
||||
wfe_war:
|
||||
b __cpu_reset_again
|
||||
|
||||
|
@ -106,9 +106,11 @@ ENTRY(tegra_shut_off_mmu)
|
||||
isb
|
||||
#ifdef CONFIG_CACHE_L2X0
|
||||
/* Disable L2 cache */
|
||||
mov32 r4, TEGRA_ARM_PERIF_BASE + 0x3000
|
||||
mov r5, #0
|
||||
str r5, [r4, #L2X0_CTRL]
|
||||
check_cpu_part_num 0xc09, r9, r10
|
||||
movweq r4, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000)
|
||||
movteq r4, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000)
|
||||
moveq r5, #0
|
||||
streq r5, [r4, #L2X0_CTRL]
|
||||
#endif
|
||||
mov pc, r0
|
||||
ENDPROC(tegra_shut_off_mmu)
|
||||
|
@ -25,6 +25,8 @@
|
||||
+ IO_PPSB_VIRT)
|
||||
#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \
|
||||
+ IO_PPSB_VIRT)
|
||||
#define TEGRA_APB_MISC_VIRT (TEGRA_APB_MISC_BASE - IO_APB_PHYS \
|
||||
+ IO_APB_VIRT)
|
||||
#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
|
||||
|
||||
/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
|
||||
@ -70,19 +72,40 @@
|
||||
movt \reg, #:upper16:\val
|
||||
.endm
|
||||
|
||||
/* Marco to check CPU part num */
|
||||
.macro check_cpu_part_num part_num, tmp1, tmp2
|
||||
mrc p15, 0, \tmp1, c0, c0, 0
|
||||
ubfx \tmp1, \tmp1, #4, #12
|
||||
mov32 \tmp2, \part_num
|
||||
cmp \tmp1, \tmp2
|
||||
.endm
|
||||
|
||||
/* Macro to exit SMP coherency. */
|
||||
.macro exit_smp, tmp1, tmp2
|
||||
mrc p15, 0, \tmp1, c1, c0, 1 @ ACTLR
|
||||
bic \tmp1, \tmp1, #(1<<6) | (1<<0) @ clear ACTLR.SMP | ACTLR.FW
|
||||
mcr p15, 0, \tmp1, c1, c0, 1 @ ACTLR
|
||||
isb
|
||||
cpu_id \tmp1
|
||||
mov \tmp1, \tmp1, lsl #2
|
||||
mov \tmp2, #0xf
|
||||
mov \tmp2, \tmp2, lsl \tmp1
|
||||
mov32 \tmp1, TEGRA_ARM_PERIF_VIRT + 0xC
|
||||
str \tmp2, [\tmp1] @ invalidate SCU tags for CPU
|
||||
#ifdef CONFIG_HAVE_ARM_SCU
|
||||
check_cpu_part_num 0xc09, \tmp1, \tmp2
|
||||
mrceq p15, 0, \tmp1, c0, c0, 5
|
||||
andeq \tmp1, \tmp1, #0xF
|
||||
moveq \tmp1, \tmp1, lsl #2
|
||||
moveq \tmp2, #0xf
|
||||
moveq \tmp2, \tmp2, lsl \tmp1
|
||||
ldreq \tmp1, =(TEGRA_ARM_PERIF_VIRT + 0xC)
|
||||
streq \tmp2, [\tmp1] @ invalidate SCU tags for CPU
|
||||
dsb
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/* Macro to check Tegra revision */
|
||||
#define APB_MISC_GP_HIDREV 0x804
|
||||
.macro tegra_get_soc_id base, tmp1
|
||||
mov32 \tmp1, \base
|
||||
ldr \tmp1, [\tmp1, #APB_MISC_GP_HIDREV]
|
||||
and \tmp1, \tmp1, #0xff00
|
||||
mov \tmp1, \tmp1, lsr #8
|
||||
.endm
|
||||
|
||||
/* Macro to resume & re-enable L2 cache */
|
||||
|
@ -183,7 +183,7 @@ static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
|
||||
u32 reg;
|
||||
|
||||
for_each_child_of_node(np, iter) {
|
||||
if (of_property_read_u32(np, "nvidia,ram-code", ®))
|
||||
if (of_property_read_u32(iter, "nvidia,ram-code", ®))
|
||||
continue;
|
||||
if (reg == tegra_bct_strapping)
|
||||
return of_node_get(iter);
|
||||
|
@ -250,6 +250,9 @@
|
||||
#define CLK_SOURCE_XUSB_DEV_SRC 0x60c
|
||||
#define CLK_SOURCE_EMC 0x19c
|
||||
|
||||
/* Tegra CPU clock and reset control regs */
|
||||
#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
|
||||
|
||||
static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];
|
||||
|
||||
static void __iomem *clk_base;
|
||||
@ -2000,7 +2003,25 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base)
|
||||
}
|
||||
}
|
||||
|
||||
static struct tegra_cpu_car_ops tegra114_cpu_car_ops;
|
||||
/* Tegra114 CPU clock and reset control functions */
|
||||
static void tegra114_wait_cpu_in_reset(u32 cpu)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
do {
|
||||
reg = readl(clk_base + CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
|
||||
cpu_relax();
|
||||
} while (!(reg & (1 << cpu))); /* check CPU been reset or not */
|
||||
}
|
||||
static void tegra114_disable_cpu_clock(u32 cpu)
|
||||
{
|
||||
/* flow controller would take care in the power sequence. */
|
||||
}
|
||||
|
||||
static struct tegra_cpu_car_ops tegra114_cpu_car_ops = {
|
||||
.wait_for_reset = tegra114_wait_cpu_in_reset,
|
||||
.disable_clock = tegra114_disable_cpu_clock,
|
||||
};
|
||||
|
||||
static const struct of_device_id pmc_match[] __initconst = {
|
||||
{ .compatible = "nvidia,tegra114-pmc" },
|
||||
|
Loading…
Reference in New Issue
Block a user