aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Kconfig38
-rw-r--r--arch/arm/mach-tegra/Makefile8
-rw-r--r--arch/arm/mach-tegra/Makefile.boot3
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra114.c46
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra30.c60
-rw-r--r--arch/arm/mach-tegra/board-harmony-pcie.c13
-rw-r--r--arch/arm/mach-tegra/board.h5
-rw-r--r--arch/arm/mach-tegra/common.c33
-rw-r--r--arch/arm/mach-tegra/common.h1
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c293
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra114.c28
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c78
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c39
-rw-r--r--arch/arm/mach-tegra/fuse.c4
-rw-r--r--arch/arm/mach-tegra/fuse.h7
-rw-r--r--arch/arm/mach-tegra/headsmp.S3
-rw-r--r--arch/arm/mach-tegra/hotplug.c33
-rw-r--r--arch/arm/mach-tegra/include/mach/powergate.h54
-rw-r--r--arch/arm/mach-tegra/include/mach/timex.h26
-rw-r--r--arch/arm/mach-tegra/include/mach/uncompress.h175
-rw-r--r--arch/arm/mach-tegra/irq.c96
-rw-r--r--arch/arm/mach-tegra/irq.h6
-rw-r--r--arch/arm/mach-tegra/pcie.c3
-rw-r--r--arch/arm/mach-tegra/platsmp.c128
-rw-r--r--arch/arm/mach-tegra/pm.c162
-rw-r--r--arch/arm/mach-tegra/pm.h17
-rw-r--r--arch/arm/mach-tegra/pmc.c310
-rw-r--r--arch/arm/mach-tegra/pmc.h18
-rw-r--r--arch/arm/mach-tegra/powergate.c7
-rw-r--r--arch/arm/mach-tegra/reset-handler.S49
-rw-r--r--arch/arm/mach-tegra/sleep-tegra20.S2
-rw-r--r--arch/arm/mach-tegra/sleep-tegra30.S4
-rw-r--r--arch/arm/mach-tegra/sleep.h12
-rw-r--r--arch/arm/mach-tegra/tegra.c (renamed from arch/arm/mach-tegra/board-dt-tegra20.c)50
-rw-r--r--arch/arm/mach-tegra/tegra114_speedo.c104
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.c7
36 files changed, 852 insertions, 1070 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index d1c4893894c..84d72fc36df 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -1,13 +1,30 @@
-if ARCH_TEGRA
+config ARCH_TEGRA
+ bool "NVIDIA Tegra" if ARCH_MULTI_V7
+ select ARCH_HAS_CPUFREQ
+ select ARCH_REQUIRE_GPIOLIB
+ select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
+ select CLKSRC_OF
+ select COMMON_CLK
+ select GENERIC_CLOCKEVENTS
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if LOCAL_TIMERS
+ select HAVE_CLK
+ select HAVE_SMP
+ select MIGHT_HAVE_CACHE_L2X0
+ select SOC_BUS
+ select SPARSE_IRQ
+ select USE_OF
+ help
+ This enables support for NVIDIA Tegra based systems.
-comment "NVIDIA Tegra options"
+menu "NVIDIA Tegra options"
+ depends on ARCH_TEGRA
config ARCH_TEGRA_2x_SOC
bool "Enable support for Tegra20 family"
select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
select ARM_ERRATA_720789
- select ARM_ERRATA_742230 if SMP
- select ARM_ERRATA_751472
select ARM_ERRATA_754327 if SMP
select ARM_ERRATA_764369 if SMP
select ARM_GIC
@@ -18,16 +35,14 @@ config ARCH_TEGRA_2x_SOC
select PL310_ERRATA_727915 if CACHE_L2X0
select PL310_ERRATA_769419 if CACHE_L2X0
select USB_ARCH_HAS_EHCI if USB_SUPPORT
- select USB_ULPI if USB
- select USB_ULPI_VIEWPORT if USB_SUPPORT
+ select USB_ULPI if USB_PHY
+ select USB_ULPI_VIEWPORT if USB_PHY
help
Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
config ARCH_TEGRA_3x_SOC
bool "Enable support for Tegra30 family"
- select ARM_ERRATA_743622
- select ARM_ERRATA_751472
select ARM_ERRATA_754322
select ARM_ERRATA_764369 if SMP
select ARM_GIC
@@ -37,8 +52,8 @@ config ARCH_TEGRA_3x_SOC
select PINCTRL_TEGRA30
select PL310_ERRATA_769419 if CACHE_L2X0
select USB_ARCH_HAS_EHCI if USB_SUPPORT
- select USB_ULPI if USB
- select USB_ULPI_VIEWPORT if USB_SUPPORT
+ select USB_ULPI if USB_PHY
+ select USB_ULPI_VIEWPORT if USB_PHY
help
Support for NVIDIA Tegra T30 processor family, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -48,6 +63,7 @@ config ARCH_TEGRA_114_SOC
select ARM_ARCH_TIMER
select ARM_GIC
select ARM_L1_CACHE_SHIFT_6
+ select CPU_FREQ_TABLE if CPU_FREQ
select CPU_V7
select PINCTRL
select PINCTRL_TEGRA114
@@ -71,4 +87,4 @@ config TEGRA_AHB
config TEGRA_EMC_SCALING_ENABLE
bool "Enable scaling the memory frequency"
-endif
+endmenu
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index f6b46ae2b7f..d011f0ad49c 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,3 +1,5 @@
+asflags-y += -march=armv7-a
+
obj-y += common.o
obj-y += io.o
obj-y += irq.o
@@ -10,6 +12,7 @@ obj-y += pm.o
obj-y += reset.o
obj-y += reset-handler.o
obj-y += sleep.o
+obj-y += tegra.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
@@ -24,12 +27,9 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
endif
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
-obj-$(CONFIG_ARCH_TEGRA_114_SOC) += board-dt-tegra114.o
+obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o
ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += cpuidle-tegra114.o
endif
diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot
deleted file mode 100644
index 29433816233..00000000000
--- a/arch/arm/mach-tegra/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
-zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC) += 0x00008000
-params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00000100
-initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC) := 0x00800000
diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c
deleted file mode 100644
index 085d63637b6..00000000000
--- a/arch/arm/mach-tegra/board-dt-tegra114.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * NVIDIA Tegra114 device tree board support
- *
- * Copyright (C) 2013 NVIDIA Corporation
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clocksource.h>
-
-#include <asm/mach/arch.h>
-
-#include "board.h"
-#include "common.h"
-
-static void __init tegra114_dt_init(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
-static const char * const tegra114_dt_board_compat[] = {
- "nvidia,tegra114",
- NULL,
-};
-
-DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)")
- .smp = smp_ops(tegra_smp_ops),
- .map_io = tegra_map_common_io,
- .init_early = tegra114_init_early,
- .init_irq = tegra_dt_init_irq,
- .init_time = clocksource_of_init,
- .init_machine = tegra114_dt_init,
- .init_late = tegra_init_late,
- .restart = tegra_assert_system_reset,
- .dt_compat = tegra114_dt_board_compat,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
deleted file mode 100644
index bf68567e549..00000000000
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * arch/arm/mach-tegra/board-dt-tegra30.c
- *
- * NVIDIA Tegra30 device tree board support
- *
- * Copyright (C) 2011 NVIDIA Corporation
- *
- * Derived from:
- *
- * arch/arm/mach-tegra/board-dt-tegra20.c
- *
- * Copyright (C) 2010 Secret Lab Technologies, Ltd.
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/clocksource.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_fdt.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-
-#include <asm/mach/arch.h>
-
-#include "board.h"
-#include "common.h"
-#include "iomap.h"
-
-static void __init tegra30_dt_init(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
-static const char *tegra30_dt_board_compat[] = {
- "nvidia,tegra30",
- NULL
-};
-
-DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)")
- .smp = smp_ops(tegra_smp_ops),
- .map_io = tegra_map_common_io,
- .init_early = tegra30_init_early,
- .init_irq = tegra_dt_init_irq,
- .init_time = clocksource_of_init,
- .init_machine = tegra30_dt_init,
- .init_late = tegra_init_late,
- .restart = tegra_assert_system_reset,
- .dt_compat = tegra30_dt_board_compat,
-MACHINE_END
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
index 3cdc1bb8254..035b240b9e1 100644
--- a/arch/arm/mach-tegra/board-harmony-pcie.c
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -56,13 +56,17 @@ int __init harmony_pcie_init(void)
gpio_direction_output(en_vdd_1v05, 1);
regulator = regulator_get(NULL, "vdd_ldo0,vddio_pex_clk");
- if (IS_ERR_OR_NULL(regulator)) {
- pr_err("%s: regulator_get failed: %d\n", __func__,
- (int)PTR_ERR(regulator));
+ if (IS_ERR(regulator)) {
+ err = PTR_ERR(regulator);
+ pr_err("%s: regulator_get failed: %d\n", __func__, err);
goto err_reg;
}
- regulator_enable(regulator);
+ err = regulator_enable(regulator);
+ if (err) {
+ pr_err("%s: regulator_enable failed: %d\n", __func__, err);
+ goto err_en;
+ }
err = tegra_pcie_init(true, true);
if (err) {
@@ -74,6 +78,7 @@ int __init harmony_pcie_init(void)
err_pcie:
regulator_disable(regulator);
+err_en:
regulator_put(regulator);
err_reg:
gpio_free(en_vdd_1v05);
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 86851c81a35..1787327fae3 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -26,9 +26,7 @@
void tegra_assert_system_reset(char mode, const char *cmd);
-void __init tegra20_init_early(void);
-void __init tegra30_init_early(void);
-void __init tegra114_init_early(void);
+void __init tegra_init_early(void);
void __init tegra_map_common_io(void);
void __init tegra_init_irq(void);
void __init tegra_dt_init_irq(void);
@@ -42,6 +40,7 @@ int tegra_clk_debugfs_init(void);
static inline int tegra_clk_debugfs_init(void) { return 0; }
#endif
+int __init tegra_powergate_init(void);
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) && defined(CONFIG_DEBUG_FS)
int __init tegra_powergate_debugfs_init(void);
#else
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 5449a3f2977..9f852c6fe5b 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -27,12 +27,11 @@
#include <asm/hardware/cache-l2x0.h>
-#include <mach/powergate.h>
-
#include "board.h"
#include "common.h"
#include "fuse.h"
#include "iomap.h"
+#include "irq.h"
#include "pmc.h"
#include "apbio.h"
#include "sleep.h"
@@ -61,8 +60,10 @@ u32 tegra_uart_config[4] = {
void __init tegra_dt_init_irq(void)
{
tegra_clocks_init();
+ tegra_pmc_init();
tegra_init_irq();
irqchip_init();
+ tegra_legacy_irq_syscore_init();
}
#endif
@@ -94,40 +95,18 @@ static void __init tegra_init_cache(void)
}
-static void __init tegra_init_early(void)
+void __init tegra_init_early(void)
{
tegra_cpu_reset_handler_init();
tegra_apb_io_init();
tegra_init_fuse();
tegra_init_cache();
- tegra_pmc_init();
tegra_powergate_init();
+ tegra_hotplug_init();
}
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-void __init tegra20_init_early(void)
-{
- tegra_init_early();
- tegra20_hotplug_init();
-}
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-void __init tegra30_init_early(void)
-{
- tegra_init_early();
- tegra30_hotplug_init();
-}
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_114_SOC
-void __init tegra114_init_early(void)
-{
- tegra_init_early();
-}
-#endif
-
void __init tegra_init_late(void)
{
+ tegra_init_suspend();
tegra_powergate_debugfs_init();
}
diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h
index 32f8eb3fe34..5900cc44f78 100644
--- a/arch/arm/mach-tegra/common.h
+++ b/arch/arm/mach-tegra/common.h
@@ -2,4 +2,3 @@ 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);
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
deleted file mode 100644
index e3d6e15ff18..00000000000
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * arch/arm/mach-tegra/cpu-tegra.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@google.com>
- * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/suspend.h>
-
-/* Frequency table index must be sequential starting at 0 */
-static struct cpufreq_frequency_table freq_table[] = {
- { 0, 216000 },
- { 1, 312000 },
- { 2, 456000 },
- { 3, 608000 },
- { 4, 760000 },
- { 5, 816000 },
- { 6, 912000 },
- { 7, 1000000 },
- { 8, CPUFREQ_TABLE_END },
-};
-
-#define NUM_CPUS 2
-
-static struct clk *cpu_clk;
-static struct clk *pll_x_clk;
-static struct clk *pll_p_clk;
-static struct clk *emc_clk;
-
-static unsigned long target_cpu_speed[NUM_CPUS];
-static DEFINE_MUTEX(tegra_cpu_lock);
-static bool is_suspended;
-
-static int tegra_verify_speed(struct cpufreq_policy *policy)
-{
- return cpufreq_frequency_table_verify(policy, freq_table);
-}
-
-static unsigned int tegra_getspeed(unsigned int cpu)
-{
- unsigned long rate;
-
- if (cpu >= NUM_CPUS)
- return 0;
-
- rate = clk_get_rate(cpu_clk) / 1000;
- return rate;
-}
-
-static int tegra_cpu_clk_set_rate(unsigned long rate)
-{
- int ret;
-
- /*
- * Take an extra reference to the main pll so it doesn't turn
- * off when we move the cpu off of it
- */
- clk_prepare_enable(pll_x_clk);
-
- ret = clk_set_parent(cpu_clk, pll_p_clk);
- if (ret) {
- pr_err("Failed to switch cpu to clock pll_p\n");
- goto out;
- }
-
- if (rate == clk_get_rate(pll_p_clk))
- goto out;
-
- ret = clk_set_rate(pll_x_clk, rate);
- if (ret) {
- pr_err("Failed to change pll_x to %lu\n", rate);
- goto out;
- }
-
- ret = clk_set_parent(cpu_clk, pll_x_clk);
- if (ret) {
- pr_err("Failed to switch cpu to clock pll_x\n");
- goto out;
- }
-
-out:
- clk_disable_unprepare(pll_x_clk);
- return ret;
-}
-
-static int tegra_update_cpu_speed(unsigned long rate)
-{
- int ret = 0;
- struct cpufreq_freqs freqs;
-
- freqs.old = tegra_getspeed(0);
- freqs.new = rate;
-
- if (freqs.old == freqs.new)
- return ret;
-
- /*
- * Vote on memory bus frequency based on cpu frequency
- * This sets the minimum frequency, display or avp may request higher
- */
- if (rate >= 816000)
- clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
- else if (rate >= 456000)
- clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
- else
- clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
-
- for_each_online_cpu(freqs.cpu)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-#ifdef CONFIG_CPU_FREQ_DEBUG
- printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
- freqs.old, freqs.new);
-#endif
-
- ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
- if (ret) {
- pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
- freqs.new);
- return ret;
- }
-
- for_each_online_cpu(freqs.cpu)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
- return 0;
-}
-
-static unsigned long tegra_cpu_highest_speed(void)
-{
- unsigned long rate = 0;
- int i;
-
- for_each_online_cpu(i)
- rate = max(rate, target_cpu_speed[i]);
- return rate;
-}
-
-static int tegra_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
-{
- unsigned int idx;
- unsigned int freq;
- int ret = 0;
-
- mutex_lock(&tegra_cpu_lock);
-
- if (is_suspended) {
- ret = -EBUSY;
- goto out;
- }
-
- cpufreq_frequency_table_target(policy, freq_table, target_freq,
- relation, &idx);
-
- freq = freq_table[idx].frequency;
-
- target_cpu_speed[policy->cpu] = freq;
-
- ret = tegra_update_cpu_speed(tegra_cpu_highest_speed());
-
-out:
- mutex_unlock(&tegra_cpu_lock);
- return ret;
-}
-
-static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
- void *dummy)
-{
- mutex_lock(&tegra_cpu_lock);
- if (event == PM_SUSPEND_PREPARE) {
- is_suspended = true;
- pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
- freq_table[0].frequency);
- tegra_update_cpu_speed(freq_table[0].frequency);
- } else if (event == PM_POST_SUSPEND) {
- is_suspended = false;
- }
- mutex_unlock(&tegra_cpu_lock);
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block tegra_cpu_pm_notifier = {
- .notifier_call = tegra_pm_notify,
-};
-
-static int tegra_cpu_init(struct cpufreq_policy *policy)
-{
- if (policy->cpu >= NUM_CPUS)
- return -EINVAL;
-
- clk_prepare_enable(emc_clk);
- clk_prepare_enable(cpu_clk);
-
- cpufreq_frequency_table_cpuinfo(policy, freq_table);
- cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
- policy->cur = tegra_getspeed(policy->cpu);
- target_cpu_speed[policy->cpu] = policy->cur;
-
- /* FIXME: what's the actual transition time? */
- policy->cpuinfo.transition_latency = 300 * 1000;
-
- cpumask_copy(policy->cpus, cpu_possible_mask);
-
- if (policy->cpu == 0)
- register_pm_notifier(&tegra_cpu_pm_notifier);
-
- return 0;
-}
-
-static int tegra_cpu_exit(struct cpufreq_policy *policy)
-{
- cpufreq_frequency_table_cpuinfo(policy, freq_table);
- clk_disable_unprepare(emc_clk);
- return 0;
-}
-
-static struct freq_attr *tegra_cpufreq_attr[] = {
- &cpufreq_freq_attr_scaling_available_freqs,
- NULL,
-};
-
-static struct cpufreq_driver tegra_cpufreq_driver = {
- .verify = tegra_verify_speed,
- .target = tegra_target,
- .get = tegra_getspeed,
- .init = tegra_cpu_init,
- .exit = tegra_cpu_exit,
- .name = "tegra",
- .attr = tegra_cpufreq_attr,
-};
-
-static int __init tegra_cpufreq_init(void)
-{
- cpu_clk = clk_get_sys(NULL, "cpu");
- if (IS_ERR(cpu_clk))
- return PTR_ERR(cpu_clk);
-
- pll_x_clk = clk_get_sys(NULL, "pll_x");
- if (IS_ERR(pll_x_clk))
- return PTR_ERR(pll_x_clk);
-
- pll_p_clk = clk_get_sys(NULL, "pll_p_cclk");
- if (IS_ERR(pll_p_clk))
- return PTR_ERR(pll_p_clk);
-
- emc_clk = clk_get_sys("cpu", "emc");
- if (IS_ERR(emc_clk)) {
- clk_put(cpu_clk);
- return PTR_ERR(emc_clk);
- }
-
- return cpufreq_register_driver(&tegra_cpufreq_driver);
-}
-
-static void __exit tegra_cpufreq_exit(void)
-{
- cpufreq_unregister_driver(&tegra_cpufreq_driver);
- clk_put(emc_clk);
- clk_put(cpu_clk);
-}
-
-
-MODULE_AUTHOR("Colin Cross <ccross@android.com>");
-MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
-MODULE_LICENSE("GPL");
-module_init(tegra_cpufreq_init);
-module_exit(tegra_cpufreq_exit);
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
index 0f4e8c483b3..1d1c6023f4a 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra114.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra114.c
@@ -23,39 +23,13 @@
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.state_count = 1,
.states = {
[0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
},
};
-static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
-
int __init tegra114_cpuidle_init(void)
{
- int ret;
- unsigned int cpu;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &tegra_idle_driver;
-
- ret = cpuidle_register_driver(&tegra_idle_driver);
- if (ret) {
- pr_err("CPUidle driver registration failed\n");
- return ret;
- }
-
- for_each_possible_cpu(cpu) {
- dev = &per_cpu(tegra_idle_device, cpu);
- dev->cpu = cpu;
-
- dev->state_count = drv->state_count;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("CPU%u: CPUidle device registration failed\n",
- cpu);
- return ret;
- }
- }
- return 0;
+ return cpuidle_register(&tegra_idle_driver, NULL);
}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index 825ced4f7a4..0cdba8de8c7 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -43,32 +43,33 @@ static atomic_t abort_barrier;
static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index);
+#define TEGRA20_MAX_STATES 2
+#else
+#define TEGRA20_MAX_STATES 1
#endif
-static struct cpuidle_state tegra_idle_states[] = {
- [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
-#ifdef CONFIG_PM_SLEEP
- [1] = {
- .enter = tegra20_idle_lp2_coupled,
- .exit_latency = 5000,
- .target_residency = 10000,
- .power_usage = 0,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_COUPLED,
- .name = "powered-down",
- .desc = "CPU power gated",
- },
-#endif
-};
-
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
+ .states = {
+ ARM_CPUIDLE_WFI_STATE_PWR(600),
+#ifdef CONFIG_PM_SLEEP
+ {
+ .enter = tegra20_idle_lp2_coupled,
+ .exit_latency = 5000,
+ .target_residency = 10000,
+ .power_usage = 0,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_COUPLED,
+ .name = "powered-down",
+ .desc = "CPU power gated",
+ },
+#endif
+ },
+ .state_count = TEGRA20_MAX_STATES,
+ .safe_state_index = 0,
};
-static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
-
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_SMP
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -130,10 +131,6 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct cpuidle_state *state = &drv->states[index];
- u32 cpu_on_time = state->exit_latency;
- u32 cpu_off_time = state->target_residency - state->exit_latency;
-
while (tegra20_cpu_is_resettable_soon())
cpu_relax();
@@ -142,7 +139,7 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
- tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
+ tegra_idle_lp2_last();
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
@@ -217,39 +214,8 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
int __init tegra20_cpuidle_init(void)
{
- int ret;
- unsigned int cpu;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &tegra_idle_driver;
-
#ifdef CONFIG_PM_SLEEP
tegra_tear_down_cpu = tegra20_tear_down_cpu;
#endif
-
- drv->state_count = ARRAY_SIZE(tegra_idle_states);
- memcpy(drv->states, tegra_idle_states,
- drv->state_count * sizeof(drv->states[0]));
-
- ret = cpuidle_register_driver(&tegra_idle_driver);
- if (ret) {
- pr_err("CPUidle driver registration failed\n");
- return ret;
- }
-
- for_each_possible_cpu(cpu) {
- dev = &per_cpu(tegra_idle_device, cpu);
- dev->cpu = cpu;
-#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
- dev->coupled_cpus = *cpu_possible_mask;
-#endif
-
- dev->state_count = drv->state_count;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("CPU%u: CPUidle device registration failed\n",
- cpu);
- return ret;
- }
- }
- return 0;
+ return cpuidle_register(&tegra_idle_driver, cpu_possible_mask);
}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 8b50cf4ddd6..3cf9aca5f3e 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -43,7 +43,6 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
#ifdef CONFIG_PM_SLEEP
.state_count = 2,
#else
@@ -65,17 +64,11 @@ static struct cpuidle_driver tegra_idle_driver = {
},
};
-static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
-
#ifdef CONFIG_PM_SLEEP
static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct cpuidle_state *state = &drv->states[index];
- u32 cpu_on_time = state->exit_latency;
- u32 cpu_off_time = state->target_residency - state->exit_latency;
-
/* All CPUs entering LP2 is not working.
* Don't let CPU0 enter LP2 when any secondary CPU is online.
*/
@@ -86,7 +79,7 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
- tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
+ tegra_idle_lp2_last();
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
@@ -102,12 +95,8 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
smp_wmb();
- save_cpu_arch_register();
-
cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
- restore_cpu_arch_register();
-
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
return true;
@@ -157,32 +146,8 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
int __init tegra30_cpuidle_init(void)
{
- int ret;
- unsigned int cpu;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &tegra_idle_driver;
-
#ifdef CONFIG_PM_SLEEP
tegra_tear_down_cpu = tegra30_tear_down_cpu;
#endif
-
- ret = cpuidle_register_driver(&tegra_idle_driver);
- if (ret) {
- pr_err("CPUidle driver registration failed\n");
- return ret;
- }
-
- for_each_possible_cpu(cpu) {
- dev = &per_cpu(tegra_idle_device, cpu);
- dev->cpu = cpu;
-
- dev->state_count = drv->state_count;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("CPU%u: CPUidle device registration failed\n",
- cpu);
- return ret;
- }
- }
- return 0;
+ return cpuidle_register(&tegra_idle_driver, NULL);
}
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index f7db0782a6b..e035cd284a6 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/fuse.c
*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@android.com>
@@ -137,6 +138,9 @@ void tegra_init_fuse(void)
tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
tegra_init_speedo_data = &tegra30_init_speedo_data;
break;
+ case TEGRA114:
+ tegra_init_speedo_data = &tegra114_init_speedo_data;
+ break;
default:
pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index da78434678c..aacc00d0598 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@android.com>
@@ -66,4 +67,10 @@ void tegra30_init_speedo_data(void);
static inline void tegra30_init_speedo_data(void) {}
#endif
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+void tegra114_init_speedo_data(void);
+#else
+static inline void tegra114_init_speedo_data(void) {}
+#endif
+
#endif
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index fd473f2b4c3..045c16f2dd5 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -7,8 +7,5 @@
ENTRY(tegra_secondary_startup)
bl v7_invalidate_l1
- /* Enable coresight */
- mov32 r0, 0xC5ACCE55
- mcr p14, 0, r0, c7, c12, 6
b secondary_startup
ENDPROC(tegra_secondary_startup)
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index a599f6e36de..184914a68d7 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -1,8 +1,7 @@
/*
- *
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
- * Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2010, 2012-2013, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +11,9 @@
#include <linux/smp.h>
#include <linux/clk/tegra.h>
-#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
+#include "fuse.h"
#include "sleep.h"
static void (*tegra_hotplug_shutdown)(void);
@@ -47,27 +46,13 @@ void __ref tegra_cpu_die(unsigned int cpu)
BUG();
}
-int tegra_cpu_disable(unsigned int cpu)
-{
- /*
- * we don't allow CPU 0 to be shutdown (it is still too special
- * e.g. clock tick interrupts)
- */
- return cpu == 0 ? -EPERM : 0;
-}
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-extern void tegra20_hotplug_shutdown(void);
-void __init tegra20_hotplug_init(void)
+void __init tegra_hotplug_init(void)
{
- tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
-}
-#endif
+ if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
+ return;
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-extern void tegra30_hotplug_shutdown(void);
-void __init tegra30_hotplug_init(void)
-{
- tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
+ if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
+ tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
+ if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
+ tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
}
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/powergate.h b/arch/arm/mach-tegra/include/mach/powergate.h
deleted file mode 100644
index 06763fe7529..00000000000
--- a/arch/arm/mach-tegra/include/mach/powergate.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * drivers/regulator/tegra-regulator.c
- *
- * Copyright (c) 2010 Google, Inc
- *
- * Author:
- * Colin Cross <ccross@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _MACH_TEGRA_POWERGATE_H_
-#define _MACH_TEGRA_POWERGATE_H_
-
-struct clk;
-
-#define TEGRA_POWERGATE_CPU 0
-#define TEGRA_POWERGATE_3D 1
-#define TEGRA_POWERGATE_VENC 2
-#define TEGRA_POWERGATE_PCIE 3
-#define TEGRA_POWERGATE_VDEC 4
-#define TEGRA_POWERGATE_L2 5
-#define TEGRA_POWERGATE_MPE 6
-#define TEGRA_POWERGATE_HEG 7
-#define TEGRA_POWERGATE_SATA 8
-#define TEGRA_POWERGATE_CPU1 9
-#define TEGRA_POWERGATE_CPU2 10
-#define TEGRA_POWERGATE_CPU3 11
-#define TEGRA_POWERGATE_CELP 12
-#define TEGRA_POWERGATE_3D1 13
-
-#define TEGRA_POWERGATE_CPU0 TEGRA_POWERGATE_CPU
-#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
-
-int __init tegra_powergate_init(void);
-
-int tegra_cpu_powergate_id(int cpuid);
-int tegra_powergate_is_powered(int id);
-int tegra_powergate_power_on(int id);
-int tegra_powergate_power_off(int id);
-int tegra_powergate_remove_clamping(int id);
-
-/* Must be called with clk disabled, and returns with clk enabled */
-int tegra_powergate_sequence_power_up(int id, struct clk *clk);
-
-#endif /* _MACH_TEGRA_POWERGATE_H_ */
diff --git a/arch/arm/mach-tegra/include/mach/timex.h b/arch/arm/mach-tegra/include/mach/timex.h
deleted file mode 100644
index a44ccbdb7db..00000000000
--- a/arch/arm/mach-tegra/include/mach/timex.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/timex.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@google.com>
- * Erik Gilling <konkers@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MACH_TEGRA_TIMEX_H
-#define __MACH_TEGRA_TIMEX_H
-
-#define CLOCK_TICK_RATE 1000000
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
deleted file mode 100644
index 08386418196..00000000000
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/uncompress.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2011 Google, Inc.
- * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
- *
- * Author:
- * Colin Cross <ccross@google.com>
- * Erik Gilling <konkers@google.com>
- * Doug Anderson <dianders@chromium.org>
- * Stephen Warren <swarren@nvidia.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MACH_TEGRA_UNCOMPRESS_H
-#define __MACH_TEGRA_UNCOMPRESS_H
-
-#include <linux/types.h>
-#include <linux/serial_reg.h>
-
-#include "../../iomap.h"
-
-#define BIT(x) (1 << (x))
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-#define DEBUG_UART_SHIFT 2
-
-volatile u8 *uart;
-
-static void putc(int c)
-{
- if (uart == NULL)
- return;
-
- while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
- barrier();
- uart[UART_TX << DEBUG_UART_SHIFT] = c;
-}
-
-static inline void flush(void)
-{
-}
-
-static const struct {
- u32 base;
- u32 reset_reg;
- u32 clock_reg;
- u32 bit;
-} uarts[] = {
- {
- TEGRA_UARTA_BASE,
- TEGRA_CLK_RESET_BASE + 0x04,
- TEGRA_CLK_RESET_BASE + 0x10,
- 6,
- },
- {
- TEGRA_UARTB_BASE,
- TEGRA_CLK_RESET_BASE + 0x04,
- TEGRA_CLK_RESET_BASE + 0x10,
- 7,
- },
- {
- TEGRA_UARTC_BASE,
- TEGRA_CLK_RESET_BASE + 0x08,
- TEGRA_CLK_RESET_BASE + 0x14,
- 23,
- },
- {
- TEGRA_UARTD_BASE,
- TEGRA_CLK_RESET_BASE + 0x0c,
- TEGRA_CLK_RESET_BASE + 0x18,
- 1,
- },
- {
- TEGRA_UARTE_BASE,
- TEGRA_CLK_RESET_BASE + 0x0c,
- TEGRA_CLK_RESET_BASE + 0x18,
- 2,
- },
-};
-
-static inline bool uart_clocked(int i)
-{
- if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
- return false;
-
- if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
- return false;
-
- return true;
-}
-
-#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA
-int auto_odmdata(void)
-{
- volatile u32 *pmc = (volatile u32 *)TEGRA_PMC_BASE;
- u32 odmdata = pmc[0xa0 / 4];
-
- /*
- * Bits 19:18 are the console type: 0=default, 1=none, 2==DCC, 3==UART
- * Some boards apparently swap the last two values, but we don't have
- * any way of catering for that here, so we just accept either. If this
- * doesn't make sense for your board, just don't enable this feature.
- *
- * Bits 17:15 indicate the UART to use, 0/1/2/3/4 are UART A/B/C/D/E.
- */
-
- switch ((odmdata >> 18) & 3) {
- case 2:
- case 3:
- break;
- default:
- return -1;
- }
-
- return (odmdata >> 15) & 7;
-}
-#endif
-
-/*
- * Setup before decompression. This is where we do UART selection for
- * earlyprintk and init the uart_base register.
- */
-static inline void arch_decomp_setup(void)
-{
- int uart_id;
- volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
- u32 chip, div;
-
-#if defined(CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA)
- uart_id = auto_odmdata();
-#elif defined(CONFIG_TEGRA_DEBUG_UARTA)
- uart_id = 0;
-#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
- uart_id = 1;
-#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
- uart_id = 2;
-#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
- uart_id = 3;
-#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
- uart_id = 4;
-#endif
-
- if (uart_id < 0 || uart_id >= ARRAY_SIZE(uarts) ||
- !uart_clocked(uart_id))
- uart = NULL;
- else
- uart = (volatile u8 *)uarts[uart_id].base;
-
- if (uart == NULL)
- return;
-
- chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
- if (chip == 0x20)
- div = 0x0075;
- else
- div = 0x00dd;
-
- uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
- uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
- uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
- uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 1952e82797c..0de4eed1493 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -4,7 +4,7 @@
* Author:
* Colin Cross <ccross@android.com>
*
- * Copyright (C) 2010, NVIDIA Corporation
+ * Copyright (C) 2010,2013, NVIDIA Corporation
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/syscore_ops.h>
#include "board.h"
#include "iomap.h"
@@ -43,6 +44,7 @@
#define ICTLR_COP_IEP_CLASS 0x3c
#define FIRST_LEGACY_IRQ 32
+#define TEGRA_MAX_NUM_ICTLRS 5
#define SGI_MASK 0xFFFF
@@ -56,6 +58,15 @@ static void __iomem *ictlr_reg_base[] = {
IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
};
+#ifdef CONFIG_PM_SLEEP
+static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS];
+static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS];
+static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS];
+static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS];
+
+static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS];
+#endif
+
bool tegra_pending_sgi(void)
{
u32 pending_set;
@@ -125,6 +136,87 @@ static int tegra_retrigger(struct irq_data *d)
return 1;
}
+#ifdef CONFIG_PM_SLEEP
+static int tegra_set_wake(struct irq_data *d, unsigned int enable)
+{
+ u32 irq = d->irq;
+ u32 index, mask;
+
+ if (irq < FIRST_LEGACY_IRQ ||
+ irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32)
+ return -EINVAL;
+
+ index = ((irq - FIRST_LEGACY_IRQ) / 32);
+ mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
+ if (enable)
+ ictlr_wake_mask[index] |= mask;
+ else
+ ictlr_wake_mask[index] &= ~mask;
+
+ return 0;
+}
+
+static int tegra_legacy_irq_suspend(void)
+{
+ unsigned long flags;
+ int i;
+
+ local_irq_save(flags);
+ for (i = 0; i < num_ictlrs; i++) {
+ void __iomem *ictlr = ictlr_reg_base[i];
+ /* Save interrupt state */
+ cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER);
+ cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS);
+ cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER);
+ cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS);
+
+ /* Disable COP interrupts */
+ writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
+
+ /* Disable CPU interrupts */
+ writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+
+ /* Enable the wakeup sources of ictlr */
+ writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
+ }
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static void tegra_legacy_irq_resume(void)
+{
+ unsigned long flags;
+ int i;
+
+ local_irq_save(flags);
+ for (i = 0; i < num_ictlrs; i++) {
+ void __iomem *ictlr = ictlr_reg_base[i];
+ writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
+ writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+ writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
+ writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS);
+ writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR);
+ writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
+ }
+ local_irq_restore(flags);
+}
+
+static struct syscore_ops tegra_legacy_irq_syscore_ops = {
+ .suspend = tegra_legacy_irq_suspend,
+ .resume = tegra_legacy_irq_resume,
+};
+
+int tegra_legacy_irq_syscore_init(void)
+{
+ register_syscore_ops(&tegra_legacy_irq_syscore_ops);
+
+ return 0;
+}
+#else
+#define tegra_set_wake NULL
+#endif
+
void __init tegra_init_irq(void)
{
int i;
@@ -150,6 +242,8 @@ void __init tegra_init_irq(void)
gic_arch_extn.irq_mask = tegra_mask;
gic_arch_extn.irq_unmask = tegra_unmask;
gic_arch_extn.irq_retrigger = tegra_retrigger;
+ gic_arch_extn.irq_set_wake = tegra_set_wake;
+ gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
/*
* Check if there is a devicetree present, since the GIC will be
diff --git a/arch/arm/mach-tegra/irq.h b/arch/arm/mach-tegra/irq.h
index 5142649bba0..bc05ce5613f 100644
--- a/arch/arm/mach-tegra/irq.h
+++ b/arch/arm/mach-tegra/irq.h
@@ -19,4 +19,10 @@
bool tegra_pending_sgi(void);
+#ifdef CONFIG_PM_SLEEP
+int tegra_legacy_irq_syscore_init(void);
+#else
+static inline int tegra_legacy_irq_syscore_init(void) { return 0; }
+#endif
+
#endif
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index b60165f1ca0..46144a19a7e 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -34,12 +34,11 @@
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/clk/tegra.h>
+#include <linux/tegra-powergate.h>
#include <asm/sizes.h>
#include <asm/mach/pci.h>
-#include <mach/powergate.h>
-
#include "board.h"
#include "iomap.h"
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 2c6b3d55213..fad4226ef71 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -18,7 +18,6 @@
#include <linux/jiffies.h>
#include <linux/smp.h>
#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
#include <linux/clk/tegra.h>
#include <asm/cacheflush.h>
@@ -26,53 +25,58 @@
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>
-#include <mach/powergate.h>
-
#include "fuse.h"
#include "flowctrl.h"
#include "reset.h"
+#include "pmc.h"
#include "common.h"
#include "iomap.h"
-extern void tegra_secondary_startup(void);
-
static cpumask_t tegra_cpu_init_mask;
-#define EVP_CPU_RESET_VECTOR \
- (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
-
static void __cpuinit tegra_secondary_init(unsigned int cpu)
{
- /*
- * if any interrupts are already enabled for the primary
- * core (e.g. timer irq), then they will not have been enabled
- * for us: do so
- */
- gic_secondary_init(0);
-
cpumask_set_cpu(cpu, &tegra_cpu_init_mask);
}
-static int tegra20_power_up_cpu(unsigned int cpu)
+
+static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- /* Enable the CPU clock. */
- tegra_enable_cpu_clock(cpu);
+ cpu = cpu_logical_map(cpu);
+
+ /*
+ * Force the CPU into reset. The CPU must remain in reset when
+ * the flow controller state is cleared (which will cause the
+ * flow controller to stop driving reset if the CPU has been
+ * power-gated via the flow controller). This will have no
+ * effect on first boot of the CPU since it should already be
+ * in reset.
+ */
+ tegra_put_cpu_in_reset(cpu);
- /* Clear flow controller CSR. */
- flowctrl_write_cpu_csr(cpu, 0);
+ /*
+ * Unhalt the CPU. If the flow controller was used to
+ * power-gate the CPU this will cause the flow controller to
+ * stop driving reset. The CPU will remain in reset because the
+ * clock and reset block is now driving reset.
+ */
+ flowctrl_write_cpu_halt(cpu, 0);
+ tegra_enable_cpu_clock(cpu);
+ flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */
+ tegra_cpu_out_of_reset(cpu);
return 0;
}
-static int tegra30_power_up_cpu(unsigned int cpu)
+static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- int ret, pwrgateid;
+ int ret;
unsigned long timeout;
- pwrgateid = tegra_cpu_powergate_id(cpu);
- if (pwrgateid < 0)
- return pwrgateid;
+ cpu = cpu_logical_map(cpu);
+ tegra_put_cpu_in_reset(cpu);
+ flowctrl_write_cpu_halt(cpu, 0);
/*
* The power up sequence of cold boot CPU and warm boot CPU
@@ -85,13 +89,13 @@ static int tegra30_power_up_cpu(unsigned int cpu)
* the IO clamps.
* For cold boot CPU, do not wait. After the cold boot CPU be
* booted, it will run to tegra_secondary_init() and set
- * tegra_cpu_init_mask which influences what tegra30_power_up_cpu()
+ * tegra_cpu_init_mask which influences what tegra30_boot_secondary()
* next time around.
*/
if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) {
timeout = jiffies + msecs_to_jiffies(50);
do {
- if (!tegra_powergate_is_powered(pwrgateid))
+ if (tegra_pmc_cpu_is_powered(cpu))
goto remove_clamps;
udelay(10);
} while (time_before(jiffies, timeout));
@@ -103,14 +107,14 @@ static int tegra30_power_up_cpu(unsigned int cpu)
* be un-gated by un-toggling the power gate register
* manually.
*/
- if (!tegra_powergate_is_powered(pwrgateid)) {
- ret = tegra_powergate_power_on(pwrgateid);
+ if (!tegra_pmc_cpu_is_powered(cpu)) {
+ ret = tegra_pmc_cpu_power_on(cpu);
if (ret)
return ret;
/* Wait for the power to come up. */
timeout = jiffies + msecs_to_jiffies(100);
- while (tegra_powergate_is_powered(pwrgateid)) {
+ while (tegra_pmc_cpu_is_powered(cpu)) {
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
udelay(10);
@@ -123,57 +127,34 @@ remove_clamps:
udelay(10);
/* Remove I/O clamps. */
- ret = tegra_powergate_remove_clamping(pwrgateid);
- udelay(10);
+ ret = tegra_pmc_cpu_remove_clamping(cpu);
+ if (ret)
+ return ret;
- /* Clear flow controller CSR. */
- flowctrl_write_cpu_csr(cpu, 0);
+ udelay(10);
+ flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */
+ tegra_cpu_out_of_reset(cpu);
return 0;
}
-static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct *idle)
+static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- int status;
-
cpu = cpu_logical_map(cpu);
+ return tegra_pmc_cpu_power_on(cpu);
+}
- /*
- * Force the CPU into reset. The CPU must remain in reset when the
- * flow controller state is cleared (which will cause the flow
- * controller to stop driving reset if the CPU has been power-gated
- * via the flow controller). This will have no effect on first boot
- * of the CPU since it should already be in reset.
- */
- tegra_put_cpu_in_reset(cpu);
-
- /*
- * Unhalt the CPU. If the flow controller was used to power-gate the
- * CPU this will cause the flow controller to stop driving reset.
- * The CPU will remain in reset because the clock and reset block
- * is now driving reset.
- */
- flowctrl_write_cpu_halt(cpu, 0);
-
- switch (tegra_chip_id) {
- case TEGRA20:
- status = tegra20_power_up_cpu(cpu);
- break;
- case TEGRA30:
- status = tegra30_power_up_cpu(cpu);
- break;
- default:
- status = -EINVAL;
- break;
- }
-
- if (status)
- goto done;
-
- /* Take the CPU out of reset. */
- tegra_cpu_out_of_reset(cpu);
-done:
- return status;
+static int __cpuinit tegra_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20)
+ return tegra20_boot_secondary(cpu, idle);
+ if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30)
+ return tegra30_boot_secondary(cpu, idle);
+ if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114)
+ return tegra114_boot_secondary(cpu, idle);
+
+ return -EINVAL;
}
static void __init tegra_smp_prepare_cpus(unsigned int max_cpus)
@@ -192,6 +173,5 @@ 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
};
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 523604de666..45cf52c7e52 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -22,7 +22,7 @@
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/cpu_pm.h>
-#include <linux/clk.h>
+#include <linux/suspend.h>
#include <linux/err.h>
#include <linux/clk/tegra.h>
@@ -37,67 +37,13 @@
#include "reset.h"
#include "flowctrl.h"
#include "fuse.h"
+#include "pmc.h"
#include "sleep.h"
-#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
-
-#define PMC_CTRL 0x0
-#define PMC_CPUPWRGOOD_TIMER 0xc8
-#define PMC_CPUPWROFF_TIMER 0xcc
-
#ifdef CONFIG_PM_SLEEP
-static unsigned int g_diag_reg;
static DEFINE_SPINLOCK(tegra_lp2_lock);
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-static struct clk *tegra_pclk;
void (*tegra_tear_down_cpu)(void);
-void save_cpu_arch_register(void)
-{
- /* read diagnostic register */
- asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
- return;
-}
-
-void restore_cpu_arch_register(void)
-{
- /* write diagnostic register */
- asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
- return;
-}
-
-static void set_power_timers(unsigned long us_on, unsigned long us_off)
-{
- unsigned long long ticks;
- unsigned long long pclk;
- unsigned long rate;
- static unsigned long tegra_last_pclk;
-
- if (tegra_pclk == NULL) {
- tegra_pclk = clk_get_sys(NULL, "pclk");
- WARN_ON(IS_ERR(tegra_pclk));
- }
-
- rate = clk_get_rate(tegra_pclk);
-
- if (WARN_ON_ONCE(rate <= 0))
- pclk = 100000000;
- else
- pclk = rate;
-
- if ((rate != tegra_last_pclk)) {
- ticks = (us_on * pclk) + 999999ull;
- do_div(ticks, 1000000);
- writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
-
- ticks = (us_off * pclk) + 999999ull;
- do_div(ticks, 1000000);
- writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
- wmb();
- }
- tegra_last_pclk = pclk;
-}
-
/*
* restore_cpu_complex
*
@@ -119,8 +65,6 @@ static void restore_cpu_complex(void)
tegra_cpu_clock_resume();
flowctrl_cpu_suspend_exit(cpu);
-
- restore_cpu_arch_register();
}
/*
@@ -145,8 +89,6 @@ static void suspend_cpu_complex(void)
tegra_cpu_clock_suspend();
flowctrl_cpu_suspend_enter(cpu);
-
- save_cpu_arch_register();
}
void tegra_clear_cpu_in_lp2(int phy_cpu_id)
@@ -181,14 +123,14 @@ bool tegra_set_cpu_in_lp2(int phy_cpu_id)
return last_cpu;
}
-static int tegra_sleep_cpu(unsigned long v2p)
+int tegra_cpu_do_idle(void)
{
- /* Switch to the identity mapping. */
- cpu_switch_mm(idmap_pgd, &init_mm);
-
- /* Flush the TLB. */
- local_flush_tlb_all();
+ return cpu_do_idle();
+}
+static int tegra_sleep_cpu(unsigned long v2p)
+{
+ setup_mm_for_reboot();
tegra_sleep_cpu_finish(v2p);
/* should never here */
@@ -197,16 +139,9 @@ static int tegra_sleep_cpu(unsigned long v2p)
return 0;
}
-void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
+void tegra_idle_lp2_last(void)
{
- u32 mode;
-
- /* Only the last cpu down does the final suspend steps */
- mode = readl(pmc + PMC_CTRL);
- mode |= TEGRA_POWER_CPU_PWRREQ_OE;
- writel(mode, pmc + PMC_CTRL);
-
- set_power_timers(cpu_on_time, cpu_off_time);
+ tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
cpu_cluster_pm_enter();
suspend_cpu_complex();
@@ -216,4 +151,81 @@ void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
restore_cpu_complex();
cpu_cluster_pm_exit();
}
+
+enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
+ enum tegra_suspend_mode mode)
+{
+ /* Tegra114 didn't support any suspending mode yet. */
+ if (tegra_chip_id == TEGRA114)
+ return TEGRA_SUSPEND_NONE;
+
+ /*
+ * The Tegra devices only support suspending to LP2 currently.
+ */
+ if (mode > TEGRA_SUSPEND_LP2)
+ return TEGRA_SUSPEND_LP2;
+
+ return mode;
+}
+
+static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
+ [TEGRA_SUSPEND_NONE] = "none",
+ [TEGRA_SUSPEND_LP2] = "LP2",
+ [TEGRA_SUSPEND_LP1] = "LP1",
+ [TEGRA_SUSPEND_LP0] = "LP0",
+};
+
+static int __cpuinit tegra_suspend_enter(suspend_state_t state)
+{
+ enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
+
+ if (WARN_ON(mode < TEGRA_SUSPEND_NONE ||
+ mode >= TEGRA_MAX_SUSPEND_MODE))
+ return -EINVAL;
+
+ pr_info("Entering suspend state %s\n", lp_state[mode]);
+
+ tegra_pmc_pm_set(mode);
+
+ local_fiq_disable();
+
+ suspend_cpu_complex();
+ switch (mode) {
+ case TEGRA_SUSPEND_LP2:
+ tegra_set_cpu_in_lp2(0);
+ break;
+ default:
+ break;
+ }
+
+ cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
+
+ switch (mode) {
+ case TEGRA_SUSPEND_LP2:
+ tegra_clear_cpu_in_lp2(0);
+ break;
+ default:
+ break;
+ }
+ restore_cpu_complex();
+
+ local_fiq_enable();
+
+ return 0;
+}
+
+static const struct platform_suspend_ops tegra_suspend_ops = {
+ .valid = suspend_valid_only_mem,
+ .enter = tegra_suspend_enter,
+};
+
+void __init tegra_init_suspend(void)
+{
+ if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
+ return;
+
+ tegra_pmc_suspend_init();
+
+ suspend_set_ops(&tegra_suspend_ops);
+}
#endif
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index 787335cc964..778a4aa7c3f 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -21,6 +21,8 @@
#ifndef _MACH_TEGRA_PM_H_
#define _MACH_TEGRA_PM_H_
+#include "pmc.h"
+
extern unsigned long l2x0_saved_regs_addr;
void save_cpu_arch_register(void);
@@ -29,7 +31,20 @@ 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_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time);
+void tegra_idle_lp2_last(void);
extern void (*tegra_tear_down_cpu)(void);
+#ifdef CONFIG_PM_SLEEP
+enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
+ enum tegra_suspend_mode mode);
+void tegra_init_suspend(void);
+#else
+static inline enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
+ enum tegra_suspend_mode mode)
+{
+ return TEGRA_SUSPEND_NONE;
+}
+static inline void tegra_init_suspend(void) {}
+#endif
+
#endif /* _MACH_TEGRA_PM_H_ */
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
index d4fdb5fcec2..32360e540ce 100644
--- a/arch/arm/mach-tegra/pmc.c
+++ b/arch/arm/mach-tegra/pmc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2012,2013 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -16,59 +16,313 @@
*/
#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
-#include "iomap.h"
+#include "fuse.h"
+#include "pm.h"
+#include "pmc.h"
+#include "sleep.h"
-#define PMC_CTRL 0x0
-#define PMC_CTRL_INTR_LOW (1 << 17)
+#define TEGRA_POWER_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */
+#define TEGRA_POWER_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */
+#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
+
+#define PMC_CTRL 0x0
+#define PMC_CTRL_INTR_LOW (1 << 17)
+#define PMC_PWRGATE_TOGGLE 0x30
+#define PMC_PWRGATE_TOGGLE_START (1 << 8)
+#define PMC_REMOVE_CLAMPING 0x34
+#define PMC_PWRGATE_STATUS 0x38
+
+#define PMC_CPUPWRGOOD_TIMER 0xc8
+#define PMC_CPUPWROFF_TIMER 0xcc
+
+#define TEGRA_POWERGATE_PCIE 3
+#define TEGRA_POWERGATE_VDEC 4
+#define TEGRA_POWERGATE_CPU1 9
+#define TEGRA_POWERGATE_CPU2 10
+#define TEGRA_POWERGATE_CPU3 11
+
+static u8 tegra_cpu_domains[] = {
+ 0xFF, /* not available for CPU0 */
+ TEGRA_POWERGATE_CPU1,
+ TEGRA_POWERGATE_CPU2,
+ TEGRA_POWERGATE_CPU3,
+};
+static DEFINE_SPINLOCK(tegra_powergate_lock);
+
+static void __iomem *tegra_pmc_base;
+static bool tegra_pmc_invert_interrupt;
+static struct clk *tegra_pclk;
+
+struct pmc_pm_data {
+ u32 cpu_good_time; /* CPU power good time in uS */
+ u32 cpu_off_time; /* CPU power off time in uS */
+ u32 core_osc_time; /* Core power good osc time in uS */
+ u32 core_pmu_time; /* Core power good pmu time in uS */
+ u32 core_off_time; /* Core power off time in uS */
+ bool corereq_high; /* Core power request active-high */
+ bool sysclkreq_high; /* System clock request active-high */
+ bool combined_req; /* Combined pwr req for CPU & Core */
+ bool cpu_pwr_good_en; /* CPU power good signal is enabled */
+ u32 lp0_vec_phy_addr; /* The phy addr of LP0 warm boot code */
+ u32 lp0_vec_size; /* The size of LP0 warm boot code */
+ enum tegra_suspend_mode suspend_mode;
+};
+static struct pmc_pm_data pmc_pm_data;
static inline u32 tegra_pmc_readl(u32 reg)
{
- return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
+ return readl(tegra_pmc_base + reg);
}
static inline void tegra_pmc_writel(u32 val, u32 reg)
{
- writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
+ writel(val, tegra_pmc_base + reg);
+}
+
+static int tegra_pmc_get_cpu_powerdomain_id(int cpuid)
+{
+ if (cpuid <= 0 || cpuid >= num_possible_cpus())
+ return -EINVAL;
+ return tegra_cpu_domains[cpuid];
+}
+
+static bool tegra_pmc_powergate_is_powered(int id)
+{
+ return (tegra_pmc_readl(PMC_PWRGATE_STATUS) >> id) & 1;
+}
+
+static int tegra_pmc_powergate_set(int id, bool new_state)
+{
+ bool old_state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tegra_powergate_lock, flags);
+
+ old_state = tegra_pmc_powergate_is_powered(id);
+ WARN_ON(old_state == new_state);
+
+ tegra_pmc_writel(PMC_PWRGATE_TOGGLE_START | id, PMC_PWRGATE_TOGGLE);
+
+ spin_unlock_irqrestore(&tegra_powergate_lock, flags);
+
+ return 0;
+}
+
+static int tegra_pmc_powergate_remove_clamping(int id)
+{
+ u32 mask;
+
+ /*
+ * Tegra has a bug where PCIE and VDE clamping masks are
+ * swapped relatively to the partition ids.
+ */
+ if (id == TEGRA_POWERGATE_VDEC)
+ mask = (1 << TEGRA_POWERGATE_PCIE);
+ else if (id == TEGRA_POWERGATE_PCIE)
+ mask = (1 << TEGRA_POWERGATE_VDEC);
+ else
+ mask = (1 << id);
+
+ tegra_pmc_writel(mask, PMC_REMOVE_CLAMPING);
+
+ return 0;
+}
+
+bool tegra_pmc_cpu_is_powered(int cpuid)
+{
+ int id;
+
+ id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
+ if (id < 0)
+ return false;
+ return tegra_pmc_powergate_is_powered(id);
}
-#ifdef CONFIG_OF
+int tegra_pmc_cpu_power_on(int cpuid)
+{
+ int id;
+
+ id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
+ if (id < 0)
+ return id;
+ return tegra_pmc_powergate_set(id, true);
+}
+
+int tegra_pmc_cpu_remove_clamping(int cpuid)
+{
+ int id;
+
+ id = tegra_pmc_get_cpu_powerdomain_id(cpuid);
+ if (id < 0)
+ return id;
+ return tegra_pmc_powergate_remove_clamping(id);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void set_power_timers(u32 us_on, u32 us_off, unsigned long rate)
+{
+ unsigned long long ticks;
+ unsigned long long pclk;
+ static unsigned long tegra_last_pclk;
+
+ if (WARN_ON_ONCE(rate <= 0))
+ pclk = 100000000;
+ else
+ pclk = rate;
+
+ if ((rate != tegra_last_pclk)) {
+ ticks = (us_on * pclk) + 999999ull;
+ do_div(ticks, 1000000);
+ tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWRGOOD_TIMER);
+
+ ticks = (us_off * pclk) + 999999ull;
+ do_div(ticks, 1000000);
+ tegra_pmc_writel((unsigned long)ticks, PMC_CPUPWROFF_TIMER);
+ wmb();
+ }
+ tegra_last_pclk = pclk;
+}
+
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void)
+{
+ return pmc_pm_data.suspend_mode;
+}
+
+void tegra_pmc_pm_set(enum tegra_suspend_mode mode)
+{
+ u32 reg;
+ unsigned long rate = 0;
+
+ reg = tegra_pmc_readl(PMC_CTRL);
+ reg |= TEGRA_POWER_CPU_PWRREQ_OE;
+ reg &= ~TEGRA_POWER_EFFECT_LP0;
+
+ switch (mode) {
+ case TEGRA_SUSPEND_LP2:
+ rate = clk_get_rate(tegra_pclk);
+ break;
+ default:
+ break;
+ }
+
+ set_power_timers(pmc_pm_data.cpu_good_time, pmc_pm_data.cpu_off_time,
+ rate);
+
+ tegra_pmc_writel(reg, PMC_CTRL);
+}
+
+void tegra_pmc_suspend_init(void)
+{
+ u32 reg;
+
+ /* Always enable CPU power request */
+ reg = tegra_pmc_readl(PMC_CTRL);
+ reg |= TEGRA_POWER_CPU_PWRREQ_OE;
+ tegra_pmc_writel(reg, PMC_CTRL);
+}
+#endif
+
static const struct of_device_id matches[] __initconst = {
+ { .compatible = "nvidia,tegra114-pmc" },
+ { .compatible = "nvidia,tegra30-pmc" },
{ .compatible = "nvidia,tegra20-pmc" },
{ }
};
-#endif
-void __init tegra_pmc_init(void)
+static void tegra_pmc_parse_dt(void)
{
- /*
- * For now, Harmony is the only board that uses the PMC, and it wants
- * the signal inverted. Seaboard would too if it used the PMC.
- * Hopefully by the time other boards want to use the PMC, everything
- * will be device-tree, or they also want it inverted.
- */
- bool invert_interrupt = true;
- u32 val;
+ struct device_node *np;
+ u32 prop;
+ enum tegra_suspend_mode suspend_mode;
+ u32 core_good_time[2] = {0, 0};
+ u32 lp0_vec[2] = {0, 0};
-#ifdef CONFIG_OF
- if (of_have_populated_dt()) {
- struct device_node *np;
+ np = of_find_matching_node(NULL, matches);
+ BUG_ON(!np);
- invert_interrupt = false;
+ tegra_pmc_base = of_iomap(np, 0);
- np = of_find_matching_node(NULL, matches);
- if (np) {
- if (of_find_property(np, "nvidia,invert-interrupt",
- NULL))
- invert_interrupt = true;
+ tegra_pmc_invert_interrupt = of_property_read_bool(np,
+ "nvidia,invert-interrupt");
+ tegra_pclk = of_clk_get_by_name(np, "pclk");
+ WARN_ON(IS_ERR(tegra_pclk));
+
+ /* Grabbing the power management configurations */
+ if (of_property_read_u32(np, "nvidia,suspend-mode", &prop)) {
+ suspend_mode = TEGRA_SUSPEND_NONE;
+ } else {
+ switch (prop) {
+ case 0:
+ suspend_mode = TEGRA_SUSPEND_LP0;
+ break;
+ case 1:
+ suspend_mode = TEGRA_SUSPEND_LP1;
+ break;
+ case 2:
+ suspend_mode = TEGRA_SUSPEND_LP2;
+ break;
+ default:
+ suspend_mode = TEGRA_SUSPEND_NONE;
+ break;
}
}
-#endif
+ suspend_mode = tegra_pm_validate_suspend_mode(suspend_mode);
+
+ if (of_property_read_u32(np, "nvidia,cpu-pwr-good-time", &prop))
+ suspend_mode = TEGRA_SUSPEND_NONE;
+ pmc_pm_data.cpu_good_time = prop;
+
+ if (of_property_read_u32(np, "nvidia,cpu-pwr-off-time", &prop))
+ suspend_mode = TEGRA_SUSPEND_NONE;
+ pmc_pm_data.cpu_off_time = prop;
+
+ if (of_property_read_u32_array(np, "nvidia,core-pwr-good-time",
+ core_good_time, ARRAY_SIZE(core_good_time)))
+ suspend_mode = TEGRA_SUSPEND_NONE;
+ pmc_pm_data.core_osc_time = core_good_time[0];
+ pmc_pm_data.core_pmu_time = core_good_time[1];
+
+ if (of_property_read_u32(np, "nvidia,core-pwr-off-time",
+ &prop))
+ suspend_mode = TEGRA_SUSPEND_NONE;
+ pmc_pm_data.core_off_time = prop;
+
+ pmc_pm_data.corereq_high = of_property_read_bool(np,
+ "nvidia,core-power-req-active-high");
+
+ pmc_pm_data.sysclkreq_high = of_property_read_bool(np,
+ "nvidia,sys-clock-req-active-high");
+
+ pmc_pm_data.combined_req = of_property_read_bool(np,
+ "nvidia,combined-power-req");
+
+ pmc_pm_data.cpu_pwr_good_en = of_property_read_bool(np,
+ "nvidia,cpu-pwr-good-en");
+
+ if (of_property_read_u32_array(np, "nvidia,lp0-vec", lp0_vec,
+ ARRAY_SIZE(lp0_vec)))
+ if (suspend_mode == TEGRA_SUSPEND_LP0)
+ suspend_mode = TEGRA_SUSPEND_LP1;
+
+ pmc_pm_data.lp0_vec_phy_addr = lp0_vec[0];
+ pmc_pm_data.lp0_vec_size = lp0_vec[1];
+
+ pmc_pm_data.suspend_mode = suspend_mode;
+}
+
+void __init tegra_pmc_init(void)
+{
+ u32 val;
+
+ tegra_pmc_parse_dt();
val = tegra_pmc_readl(PMC_CTRL);
- if (invert_interrupt)
+ if (tegra_pmc_invert_interrupt)
val |= PMC_CTRL_INTR_LOW;
else
val &= ~PMC_CTRL_INTR_LOW;
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
index 8995ee4a876..e1c2df272f7 100644
--- a/arch/arm/mach-tegra/pmc.h
+++ b/arch/arm/mach-tegra/pmc.h
@@ -18,6 +18,24 @@
#ifndef __MACH_TEGRA_PMC_H
#define __MACH_TEGRA_PMC_H
+enum tegra_suspend_mode {
+ TEGRA_SUSPEND_NONE = 0,
+ TEGRA_SUSPEND_LP2, /* CPU voltage off */
+ TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
+ TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
+ TEGRA_MAX_SUSPEND_MODE,
+};
+
+#ifdef CONFIG_PM_SLEEP
+enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void);
+void tegra_pmc_pm_set(enum tegra_suspend_mode mode);
+void tegra_pmc_suspend_init(void);
+#endif
+
+bool tegra_pmc_cpu_is_powered(int cpuid);
+int tegra_pmc_cpu_power_on(int cpuid);
+int tegra_pmc_cpu_remove_clamping(int cpuid);
+
void tegra_pmc_init(void);
#endif
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index c6bc8f85759..f076f0f80fc 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -22,13 +22,13 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/export.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/clk/tegra.h>
-
-#include <mach/powergate.h>
+#include <linux/tegra-powergate.h>
#include "fuse.h"
#include "iomap.h"
@@ -75,7 +75,7 @@ static int tegra_powergate_set(int id, bool new_state)
if (status == new_state) {
spin_unlock_irqrestore(&tegra_powergate_lock, flags);
- return -EINVAL;
+ return 0;
}
pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
@@ -168,6 +168,7 @@ err_clk:
err_power:
return ret;
}
+EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
int tegra_cpu_powergate_id(int cpuid)
{
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 54382ceade4..e6de88a2ea0 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -41,12 +41,10 @@
*/
ENTRY(tegra_resume)
bl v7_invalidate_l1
- /* Enable coresight */
- mov32 r0, 0xC5ACCE55
- mcr p14, 0, r0, c7, c12, 6
cpu_id r0
cmp r0, #0 @ CPU0?
+ THUMB( it ne )
bne cpu_resume @ no
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -99,6 +97,8 @@ ENTRY(__tegra_cpu_reset_handler_start)
*
* Register usage within the reset handler:
*
+ * Others: scratch
+ * R6 = SoC ID << 8
* R7 = CPU present (to the OS) mask
* R8 = CPU in LP1 state mask
* R9 = CPU in LP2 state mask
@@ -114,6 +114,40 @@ ENTRY(__tegra_cpu_reset_handler_start)
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
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+t20_check:
+ cmp r6, #(0x20 << 8)
+ bne after_t20_check
+t20_errata:
+ # Tegra20 is a Cortex-A9 r1p1
+ mrc p15, 0, r0, c1, c0, 0 @ read system control register
+ orr r0, r0, #1 << 14 @ erratum 716044
+ mcr p15, 0, r0, c1, c0, 0 @ write system control register
+ mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
+ orr r0, r0, #1 << 4 @ erratum 742230
+ orr r0, r0, #1 << 11 @ erratum 751472
+ mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
+ b after_errata
+after_t20_check:
+#endif
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+t30_check:
+ cmp r6, #(0x30 << 8)
+ bne after_t30_check
+t30_errata:
+ # Tegra30 is a Cortex-A9 r2p9
+ mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register
+ orr r0, r0, #1 << 6 @ erratum 743622
+ orr r0, r0, #1 << 11 @ erratum 751472
+ mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register
+ b after_errata
+after_t30_check:
+#endif
+after_errata:
mrc p15, 0, r10, c0, c0, 5 @ MPIDR
and r10, r10, #0x3 @ R10 = CPU number
mov r11, #1
@@ -129,16 +163,13 @@ ENTRY(__tegra_cpu_reset_handler)
#ifdef CONFIG_ARCH_TEGRA_2x_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, #(0x20 << 8)
bne 1f
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
- mov32 r6, TEGRA_PMC_BASE
+ mov32 r5, TEGRA_PMC_BASE
mov r0, #0
cmp r10, #0
- strne r0, [r6, #PMC_SCRATCH41]
+ strne r0, [r5, #PMC_SCRATCH41]
1:
#endif
diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S
index 9f6bfafdd51..e3f2417c420 100644
--- a/arch/arm/mach-tegra/sleep-tegra20.S
+++ b/arch/arm/mach-tegra/sleep-tegra20.S
@@ -197,7 +197,7 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
mov r3, #CPU_RESETTABLE
str r3, [r0]
- bl cpu_do_idle
+ bl tegra_cpu_do_idle
/*
* cpu may be reset while in wfi, which will return through
diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S
index 63a15bd9b65..d29dfcce948 100644
--- a/arch/arm/mach-tegra/sleep-tegra30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -66,7 +66,9 @@ ENTRY(tegra30_cpu_shutdown)
FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
FLOW_CTRL_CSR_ENABLE
mov r4, #(1 << 4)
- orr r12, r12, r4, lsl r3
+ ARM( orr r12, r12, r4, lsl r3 )
+ THUMB( lsl r4, r4, r3 )
+ THUMB( orr r12, r12, r4 )
str r12, [r1]
/* Halt this CPU. */
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 4ffae541726..2080fb12ce2 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -92,7 +92,7 @@
#ifdef CONFIG_CACHE_L2X0
.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs
- adr \tmp1, \phys_l2x0_saved_regs
+ W(adr) \tmp1, \phys_l2x0_saved_regs
ldr \tmp1, [\tmp1]
ldr \tmp2, [\tmp1, #L2X0_R_PHY_BASE]
ldr \tmp3, [\tmp2, #L2X0_CTRL]
@@ -124,11 +124,11 @@ int tegra_sleep_cpu_finish(unsigned long);
void tegra_disable_clean_inv_dcache(void);
#ifdef CONFIG_HOTPLUG_CPU
-void tegra20_hotplug_init(void);
-void tegra30_hotplug_init(void);
+void tegra20_hotplug_shutdown(void);
+void tegra30_hotplug_shutdown(void);
+void tegra_hotplug_init(void);
#else
-static inline void tegra20_hotplug_init(void) {}
-static inline void tegra30_hotplug_init(void) {}
+static inline void tegra_hotplug_init(void) {}
#endif
void tegra20_cpu_shutdown(int cpu);
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/tegra.c
index a0edf251028..0d1e4128d46 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -1,6 +1,7 @@
/*
- * nVidia Tegra device tree board support
+ * NVIDIA Tegra SoC device tree board support
*
+ * Copyright (C) 2011, 2013, NVIDIA Corporation
* Copyright (C) 2010 Secret Lab Technologies, Ltd.
* Copyright (C) 2010 Google, Inc.
*
@@ -30,9 +31,10 @@
#include <linux/pda_power.h>
#include <linux/platform_data/tegra_usb.h>
#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/i2c-tegra.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
#include <linux/usb/tegra_usb_phy.h>
+#include <linux/clk/tegra.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -41,6 +43,7 @@
#include "board.h"
#include "common.h"
+#include "fuse.h"
#include "iomap.h"
static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
@@ -79,12 +82,38 @@ static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
static void __init tegra_dt_init(void)
{
+ struct soc_device_attribute *soc_dev_attr;
+ struct soc_device *soc_dev;
+ struct device *parent = NULL;
+
+ tegra_clocks_apply_init_table();
+
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ goto out;
+
+ soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra");
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision);
+ soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id);
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev)) {
+ kfree(soc_dev_attr->family);
+ kfree(soc_dev_attr->revision);
+ kfree(soc_dev_attr->soc_id);
+ kfree(soc_dev_attr);
+ goto out;
+ }
+
+ parent = soc_device_to_device(soc_dev);
+
/*
* Finished with the static registrations now; fill in the missing
* devices
*/
+out:
of_platform_populate(NULL, of_default_bus_match_table,
- tegra20_auxdata_lookup, NULL);
+ tegra20_auxdata_lookup, parent);
}
static void __init trimslice_init(void)
@@ -111,7 +140,8 @@ static void __init harmony_init(void)
static void __init paz00_init(void)
{
- tegra_paz00_wifikill_init();
+ if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
+ tegra_paz00_wifikill_init();
}
static struct {
@@ -137,19 +167,21 @@ static void __init tegra_dt_init_late(void)
}
}
-static const char *tegra20_dt_board_compat[] = {
+static const char * const tegra_dt_board_compat[] = {
+ "nvidia,tegra114",
+ "nvidia,tegra30",
"nvidia,tegra20",
NULL
};
-DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)")
+DT_MACHINE_START(TEGRA_DT, "NVIDIA Tegra SoC (Flattened Device Tree)")
.map_io = tegra_map_common_io,
.smp = smp_ops(tegra_smp_ops),
- .init_early = tegra20_init_early,
+ .init_early = tegra_init_early,
.init_irq = tegra_dt_init_irq,
.init_time = clocksource_of_init,
.init_machine = tegra_dt_init,
.init_late = tegra_dt_init_late,
.restart = tegra_assert_system_reset,
- .dt_compat = tegra20_dt_board_compat,
+ .dt_compat = tegra_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c
new file mode 100644
index 00000000000..5218d4853cd
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114_speedo.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+
+#include "fuse.h"
+
+#define CORE_PROCESS_CORNERS_NUM 2
+#define CPU_PROCESS_CORNERS_NUM 2
+
+enum {
+ THRESHOLD_INDEX_0,
+ THRESHOLD_INDEX_1,
+ THRESHOLD_INDEX_COUNT,
+};
+
+static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+ {1123, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+ {1695, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold)
+{
+ u32 tmp;
+
+ switch (sku) {
+ case 0x00:
+ case 0x10:
+ case 0x05:
+ case 0x06:
+ tegra_cpu_speedo_id = 1;
+ tegra_soc_speedo_id = 0;
+ *threshold = THRESHOLD_INDEX_0;
+ break;
+
+ case 0x03:
+ case 0x04:
+ tegra_cpu_speedo_id = 2;
+ tegra_soc_speedo_id = 1;
+ *threshold = THRESHOLD_INDEX_1;
+ break;
+
+ default:
+ pr_err("Tegra114 Unknown SKU %d\n", sku);
+ tegra_cpu_speedo_id = 0;
+ tegra_soc_speedo_id = 0;
+ *threshold = THRESHOLD_INDEX_0;
+ break;
+ }
+
+ if (rev == TEGRA_REVISION_A01) {
+ tmp = tegra_fuse_readl(0x270) << 1;
+ tmp |= tegra_fuse_readl(0x26c);
+ if (!tmp)
+ tegra_cpu_speedo_id = 0;
+ }
+}
+
+void tegra114_init_speedo_data(void)
+{
+ u32 cpu_speedo_val;
+ u32 core_speedo_val;
+ int threshold;
+ int i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
+ THRESHOLD_INDEX_COUNT);
+ BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
+ THRESHOLD_INDEX_COUNT);
+
+ rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold);
+
+ cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024;
+ core_speedo_val = tegra_fuse_readl(0x134);
+
+ for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
+ if (cpu_speedo_val < cpu_process_speedos[threshold][i])
+ break;
+ tegra_cpu_process_id = i;
+
+ for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
+ if (core_speedo_val < core_process_speedos[threshold][i])
+ break;
+ tegra_core_process_id = i;
+}
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
index ce7ce42a1ac..31e69a019bd 100644
--- a/arch/arm/mach-tegra/tegra2_emc.c
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -276,7 +276,7 @@ static struct tegra_emc_pdata *tegra_emc_fill_pdata(struct platform_device *pdev
int i;
WARN_ON(pdev->dev.platform_data);
- BUG_ON(IS_ERR_OR_NULL(c));
+ BUG_ON(IS_ERR(c));
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables),
@@ -307,11 +307,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "missing register base\n");
- return -ENOMEM;
- }
-
emc_regbase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(emc_regbase))
return PTR_ERR(emc_regbase);