diff options
Diffstat (limited to 'arch/arm/mach-tegra')
49 files changed, 1796 insertions, 665 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 9ff6f6ea361..e426d1b7747 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -57,57 +57,6 @@ config TEGRA_AHB  	  which controls AHB bus master arbitration and some  	  perfomance parameters(priority, prefech size). -choice -        prompt "Default low-level debug console UART" -        default TEGRA_DEBUG_UART_NONE - -config TEGRA_DEBUG_UART_NONE -        bool "None" - -config TEGRA_DEBUG_UARTA -        bool "UART-A" - -config TEGRA_DEBUG_UARTB -        bool "UART-B" - -config TEGRA_DEBUG_UARTC -        bool "UART-C" - -config TEGRA_DEBUG_UARTD -        bool "UART-D" - -config TEGRA_DEBUG_UARTE -        bool "UART-E" - -endchoice - -choice -	prompt "Automatic low-level debug console UART" -	default TEGRA_DEBUG_UART_AUTO_NONE - -config TEGRA_DEBUG_UART_AUTO_NONE -	bool "None" - -config TEGRA_DEBUG_UART_AUTO_ODMDATA -	bool "Via ODMDATA" -	help -	  Automatically determines which UART to use for low-level debug based -	  on the ODMDATA value. This value is part of the BCT, and is written -	  to the boot memory device using nvflash, or other flashing tool. -	  When bits 19:18 are 3, then bits 17:15 indicate which UART to use; -	  0/1/2/3/4 are UART A/B/C/D/E. - -config TEGRA_DEBUG_UART_AUTO_SCRATCH -	bool "Via UART scratch register" -	help -	  Automatically determines which UART to use for low-level debug based -	  on the UART scratch register value. Some bootloaders put ASCII 'D' -	  in this register when they initialize their own console UART output. -	  Using this option allows the kernel to automatically pick the same -	  UART. - -endchoice -  config TEGRA_EMC_SCALING_ENABLE  	bool "Enable scaling the memory frequency" diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 9aa653b3eb3..0979e8bba78 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -8,15 +8,24 @@ obj-y					+= pmc.o  obj-y					+= flowctrl.o  obj-y					+= powergate.o  obj-y					+= apbio.o +obj-y					+= pm.o  obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o  obj-$(CONFIG_CPU_IDLE)			+= sleep.o  obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks.o  obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks_data.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra20_speedo.o  obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-t20.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-tegra20.o +ifeq ($(CONFIG_CPU_IDLE),y) +obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= cpuidle-tegra20.o +endif  obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o  obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks_data.o -obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-t30.o +obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_speedo.o +obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-tegra30.o +ifeq ($(CONFIG_CPU_IDLE),y) +obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= cpuidle-tegra30.o +endif  obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o  obj-$(CONFIG_SMP)                       += reset.o  obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index b5015d0f191..d091675ba37 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -15,7 +15,6 @@  #include <linux/kernel.h>  #include <linux/io.h> -#include <mach/iomap.h>  #include <linux/of.h>  #include <linux/dmaengine.h>  #include <linux/dma-mapping.h> @@ -24,9 +23,8 @@  #include <linux/sched.h>  #include <linux/mutex.h> -#include <mach/dma.h> -  #include "apbio.h" +#include "iomap.h"  #if defined(CONFIG_TEGRA20_APB_DMA)  static DEFINE_MUTEX(tegra_apb_dma_lock); @@ -71,7 +69,6 @@ bool tegra_apb_dma_init(void)  	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;  	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -	dma_sconfig.slave_id = TEGRA_DMA_REQ_SEL_CNTR;  	dma_sconfig.src_maxburst = 1;  	dma_sconfig.dst_maxburst = 1; diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index aa5325cd1c4..734d9cc87f2 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -40,12 +40,10 @@  #include <asm/mach/time.h>  #include <asm/setup.h> -#include <mach/iomap.h> -#include <mach/irqs.h> -  #include "board.h"  #include "clock.h"  #include "common.h" +#include "iomap.h"  struct tegra_ehci_platform_data tegra_ehci1_pdata = {  	.operating_mode = TEGRA_USB_OTG, @@ -91,6 +89,17 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {  		       &tegra_ehci3_pdata),  	OF_DEV_AUXDATA("nvidia,tegra20-apbdma", TEGRA_APB_DMA_BASE, "tegra-apbdma", NULL),  	OF_DEV_AUXDATA("nvidia,tegra20-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-sflash", 0x7000c380, "spi", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D400, "spi_tegra.0", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D600, "spi_tegra.1", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000D800, "spi_tegra.2", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-slink", 0x7000DA00, "spi_tegra.3", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-host1x", 0x50000000, "host1x", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54200000, "tegradc.0", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-dc", 0x54240000, "tegradc.1", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-hdmi", 0x54280000, "hdmi", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-dsi", 0x54300000, "dsi", NULL), +	OF_DEV_AUXDATA("nvidia,tegra20-tvo", 0x542c0000, "tvo", NULL),  	{}  }; @@ -104,8 +113,20 @@ static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {  	{ "pll_a",      "pll_p_out1",   56448000,       true },  	{ "pll_a_out0", "pll_a",        11289600,       true },  	{ "cdev1",      NULL,           0,              true }, +	{ "blink",      "clk_32k",      32768,          true },  	{ "i2s1",       "pll_a_out0",   11289600,       false},  	{ "i2s2",       "pll_a_out0",   11289600,       false}, +	{ "sdmmc1",	"pll_p",	48000000,	false}, +	{ "sdmmc3",	"pll_p",	48000000,	false}, +	{ "sdmmc4",	"pll_p",	48000000,	false}, +	{ "spi",	"pll_p",	20000000,	false }, +	{ "sbc1",	"pll_p",	100000000,	false }, +	{ "sbc2",	"pll_p",	100000000,	false }, +	{ "sbc3",	"pll_p",	100000000,	false }, +	{ "sbc4",	"pll_p",	100000000,	false }, +	{ "host1x",	"pll_c",	150000000,	false }, +	{ "disp1",	"pll_p",	600000000,	false }, +	{ "disp2",	"pll_p",	600000000,	false },  	{ NULL,		NULL,		0,		0},  }; diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 5e92a81f9a2..6497d1236b0 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -33,11 +33,10 @@  #include <asm/mach/arch.h>  #include <asm/hardware/gic.h> -#include <mach/iomap.h> -  #include "board.h"  #include "clock.h"  #include "common.h" +#include "iomap.h"  struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {  	OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL), @@ -52,6 +51,18 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {  	OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL),  	OF_DEV_AUXDATA("nvidia,tegra30-apbdma", 0x6000a000, "tegra-apbdma", NULL),  	OF_DEV_AUXDATA("nvidia,tegra30-pwm", TEGRA_PWFM_BASE, "tegra-pwm", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D400, "spi_tegra.0", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D600, "spi_tegra.1", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000D800, "spi_tegra.2", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DA00, "spi_tegra.3", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DC00, "spi_tegra.4", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-slink", 0x7000DE00, "spi_tegra.5", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-host1x", 0x50000000, "host1x", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54200000, "tegradc.0", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-dc", 0x54240000, "tegradc.1", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-hdmi", 0x54280000, "hdmi", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-dsi", 0x54300000, "dsi", NULL), +	OF_DEV_AUXDATA("nvidia,tegra30-tvo", 0x542c0000, "tvo", NULL),  	{}  }; @@ -62,11 +73,24 @@ static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {  	{ "pll_a_out0",	"pll_a",	11289600,	true },  	{ "extern1",	"pll_a_out0",	0,		true },  	{ "clk_out_1",	"extern1",	0,		true }, +	{ "blink",	"clk_32k",	32768,		true },  	{ "i2s0",	"pll_a_out0",	11289600,	false},  	{ "i2s1",	"pll_a_out0",	11289600,	false},  	{ "i2s2",	"pll_a_out0",	11289600,	false},  	{ "i2s3",	"pll_a_out0",	11289600,	false},  	{ "i2s4",	"pll_a_out0",	11289600,	false}, +	{ "sdmmc1",	"pll_p",	48000000,	false}, +	{ "sdmmc3",	"pll_p",	48000000,	false}, +	{ "sdmmc4",	"pll_p",	48000000,	false}, +	{ "sbc1",	"pll_p",	100000000,	false}, +	{ "sbc2",	"pll_p",	100000000,	false}, +	{ "sbc3",	"pll_p",	100000000,	false}, +	{ "sbc4",	"pll_p",	100000000,	false}, +	{ "sbc5",	"pll_p",	100000000,	false}, +	{ "sbc6",	"pll_p",	100000000,	false}, +	{ "host1x",	"pll_c",	150000000,	false}, +	{ "disp1",	"pll_p",	600000000,	false}, +	{ "disp2",	"pll_p",	600000000,	false},  	{ NULL,		NULL,		0,		0},  }; diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index fd82085eca5..867bf8bf556 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -27,8 +27,6 @@  #include <linux/seq_file.h>  #include <linux/slab.h> -#include <mach/clk.h> -  #include "board.h"  #include "clock.h"  #include "tegra_cpu_car.h" diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 0b0a5f556d3..0816562725f 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -26,16 +26,17 @@  #include <asm/hardware/cache-l2x0.h>  #include <asm/hardware/gic.h> -#include <mach/iomap.h>  #include <mach/powergate.h>  #include "board.h"  #include "clock.h"  #include "common.h"  #include "fuse.h" +#include "iomap.h"  #include "pmc.h"  #include "apbio.h"  #include "sleep.h" +#include "pm.h"  /*   * Storage for debug-macro.S's state. @@ -44,14 +45,15 @@   * kernel is loaded. The data is declared here rather than debug-macro.S so   * that multiple inclusions of debug-macro.S point at the same data.   */ -#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF) -u32 tegra_uart_config[3] = { +u32 tegra_uart_config[4] = {  	/* Debug UART initialization required */  	1,  	/* Debug UART physical address */ -	(u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET), +	0,  	/* Debug UART virtual address */ -	(u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET), +	0, +	/* Scratch space for debug macro */ +	0,  };  #ifdef CONFIG_OF @@ -104,25 +106,30 @@ static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = {  	{ "clk_m",	NULL,		0,		true },  	{ "pll_p",	"clk_m",	408000000,	true },  	{ "pll_p_out1",	"pll_p",	9600000,	true }, +	{ "pll_p_out4",	"pll_p",	102000000,	true }, +	{ "sclk",	"pll_p_out4",	102000000,	true }, +	{ "hclk",	"sclk",		102000000,	true }, +	{ "pclk",	"hclk",		51000000,	true }, +	{ "csite",	NULL,		0,		true },  	{ NULL,		NULL,		0,		0},  };  #endif -static void __init tegra_init_cache(u32 tag_latency, u32 data_latency) +static void __init tegra_init_cache(void)  {  #ifdef CONFIG_CACHE_L2X0 +	int ret;  	void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;  	u32 aux_ctrl, cache_type; -	writel_relaxed(tag_latency, p + L2X0_TAG_LATENCY_CTRL); -	writel_relaxed(data_latency, p + L2X0_DATA_LATENCY_CTRL); -  	cache_type = readl(p + L2X0_CACHE_TYPE);  	aux_ctrl = (cache_type & 0x700) << (17-8); -	aux_ctrl |= 0x6C000001; +	aux_ctrl |= 0x7C400001; -	l2x0_init(p, aux_ctrl, 0x8200c3fe); +	ret = l2x0_of_init(aux_ctrl, 0x8200c3fe); +	if (!ret) +		l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs);  #endif  } @@ -134,7 +141,7 @@ void __init tegra20_init_early(void)  	tegra_init_fuse();  	tegra2_init_clocks();  	tegra_clk_init_from_table(tegra20_clk_init_table); -	tegra_init_cache(0x331, 0x441); +	tegra_init_cache();  	tegra_pmc_init();  	tegra_powergate_init();  	tegra20_hotplug_init(); @@ -147,7 +154,7 @@ void __init tegra30_init_early(void)  	tegra_init_fuse();  	tegra30_init_clocks();  	tegra_clk_init_from_table(tegra30_clk_init_table); -	tegra_init_cache(0x441, 0x551); +	tegra_init_cache();  	tegra_pmc_init();  	tegra_powergate_init();  	tegra30_hotplug_init(); diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index 627bf0f4262..a74d3c7d2e2 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -30,9 +30,6 @@  #include <linux/io.h>  #include <linux/suspend.h> - -#include <mach/clk.h> -  /* Frequency table index must be sequential starting at 0 */  static struct cpufreq_frequency_table freq_table[] = {  	{ 0, 216000 }, diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c new file mode 100644 index 00000000000..d32e8b0dbd4 --- /dev/null +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -0,0 +1,66 @@ +/* + * CPU idle driver for Tegra CPUs + * + * Copyright (c) 2010-2012, NVIDIA Corporation. + * Copyright (c) 2011 Google, Inc. + * Author: Colin Cross <ccross@android.com> + *         Gary King <gking@nvidia.com> + * + * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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/cpuidle.h> + +#include <asm/cpuidle.h> + +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 tegra20_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; +} diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c new file mode 100644 index 00000000000..5e8cbf5b799 --- /dev/null +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -0,0 +1,188 @@ +/* + * CPU idle driver for Tegra CPUs + * + * Copyright (c) 2010-2012, NVIDIA Corporation. + * Copyright (c) 2011 Google, Inc. + * Author: Colin Cross <ccross@android.com> + *         Gary King <gking@nvidia.com> + * + * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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/cpuidle.h> +#include <linux/cpu_pm.h> +#include <linux/clockchips.h> + +#include <asm/cpuidle.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> +#include <asm/smp_plat.h> + +#include "pm.h" +#include "sleep.h" +#include "tegra_cpu_car.h" + +#ifdef CONFIG_PM_SLEEP +static int tegra30_idle_lp2(struct cpuidle_device *dev, +			    struct cpuidle_driver *drv, +			    int index); +#endif + +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 +	.state_count = 1, +#endif +	.states = { +		[0] = ARM_CPUIDLE_WFI_STATE_PWR(600), +#ifdef CONFIG_PM_SLEEP +		[1] = { +			.enter			= tegra30_idle_lp2, +			.exit_latency		= 2000, +			.target_residency	= 2200, +			.power_usage		= 0, +			.flags			= CPUIDLE_FLAG_TIME_VALID, +			.name			= "powered-down", +			.desc			= "CPU power gated", +		}, +#endif +	}, +}; + +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. +	 */ +	if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) { +		cpu_do_idle(); +		return false; +	} + +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); + +	tegra_idle_lp2_last(cpu_on_time, cpu_off_time); + +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); + +	return true; +} + +#ifdef CONFIG_SMP +static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, +					struct cpuidle_driver *drv, +					int index) +{ +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); + +	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; +} +#else +static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, +					       struct cpuidle_driver *drv, +					       int index) +{ +	return true; +} +#endif + +static int __cpuinit 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); +	cpu_pm_enter(); + +	if (cpu == 0) { +		if (last_cpu) +			entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, +								     index); +		else +			cpu_do_idle(); +	} else { +		entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index); +	} + +	cpu_pm_exit(); +	tegra_clear_cpu_in_lp2(cpu); + +	local_fiq_enable(); + +	smp_rmb(); + +	return (entered_lp2) ? index : 0; +} +#endif + +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; +} diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index 566e2f88899..d0651397aec 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c @@ -23,85 +23,26 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/cpu.h> -#include <linux/cpuidle.h> -#include <linux/hrtimer.h> -#include <asm/proc-fns.h> - -#include <mach/iomap.h> - -static int tegra_idle_enter_lp3(struct cpuidle_device *dev, -				struct cpuidle_driver *drv, int index); - -struct cpuidle_driver tegra_idle_driver = { -	.name = "tegra_idle", -	.owner = THIS_MODULE, -	.state_count = 1, -	.states = { -		[0] = { -			.enter			= tegra_idle_enter_lp3, -			.exit_latency		= 10, -			.target_residency	= 10, -			.power_usage		= 600, -			.flags			= CPUIDLE_FLAG_TIME_VALID, -			.name			= "LP3", -			.desc			= "CPU flow-controlled", -		}, -	}, -}; - -static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); - -static int tegra_idle_enter_lp3(struct cpuidle_device *dev, -	struct cpuidle_driver *drv, int index) -{ -	ktime_t enter, exit; -	s64 us; - -	local_irq_disable(); -	local_fiq_disable(); - -	enter = ktime_get(); - -	cpu_do_idle(); - -	exit = ktime_sub(ktime_get(), enter); -	us = ktime_to_us(exit); - -	local_fiq_enable(); -	local_irq_enable(); - -	dev->last_residency = us; - -	return index; -} +#include "fuse.h" +#include "cpuidle.h"  static int __init tegra_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; +	switch (tegra_chip_id) { +	case TEGRA20: +		ret = tegra20_cpuidle_init(); +		break; +	case TEGRA30: +		ret = tegra30_cpuidle_init(); +		break; +	default: +		ret = -ENODEV; +		break;  	} -	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 ret;  }  device_initcall(tegra_cpuidle_init); diff --git a/arch/arm/mach-tegra/cpuidle.h b/arch/arm/mach-tegra/cpuidle.h new file mode 100644 index 00000000000..496204d34e5 --- /dev/null +++ b/arch/arm/mach-tegra/cpuidle.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, 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/>. + */ + +#ifndef __MACH_TEGRA_CPUIDLE_H +#define __MACH_TEGRA_CPUIDLE_H + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +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 + +#endif diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index f07488e0bd3..a2250ddae79 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -21,10 +21,10 @@  #include <linux/init.h>  #include <linux/kernel.h>  #include <linux/io.h> - -#include <mach/iomap.h> +#include <linux/cpumask.h>  #include "flowctrl.h" +#include "iomap.h"  u8 flowctrl_offset_halt_cpu[] = {  	FLOW_CTRL_HALT_CPU0_EVENTS, @@ -51,6 +51,14 @@ static void flowctrl_update(u8 offset, u32 value)  	readl_relaxed(addr);  } +u32 flowctrl_read_cpu_csr(unsigned int cpuid) +{ +	u8 offset = flowctrl_offset_cpu_csr[cpuid]; +	void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset; + +	return readl(addr); +} +  void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)  {  	return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value); @@ -60,3 +68,41 @@ void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)  {  	return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);  } + +void flowctrl_cpu_suspend_enter(unsigned int cpuid) +{ +	unsigned int reg; +	int i; + +	reg = flowctrl_read_cpu_csr(cpuid); +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;	/* clear wfe bitmap */ +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;	/* clear wfi bitmap */ +	reg |= FLOW_CTRL_CSR_INTR_FLAG;			/* clear intr flag */ +	reg |= FLOW_CTRL_CSR_EVENT_FLAG;		/* clear event flag */ +	reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;	/* pwr gating on wfi */ +	reg |= FLOW_CTRL_CSR_ENABLE;			/* pwr gating */ +	flowctrl_write_cpu_csr(cpuid, reg); + +	for (i = 0; i < num_possible_cpus(); i++) { +		if (i == cpuid) +			continue; +		reg = flowctrl_read_cpu_csr(i); +		reg |= FLOW_CTRL_CSR_EVENT_FLAG; +		reg |= FLOW_CTRL_CSR_INTR_FLAG; +		flowctrl_write_cpu_csr(i, reg); +	} +} + +void flowctrl_cpu_suspend_exit(unsigned int cpuid) +{ +	unsigned int reg; + +	/* Disable powergating via flow controller for CPU0 */ +	reg = flowctrl_read_cpu_csr(cpuid); +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;	/* clear wfe bitmap */ +	reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;	/* clear wfi bitmap */ +	reg &= ~FLOW_CTRL_CSR_ENABLE;			/* clear enable */ +	reg |= FLOW_CTRL_CSR_INTR_FLAG;			/* clear intr */ +	reg |= FLOW_CTRL_CSR_EVENT_FLAG;		/* clear event */ +	flowctrl_write_cpu_csr(cpuid, reg); +} diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h index 19428173855..0798dec1832 100644 --- a/arch/arm/mach-tegra/flowctrl.h +++ b/arch/arm/mach-tegra/flowctrl.h @@ -34,9 +34,17 @@  #define FLOW_CTRL_HALT_CPU1_EVENTS	0x14  #define FLOW_CTRL_CPU1_CSR		0x18 +#define TEGRA30_FLOW_CTRL_CSR_WFI_CPU0		(1 << 8) +#define TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP	(0xF << 4) +#define TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP	(0xF << 8) +  #ifndef __ASSEMBLY__ +u32 flowctrl_read_cpu_csr(unsigned int cpuid);  void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);  void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value); + +void flowctrl_cpu_suspend_enter(unsigned int cpuid); +void flowctrl_cpu_suspend_exit(unsigned int cpuid);  #endif  #endif diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 0b7db174a5d..8121742711f 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -21,22 +21,28 @@  #include <linux/io.h>  #include <linux/export.h> -#include <mach/iomap.h> -  #include "fuse.h" +#include "iomap.h"  #include "apbio.h"  #define FUSE_UID_LOW		0x108  #define FUSE_UID_HIGH		0x10c  #define FUSE_SKU_INFO		0x110 -#define FUSE_SPARE_BIT		0x200 + +#define TEGRA20_FUSE_SPARE_BIT		0x200 +#define TEGRA30_FUSE_SPARE_BIT		0x244  int tegra_sku_id;  int tegra_cpu_process_id;  int tegra_core_process_id;  int tegra_chip_id; +int tegra_cpu_speedo_id;		/* only exist in Tegra30 and later */ +int tegra_soc_speedo_id;  enum tegra_revision tegra_revision; +static int tegra_fuse_spare_bit; +static void (*tegra_init_speedo_data)(void); +  /* The BCT to use at boot is specified by board straps that can be read   * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.   */ @@ -57,14 +63,14 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {  	[TEGRA_REVISION_A04]     = "A04",  }; -static inline u32 tegra_fuse_readl(unsigned long offset) +u32 tegra_fuse_readl(unsigned long offset)  {  	return tegra_apb_readl(TEGRA_FUSE_BASE + offset);  } -static inline bool get_spare_fuse(int bit) +bool tegra_spare_fuse(int bit)  { -	return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4); +	return tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);  }  static enum tegra_revision tegra_get_revision(u32 id) @@ -78,7 +84,7 @@ static enum tegra_revision tegra_get_revision(u32 id)  		return TEGRA_REVISION_A02;  	case 3:  		if (tegra_chip_id == TEGRA20 && -			(get_spare_fuse(18) || get_spare_fuse(19))) +			(tegra_spare_fuse(18) || tegra_spare_fuse(19)))  			return TEGRA_REVISION_A03p;  		else  			return TEGRA_REVISION_A03; @@ -89,6 +95,16 @@ static enum tegra_revision tegra_get_revision(u32 id)  	}  } +static void tegra_get_process_id(void) +{ +	u32 reg; + +	reg = tegra_fuse_readl(tegra_fuse_spare_bit); +	tegra_cpu_process_id = (reg >> 6) & 3; +	reg = tegra_fuse_readl(tegra_fuse_spare_bit); +	tegra_core_process_id = (reg >> 12) & 3; +} +  void tegra_init_fuse(void)  {  	u32 id; @@ -100,19 +116,29 @@ void tegra_init_fuse(void)  	reg = tegra_fuse_readl(FUSE_SKU_INFO);  	tegra_sku_id = reg & 0xFF; -	reg = tegra_fuse_readl(FUSE_SPARE_BIT); -	tegra_cpu_process_id = (reg >> 6) & 3; - -	reg = tegra_fuse_readl(FUSE_SPARE_BIT); -	tegra_core_process_id = (reg >> 12) & 3; -  	reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);  	tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;  	id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);  	tegra_chip_id = (id >> 8) & 0xff; +	switch (tegra_chip_id) { +	case TEGRA20: +		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; +		tegra_init_speedo_data = &tegra20_init_speedo_data; +		break; +	case TEGRA30: +		tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT; +		tegra_init_speedo_data = &tegra30_init_speedo_data; +		break; +	default: +		pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id); +		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; +		tegra_init_speedo_data = &tegra_get_process_id; +	} +  	tegra_revision = tegra_get_revision(id); +	tegra_init_speedo_data();  	pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",  		tegra_revision_name[tegra_revision], diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index d2107b2cb85..ff1383dd61a 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -42,11 +42,27 @@ extern int tegra_sku_id;  extern int tegra_cpu_process_id;  extern int tegra_core_process_id;  extern int tegra_chip_id; +extern int tegra_cpu_speedo_id;		/* only exist in Tegra30 and later */ +extern int tegra_soc_speedo_id;  extern enum tegra_revision tegra_revision;  extern int tegra_bct_strapping;  unsigned long long tegra_chip_uid(void);  void tegra_init_fuse(void); +bool tegra_spare_fuse(int bit); +u32 tegra_fuse_readl(unsigned long offset); + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +void tegra20_init_speedo_data(void); +#else +static inline void tegra20_init_speedo_data(void) {} +#endif + +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +void tegra30_init_speedo_data(void); +#else +static inline void tegra30_init_speedo_data(void) {} +#endif  #endif diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index 6addc78cb6b..4a317fae686 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -2,10 +2,11 @@  #include <linux/init.h>  #include <asm/cache.h> - -#include <mach/iomap.h> +#include <asm/asm-offsets.h> +#include <asm/hardware/cache-l2x0.h>  #include "flowctrl.h" +#include "iomap.h"  #include "reset.h"  #include "sleep.h" @@ -69,6 +70,64 @@ ENTRY(tegra_secondary_startup)          b       secondary_startup  ENDPROC(tegra_secondary_startup) +#ifdef CONFIG_PM_SLEEP +/* + *	tegra_resume + * + *	  CPU boot vector when restarting the a CPU following + *	  an LP2 transition. Also branched to by LP0 and LP1 resume after + *	  re-enabling sdram. + */ +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? +	bne	cpu_resume			@ no + +#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) +	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] +	/* 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 +	bic	r1, r1, r0 +	str	r1, [r2] +1: +#endif + +#ifdef CONFIG_HAVE_ARM_SCU +	/* enable SCU */ +	mov32	r0, TEGRA_ARM_PERIF_BASE +	ldr	r1, [r0] +	orr	r1, r1, #1 +	str	r1, [r0] +#endif + +	/* L2 cache resume & re-enable */ +	l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr + +	b	cpu_resume +ENDPROC(tegra_resume) +#endif + +#ifdef CONFIG_CACHE_L2X0 +	.globl	l2x0_saved_regs_addr +l2x0_saved_regs_addr: +	.long	0 +#endif +  	.align L1_CACHE_SHIFT  ENTRY(__tegra_cpu_reset_handler_start) @@ -122,6 +181,17 @@ ENTRY(__tegra_cpu_reset_handler)  1:  #endif +	/* Waking up from LP2? */ +	ldr	r9, [r12, #RESET_DATA(MASK_LP2)] +	tst	r9, r11				@ if in_lp2 +	beq	__is_not_lp2 +	ldr	lr, [r12, #RESET_DATA(STARTUP_LP2)] +	cmp	lr, #0 +	bleq	__die				@ no LP2 startup handler +	bx	lr + +__is_not_lp2: +  #ifdef CONFIG_SMP  	/*  	 * Can only be secondary boot (initial or hotplug) but CPU 0 diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S deleted file mode 100644 index 8ce0661b8a3..00000000000 --- a/arch/arm/mach-tegra/include/mach/debug-macro.S +++ /dev/null @@ -1,100 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/debug-macro.S - * - * Copyright (C) 2010,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> - * - * Portions based on mach-omap2's debug-macro.S - * Copyright (C) 1994-1999 Russell King - * - * 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/serial_reg.h> - -#include <mach/iomap.h> -#include <mach/irammap.h> - -		.macro  addruart, rp, rv, tmp -		adr	\rp, 99f		@ actual addr of 99f -		ldr	\rv, [\rp]		@ linked addr is stored there -		sub	\rv, \rv, \rp		@ offset between the two -		ldr	\rp, [\rp, #4]		@ linked tegra_uart_config -		sub	\tmp, \rp, \rv		@ actual tegra_uart_config -		ldr	\rp, [\tmp]		@ Load tegra_uart_config -		cmp	\rp, #1			@ needs intitialization? -		bne	100f			@ no; go load the addresses -		mov	\rv, #0			@ yes; record init is done -		str	\rv, [\tmp] -		mov	\rp, #TEGRA_IRAM_BASE	@ See if cookie is in IRAM -		ldr	\rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET] -		movw	\rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff -		movt	\rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16 -		cmp	\rv, \rp		@ Cookie present? -		bne	100f			@ No, use default UART -		mov	\rp, #TEGRA_IRAM_BASE	@ Load UART address from IRAM -		ldr	\rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4] -		str	\rv, [\tmp, #4]		@ Store in tegra_uart_phys -		sub	\rv, \rv, #IO_APB_PHYS	@ Calculate virt address -		add	\rv, \rv, #IO_APB_VIRT -		str	\rv, [\tmp, #8]		@ Store in tegra_uart_virt -		b	100f - -		.align -99:		.word	. -		.word	tegra_uart_config -		.ltorg - -100:		ldr	\rp, [\tmp, #4]		@ Load tegra_uart_phys -		ldr	\rv, [\tmp, #8]		@ Load tegra_uart_virt -		.endm - -#define UART_SHIFT 2 - -/* - * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra - * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case. - * We use the fact that all 5 valid UART addresses all have something in the - * 2nd-to-lowest byte. - */ - -		.macro	senduart, rd, rx -		tst	\rx, #0x0000ff00 -		strneb	\rd, [\rx, #UART_TX << UART_SHIFT] -1001: -		.endm - -		.macro	busyuart, rd, rx -		tst	\rx, #0x0000ff00 -		beq	1002f -1001:		ldrb	\rd, [\rx, #UART_LSR << UART_SHIFT] -		and	\rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE -		teq	\rd, #UART_LSR_TEMT | UART_LSR_THRE -		bne	1001b -1002: -		.endm - -		.macro	waituart, rd, rx -#ifdef FLOW_CONTROL -		tst	\rx, #0x0000ff00 -		beq	1002f -1001:		ldrb	\rd, [\rx, #UART_MSR << UART_SHIFT] -		tst	\rd, #UART_MSR_CTS -		beq	1001b -1002: -#endif -		.endm diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h deleted file mode 100644 index 3081cc6dda3..00000000000 --- a/arch/arm/mach-tegra/include/mach/dma.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/dma.h - * - * Copyright (c) 2008-2009, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. - */ - -#ifndef __MACH_TEGRA_DMA_H -#define __MACH_TEGRA_DMA_H - -#include <linux/list.h> - -#define TEGRA_DMA_REQ_SEL_CNTR			0 -#define TEGRA_DMA_REQ_SEL_I2S_2			1 -#define TEGRA_DMA_REQ_SEL_I2S_1			2 -#define TEGRA_DMA_REQ_SEL_SPD_I			3 -#define TEGRA_DMA_REQ_SEL_UI_I			4 -#define TEGRA_DMA_REQ_SEL_MIPI			5 -#define TEGRA_DMA_REQ_SEL_I2S2_2		6 -#define TEGRA_DMA_REQ_SEL_I2S2_1		7 -#define TEGRA_DMA_REQ_SEL_UARTA			8 -#define TEGRA_DMA_REQ_SEL_UARTB			9 -#define TEGRA_DMA_REQ_SEL_UARTC			10 -#define TEGRA_DMA_REQ_SEL_SPI			11 -#define TEGRA_DMA_REQ_SEL_AC97			12 -#define TEGRA_DMA_REQ_SEL_ACMODEM		13 -#define TEGRA_DMA_REQ_SEL_SL4B			14 -#define TEGRA_DMA_REQ_SEL_SL2B1			15 -#define TEGRA_DMA_REQ_SEL_SL2B2			16 -#define TEGRA_DMA_REQ_SEL_SL2B3			17 -#define TEGRA_DMA_REQ_SEL_SL2B4			18 -#define TEGRA_DMA_REQ_SEL_UARTD			19 -#define TEGRA_DMA_REQ_SEL_UARTE			20 -#define TEGRA_DMA_REQ_SEL_I2C			21 -#define TEGRA_DMA_REQ_SEL_I2C2			22 -#define TEGRA_DMA_REQ_SEL_I2C3			23 -#define TEGRA_DMA_REQ_SEL_DVC_I2C		24 -#define TEGRA_DMA_REQ_SEL_OWR			25 -#define TEGRA_DMA_REQ_SEL_INVALID		31 - -#endif diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h deleted file mode 100644 index aad1a2c1d71..00000000000 --- a/arch/arm/mach-tegra/include/mach/irqs.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * arch/arm/mach-tegra/include/mach/irqs.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_IRQS_H -#define __MACH_TEGRA_IRQS_H - -#define INT_GIC_BASE			0 - -#define IRQ_LOCALTIMER                  29 - -/* Primary Interrupt Controller */ -#define INT_PRI_BASE			(INT_GIC_BASE + 32) -#define INT_TMR1			(INT_PRI_BASE + 0) -#define INT_TMR2			(INT_PRI_BASE + 1) -#define INT_RTC				(INT_PRI_BASE + 2) -#define INT_I2S2			(INT_PRI_BASE + 3) -#define INT_SHR_SEM_INBOX_IBF		(INT_PRI_BASE + 4) -#define INT_SHR_SEM_INBOX_IBE		(INT_PRI_BASE + 5) -#define INT_SHR_SEM_OUTBOX_IBF		(INT_PRI_BASE + 6) -#define INT_SHR_SEM_OUTBOX_IBE		(INT_PRI_BASE + 7) -#define INT_VDE_UCQ_ERROR		(INT_PRI_BASE + 8) -#define INT_VDE_SYNC_TOKEN		(INT_PRI_BASE + 9) -#define INT_VDE_BSE_V			(INT_PRI_BASE + 10) -#define INT_VDE_BSE_A			(INT_PRI_BASE + 11) -#define INT_VDE_SXE			(INT_PRI_BASE + 12) -#define INT_I2S1			(INT_PRI_BASE + 13) -#define INT_SDMMC1			(INT_PRI_BASE + 14) -#define INT_SDMMC2			(INT_PRI_BASE + 15) -#define INT_XIO				(INT_PRI_BASE + 16) -#define INT_VDE				(INT_PRI_BASE + 17) -#define INT_AVP_UCQ			(INT_PRI_BASE + 18) -#define INT_SDMMC3			(INT_PRI_BASE + 19) -#define INT_USB				(INT_PRI_BASE + 20) -#define INT_USB2			(INT_PRI_BASE + 21) -#define INT_PRI_RES_22			(INT_PRI_BASE + 22) -#define INT_EIDE			(INT_PRI_BASE + 23) -#define INT_NANDFLASH			(INT_PRI_BASE + 24) -#define INT_VCP				(INT_PRI_BASE + 25) -#define INT_APB_DMA			(INT_PRI_BASE + 26) -#define INT_AHB_DMA			(INT_PRI_BASE + 27) -#define INT_GNT_0			(INT_PRI_BASE + 28) -#define INT_GNT_1			(INT_PRI_BASE + 29) -#define INT_OWR				(INT_PRI_BASE + 30) -#define INT_SDMMC4			(INT_PRI_BASE + 31) - -/* Secondary Interrupt Controller */ -#define INT_SEC_BASE			(INT_PRI_BASE + 32) -#define INT_GPIO1			(INT_SEC_BASE + 0) -#define INT_GPIO2			(INT_SEC_BASE + 1) -#define INT_GPIO3			(INT_SEC_BASE + 2) -#define INT_GPIO4			(INT_SEC_BASE + 3) -#define INT_UARTA			(INT_SEC_BASE + 4) -#define INT_UARTB			(INT_SEC_BASE + 5) -#define INT_I2C				(INT_SEC_BASE + 6) -#define INT_SPI				(INT_SEC_BASE + 7) -#define INT_TWC				(INT_SEC_BASE + 8) -#define INT_TMR3			(INT_SEC_BASE + 9) -#define INT_TMR4			(INT_SEC_BASE + 10) -#define INT_FLOW_RSM0			(INT_SEC_BASE + 11) -#define INT_FLOW_RSM1			(INT_SEC_BASE + 12) -#define INT_SPDIF			(INT_SEC_BASE + 13) -#define INT_UARTC			(INT_SEC_BASE + 14) -#define INT_MIPI			(INT_SEC_BASE + 15) -#define INT_EVENTA			(INT_SEC_BASE + 16) -#define INT_EVENTB			(INT_SEC_BASE + 17) -#define INT_EVENTC			(INT_SEC_BASE + 18) -#define INT_EVENTD			(INT_SEC_BASE + 19) -#define INT_VFIR			(INT_SEC_BASE + 20) -#define INT_DVC				(INT_SEC_BASE + 21) -#define INT_SYS_STATS_MON		(INT_SEC_BASE + 22) -#define INT_GPIO5			(INT_SEC_BASE + 23) -#define INT_CPU0_PMU_INTR		(INT_SEC_BASE + 24) -#define INT_CPU1_PMU_INTR		(INT_SEC_BASE + 25) -#define INT_SEC_RES_26			(INT_SEC_BASE + 26) -#define INT_S_LINK1			(INT_SEC_BASE + 27) -#define INT_APB_DMA_COP			(INT_SEC_BASE + 28) -#define INT_AHB_DMA_COP			(INT_SEC_BASE + 29) -#define INT_DMA_TX			(INT_SEC_BASE + 30) -#define INT_DMA_RX			(INT_SEC_BASE + 31) - -/* Tertiary Interrupt Controller */ -#define INT_TRI_BASE			(INT_SEC_BASE + 32) -#define INT_HOST1X_COP_SYNCPT		(INT_TRI_BASE + 0) -#define INT_HOST1X_MPCORE_SYNCPT	(INT_TRI_BASE + 1) -#define INT_HOST1X_COP_GENERAL		(INT_TRI_BASE + 2) -#define INT_HOST1X_MPCORE_GENERAL	(INT_TRI_BASE + 3) -#define INT_MPE_GENERAL			(INT_TRI_BASE + 4) -#define INT_VI_GENERAL			(INT_TRI_BASE + 5) -#define INT_EPP_GENERAL			(INT_TRI_BASE + 6) -#define INT_ISP_GENERAL			(INT_TRI_BASE + 7) -#define INT_2D_GENERAL			(INT_TRI_BASE + 8) -#define INT_DISPLAY_GENERAL		(INT_TRI_BASE + 9) -#define INT_DISPLAY_B_GENERAL		(INT_TRI_BASE + 10) -#define INT_HDMI			(INT_TRI_BASE + 11) -#define INT_TVO_GENERAL			(INT_TRI_BASE + 12) -#define INT_MC_GENERAL			(INT_TRI_BASE + 13) -#define INT_EMC_GENERAL			(INT_TRI_BASE + 14) -#define INT_TRI_RES_15			(INT_TRI_BASE + 15) -#define INT_TRI_RES_16			(INT_TRI_BASE + 16) -#define INT_AC97			(INT_TRI_BASE + 17) -#define INT_SPI_2			(INT_TRI_BASE + 18) -#define INT_SPI_3			(INT_TRI_BASE + 19) -#define INT_I2C2			(INT_TRI_BASE + 20) -#define INT_KBC				(INT_TRI_BASE + 21) -#define INT_EXTERNAL_PMU		(INT_TRI_BASE + 22) -#define INT_GPIO6			(INT_TRI_BASE + 23) -#define INT_TVDAC			(INT_TRI_BASE + 24) -#define INT_GPIO7			(INT_TRI_BASE + 25) -#define INT_UARTD			(INT_TRI_BASE + 26) -#define INT_UARTE			(INT_TRI_BASE + 27) -#define INT_I2C3			(INT_TRI_BASE + 28) -#define INT_SPI_4			(INT_TRI_BASE + 29) -#define INT_TRI_RES_30			(INT_TRI_BASE + 30) -#define INT_SW_RESERVED			(INT_TRI_BASE + 31) - -/* Quaternary Interrupt Controller */ -#define INT_QUAD_BASE			(INT_TRI_BASE + 32) -#define INT_SNOR			(INT_QUAD_BASE + 0) -#define INT_USB3			(INT_QUAD_BASE + 1) -#define INT_PCIE_INTR			(INT_QUAD_BASE + 2) -#define INT_PCIE_MSI			(INT_QUAD_BASE + 3) -#define INT_QUAD_RES_4			(INT_QUAD_BASE + 4) -#define INT_QUAD_RES_5			(INT_QUAD_BASE + 5) -#define INT_QUAD_RES_6			(INT_QUAD_BASE + 6) -#define INT_QUAD_RES_7			(INT_QUAD_BASE + 7) -#define INT_APB_DMA_CH0			(INT_QUAD_BASE + 8) -#define INT_APB_DMA_CH1			(INT_QUAD_BASE + 9) -#define INT_APB_DMA_CH2			(INT_QUAD_BASE + 10) -#define INT_APB_DMA_CH3			(INT_QUAD_BASE + 11) -#define INT_APB_DMA_CH4			(INT_QUAD_BASE + 12) -#define INT_APB_DMA_CH5			(INT_QUAD_BASE + 13) -#define INT_APB_DMA_CH6			(INT_QUAD_BASE + 14) -#define INT_APB_DMA_CH7			(INT_QUAD_BASE + 15) -#define INT_APB_DMA_CH8			(INT_QUAD_BASE + 16) -#define INT_APB_DMA_CH9			(INT_QUAD_BASE + 17) -#define INT_APB_DMA_CH10		(INT_QUAD_BASE + 18) -#define INT_APB_DMA_CH11		(INT_QUAD_BASE + 19) -#define INT_APB_DMA_CH12		(INT_QUAD_BASE + 20) -#define INT_APB_DMA_CH13		(INT_QUAD_BASE + 21) -#define INT_APB_DMA_CH14		(INT_QUAD_BASE + 22) -#define INT_APB_DMA_CH15		(INT_QUAD_BASE + 23) -#define INT_QUAD_RES_24			(INT_QUAD_BASE + 24) -#define INT_QUAD_RES_25			(INT_QUAD_BASE + 25) -#define INT_QUAD_RES_26			(INT_QUAD_BASE + 26) -#define INT_QUAD_RES_27			(INT_QUAD_BASE + 27) -#define INT_QUAD_RES_28			(INT_QUAD_BASE + 28) -#define INT_QUAD_RES_29			(INT_QUAD_BASE + 29) -#define INT_QUAD_RES_30			(INT_QUAD_BASE + 30) -#define INT_QUAD_RES_31			(INT_QUAD_BASE + 31) - -/* Tegra30 has 5 banks of 32 IRQs */ -#define INT_MAIN_NR			(32 * 5) -#define INT_GPIO_BASE			(INT_PRI_BASE + INT_MAIN_NR) - -/* Tegra30 has 8 banks of 32 GPIOs */ -#define INT_GPIO_NR			(32 * 8) - -#define TEGRA_NR_IRQS			(INT_GPIO_BASE + INT_GPIO_NR) - -#define INT_BOARD_BASE			TEGRA_NR_IRQS -#define NR_BOARD_IRQS			32 - -#define NR_IRQS				(INT_BOARD_BASE + NR_BOARD_IRQS) - -#endif diff --git a/arch/arm/mach-tegra/include/mach/powergate.h b/arch/arm/mach-tegra/include/mach/powergate.h index 4752b1a68f3..06763fe7529 100644 --- a/arch/arm/mach-tegra/include/mach/powergate.h +++ b/arch/arm/mach-tegra/include/mach/powergate.h @@ -20,6 +20,8 @@  #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 diff --git a/arch/arm/mach-tegra/include/mach/tegra-ahb.h b/arch/arm/mach-tegra/include/mach/tegra-ahb.h deleted file mode 100644 index e0f8c84b1d8..00000000000 --- a/arch/arm/mach-tegra/include/mach/tegra-ahb.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2012, 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. - */ - -#ifndef __MACH_TEGRA_AHB_H__ -#define __MACH_TEGRA_AHB_H__ - -extern int tegra_ahb_enable_smmu(struct device_node *ahb); - -#endif	/* __MACH_TEGRA_AHB_H__ */ diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 937c4c50219..485003f9b63 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -28,8 +28,7 @@  #include <linux/types.h>  #include <linux/serial_reg.h> -#include <mach/iomap.h> -#include <mach/irammap.h> +#include "../../iomap.h"  #define BIT(x) (1 << (x))  #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -52,17 +51,6 @@ static inline void flush(void)  {  } -static inline void save_uart_address(void) -{ -	u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET); - -	if (uart) { -		buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE; -		buf[1] = (u32)uart; -	} else -		buf[0] = 0; -} -  static const struct {  	u32 base;  	u32 reset_reg; @@ -139,51 +127,19 @@ int auto_odmdata(void)  }  #endif -#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH -int auto_scratch(void) -{ -	int i; - -	/* -	 * Look for the first UART that: -	 * a) Is not in reset. -	 * b) Is clocked. -	 * c) Has a 'D' in the scratchpad register. -	 * -	 * Note that on Tegra30, the first two conditions are required, since -	 * if not true, accesses to the UART scratch register will hang. -	 * Tegra20 doesn't have this issue. -	 * -	 * The intent is that the bootloader will tell the kernel which UART -	 * to use by setting up those conditions. If nothing found, we'll fall -	 * back to what's specified in TEGRA_DEBUG_UART_BASE. -	 */ -	for (i = 0; i < ARRAY_SIZE(uarts); i++) { -		if (!uart_clocked(i)) -			continue; - -		uart = (volatile u8 *)uarts[i].base; -		if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') -			continue; - -		return i; -	} - -	return -1; -} -#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, auto_uart_id; +	int uart_id;  	volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;  	u32 chip, div; -#if defined(CONFIG_TEGRA_DEBUG_UARTA) +#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; @@ -193,19 +149,7 @@ static inline void arch_decomp_setup(void)  	uart_id = 3;  #elif defined(CONFIG_TEGRA_DEBUG_UARTE)  	uart_id = 4; -#else -	uart_id = -1; -#endif - -#if defined(CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA) -	auto_uart_id = auto_odmdata(); -#elif defined(CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH) -	auto_uart_id = auto_scratch(); -#else -	auto_uart_id = -1;  #endif -	if (auto_uart_id != -1) -		uart_id = auto_uart_id;  	if (uart_id < 0 || uart_id >= ARRAY_SIZE(uarts) ||  	    !uart_clocked(uart_id)) @@ -213,7 +157,6 @@ static inline void arch_decomp_setup(void)  	else  		uart = (volatile u8 *)uarts[uart_id].base; -	save_uart_address();  	if (uart == NULL)  		return; diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c index 58b4baf9c48..bb9c9c29d18 100644 --- a/arch/arm/mach-tegra/io.c +++ b/arch/arm/mach-tegra/io.c @@ -26,9 +26,9 @@  #include <asm/page.h>  #include <asm/mach/map.h> -#include <mach/iomap.h>  #include "board.h" +#include "iomap.h"  static struct map_desc tegra_io_desc[] __initdata = {  	{ @@ -59,5 +59,6 @@ static struct map_desc tegra_io_desc[] __initdata = {  void __init tegra_map_common_io(void)  { +	debug_ll_io_init();  	iotable_init(tegra_io_desc, ARRAY_SIZE(tegra_io_desc));  } diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/iomap.h index fee3a94c454..db8be51cad8 100644 --- a/arch/arm/mach-tegra/include/mach/iomap.h +++ b/arch/arm/mach-tegra/iomap.h @@ -1,6 +1,4 @@  /* - * arch/arm/mach-tegra/include/mach/iomap.h - *   * Copyright (C) 2010 Google, Inc.   *   * Author: @@ -263,20 +261,6 @@  #define TEGRA_SDMMC4_BASE		0xC8000600  #define TEGRA_SDMMC4_SIZE		SZ_512 -#if defined(CONFIG_TEGRA_DEBUG_UART_NONE) -# define TEGRA_DEBUG_UART_BASE 0 -#elif defined(CONFIG_TEGRA_DEBUG_UARTA) -# define TEGRA_DEBUG_UART_BASE TEGRA_UARTA_BASE -#elif defined(CONFIG_TEGRA_DEBUG_UARTB) -# define TEGRA_DEBUG_UART_BASE TEGRA_UARTB_BASE -#elif defined(CONFIG_TEGRA_DEBUG_UARTC) -# define TEGRA_DEBUG_UART_BASE TEGRA_UARTC_BASE -#elif defined(CONFIG_TEGRA_DEBUG_UARTD) -# define TEGRA_DEBUG_UART_BASE TEGRA_UARTD_BASE -#elif defined(CONFIG_TEGRA_DEBUG_UARTE) -# define TEGRA_DEBUG_UART_BASE TEGRA_UARTE_BASE -#endif -  /* On TEGRA, many peripherals are very closely packed in   * two 256MB io windows (that actually only use about 64KB   * at the start of each). diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/irammap.h index 0cbe6326185..501952a8434 100644 --- a/arch/arm/mach-tegra/include/mach/irammap.h +++ b/arch/arm/mach-tegra/irammap.h @@ -23,13 +23,4 @@  #define TEGRA_IRAM_RESET_HANDLER_OFFSET	0  #define TEGRA_IRAM_RESET_HANDLER_SIZE	SZ_1K -/* - * These locations are written to by uncompress.h, and read by debug-macro.S. - * The first word holds the cookie value if the data is valid. The second - * word holds the UART physical address. - */ -#define TEGRA_IRAM_DEBUG_UART_OFFSET	SZ_1K -#define TEGRA_IRAM_DEBUG_UART_SIZE	8 -#define TEGRA_IRAM_DEBUG_UART_COOKIE	0x55415254 -  #endif diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 2f5bd2db8e1..b7886f18351 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -25,9 +25,8 @@  #include <asm/hardware/gic.h> -#include <mach/iomap.h> -  #include "board.h" +#include "iomap.h"  #define ICTLR_CPU_IEP_VFIQ	0x08  #define ICTLR_CPU_IEP_FIR	0x14 diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c index a8dba6489c9..53d08587179 100644 --- a/arch/arm/mach-tegra/pcie.c +++ b/arch/arm/mach-tegra/pcie.c @@ -37,11 +37,14 @@  #include <asm/sizes.h>  #include <asm/mach/pci.h> -#include <mach/iomap.h>  #include <mach/clk.h>  #include <mach/powergate.h>  #include "board.h" +#include "iomap.h" + +/* Hack - need to parse this from DT */ +#define INT_PCIE_INTR 130  /* register definitions */  #define AFI_OFFSET	0x3800 diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 81cb26591ac..1b926df99c4 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -24,8 +24,6 @@  #include <asm/mach-types.h>  #include <asm/smp_scu.h> -#include <mach/clk.h> -#include <mach/iomap.h>  #include <mach/powergate.h>  #include "fuse.h" @@ -34,6 +32,7 @@  #include "tegra_cpu_car.h"  #include "common.h" +#include "iomap.h"  extern void tegra_secondary_startup(void); diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c new file mode 100644 index 00000000000..1b11707eaca --- /dev/null +++ b/arch/arm/mach-tegra/pm.c @@ -0,0 +1,216 @@ +/* + * CPU complex suspend & resume functions for Tegra SoCs + * + * Copyright (c) 2009-2012, 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/spinlock.h> +#include <linux/io.h> +#include <linux/cpumask.h> +#include <linux/delay.h> +#include <linux/cpu_pm.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <asm/smp_plat.h> +#include <asm/cacheflush.h> +#include <asm/suspend.h> +#include <asm/idmap.h> +#include <asm/proc-fns.h> +#include <asm/tlbflush.h> + +#include "iomap.h" +#include "reset.h" +#include "flowctrl.h" +#include "sleep.h" +#include "tegra_cpu_car.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 + * + * restores cpu clock setting, clears flow controller + * + * Always called on CPU 0. + */ +static void restore_cpu_complex(void) +{ +	int cpu = smp_processor_id(); + +	BUG_ON(cpu != 0); + +#ifdef CONFIG_SMP +	cpu = cpu_logical_map(cpu); +#endif + +	/* Restore the CPU clock settings */ +	tegra_cpu_clock_resume(); + +	flowctrl_cpu_suspend_exit(cpu); + +	restore_cpu_arch_register(); +} + +/* + * suspend_cpu_complex + * + * saves pll state for use by restart_plls, prepares flow controller for + * transition to suspend state + * + * Must always be called on cpu 0. + */ +static void suspend_cpu_complex(void) +{ +	int cpu = smp_processor_id(); + +	BUG_ON(cpu != 0); + +#ifdef CONFIG_SMP +	cpu = cpu_logical_map(cpu); +#endif + +	/* Save the CPU clock settings */ +	tegra_cpu_clock_suspend(); + +	flowctrl_cpu_suspend_enter(cpu); + +	save_cpu_arch_register(); +} + +void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id) +{ +	u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; + +	spin_lock(&tegra_lp2_lock); + +	BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id))); +	*cpu_in_lp2 &= ~BIT(phy_cpu_id); + +	spin_unlock(&tegra_lp2_lock); +} + +bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id) +{ +	bool last_cpu = false; +	cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask; +	u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; + +	spin_lock(&tegra_lp2_lock); + +	BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id))); +	*cpu_in_lp2 |= BIT(phy_cpu_id); + +	if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask)) +		last_cpu = true; + +	spin_unlock(&tegra_lp2_lock); +	return last_cpu; +} + +static int tegra_sleep_cpu(unsigned long v2p) +{ +	/* Switch to the identity mapping. */ +	cpu_switch_mm(idmap_pgd, &init_mm); + +	/* Flush the TLB. */ +	local_flush_tlb_all(); + +	tegra_sleep_cpu_finish(v2p); + +	/* should never here */ +	BUG(); + +	return 0; +} + +void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) +{ +	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); + +	cpu_cluster_pm_enter(); +	suspend_cpu_complex(); + +	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); + +	restore_cpu_complex(); +	cpu_cluster_pm_exit(); +} +#endif diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h new file mode 100644 index 00000000000..787335cc964 --- /dev/null +++ b/arch/arm/mach-tegra/pm.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 Google, Inc. + * Copyright (c) 2010-2012 NVIDIA Corporation. All rights reserved. + * + * Author: + *	Colin Cross <ccross@google.com> + * + * 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/>. + */ + +#ifndef _MACH_TEGRA_PM_H_ +#define _MACH_TEGRA_PM_H_ + +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_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time); +extern void (*tegra_tear_down_cpu)(void); + +#endif /* _MACH_TEGRA_PM_H_ */ diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index 7af6a54404b..d4fdb5fcec2 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -19,7 +19,7 @@  #include <linux/io.h>  #include <linux/of.h> -#include <mach/iomap.h> +#include "iomap.h"  #define PMC_CTRL		0x0  #define PMC_CTRL_INTR_LOW	(1 << 17) diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index de0662de28a..2cc1185d902 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -28,10 +28,10 @@  #include <linux/spinlock.h>  #include <mach/clk.h> -#include <mach/iomap.h>  #include <mach/powergate.h>  #include "fuse.h" +#include "iomap.h"  #define PWRGATE_TOGGLE		0x30  #define  PWRGATE_TOGGLE_START	(1 << 8) diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index 5beb7ebe294..3fd89ecd158 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -22,10 +22,10 @@  #include <asm/cacheflush.h>  #include <asm/hardware/cache-l2x0.h> -#include <mach/iomap.h> -#include <mach/irammap.h> - +#include "iomap.h" +#include "irammap.h"  #include "reset.h" +#include "sleep.h"  #include "fuse.h"  #define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \ @@ -80,5 +80,10 @@ void __init tegra_cpu_reset_handler_init(void)  		virt_to_phys((void *)tegra_secondary_startup);  #endif +#ifdef CONFIG_PM_SLEEP +	__tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] = +		virt_to_phys((void *)tegra_resume); +#endif +  	tegra_cpu_reset_handler_enable();  } diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h index de88bf851dd..c90d8e9c4ad 100644 --- a/arch/arm/mach-tegra/reset.h +++ b/arch/arm/mach-tegra/reset.h @@ -29,6 +29,8 @@  #ifndef __ASSEMBLY__ +#include "irammap.h" +  extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];  void __tegra_cpu_reset_handler_start(void); @@ -36,6 +38,13 @@ void __tegra_cpu_reset_handler(void);  void __tegra_cpu_reset_handler_end(void);  void tegra_secondary_startup(void); +#ifdef CONFIG_PM_SLEEP +#define tegra_cpu_lp2_mask \ +	(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \ +	((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \ +	 (u32)__tegra_cpu_reset_handler_start))) +#endif +  #define tegra_cpu_reset_handler_offset \  		((u32)__tegra_cpu_reset_handler - \  		 (u32)__tegra_cpu_reset_handler_start) diff --git a/arch/arm/mach-tegra/sleep-t20.S b/arch/arm/mach-tegra/sleep-tegra20.S index a36ae413e2b..72ce709799d 100644 --- a/arch/arm/mach-tegra/sleep-t20.S +++ b/arch/arm/mach-tegra/sleep-tegra20.S @@ -22,8 +22,6 @@  #include <asm/assembler.h> -#include <mach/iomap.h> -  #include "sleep.h"  #include "flowctrl.h" diff --git a/arch/arm/mach-tegra/sleep-t30.S b/arch/arm/mach-tegra/sleep-tegra30.S index 777d9cee8b9..562a8e7e413 100644 --- a/arch/arm/mach-tegra/sleep-t30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -17,8 +17,7 @@  #include <linux/linkage.h>  #include <asm/assembler.h> - -#include <mach/iomap.h> +#include <asm/asm-offsets.h>  #include "sleep.h"  #include "flowctrl.h" @@ -82,6 +81,7 @@ delay_1:  	ldr	r3, [r1]			@ read CSR  	str	r3, [r1]			@ clear CSR  	tst	r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN +	moveq   r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT	@ For LP2  	movne	r3, #FLOW_CTRL_WAITEVENT		@ For hotplug  	str	r3, [r2]  	ldr	r0, [r2] @@ -105,3 +105,67 @@ wfe_war:  ENDPROC(tegra30_cpu_shutdown)  #endif + +#ifdef CONFIG_PM_SLEEP +/* + * tegra30_sleep_cpu_secondary_finish(unsigned long v2p) + * + * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU. + */ +ENTRY(tegra30_sleep_cpu_secondary_finish) +	mov	r7, lr + +	/* Flush and disable the L1 data cache */ +	bl	tegra_disable_clean_inv_dcache + +	/* Powergate this CPU. */ +	mov	r0, #0                          @ power mode flags (!hotplug) +	bl	tegra30_cpu_shutdown +	mov	r0, #1                          @ never return here +	mov	pc, r7 +ENDPROC(tegra30_sleep_cpu_secondary_finish) + +/* + * tegra30_tear_down_cpu + * + * Switches the CPU to enter sleep. + */ +ENTRY(tegra30_tear_down_cpu) +	mov32	r6, TEGRA_FLOW_CTRL_BASE + +	b	tegra30_enter_sleep +ENDPROC(tegra30_tear_down_cpu) + +/* + * tegra30_enter_sleep + * + * uses flow controller to enter sleep state + * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1 + * executes from SDRAM with target state is LP2 + * r6 = TEGRA_FLOW_CTRL_BASE + */ +tegra30_enter_sleep: +	cpu_id	r1 + +	cpu_to_csr_reg	r2, r1 +	ldr	r0, [r6, r2] +	orr	r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG +	orr	r0, r0, #FLOW_CTRL_CSR_ENABLE +	str	r0, [r6, r2] + +	mov	r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT +	orr	r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ +	cpu_to_halt_reg r2, r1 +	str	r0, [r6, r2] +	dsb +	ldr	r0, [r6, r2] /* memory barrier */ + +halted: +	isb +	dsb +	wfi	/* CPU should be power gated here */ + +	/* !!!FIXME!!! Implement halt failure handler */ +	b	halted + +#endif diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S index ea81554c483..26afa7cbed1 100644 --- a/arch/arm/mach-tegra/sleep.S +++ b/arch/arm/mach-tegra/sleep.S @@ -25,9 +25,87 @@  #include <linux/linkage.h>  #include <asm/assembler.h> +#include <asm/cache.h> +#include <asm/cp15.h> +#include <asm/hardware/cache-l2x0.h> -#include <mach/iomap.h> +#include "iomap.h"  #include "flowctrl.h"  #include "sleep.h" +#ifdef CONFIG_PM_SLEEP +/* + * tegra_disable_clean_inv_dcache + * + * disable, clean & invalidate the D-cache + * + * Corrupted registers: r1-r3, r6, r8, r9-r11 + */ +ENTRY(tegra_disable_clean_inv_dcache) +	stmfd	sp!, {r0, r4-r5, r7, r9-r11, lr} +	dmb					@ ensure ordering + +	/* Disable the D-cache */ +	mrc	p15, 0, r2, c1, c0, 0 +	bic	r2, r2, #CR_C +	mcr	p15, 0, r2, c1, c0, 0 +	isb + +	/* Flush the D-cache */ +	bl	v7_flush_dcache_louis + +	/* Trun off coherency */ +	exit_smp r4, r5 + +	ldmfd	sp!, {r0, r4-r5, r7, r9-r11, pc} +ENDPROC(tegra_disable_clean_inv_dcache) + +/* + * tegra_sleep_cpu_finish(unsigned long v2p) + * + * enters suspend in LP2 by turning off the mmu and jumping to + * tegra?_tear_down_cpu + */ +ENTRY(tegra_sleep_cpu_finish) +	/* Flush and disable the L1 data cache */ +	bl	tegra_disable_clean_inv_dcache + +	mov32	r6, tegra_tear_down_cpu +	ldr	r1, [r6] +	add	r1, r1, r0 + +	mov32	r3, tegra_shut_off_mmu +	add	r3, r3, r0 +	mov	r0, r1 + +	mov	pc, r3 +ENDPROC(tegra_sleep_cpu_finish) + +/* + * tegra_shut_off_mmu + * + * r0 = physical address to jump to with mmu off + * + * called with VA=PA mapping + * turns off MMU, icache, dcache and branch prediction + */ +	.align	L1_CACHE_SHIFT +	.pushsection	.idmap.text, "ax" +ENTRY(tegra_shut_off_mmu) +	mrc	p15, 0, r3, c1, c0, 0 +	movw	r2, #CR_I | CR_Z | CR_C | CR_M +	bic	r3, r3, r2 +	dsb +	mcr	p15, 0, r3, c1, c0, 0 +	isb +#ifdef CONFIG_CACHE_L2X0 +	/* Disable L2 cache */ +	mov32	r4, TEGRA_ARM_PERIF_BASE + 0x3000 +	mov	r5, #0 +	str	r5, [r4, #L2X0_CTRL] +#endif +	mov	pc, r0 +ENDPROC(tegra_shut_off_mmu) +	.popsection +#endif diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h index e25a7cd703d..9821ee72542 100644 --- a/arch/arm/mach-tegra/sleep.h +++ b/arch/arm/mach-tegra/sleep.h @@ -17,7 +17,7 @@  #ifndef __MACH_TEGRA_SLEEP_H  #define __MACH_TEGRA_SLEEP_H -#include <mach/iomap.h> +#include "iomap.h"  #define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \  					+ IO_CPU_VIRT) @@ -71,7 +71,41 @@  	str	\tmp2, [\tmp1]			@ invalidate SCU tags for CPU  	dsb  .endm + +/* Macro to resume & re-enable L2 cache */ +#ifndef L2X0_CTRL_EN +#define L2X0_CTRL_EN	1 +#endif + +#ifdef CONFIG_CACHE_L2X0 +.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs +	adr	\tmp1, \phys_l2x0_saved_regs +	ldr	\tmp1, [\tmp1] +	ldr	\tmp2, [\tmp1, #L2X0_R_PHY_BASE] +	ldr	\tmp3, [\tmp2, #L2X0_CTRL] +	tst	\tmp3, #L2X0_CTRL_EN +	bne	exit_l2_resume +	ldr	\tmp3, [\tmp1, #L2X0_R_TAG_LATENCY] +	str	\tmp3, [\tmp2, #L2X0_TAG_LATENCY_CTRL] +	ldr	\tmp3, [\tmp1, #L2X0_R_DATA_LATENCY] +	str	\tmp3, [\tmp2, #L2X0_DATA_LATENCY_CTRL] +	ldr	\tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL] +	str	\tmp3, [\tmp2, #L2X0_PREFETCH_CTRL] +	ldr	\tmp3, [\tmp1, #L2X0_R_PWR_CTRL] +	str	\tmp3, [\tmp2, #L2X0_POWER_CTRL] +	ldr	\tmp3, [\tmp1, #L2X0_R_AUX_CTRL] +	str	\tmp3, [\tmp2, #L2X0_AUX_CTRL] +	mov	\tmp3, #L2X0_CTRL_EN +	str	\tmp3, [\tmp2, #L2X0_CTRL] +exit_l2_resume: +.endm +#else /* CONFIG_CACHE_L2X0 */ +.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs +.endm +#endif /* CONFIG_CACHE_L2X0 */  #else +void tegra_resume(void); +int tegra_sleep_cpu_finish(unsigned long);  #ifdef CONFIG_HOTPLUG_CPU  void tegra20_hotplug_init(void); @@ -81,5 +115,8 @@ static inline void tegra20_hotplug_init(void) {}  static inline void tegra30_hotplug_init(void) {}  #endif +int tegra30_sleep_cpu_secondary_finish(unsigned long); +void tegra30_tear_down_cpu(void); +  #endif  #endif diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c index deb873fb12b..4eb6bc81a87 100644 --- a/arch/arm/mach-tegra/tegra20_clocks.c +++ b/arch/arm/mach-tegra/tegra20_clocks.c @@ -27,10 +27,9 @@  #include <linux/clkdev.h>  #include <linux/clk.h> -#include <mach/iomap.h> -  #include "clock.h"  #include "fuse.h" +#include "iomap.h"  #include "tegra2_emc.h"  #include "tegra_cpu_car.h" diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c index 8d398a33adf..a23a0734e35 100644 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ b/arch/arm/mach-tegra/tegra20_clocks_data.c @@ -27,8 +27,6 @@  #include <linux/io.h>  #include <linux/clk.h> -#include <mach/iomap.h> -  #include "clock.h"  #include "fuse.h"  #include "tegra2_emc.h" @@ -248,11 +246,16 @@ static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {  	{ 19200000, 216000000, 135, 12, 1, 3},  	{ 26000000, 216000000, 216, 26, 1, 4}, +	{ 12000000, 297000000,  99,  4, 1, 4 }, +	{ 12000000, 339000000, 113,  4, 1, 4 }, +  	{ 12000000, 594000000, 594, 12, 1, 8},  	{ 13000000, 594000000, 594, 13, 1, 8},  	{ 19200000, 594000000, 495, 16, 1, 8},  	{ 26000000, 594000000, 594, 26, 1, 8}, +	{ 12000000, 616000000, 616, 12, 1, 8}, +  	{ 12000000, 1000000000, 1000, 12, 1, 12},  	{ 13000000, 1000000000, 1000, 13, 1, 12},  	{ 19200000, 1000000000, 625,  12, 1, 8}, @@ -1038,9 +1041,6 @@ static struct clk_duplicate tegra_clk_duplicates[] = {  	CLK_DUPLICATE("usbd",	"utmip-pad",	NULL),  	CLK_DUPLICATE("usbd",	"tegra-ehci.0",	NULL),  	CLK_DUPLICATE("usbd",	"tegra-otg",	NULL), -	CLK_DUPLICATE("hdmi",	"tegradc.0",	"hdmi"), -	CLK_DUPLICATE("hdmi",	"tegradc.1",	"hdmi"), -	CLK_DUPLICATE("host1x",	"tegra_grhost",	"host1x"),  	CLK_DUPLICATE("2d",	"tegra_grhost",	"gr2d"),  	CLK_DUPLICATE("3d",	"tegra_grhost",	"gr3d"),  	CLK_DUPLICATE("epp",	"tegra_grhost",	"epp"), @@ -1053,6 +1053,9 @@ static struct clk_duplicate tegra_clk_duplicates[] = {  	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"),  	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),  	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), +	CLK_DUPLICATE("pll_p", "tegradc.0", "parent"), +	CLK_DUPLICATE("pll_p", "tegradc.1", "parent"), +	CLK_DUPLICATE("pll_d_out0", "hdmi", "parent"),  };  #define CLK(dev, con, ck)	\ diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c new file mode 100644 index 00000000000..fa6eb570623 --- /dev/null +++ b/arch/arm/mach-tegra/tegra20_speedo.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2012, 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 CPU_SPEEDO_LSBIT		20 +#define CPU_SPEEDO_MSBIT		29 +#define CPU_SPEEDO_REDUND_LSBIT		30 +#define CPU_SPEEDO_REDUND_MSBIT		39 +#define CPU_SPEEDO_REDUND_OFFS	(CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) + +#define CORE_SPEEDO_LSBIT		40 +#define CORE_SPEEDO_MSBIT		47 +#define CORE_SPEEDO_REDUND_LSBIT	48 +#define CORE_SPEEDO_REDUND_MSBIT	55 +#define CORE_SPEEDO_REDUND_OFFS	(CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) + +#define SPEEDO_MULT			4 + +#define PROCESS_CORNERS_NUM		4 + +#define SPEEDO_ID_SELECT_0(rev)		((rev) <= 2) +#define SPEEDO_ID_SELECT_1(sku)		\ +	(((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ +	 ((sku) != 27) && ((sku) != 28)) + +enum { +	SPEEDO_ID_0, +	SPEEDO_ID_1, +	SPEEDO_ID_2, +	SPEEDO_ID_COUNT, +}; + +static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { +	{315, 366, 420, UINT_MAX}, +	{303, 368, 419, UINT_MAX}, +	{316, 331, 383, UINT_MAX}, +}; + +static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { +	{165, 195, 224, UINT_MAX}, +	{165, 195, 224, UINT_MAX}, +	{165, 195, 224, UINT_MAX}, +}; + +void tegra20_init_speedo_data(void) +{ +	u32 reg; +	u32 val; +	int i; + +	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); +	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); + +	if (SPEEDO_ID_SELECT_0(tegra_revision)) +		tegra_soc_speedo_id = SPEEDO_ID_0; +	else if (SPEEDO_ID_SELECT_1(tegra_sku_id)) +		tegra_soc_speedo_id = SPEEDO_ID_1; +	else +		tegra_soc_speedo_id = SPEEDO_ID_2; + +	val = 0; +	for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { +		reg = tegra_spare_fuse(i) | +			tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS); +		val = (val << 1) | (reg & 0x1); +	} +	val = val * SPEEDO_MULT; +	pr_debug("%s CPU speedo value %u\n", __func__, val); + +	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { +		if (val <= cpu_process_speedos[tegra_soc_speedo_id][i]) +			break; +	} +	tegra_cpu_process_id = i; + +	val = 0; +	for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { +		reg = tegra_spare_fuse(i) | +			tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS); +		val = (val << 1) | (reg & 0x1); +	} +	val = val * SPEEDO_MULT; +	pr_debug("%s Core speedo value %u\n", __func__, val); + +	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { +		if (val <= core_process_speedos[tegra_soc_speedo_id][i]) +			break; +	} +	tegra_core_process_id = i; + +	pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id); +} diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index 5070d833bdd..837c7b9ea63 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -25,8 +25,6 @@  #include <linux/platform_device.h>  #include <linux/platform_data/tegra_emc.h> -#include <mach/iomap.h> -  #include "tegra2_emc.h"  #include "fuse.h" diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index e9de5dfd94e..efc000e32e1 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -31,10 +31,11 @@  #include <asm/clkdev.h> -#include <mach/iomap.h> +#include <mach/powergate.h>  #include "clock.h"  #include "fuse.h" +#include "iomap.h"  #include "tegra_cpu_car.h"  #define USE_PLL_LOCK_BITS 0 @@ -310,6 +311,31 @@  #define CPU_CLOCK(cpu)	(0x1 << (8 + cpu))  #define CPU_RESET(cpu)	(0x1111ul << (cpu)) +#define CLK_RESET_CCLK_BURST	0x20 +#define CLK_RESET_CCLK_DIVIDER  0x24 +#define CLK_RESET_PLLX_BASE	0xe0 +#define CLK_RESET_PLLX_MISC	0xe4 + +#define CLK_RESET_SOURCE_CSITE	0x1d4 + +#define CLK_RESET_CCLK_BURST_POLICY_SHIFT	28 +#define CLK_RESET_CCLK_RUN_POLICY_SHIFT		4 +#define CLK_RESET_CCLK_IDLE_POLICY_SHIFT	0 +#define CLK_RESET_CCLK_IDLE_POLICY		1 +#define CLK_RESET_CCLK_RUN_POLICY		2 +#define CLK_RESET_CCLK_BURST_POLICY_PLLX	8 + +#ifdef CONFIG_PM_SLEEP +static struct cpu_clk_suspend_context { +	u32 pllx_misc; +	u32 pllx_base; + +	u32 cpu_burst; +	u32 clk_csite_src; +	u32 cclk_divider; +} tegra30_cpu_clk_sctx; +#endif +  /**  * Structure defining the fields for USB UTMI clocks Parameters.  */ @@ -792,6 +818,112 @@ struct clk_ops tegra30_twd_ops = {  	.recalc_rate = tegra30_twd_clk_recalc_rate,  }; +/* bus clock functions */ +static int tegra30_bus_clk_is_enabled(struct clk_hw *hw) +{ +	struct clk_tegra *c = to_clk_tegra(hw); +	u32 val = clk_readl(c->reg); + +	c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON; +	return c->state; +} + +static int tegra30_bus_clk_enable(struct clk_hw *hw) +{ +	struct clk_tegra *c = to_clk_tegra(hw); +	u32 val; + +	val = clk_readl(c->reg); +	val &= ~(BUS_CLK_DISABLE << c->reg_shift); +	clk_writel(val, c->reg); + +	return 0; +} + +static void tegra30_bus_clk_disable(struct clk_hw *hw) +{ +	struct clk_tegra *c = to_clk_tegra(hw); +	u32 val; + +	val = clk_readl(c->reg); +	val |= BUS_CLK_DISABLE << c->reg_shift; +	clk_writel(val, c->reg); +} + +static unsigned long tegra30_bus_clk_recalc_rate(struct clk_hw *hw, +			unsigned long prate) +{ +	struct clk_tegra *c = to_clk_tegra(hw); +	u32 val = clk_readl(c->reg); +	u64 rate = prate; + +	c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1; +	c->mul = 1; + +	if (c->mul != 0 && c->div != 0) { +		rate *= c->mul; +		rate += c->div - 1; /* round up */ +		do_div(rate, c->div); +	} +	return rate; +} + +static int tegra30_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate, +		unsigned long parent_rate) +{ +	struct clk_tegra *c = to_clk_tegra(hw); +	int ret = -EINVAL; +	u32 val; +	int i; + +	val = clk_readl(c->reg); +	for (i = 1; i <= 4; i++) { +		if (rate == parent_rate / i) { +			val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); +			val |= (i - 1) << c->reg_shift; +			clk_writel(val, c->reg); +			c->div = i; +			c->mul = 1; +			ret = 0; +			break; +		} +	} + +	return ret; +} + +static long tegra30_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate, +				unsigned long *prate) +{ +	unsigned long parent_rate = *prate; +	s64 divider; + +	if (rate >= parent_rate) +		return parent_rate; + +	divider = parent_rate; +	divider += rate - 1; +	do_div(divider, rate); + +	if (divider < 0) +		return divider; + +	if (divider > 4) +		divider = 4; +	do_div(parent_rate, divider); + +	return parent_rate; +} + +struct clk_ops tegra30_bus_ops = { +	.is_enabled = tegra30_bus_clk_is_enabled, +	.enable = tegra30_bus_clk_enable, +	.disable = tegra30_bus_clk_disable, +	.set_rate = tegra30_bus_clk_set_rate, +	.round_rate = tegra30_bus_clk_round_rate, +	.recalc_rate = tegra30_bus_clk_recalc_rate, +}; +  /* Blink output functions */  static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)  { @@ -2281,12 +2413,93 @@ static void tegra30_disable_cpu_clock(u32 cpu)  	       reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);  } +#ifdef CONFIG_PM_SLEEP +static bool tegra30_cpu_rail_off_ready(void) +{ +	unsigned int cpu_rst_status; +	int cpu_pwr_status; + +	cpu_rst_status = readl(reg_clk_base + +			       TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); +	cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || +			 tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || +			 tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); + +	if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) +		return false; + +	return true; +} + +static void tegra30_cpu_clock_suspend(void) +{ +	/* switch coresite to clk_m, save off original source */ +	tegra30_cpu_clk_sctx.clk_csite_src = +				readl(reg_clk_base + CLK_RESET_SOURCE_CSITE); +	writel(3<<30, reg_clk_base + CLK_RESET_SOURCE_CSITE); + +	tegra30_cpu_clk_sctx.cpu_burst = +				readl(reg_clk_base + CLK_RESET_CCLK_BURST); +	tegra30_cpu_clk_sctx.pllx_base = +				readl(reg_clk_base + CLK_RESET_PLLX_BASE); +	tegra30_cpu_clk_sctx.pllx_misc = +				readl(reg_clk_base + CLK_RESET_PLLX_MISC); +	tegra30_cpu_clk_sctx.cclk_divider = +				readl(reg_clk_base + CLK_RESET_CCLK_DIVIDER); +} + +static void tegra30_cpu_clock_resume(void) +{ +	unsigned int reg, policy; + +	/* Is CPU complex already running on PLLX? */ +	reg = readl(reg_clk_base + CLK_RESET_CCLK_BURST); +	policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF; + +	if (policy == CLK_RESET_CCLK_IDLE_POLICY) +		reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF; +	else if (policy == CLK_RESET_CCLK_RUN_POLICY) +		reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF; +	else +		BUG(); + +	if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { +		/* restore PLLX settings if CPU is on different PLL */ +		writel(tegra30_cpu_clk_sctx.pllx_misc, +					reg_clk_base + CLK_RESET_PLLX_MISC); +		writel(tegra30_cpu_clk_sctx.pllx_base, +					reg_clk_base + CLK_RESET_PLLX_BASE); + +		/* wait for PLL stabilization if PLLX was enabled */ +		if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) +			udelay(300); +	} + +	/* +	 * Restore original burst policy setting for calls resulting from CPU +	 * LP2 in idle or system suspend. +	 */ +	writel(tegra30_cpu_clk_sctx.cclk_divider, +					reg_clk_base + CLK_RESET_CCLK_DIVIDER); +	writel(tegra30_cpu_clk_sctx.cpu_burst, +					reg_clk_base + CLK_RESET_CCLK_BURST); + +	writel(tegra30_cpu_clk_sctx.clk_csite_src, +					reg_clk_base + CLK_RESET_SOURCE_CSITE); +} +#endif +  static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {  	.wait_for_reset	= tegra30_wait_cpu_in_reset,  	.put_in_reset	= tegra30_put_cpu_in_reset,  	.out_of_reset	= tegra30_cpu_out_of_reset,  	.enable_clock	= tegra30_enable_cpu_clock,  	.disable_clock	= tegra30_disable_cpu_clock, +#ifdef CONFIG_PM_SLEEP +	.rail_off_ready	= tegra30_cpu_rail_off_ready, +	.suspend	= tegra30_cpu_clock_suspend, +	.resume		= tegra30_cpu_clock_resume, +#endif  };  void __init tegra30_cpu_car_ops_init(void) diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h index f2f88fef6b8..7a34adb2f72 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.h +++ b/arch/arm/mach-tegra/tegra30_clocks.h @@ -34,6 +34,7 @@ extern struct clk_ops tegra_clk_out_ops;  extern struct clk_ops tegra30_super_ops;  extern struct clk_ops tegra30_blink_clk_ops;  extern struct clk_ops tegra30_twd_ops; +extern struct clk_ops tegra30_bus_ops;  extern struct clk_ops tegra30_periph_clk_ops;  extern struct clk_ops tegra30_dsib_clk_ops;  extern struct clk_ops tegra_nand_clk_ops; diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c index 3d2e5532a9e..6942c7add3b 100644 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ b/arch/arm/mach-tegra/tegra30_clocks_data.c @@ -711,6 +711,50 @@ static struct clk tegra_clk_sclk = {  	.num_parents = ARRAY_SIZE(mux_sclk),  }; +static const char *tegra_hclk_parent_names[] = { +	"tegra_sclk", +}; + +static struct clk *tegra_hclk_parents[] = { +	&tegra_clk_sclk, +}; + +static struct clk tegra_hclk; +static struct clk_tegra tegra_hclk_hw = { +	.hw = { +		.clk = &tegra_hclk, +	}, +	.flags = DIV_BUS, +	.reg = 0x30, +	.reg_shift = 4, +	.max_rate = 378000000, +	.min_rate = 12000000, +}; +DEFINE_CLK_TEGRA(hclk, 0, &tegra30_bus_ops, 0, tegra_hclk_parent_names, +		tegra_hclk_parents, &tegra_clk_sclk); + +static const char *tegra_pclk_parent_names[] = { +	"tegra_hclk", +}; + +static struct clk *tegra_pclk_parents[] = { +	&tegra_hclk, +}; + +static struct clk tegra_pclk; +static struct clk_tegra tegra_pclk_hw = { +	.hw = { +		.clk = &tegra_pclk, +	}, +	.flags = DIV_BUS, +	.reg = 0x30, +	.reg_shift = 0, +	.max_rate = 167000000, +	.min_rate = 12000000, +}; +DEFINE_CLK_TEGRA(pclk, 0, &tegra30_bus_ops, 0, tegra_pclk_parent_names, +		tegra_pclk_parents, &tegra_hclk); +  static const char *mux_blink[] = {  	"clk_32k",  }; @@ -1254,8 +1298,6 @@ struct clk_duplicate tegra_clk_duplicates[] = {  	CLK_DUPLICATE("usbd", "utmip-pad", NULL),  	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),  	CLK_DUPLICATE("usbd", "tegra-otg", NULL), -	CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"), -	CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),  	CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),  	CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),  	CLK_DUPLICATE("bsev", "tegra-avp", "bsev"), @@ -1293,6 +1335,9 @@ struct clk_duplicate tegra_clk_duplicates[] = {  	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"),  	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"),  	CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"), +	CLK_DUPLICATE("pll_p", "tegradc.0", "parent"), +	CLK_DUPLICATE("pll_p", "tegradc.1", "parent"), +	CLK_DUPLICATE("pll_d2_out0", "hdmi", "parent"),  };  struct clk *tegra_ptr_clks[] = { @@ -1325,6 +1370,8 @@ struct clk *tegra_ptr_clks[] = {  	&tegra_cml1,  	&tegra_pciex,  	&tegra_clk_sclk, +	&tegra_hclk, +	&tegra_pclk,  	&tegra_clk_blink,  	&tegra30_clk_twd,  }; diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c new file mode 100644 index 00000000000..125cb16424a --- /dev/null +++ b/arch/arm/mach-tegra/tegra30_speedo.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2012, 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	1 +#define CPU_PROCESS_CORNERS_NUM		6 + +#define FUSE_SPEEDO_CALIB_0	0x114 +#define FUSE_PACKAGE_INFO	0X1FC +#define FUSE_TEST_PROG_VER	0X128 + +#define G_SPEEDO_BIT_MINUS1	58 +#define G_SPEEDO_BIT_MINUS1_R	59 +#define G_SPEEDO_BIT_MINUS2	60 +#define G_SPEEDO_BIT_MINUS2_R	61 +#define LP_SPEEDO_BIT_MINUS1	62 +#define LP_SPEEDO_BIT_MINUS1_R	63 +#define LP_SPEEDO_BIT_MINUS2	64 +#define LP_SPEEDO_BIT_MINUS2_R	65 + +enum { +	THRESHOLD_INDEX_0, +	THRESHOLD_INDEX_1, +	THRESHOLD_INDEX_2, +	THRESHOLD_INDEX_3, +	THRESHOLD_INDEX_4, +	THRESHOLD_INDEX_5, +	THRESHOLD_INDEX_6, +	THRESHOLD_INDEX_7, +	THRESHOLD_INDEX_8, +	THRESHOLD_INDEX_9, +	THRESHOLD_INDEX_10, +	THRESHOLD_INDEX_11, +	THRESHOLD_INDEX_COUNT, +}; + +static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { +	{180}, +	{170}, +	{195}, +	{180}, +	{168}, +	{192}, +	{180}, +	{170}, +	{195}, +	{180}, +	{180}, +	{180}, +}; + +static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { +	{306, 338, 360, 376, UINT_MAX}, +	{295, 336, 358, 375, UINT_MAX}, +	{325, 325, 358, 375, UINT_MAX}, +	{325, 325, 358, 375, UINT_MAX}, +	{292, 324, 348, 364, UINT_MAX}, +	{324, 324, 348, 364, UINT_MAX}, +	{324, 324, 348, 364, UINT_MAX}, +	{295, 336, 358, 375, UINT_MAX}, +	{358, 358, 358, 358, 397, UINT_MAX}, +	{364, 364, 364, 364, 397, UINT_MAX}, +	{295, 336, 358, 375, 391, UINT_MAX}, +	{295, 336, 358, 375, 391, UINT_MAX}, +}; + +static int threshold_index; +static int package_id; + +static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) +{ +	u32 reg; +	int ate_ver; +	int bit_minus1; +	int bit_minus2; + +	reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0); + +	*speedo_lp = (reg & 0xFFFF) * 4; +	*speedo_g = ((reg >> 16) & 0xFFFF) * 4; + +	ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER); +	pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10); + +	if (ate_ver >= 26) { +		bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1); +		bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); +		bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2); +		bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); +		*speedo_lp |= (bit_minus1 << 1) | bit_minus2; + +		bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1); +		bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R); +		bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2); +		bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R); +		*speedo_g |= (bit_minus1 << 1) | bit_minus2; +	} else { +		*speedo_lp |= 0x3; +		*speedo_g |= 0x3; +	} +} + +static void rev_sku_to_speedo_ids(int rev, int sku) +{ +	switch (rev) { +	case TEGRA_REVISION_A01: +		tegra_cpu_speedo_id = 0; +		tegra_soc_speedo_id = 0; +		threshold_index = THRESHOLD_INDEX_0; +		break; +	case TEGRA_REVISION_A02: +	case TEGRA_REVISION_A03: +		switch (sku) { +		case 0x87: +		case 0x82: +			tegra_cpu_speedo_id = 1; +			tegra_soc_speedo_id = 1; +			threshold_index = THRESHOLD_INDEX_1; +			break; +		case 0x81: +			switch (package_id) { +			case 1: +				tegra_cpu_speedo_id = 2; +				tegra_soc_speedo_id = 2; +				threshold_index = THRESHOLD_INDEX_2; +				break; +			case 2: +				tegra_cpu_speedo_id = 4; +				tegra_soc_speedo_id = 1; +				threshold_index = THRESHOLD_INDEX_7; +				break; +			default: +				pr_err("Tegra30: Unknown pkg %d\n", package_id); +				BUG(); +				break; +			} +			break; +		case 0x80: +			switch (package_id) { +			case 1: +				tegra_cpu_speedo_id = 5; +				tegra_soc_speedo_id = 2; +				threshold_index = THRESHOLD_INDEX_8; +				break; +			case 2: +				tegra_cpu_speedo_id = 6; +				tegra_soc_speedo_id = 2; +				threshold_index = THRESHOLD_INDEX_9; +				break; +			default: +				pr_err("Tegra30: Unknown pkg %d\n", package_id); +				BUG(); +				break; +			} +			break; +		case 0x83: +			switch (package_id) { +			case 1: +				tegra_cpu_speedo_id = 7; +				tegra_soc_speedo_id = 1; +				threshold_index = THRESHOLD_INDEX_10; +				break; +			case 2: +				tegra_cpu_speedo_id = 3; +				tegra_soc_speedo_id = 2; +				threshold_index = THRESHOLD_INDEX_3; +				break; +			default: +				pr_err("Tegra30: Unknown pkg %d\n", package_id); +				BUG(); +				break; +			} +			break; +		case 0x8F: +			tegra_cpu_speedo_id = 8; +			tegra_soc_speedo_id = 1; +			threshold_index = THRESHOLD_INDEX_11; +			break; +		case 0x08: +			tegra_cpu_speedo_id = 1; +			tegra_soc_speedo_id = 1; +			threshold_index = THRESHOLD_INDEX_4; +			break; +		case 0x02: +			tegra_cpu_speedo_id = 2; +			tegra_soc_speedo_id = 2; +			threshold_index = THRESHOLD_INDEX_5; +			break; +		case 0x04: +			tegra_cpu_speedo_id = 3; +			tegra_soc_speedo_id = 2; +			threshold_index = THRESHOLD_INDEX_6; +			break; +		case 0: +			switch (package_id) { +			case 1: +				tegra_cpu_speedo_id = 2; +				tegra_soc_speedo_id = 2; +				threshold_index = THRESHOLD_INDEX_2; +				break; +			case 2: +				tegra_cpu_speedo_id = 3; +				tegra_soc_speedo_id = 2; +				threshold_index = THRESHOLD_INDEX_3; +				break; +			default: +				pr_err("Tegra30: Unknown pkg %d\n", package_id); +				BUG(); +				break; +			} +			break; +		default: +			pr_warn("Tegra30: Unknown SKU %d\n", sku); +			tegra_cpu_speedo_id = 0; +			tegra_soc_speedo_id = 0; +			threshold_index = THRESHOLD_INDEX_0; +			break; +		} +		break; +	default: +		pr_warn("Tegra30: Unknown chip rev %d\n", rev); +		tegra_cpu_speedo_id = 0; +		tegra_soc_speedo_id = 0; +		threshold_index = THRESHOLD_INDEX_0; +		break; +	} +} + +void tegra30_init_speedo_data(void) +{ +	u32 cpu_speedo_val; +	u32 core_speedo_val; +	int i; + +	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != +			THRESHOLD_INDEX_COUNT); +	BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != +			THRESHOLD_INDEX_COUNT); + +	package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; + +	rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id); +	fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); +	pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val); +	pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val); + +	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) { +		if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) +			break; +	} +	tegra_cpu_process_id = i - 1; + +	if (tegra_cpu_process_id == -1) { +		pr_warn("Tegra30: CPU speedo value %3d out of range", +		       cpu_speedo_val); +		tegra_cpu_process_id = 0; +		tegra_cpu_speedo_id = 1; +	} + +	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) { +		if (core_speedo_val < core_process_speedos[threshold_index][i]) +			break; +	} +	tegra_core_process_id = i - 1; + +	if (tegra_core_process_id == -1) { +		pr_warn("Tegra30: CORE speedo value %3d out of range", +		       core_speedo_val); +		tegra_core_process_id = 0; +		tegra_soc_speedo_id = 1; +	} + +	pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d", +		tegra_cpu_speedo_id, tegra_soc_speedo_id); +} diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/arch/arm/mach-tegra/tegra_cpu_car.h index 30d063ad2be..9764d31032b 100644 --- a/arch/arm/mach-tegra/tegra_cpu_car.h +++ b/arch/arm/mach-tegra/tegra_cpu_car.h @@ -30,6 +30,12 @@   *	CPU clock un-gate   * disable_clock:   *	CPU clock gate + * rail_off_ready: + *	CPU is ready for rail off + * suspend: + *	save the clock settings when CPU go into low-power state + * resume: + *	restore the clock settings when CPU exit low-power state   */  struct tegra_cpu_car_ops {  	void (*wait_for_reset)(u32 cpu); @@ -37,6 +43,11 @@ struct tegra_cpu_car_ops {  	void (*out_of_reset)(u32 cpu);  	void (*enable_clock)(u32 cpu);  	void (*disable_clock)(u32 cpu); +#ifdef CONFIG_PM_SLEEP +	bool (*rail_off_ready)(void); +	void (*suspend)(void); +	void (*resume)(void); +#endif  };  extern struct tegra_cpu_car_ops *tegra_cpu_car_ops; @@ -81,6 +92,32 @@ static inline void tegra_disable_cpu_clock(u32 cpu)  	tegra_cpu_car_ops->disable_clock(cpu);  } +#ifdef CONFIG_PM_SLEEP +static inline bool tegra_cpu_rail_off_ready(void) +{ +	if (WARN_ON(!tegra_cpu_car_ops->rail_off_ready)) +		return false; + +	return tegra_cpu_car_ops->rail_off_ready(); +} + +static inline void tegra_cpu_clock_suspend(void) +{ +	if (WARN_ON(!tegra_cpu_car_ops->suspend)) +		return; + +	tegra_cpu_car_ops->suspend(); +} + +static inline void tegra_cpu_clock_resume(void) +{ +	if (WARN_ON(!tegra_cpu_car_ops->resume)) +		return; + +	tegra_cpu_car_ops->resume(); +} +#endif +  void tegra20_cpu_car_ops_init(void);  void tegra30_cpu_car_ops_init(void); diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c index d3b8c8e7368..e4863f3e9ee 100644 --- a/arch/arm/mach-tegra/timer.c +++ b/arch/arm/mach-tegra/timer.c @@ -26,16 +26,14 @@  #include <linux/clocksource.h>  #include <linux/clk.h>  #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <asm/mach/time.h>  #include <asm/smp_twd.h>  #include <asm/sched_clock.h> -#include <mach/iomap.h> -#include <mach/irqs.h> -  #include "board.h" -#include "clock.h"  #define RTC_SECONDS            0x08  #define RTC_SHADOW_SECONDS     0x0c @@ -53,8 +51,8 @@  #define TIMER_PTV 0x0  #define TIMER_PCR 0x4 -static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE); -static void __iomem *rtc_base = IO_ADDRESS(TEGRA_RTC_BASE); +static void __iomem *timer_reg_base; +static void __iomem *rtc_base;  static struct timespec persistent_ts;  static u64 persistent_ms, last_persistent_ms; @@ -158,40 +156,66 @@ static struct irqaction tegra_timer_irq = {  	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH,  	.handler	= tegra_timer_interrupt,  	.dev_id		= &tegra_clockevent, -	.irq		= INT_TMR3,  }; -#ifdef CONFIG_HAVE_ARM_TWD -static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, -			      TEGRA_ARM_PERIF_BASE + 0x600, -			      IRQ_LOCALTIMER); +static const struct of_device_id timer_match[] __initconst = { +	{ .compatible = "nvidia,tegra20-timer" }, +	{} +}; -static void __init tegra_twd_init(void) -{ -	int err = twd_local_timer_register(&twd_local_timer); -	if (err) -		pr_err("twd_local_timer_register failed %d\n", err); -} -#else -#define tegra_twd_init()	do {} while(0) -#endif +static const struct of_device_id rtc_match[] __initconst = { +	{ .compatible = "nvidia,tegra20-rtc" }, +	{} +};  static void __init tegra_init_timer(void)  { +	struct device_node *np;  	struct clk *clk;  	unsigned long rate;  	int ret; +	np = of_find_matching_node(NULL, timer_match); +	if (!np) { +		pr_err("Failed to find timer DT node\n"); +		BUG(); +	} + +	timer_reg_base = of_iomap(np, 0); +	if (!timer_reg_base) { +		pr_err("Can't map timer registers"); +		BUG(); +	} + +	tegra_timer_irq.irq = irq_of_parse_and_map(np, 2); +	if (tegra_timer_irq.irq <= 0) { +		pr_err("Failed to map timer IRQ\n"); +		BUG(); +	} +  	clk = clk_get_sys("timer", NULL);  	if (IS_ERR(clk)) { -		pr_warn("Unable to get timer clock." -			" Assuming 12Mhz input clock.\n"); +		pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n");  		rate = 12000000;  	} else {  		clk_prepare_enable(clk);  		rate = clk_get_rate(clk);  	} +	of_node_put(np); + +	np = of_find_matching_node(NULL, rtc_match); +	if (!np) { +		pr_err("Failed to find RTC DT node\n"); +		BUG(); +	} + +	rtc_base = of_iomap(np, 0); +	if (!rtc_base) { +		pr_err("Can't map RTC registers"); +		BUG(); +	} +  	/*  	 * rtc registers are used by read_persistent_clock, keep the rtc clock  	 * enabled @@ -202,6 +226,8 @@ static void __init tegra_init_timer(void)  	else  		clk_prepare_enable(clk); +	of_node_put(np); +  	switch (rate) {  	case 12000000:  		timer_writel(0x000b, TIMERUS_USEC_CFG); @@ -223,13 +249,13 @@ static void __init tegra_init_timer(void)  	if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,  		"timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) { -		printk(KERN_ERR "Failed to register clocksource\n"); +		pr_err("Failed to register clocksource\n");  		BUG();  	}  	ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq);  	if (ret) { -		printk(KERN_ERR "Failed to register timer IRQ: %d\n", ret); +		pr_err("Failed to register timer IRQ: %d\n", ret);  		BUG();  	} @@ -241,7 +267,9 @@ static void __init tegra_init_timer(void)  	tegra_clockevent.cpumask = cpu_all_mask;  	tegra_clockevent.irq = tegra_timer_irq.irq;  	clockevents_register_device(&tegra_clockevent); -	tegra_twd_init(); +#ifdef CONFIG_HAVE_ARM_TWD +	twd_local_timer_of_register(); +#endif  	register_persistent_clock(NULL, tegra_read_persistent_clock);  }  |