diff options
Diffstat (limited to 'arch/arm/mach-tegra')
25 files changed, 351 insertions, 599 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index b442f15fd01a..1ec7f80e2af5 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -6,9 +6,9 @@ config ARCH_TEGRA_2x_SOC bool "Enable support for Tegra20 family" select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_720789 - select ARM_ERRATA_742230 + select ARM_ERRATA_742230 if SMP select ARM_ERRATA_751472 - select ARM_ERRATA_754327 + select ARM_ERRATA_754327 if SMP select ARM_ERRATA_764369 if SMP select ARM_GIC select CPU_FREQ_TABLE if CPU_FREQ diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 0979e8bba78a..f0520961bafe 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -2,15 +2,16 @@ obj-y += common.o obj-y += io.o obj-y += irq.o obj-y += clock.o -obj-y += timer.o obj-y += fuse.o obj-y += pmc.o obj-y += flowctrl.o obj-y += powergate.o obj-y += apbio.o obj-y += pm.o +obj-y += reset.o +obj-y += reset-handler.o +obj-y += sleep.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 @@ -27,7 +28,6 @@ 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 obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index d091675ba376..d7aa52ea6cfc 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -38,7 +38,7 @@ static void tegra_apb_writel_direct(u32 value, unsigned long offset); static struct dma_chan *tegra_apb_dma_chan; static struct dma_slave_config dma_sconfig; -bool tegra_apb_dma_init(void) +static bool tegra_apb_dma_init(void) { dma_cap_mask_t mask; diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index 734d9cc87f2e..d320f7ad7350 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -15,6 +15,7 @@ * */ +#include <linux/clocksource.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> @@ -25,7 +26,6 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_fdt.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/pda_power.h> #include <linux/platform_data/tegra_usb.h> @@ -34,7 +34,6 @@ #include <linux/i2c-tegra.h> #include <linux/usb/tegra_usb_phy.h> -#include <asm/hardware/gic.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/time.h> @@ -45,31 +44,31 @@ #include "common.h" #include "iomap.h" -struct tegra_ehci_platform_data tegra_ehci1_pdata = { +static struct tegra_ehci_platform_data tegra_ehci1_pdata = { .operating_mode = TEGRA_USB_OTG, .power_down_on_bus_suspend = 1, .vbus_gpio = -1, }; -struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { +static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { .reset_gpio = -1, .clk = "cdev2", }; -struct tegra_ehci_platform_data tegra_ehci2_pdata = { +static struct tegra_ehci_platform_data tegra_ehci2_pdata = { .phy_config = &tegra_ehci2_ulpi_phy_config, .operating_mode = TEGRA_USB_HOST, .power_down_on_bus_suspend = 1, .vbus_gpio = -1, }; -struct tegra_ehci_platform_data tegra_ehci3_pdata = { +static struct tegra_ehci_platform_data tegra_ehci3_pdata = { .operating_mode = TEGRA_USB_HOST, .power_down_on_bus_suspend = 1, .vbus_gpio = -1, }; -struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { +static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL), @@ -202,8 +201,7 @@ DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)") .smp = smp_ops(tegra_smp_ops), .init_early = tegra20_init_early, .init_irq = tegra_dt_init_irq, - .handle_irq = gic_handle_irq, - .timer = &tegra_sys_timer, + .init_time = clocksource_of_init, .init_machine = tegra_dt_init, .init_late = tegra_dt_init_late, .restart = tegra_assert_system_reset, diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 6497d1236b08..97e1f67fc31d 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -23,6 +23,7 @@ * */ +#include <linux/clocksource.h> #include <linux/kernel.h> #include <linux/of.h> #include <linux/of_address.h> @@ -31,14 +32,13 @@ #include <linux/of_platform.h> #include <asm/mach/arch.h> -#include <asm/hardware/gic.h> #include "board.h" #include "clock.h" #include "common.h" #include "iomap.h" -struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { +static struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL), OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL), @@ -112,8 +112,7 @@ DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)") .map_io = tegra_map_common_io, .init_early = tegra30_init_early, .init_irq = tegra_dt_init_irq, - .handle_irq = gic_handle_irq, - .timer = &tegra_sys_timer, + .init_time = clocksource_of_init, .init_machine = tegra30_dt_init, .init_late = tegra_init_late, .restart = tegra_assert_system_reset, diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 91fbe733a21e..da8f5a3c4240 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -55,5 +55,4 @@ static inline int harmony_pcie_init(void) { return 0; } void __init tegra_paz00_wifikill_init(void); -extern struct sys_timer tegra_sys_timer; #endif diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index d54cfc54b9fe..8f0ffe97ffee 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -21,10 +21,9 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/delay.h> -#include <linux/of_irq.h> +#include <linux/irqchip.h> #include <asm/hardware/cache-l2x0.h> -#include <asm/hardware/gic.h> #include <mach/powergate.h> @@ -37,6 +36,7 @@ #include "apbio.h" #include "sleep.h" #include "pm.h" +#include "reset.h" /* * Storage for debug-macro.S's state. @@ -57,15 +57,10 @@ u32 tegra_uart_config[4] = { }; #ifdef CONFIG_OF -static const struct of_device_id tegra_dt_irq_match[] __initconst = { - { .compatible = "arm,cortex-a9-gic", .data = gic_of_init }, - { } -}; - void __init tegra_dt_init_irq(void) { tegra_init_irq(); - of_irq_init(tegra_dt_irq_match); + irqchip_init(); } #endif @@ -137,6 +132,7 @@ static void __init tegra_init_cache(void) #ifdef CONFIG_ARCH_TEGRA_2x_SOC void __init tegra20_init_early(void) { + tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); tegra2_init_clocks(); @@ -150,6 +146,7 @@ void __init tegra20_init_early(void) #ifdef CONFIG_ARCH_TEGRA_3x_SOC void __init tegra30_init_early(void) { + tegra_cpu_reset_handler_init(); tegra_apb_io_init(); tegra_init_fuse(); tegra30_init_clocks(); diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h index 02f71b4f1e51..32f8eb3fe344 100644 --- a/arch/arm/mach-tegra/common.h +++ b/arch/arm/mach-tegra/common.h @@ -1,4 +1,5 @@ extern struct smp_operations tegra_smp_ops; +extern int tegra_cpu_kill(unsigned int cpu); extern void tegra_cpu_die(unsigned int cpu); extern int tegra_cpu_disable(unsigned int cpu); diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index a36a03d3c9a0..ece29ab15b59 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -214,24 +214,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy) if (policy->cpu >= NUM_CPUS) return -EINVAL; - cpu_clk = clk_get_sys(NULL, "cpu"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); - - pll_x_clk = clk_get_sys(NULL, "pll_x"); - if (IS_ERR(pll_x_clk)) - return PTR_ERR(pll_x_clk); - - pll_p_clk = clk_get_sys(NULL, "pll_p"); - if (IS_ERR(pll_p_clk)) - return PTR_ERR(pll_p_clk); - - emc_clk = clk_get_sys("cpu", "emc"); - if (IS_ERR(emc_clk)) { - clk_put(cpu_clk); - return PTR_ERR(emc_clk); - } - clk_prepare_enable(emc_clk); clk_prepare_enable(cpu_clk); @@ -255,8 +237,6 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy) { cpufreq_frequency_table_cpuinfo(policy, freq_table); clk_disable_unprepare(emc_clk); - clk_put(emc_clk); - clk_put(cpu_clk); return 0; } @@ -277,12 +257,32 @@ static struct cpufreq_driver tegra_cpufreq_driver = { static int __init tegra_cpufreq_init(void) { + cpu_clk = clk_get_sys(NULL, "cpu"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + pll_x_clk = clk_get_sys(NULL, "pll_x"); + if (IS_ERR(pll_x_clk)) + return PTR_ERR(pll_x_clk); + + pll_p_clk = clk_get_sys(NULL, "pll_p"); + if (IS_ERR(pll_p_clk)) + return PTR_ERR(pll_p_clk); + + emc_clk = clk_get_sys("cpu", "emc"); + if (IS_ERR(emc_clk)) { + clk_put(cpu_clk); + return PTR_ERR(emc_clk); + } + return cpufreq_register_driver(&tegra_cpufreq_driver); } static void __exit tegra_cpufreq_exit(void) { cpufreq_unregister_driver(&tegra_cpufreq_driver); + clk_put(emc_clk); + clk_put(cpu_clk); } diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 5e8cbf5b799f..82530bd9b8c2 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -121,9 +121,9 @@ static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, } #endif -static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static int tegra30_idle_lp2(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index a2250ddae797..5393eb2cae21 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -26,14 +26,14 @@ #include "flowctrl.h" #include "iomap.h" -u8 flowctrl_offset_halt_cpu[] = { +static u8 flowctrl_offset_halt_cpu[] = { FLOW_CTRL_HALT_CPU0_EVENTS, FLOW_CTRL_HALT_CPU1_EVENTS, FLOW_CTRL_HALT_CPU1_EVENTS + 8, FLOW_CTRL_HALT_CPU1_EVENTS + 16, }; -u8 flowctrl_offset_cpu_csr[] = { +static u8 flowctrl_offset_cpu_csr[] = { FLOW_CTRL_CPU0_CSR, FLOW_CTRL_CPU1_CSR, FLOW_CTRL_CPU1_CSR + 8, diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index 4a317fae6860..b2834810b02b 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -1,22 +1,9 @@ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/cache.h> -#include <asm/asm-offsets.h> -#include <asm/hardware/cache-l2x0.h> - -#include "flowctrl.h" -#include "iomap.h" -#include "reset.h" #include "sleep.h" -#define APB_MISC_GP_HIDREV 0x804 -#define PMC_SCRATCH41 0x140 - -#define RESET_DATA(x) ((TEGRA_RESET_##x)*4) - .section ".text.head", "ax" - __CPUINIT /* * Tegra specific entry point for secondary CPUs. @@ -61,7 +48,6 @@ ENTRY(v7_invalidate_l1) mov pc, lr ENDPROC(v7_invalidate_l1) - ENTRY(tegra_secondary_startup) bl v7_invalidate_l1 /* Enable coresight */ @@ -69,210 +55,3 @@ ENTRY(tegra_secondary_startup) mcr p14, 0, r0, c7, c12, 6 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) - -/* - * __tegra_cpu_reset_handler: - * - * Common handler for all CPU reset events. - * - * Register usage within the reset handler: - * - * R7 = CPU present (to the OS) mask - * R8 = CPU in LP1 state mask - * R9 = CPU in LP2 state mask - * R10 = CPU number - * R11 = CPU mask - * R12 = pointer to reset handler data - * - * NOTE: This code is copied to IRAM. All code and data accesses - * must be position-independent. - */ - - .align L1_CACHE_SHIFT -ENTRY(__tegra_cpu_reset_handler) - - cpsid aif, 0x13 @ SVC mode, interrupts disabled - mrc p15, 0, r10, c0, c0, 5 @ MPIDR - and r10, r10, #0x3 @ R10 = CPU number - mov r11, #1 - mov r11, r11, lsl r10 @ R11 = CPU mask - adr r12, __tegra_cpu_reset_handler_data - -#ifdef CONFIG_SMP - /* Does the OS know about this CPU? */ - ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] - tst r7, r11 @ if !present - bleq __die @ CPU not present (to OS) -#endif - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) - bne 1f - /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ - mov32 r6, TEGRA_PMC_BASE - mov r0, #0 - cmp r10, #0 - strne r0, [r6, #PMC_SCRATCH41] -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 - * cannot be here. - */ - cmp r10, #0 - bleq __die @ CPU0 cannot be here - ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] - cmp lr, #0 - bleq __die @ no secondary startup handler - bx lr -#endif - -/* - * We don't know why the CPU reset. Just kill it. - * The LR register will contain the address we died at + 4. - */ - -__die: - sub lr, lr, #4 - mov32 r7, TEGRA_PMC_BASE - str lr, [r7, #PMC_SCRATCH41] - - mov32 r7, TEGRA_CLK_RESET_BASE - - /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) - bne 1f - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC - mov32 r0, 0x1111 - mov r1, r0, lsl r10 - str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET -#endif -1: -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - mov32 r6, TEGRA_FLOW_CTRL_BASE - - cmp r10, #0 - moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS - moveq r2, #FLOW_CTRL_CPU0_CSR - movne r1, r10, lsl #3 - addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) - addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) - - /* Clear CPU "event" and "interrupt" flags and power gate - it when halting but not before it is in the "WFI" state. */ - 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] - - /* Unconditionally halt this CPU */ - mov r0, #FLOW_CTRL_WAITEVENT - str r0, [r6, +r1] - ldr r0, [r6, +r1] @ memory barrier - - dsb - isb - wfi @ CPU should be power gated here - - /* If the CPU didn't power gate above just kill it's clock. */ - - mov r0, r11, lsl #8 - str r0, [r7, #348] @ CLK_CPU_CMPLX_SET -#endif - - /* If the CPU still isn't dead, just spin here. */ - b . -ENDPROC(__tegra_cpu_reset_handler) - - .align L1_CACHE_SHIFT - .type __tegra_cpu_reset_handler_data, %object - .globl __tegra_cpu_reset_handler_data -__tegra_cpu_reset_handler_data: - .rept TEGRA_RESET_DATA_SIZE - .long 0 - .endr - .align L1_CACHE_SHIFT - -ENTRY(__tegra_cpu_reset_handler_end) diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index dca5141a2c31..6a27de4001ee 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -19,6 +19,17 @@ static void (*tegra_hotplug_shutdown)(void); +int tegra_cpu_kill(unsigned cpu) +{ + cpu = cpu_logical_map(cpu); + + /* Clock gate the CPU */ + tegra_wait_cpu_in_reset(cpu); + tegra_disable_cpu_clock(cpu); + + return 1; +} + /* * platform-specific code to shutdown a CPU * @@ -26,18 +37,12 @@ static void (*tegra_hotplug_shutdown)(void); */ void __ref tegra_cpu_die(unsigned int cpu) { - cpu = cpu_logical_map(cpu); - - /* Flush the L1 data cache. */ - flush_cache_all(); + /* Clean L1 data cache */ + tegra_disable_clean_inv_dcache(); /* Shut down the current CPU. */ tegra_hotplug_shutdown(); - /* Clock gate the CPU */ - tegra_wait_cpu_in_reset(cpu); - tegra_disable_cpu_clock(cpu); - /* Should never return here. */ BUG(); } diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 485003f9b636..08386418196f 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -172,8 +172,4 @@ static inline void arch_decomp_setup(void) uart[UART_LCR << DEBUG_UART_SHIFT] = 3; } -static inline void arch_decomp_wdog(void) -{ -} - #endif diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index b7886f183511..2ff2128cb9d8 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -22,8 +22,7 @@ #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> - -#include <asm/hardware/gic.h> +#include <linux/irqchip/arm-gic.h> #include "board.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 1b926df99c4b..3c4a43c892a5 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -18,11 +18,12 @@ #include <linux/jiffies.h> #include <linux/smp.h> #include <linux/io.h> +#include <linux/irqchip/arm-gic.h> #include <asm/cacheflush.h> -#include <asm/hardware/gic.h> #include <asm/mach-types.h> #include <asm/smp_scu.h> +#include <asm/smp_plat.h> #include <mach/powergate.h> @@ -36,6 +37,7 @@ extern void tegra_secondary_startup(void); +static cpumask_t tegra_cpu_init_mask; static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); #define EVP_CPU_RESET_VECTOR \ @@ -50,6 +52,7 @@ static void __cpuinit tegra_secondary_init(unsigned int cpu) */ gic_secondary_init(0); + cpumask_set_cpu(cpu, &tegra_cpu_init_mask); } static int tegra20_power_up_cpu(unsigned int cpu) @@ -72,14 +75,42 @@ static int tegra30_power_up_cpu(unsigned int cpu) if (pwrgateid < 0) return pwrgateid; - /* If this is the first boot, toggle powergates directly. */ + /* + * The power up sequence of cold boot CPU and warm boot CPU + * was different. + * + * For warm boot CPU that was resumed from CPU hotplug, the + * power will be resumed automatically after un-halting the + * flow controller of the warm boot CPU. We need to wait for + * the confirmaiton that the CPU is powered then removing + * the IO clamps. + * For cold boot CPU, do not wait. After the cold boot CPU be + * booted, it will run to tegra_secondary_init() and set + * tegra_cpu_init_mask which influences what tegra30_power_up_cpu() + * next time around. + */ + if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { + timeout = jiffies + msecs_to_jiffies(50); + do { + if (!tegra_powergate_is_powered(pwrgateid)) + goto remove_clamps; + udelay(10); + } while (time_before(jiffies, timeout)); + } + + /* + * The power status of the cold boot CPU is power gated as + * default. To power up the cold boot CPU, the power should + * be un-gated by un-toggling the power gate register + * manually. + */ if (!tegra_powergate_is_powered(pwrgateid)) { ret = tegra_powergate_power_on(pwrgateid); if (ret) return ret; /* Wait for the power to come up. */ - timeout = jiffies + 10*HZ; + timeout = jiffies + msecs_to_jiffies(100); while (tegra_powergate_is_powered(pwrgateid)) { if (time_after(jiffies, timeout)) return -ETIMEDOUT; @@ -87,6 +118,7 @@ static int tegra30_power_up_cpu(unsigned int cpu) } } +remove_clamps: /* CPU partition is powered. Enable the CPU clock. */ tegra_enable_cpu_clock(cpu); udelay(10); @@ -105,6 +137,8 @@ static int __cpuinit tegra_boot_secondary(unsigned int cpu, struct task_struct * { int status; + cpu = cpu_logical_map(cpu); + /* * Force the CPU into reset. The CPU must remain in reset when the * flow controller state is cleared (which will cause the flow @@ -159,13 +193,13 @@ static void __init tegra_smp_init_cpus(void) for (i = 0; i < ncores; i++) set_cpu_possible(i, true); - - set_smp_cross_call(gic_raise_softirq); } static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) { - tegra_cpu_reset_handler_init(); + /* Always mark the boot CPU (CPU0) as initialized. */ + cpumask_set_cpu(0, &tegra_cpu_init_mask); + scu_enable(scu_base); } @@ -175,6 +209,7 @@ struct smp_operations tegra_smp_ops __initdata = { .smp_secondary_init = tegra_secondary_init, .smp_boot_secondary = tegra_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = tegra_cpu_kill, .cpu_die = tegra_cpu_die, .cpu_disable = tegra_cpu_disable, #endif diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 1b11707eaca0..498d70b33775 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -148,7 +148,7 @@ static void suspend_cpu_complex(void) save_cpu_arch_register(); } -void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id) +void tegra_clear_cpu_in_lp2(int phy_cpu_id) { u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; @@ -160,7 +160,7 @@ void __cpuinit tegra_clear_cpu_in_lp2(int phy_cpu_id) spin_unlock(&tegra_lp2_lock); } -bool __cpuinit tegra_set_cpu_in_lp2(int phy_cpu_id) +bool tegra_set_cpu_in_lp2(int phy_cpu_id) { bool last_cpu = false; cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask; diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S new file mode 100644 index 000000000000..54382ceade4a --- /dev/null +++ b/arch/arm/mach-tegra/reset-handler.S @@ -0,0 +1,239 @@ +/* + * 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/linkage.h> +#include <linux/init.h> + +#include <asm/cache.h> +#include <asm/asm-offsets.h> +#include <asm/hardware/cache-l2x0.h> + +#include "flowctrl.h" +#include "iomap.h" +#include "reset.h" +#include "sleep.h" + +#define APB_MISC_GP_HIDREV 0x804 +#define PMC_SCRATCH41 0x140 + +#define RESET_DATA(x) ((TEGRA_RESET_##x)*4) + +#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) + +/* + * __tegra_cpu_reset_handler: + * + * Common handler for all CPU reset events. + * + * Register usage within the reset handler: + * + * R7 = CPU present (to the OS) mask + * R8 = CPU in LP1 state mask + * R9 = CPU in LP2 state mask + * R10 = CPU number + * R11 = CPU mask + * R12 = pointer to reset handler data + * + * NOTE: This code is copied to IRAM. All code and data accesses + * must be position-independent. + */ + + .align L1_CACHE_SHIFT +ENTRY(__tegra_cpu_reset_handler) + + cpsid aif, 0x13 @ SVC mode, inte |