From 61598093bbdd283a7edc367d900f223070ead8d2 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:03 +0000 Subject: [PATCH] add ax88772C AX88772C_eeprom_tools --- kernel/arch/arm/mach-tegra/pm.c | 115 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 84 insertions(+), 31 deletions(-) diff --git a/kernel/arch/arm/mach-tegra/pm.c b/kernel/arch/arm/mach-tegra/pm.c index 1ad5719..6452ebf 100644 --- a/kernel/arch/arm/mach-tegra/pm.c +++ b/kernel/arch/arm/mach-tegra/pm.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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/clk/tegra.h> @@ -27,12 +16,15 @@ #include <linux/spinlock.h> #include <linux/suspend.h> +#include <linux/firmware/trusted_foundations.h> + #include <soc/tegra/flowctrl.h> #include <soc/tegra/fuse.h> #include <soc/tegra/pm.h> #include <soc/tegra/pmc.h> #include <asm/cacheflush.h> +#include <asm/firmware.h> #include <asm/idmap.h> #include <asm/proc-fns.h> #include <asm/smp_plat.h> @@ -118,7 +110,7 @@ flowctrl_cpu_suspend_enter(cpu); } -void tegra_clear_cpu_in_lp2(void) +void tegra_pm_clear_cpu_in_lp2(void) { int phy_cpu_id = cpu_logical_map(smp_processor_id()); u32 *cpu_in_lp2 = tegra_cpu_lp2_mask; @@ -131,11 +123,9 @@ spin_unlock(&tegra_lp2_lock); } -bool tegra_set_cpu_in_lp2(void) +void tegra_pm_set_cpu_in_lp2(void) { int phy_cpu_id = cpu_logical_map(smp_processor_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); @@ -143,22 +133,38 @@ 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; - else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1) - tegra20_cpu_set_resettable_soon(); - spin_unlock(&tegra_lp2_lock); - return last_cpu; -} - -int tegra_cpu_do_idle(void) -{ - return cpu_do_idle(); } static int tegra_sleep_cpu(unsigned long v2p) { + if (tegra_cpu_car_ops->rail_off_ready && + WARN_ON(!tegra_cpu_rail_off_ready())) + return -EBUSY; + + /* + * L2 cache disabling using kernel API only allowed when all + * secondary CPU's are offline. Cache have to be disabled with + * MMU-on if cache maintenance is done via Trusted Foundations + * firmware. Note that CPUIDLE won't ever enter powergate on Tegra30 + * if any of secondary CPU's is online and this is the LP2-idle + * code-path only for Tegra20/30. + */ +#ifdef CONFIG_OUTER_CACHE + if (trusted_foundations_registered() && outer_cache.disable) + outer_cache.disable(); +#endif + /* + * Note that besides of setting up CPU reset vector this firmware + * call may also do the following, depending on the FW version: + * 1) Disable L2. But this doesn't matter since we already + * disabled the L2. + * 2) Disable D-cache. This need to be taken into account in + * particular by the tegra_disable_clean_inv_dcache() which + * shall avoid the re-disable. + */ + call_firmware_op(prepare_idle, TF_PM_MODE_LP2); + setup_mm_for_reboot(); tegra_sleep_cpu_finish(v2p); @@ -188,17 +194,31 @@ tegra_pmc_enter_suspend_mode(mode); } -void tegra_idle_lp2_last(void) +int tegra_pm_enter_lp2(void) { + int err; + tegra_pm_set(TEGRA_SUSPEND_LP2); cpu_cluster_pm_enter(); suspend_cpu_complex(); - cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); + err = cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); + + /* + * Resume L2 cache if it wasn't re-enabled early during resume, + * which is the case for Tegra30 that has to re-enable the cache + * via firmware call. In other cases cache is already enabled and + * hence re-enabling is a no-op. This is always a no-op on Tegra114+. + */ + outer_resume(); restore_cpu_complex(); cpu_cluster_pm_exit(); + + call_firmware_op(prepare_idle, TF_PM_MODE_NONE); + + return err; } enum tegra_suspend_mode tegra_pm_validate_suspend_mode( @@ -215,6 +235,15 @@ static int tegra_sleep_core(unsigned long v2p) { + /* + * Cache have to be disabled with MMU-on if cache maintenance is done + * via Trusted Foundations firmware. This is a no-op on Tegra114+. + */ + if (trusted_foundations_registered()) + outer_disable(); + + call_firmware_op(prepare_idle, TF_PM_MODE_LP1); + setup_mm_for_reboot(); tegra_sleep_core_finish(v2p); @@ -334,7 +363,7 @@ tegra_suspend_enter_lp1(); break; case TEGRA_SUSPEND_LP2: - tegra_set_cpu_in_lp2(); + tegra_pm_set_cpu_in_lp2(); break; default: break; @@ -342,12 +371,20 @@ cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func); + /* + * Resume L2 cache if it wasn't re-enabled early during resume, + * which is the case for Tegra30 that has to re-enable the cache + * via firmware call. In other cases cache is already enabled and + * hence re-enabling is a no-op. + */ + outer_resume(); + switch (mode) { case TEGRA_SUSPEND_LP1: tegra_suspend_exit_lp1(); break; case TEGRA_SUSPEND_LP2: - tegra_clear_cpu_in_lp2(); + tegra_pm_clear_cpu_in_lp2(); break; default: break; @@ -355,6 +392,8 @@ restore_cpu_complex(); local_fiq_enable(); + + call_firmware_op(prepare_idle, TF_PM_MODE_NONE); return 0; } @@ -397,4 +436,18 @@ suspend_set_ops(&tegra_suspend_ops); } + +int tegra_pm_park_secondary_cpu(unsigned long cpu) +{ + if (cpu > 0) { + tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS); + + if (tegra_get_chip_id() == TEGRA20) + tegra20_hotplug_shutdown(); + else + tegra30_hotplug_shutdown(); + } + + return -EINVAL; +} #endif -- Gitblit v1.6.2