/* * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * 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 #include #include "powergate-priv.h" int tegraxx_powergate_partition(int id, struct powergate_partition_info *pg_info) { int ret; /* If first clk_ptr is null, fill clk info for the partition */ if (pg_info->clk_info[0].clk_ptr) get_clk_info(pg_info); powergate_partition_assert_reset(pg_info); /* Powergating is done only if refcnt of all clks is 0 */ ret = is_partition_clk_disabled(pg_info); if (ret) goto err_clk_off; ret = powergate_module(id); if (ret) goto err_power_off; return 0; err_power_off: WARN(1, "Could not Powergate Partition %d", id); err_clk_off: WARN(1, "Could not Powergate Partition %d, all clks not disabled", id); return ret; } int tegraxx_unpowergate_partition(int id, struct powergate_partition_info *pg_info) { int ret; /* If first clk_ptr is null, fill clk info for the partition */ if (!pg_info->clk_info[0].clk_ptr) get_clk_info(pg_info); if (tegra_powergate_is_powered(id)) return tegra_powergate_reset_module(pg_info); ret = unpowergate_module(id); if (ret) goto err_power; powergate_partition_assert_reset(pg_info); /* Un-Powergating fails if all clks are not enabled */ ret = partition_clk_enable(pg_info); if (ret) goto err_clk_on; udelay(10); ret = tegra_powergate_remove_clamping(id); if (ret) goto err_clamp; udelay(10); powergate_partition_deassert_reset(pg_info); tegra_powergate_mc_flush_done(id); /* Disable all clks enabled earlier. Drivers should enable clks */ partition_clk_disable(pg_info); return 0; err_clamp: partition_clk_disable(pg_info); err_clk_on: powergate_module(id); err_power: WARN(1, "Could not Un-Powergate %d", id); return ret; } int tegraxx_powergate_partition_with_clk_off(int id, struct powergate_partition_info *pg_info) { int ret = 0; /* Disable clks for the partition */ partition_clk_disable(pg_info); ret = is_partition_clk_disabled(pg_info); if (ret) goto err_powergate_clk; ret = tegra_powergate_partition(id); if (ret) goto err_powergating; return ret; err_powergate_clk: WARN(1, "Could not Powergate Partition %d, all clks not disabled", id); err_powergating: ret = partition_clk_enable(pg_info); if (ret) return ret; WARN(1, "Could not Powergate Partition %d", id); return ret; } int tegraxx_unpowergate_partition_with_clk_on(int id, struct powergate_partition_info *pg_info) { int ret = 0; ret = tegra_unpowergate_partition(id); if (ret) goto err_unpowergating; /* Enable clks for the partition */ ret = partition_clk_enable(pg_info); if (ret) goto err_unpowergate_clk; return ret; err_unpowergate_clk: tegra_powergate_partition(id); WARN(1, "Could not Un-Powergate %d, err in enabling clk", id); err_unpowergating: WARN(1, "Could not Un-Powergate %d", id); return ret; }