diff options
Diffstat (limited to 'arch/arm/mach-tegra/reset.c')
-rw-r--r-- | arch/arm/mach-tegra/reset.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c new file mode 100644 index 00000000000..3ab2c132d62 --- /dev/null +++ b/arch/arm/mach-tegra/reset.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-tegra/reset.c | ||
3 | * | ||
4 | * Copyright (C) 2011-2012 NVIDIA Corporation. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/cpumask.h> | ||
20 | #include <linux/bitops.h> | ||
21 | |||
22 | #include <asm/cacheflush.h> | ||
23 | |||
24 | #include <mach/iomap.h> | ||
25 | |||
26 | #include "reset.h" | ||
27 | #include "sleep.h" | ||
28 | #include "pm.h" | ||
29 | |||
30 | static bool is_enabled; | ||
31 | |||
32 | static void tegra_cpu_reset_handler_enable(void) | ||
33 | { | ||
34 | void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_BASE); | ||
35 | #ifndef CONFIG_TRUSTED_FOUNDATIONS | ||
36 | void __iomem *evp_cpu_reset = | ||
37 | IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE + 0x100); | ||
38 | void __iomem *sb_ctrl = IO_ADDRESS(TEGRA_SB_BASE); | ||
39 | unsigned long reg; | ||
40 | #endif | ||
41 | BUG_ON(is_enabled); | ||
42 | BUG_ON(tegra_cpu_reset_handler_size > TEGRA_RESET_HANDLER_SIZE); | ||
43 | |||
44 | memcpy(iram_base, (void *)__tegra_cpu_reset_handler_start, | ||
45 | tegra_cpu_reset_handler_size); | ||
46 | |||
47 | #ifdef CONFIG_TRUSTED_FOUNDATIONS | ||
48 | tegra_generic_smc(0xFFFFF200, | ||
49 | TEGRA_RESET_HANDLER_BASE + tegra_cpu_reset_handler_offset, 0); | ||
50 | #else | ||
51 | /* NOTE: This must be the one and only write to the EVP CPU reset | ||
52 | vector in the entire system. */ | ||
53 | writel(TEGRA_RESET_HANDLER_BASE + tegra_cpu_reset_handler_offset, | ||
54 | evp_cpu_reset); | ||
55 | wmb(); | ||
56 | reg = readl(evp_cpu_reset); | ||
57 | |||
58 | /* Prevent further modifications to the physical reset vector. | ||
59 | NOTE: Has no effect on chips prior to Tegra3. */ | ||
60 | reg = readl(sb_ctrl); | ||
61 | reg |= 2; | ||
62 | writel(reg, sb_ctrl); | ||
63 | wmb(); | ||
64 | #endif | ||
65 | is_enabled = true; | ||
66 | } | ||
67 | |||
68 | #ifdef CONFIG_PM_SLEEP | ||
69 | void tegra_cpu_reset_handler_save(void) | ||
70 | { | ||
71 | unsigned int i; | ||
72 | BUG_ON(!is_enabled); | ||
73 | for (i = 0; i < TEGRA_RESET_DATA_SIZE; i++) | ||
74 | __tegra_cpu_reset_handler_data[i] = | ||
75 | tegra_cpu_reset_handler_ptr[i]; | ||
76 | is_enabled = false; | ||
77 | } | ||
78 | |||
79 | void tegra_cpu_reset_handler_restore(void) | ||
80 | { | ||
81 | unsigned int i; | ||
82 | BUG_ON(is_enabled); | ||
83 | tegra_cpu_reset_handler_enable(); | ||
84 | for (i = 0; i < TEGRA_RESET_DATA_SIZE; i++) | ||
85 | tegra_cpu_reset_handler_ptr[i] = | ||
86 | __tegra_cpu_reset_handler_data[i]; | ||
87 | is_enabled = true; | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | void __init tegra_cpu_reset_handler_init(void) | ||
92 | { | ||
93 | #ifdef CONFIG_SMP | ||
94 | __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] = | ||
95 | *((u32 *)cpu_present_mask); | ||
96 | __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] = | ||
97 | virt_to_phys((void *)tegra_secondary_startup); | ||
98 | #endif | ||
99 | #ifdef CONFIG_PM_SLEEP | ||
100 | __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP1] = | ||
101 | TEGRA_IRAM_CODE_AREA; | ||
102 | __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_LP2] = | ||
103 | virt_to_phys((void *)tegra_resume); | ||
104 | #endif | ||
105 | |||
106 | /* Push all of reset handler data out to the L3 memory system. */ | ||
107 | __cpuc_coherent_kern_range( | ||
108 | (unsigned long)&__tegra_cpu_reset_handler_data[0], | ||
109 | (unsigned long)&__tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE]); | ||
110 | |||
111 | outer_clean_range(__pa(&__tegra_cpu_reset_handler_data[0]), | ||
112 | __pa(&__tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE])); | ||
113 | |||
114 | tegra_cpu_reset_handler_enable(); | ||
115 | } | ||