forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 61598093bbdd283a7edc367d900f223070ead8d2
kernel/arch/arm/mach-tegra/pm.c
....@@ -1,19 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * CPU complex suspend & resume functions for Tegra SoCs
34 *
45 * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms and conditions of the GNU General Public License,
8
- * version 2, as published by the Free Software Foundation.
9
- *
10
- * This program is distributed in the hope it will be useful, but WITHOUT
11
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
- * more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
176 */
187
198 #include <linux/clk/tegra.h>
....@@ -27,12 +16,15 @@
2716 #include <linux/spinlock.h>
2817 #include <linux/suspend.h>
2918
19
+#include <linux/firmware/trusted_foundations.h>
20
+
3021 #include <soc/tegra/flowctrl.h>
3122 #include <soc/tegra/fuse.h>
3223 #include <soc/tegra/pm.h>
3324 #include <soc/tegra/pmc.h>
3425
3526 #include <asm/cacheflush.h>
27
+#include <asm/firmware.h>
3628 #include <asm/idmap.h>
3729 #include <asm/proc-fns.h>
3830 #include <asm/smp_plat.h>
....@@ -118,7 +110,7 @@
118110 flowctrl_cpu_suspend_enter(cpu);
119111 }
120112
121
-void tegra_clear_cpu_in_lp2(void)
113
+void tegra_pm_clear_cpu_in_lp2(void)
122114 {
123115 int phy_cpu_id = cpu_logical_map(smp_processor_id());
124116 u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
....@@ -131,11 +123,9 @@
131123 spin_unlock(&tegra_lp2_lock);
132124 }
133125
134
-bool tegra_set_cpu_in_lp2(void)
126
+void tegra_pm_set_cpu_in_lp2(void)
135127 {
136128 int phy_cpu_id = cpu_logical_map(smp_processor_id());
137
- bool last_cpu = false;
138
- cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
139129 u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
140130
141131 spin_lock(&tegra_lp2_lock);
....@@ -143,22 +133,38 @@
143133 BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
144134 *cpu_in_lp2 |= BIT(phy_cpu_id);
145135
146
- if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
147
- last_cpu = true;
148
- else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1)
149
- tegra20_cpu_set_resettable_soon();
150
-
151136 spin_unlock(&tegra_lp2_lock);
152
- return last_cpu;
153
-}
154
-
155
-int tegra_cpu_do_idle(void)
156
-{
157
- return cpu_do_idle();
158137 }
159138
160139 static int tegra_sleep_cpu(unsigned long v2p)
161140 {
141
+ if (tegra_cpu_car_ops->rail_off_ready &&
142
+ WARN_ON(!tegra_cpu_rail_off_ready()))
143
+ return -EBUSY;
144
+
145
+ /*
146
+ * L2 cache disabling using kernel API only allowed when all
147
+ * secondary CPU's are offline. Cache have to be disabled with
148
+ * MMU-on if cache maintenance is done via Trusted Foundations
149
+ * firmware. Note that CPUIDLE won't ever enter powergate on Tegra30
150
+ * if any of secondary CPU's is online and this is the LP2-idle
151
+ * code-path only for Tegra20/30.
152
+ */
153
+#ifdef CONFIG_OUTER_CACHE
154
+ if (trusted_foundations_registered() && outer_cache.disable)
155
+ outer_cache.disable();
156
+#endif
157
+ /*
158
+ * Note that besides of setting up CPU reset vector this firmware
159
+ * call may also do the following, depending on the FW version:
160
+ * 1) Disable L2. But this doesn't matter since we already
161
+ * disabled the L2.
162
+ * 2) Disable D-cache. This need to be taken into account in
163
+ * particular by the tegra_disable_clean_inv_dcache() which
164
+ * shall avoid the re-disable.
165
+ */
166
+ call_firmware_op(prepare_idle, TF_PM_MODE_LP2);
167
+
162168 setup_mm_for_reboot();
163169 tegra_sleep_cpu_finish(v2p);
164170
....@@ -188,17 +194,31 @@
188194 tegra_pmc_enter_suspend_mode(mode);
189195 }
190196
191
-void tegra_idle_lp2_last(void)
197
+int tegra_pm_enter_lp2(void)
192198 {
199
+ int err;
200
+
193201 tegra_pm_set(TEGRA_SUSPEND_LP2);
194202
195203 cpu_cluster_pm_enter();
196204 suspend_cpu_complex();
197205
198
- cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
206
+ err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
207
+
208
+ /*
209
+ * Resume L2 cache if it wasn't re-enabled early during resume,
210
+ * which is the case for Tegra30 that has to re-enable the cache
211
+ * via firmware call. In other cases cache is already enabled and
212
+ * hence re-enabling is a no-op. This is always a no-op on Tegra114+.
213
+ */
214
+ outer_resume();
199215
200216 restore_cpu_complex();
201217 cpu_cluster_pm_exit();
218
+
219
+ call_firmware_op(prepare_idle, TF_PM_MODE_NONE);
220
+
221
+ return err;
202222 }
203223
204224 enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
....@@ -215,6 +235,15 @@
215235
216236 static int tegra_sleep_core(unsigned long v2p)
217237 {
238
+ /*
239
+ * Cache have to be disabled with MMU-on if cache maintenance is done
240
+ * via Trusted Foundations firmware. This is a no-op on Tegra114+.
241
+ */
242
+ if (trusted_foundations_registered())
243
+ outer_disable();
244
+
245
+ call_firmware_op(prepare_idle, TF_PM_MODE_LP1);
246
+
218247 setup_mm_for_reboot();
219248 tegra_sleep_core_finish(v2p);
220249
....@@ -334,7 +363,7 @@
334363 tegra_suspend_enter_lp1();
335364 break;
336365 case TEGRA_SUSPEND_LP2:
337
- tegra_set_cpu_in_lp2();
366
+ tegra_pm_set_cpu_in_lp2();
338367 break;
339368 default:
340369 break;
....@@ -342,12 +371,20 @@
342371
343372 cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func);
344373
374
+ /*
375
+ * Resume L2 cache if it wasn't re-enabled early during resume,
376
+ * which is the case for Tegra30 that has to re-enable the cache
377
+ * via firmware call. In other cases cache is already enabled and
378
+ * hence re-enabling is a no-op.
379
+ */
380
+ outer_resume();
381
+
345382 switch (mode) {
346383 case TEGRA_SUSPEND_LP1:
347384 tegra_suspend_exit_lp1();
348385 break;
349386 case TEGRA_SUSPEND_LP2:
350
- tegra_clear_cpu_in_lp2();
387
+ tegra_pm_clear_cpu_in_lp2();
351388 break;
352389 default:
353390 break;
....@@ -355,6 +392,8 @@
355392 restore_cpu_complex();
356393
357394 local_fiq_enable();
395
+
396
+ call_firmware_op(prepare_idle, TF_PM_MODE_NONE);
358397
359398 return 0;
360399 }
....@@ -397,4 +436,18 @@
397436
398437 suspend_set_ops(&tegra_suspend_ops);
399438 }
439
+
440
+int tegra_pm_park_secondary_cpu(unsigned long cpu)
441
+{
442
+ if (cpu > 0) {
443
+ tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS);
444
+
445
+ if (tegra_get_chip_id() == TEGRA20)
446
+ tegra20_hotplug_shutdown();
447
+ else
448
+ tegra30_hotplug_shutdown();
449
+ }
450
+
451
+ return -EINVAL;
452
+}
400453 #endif