diff options
author | Haribabu Narayanan <hnarayanan@nvidia.com> | 2014-06-16 17:57:46 -0700 |
---|---|---|
committer | Matthew Pedro <mapedro@nvidia.com> | 2014-09-16 21:35:55 -0700 |
commit | 4d7daf785c70f7250fb854a4d8458771c2130890 (patch) | |
tree | b0379745970b12f0aa2481cc660ab2cf1f7acd04 /arch/arm/mach-tegra | |
parent | 807725d6864bacd838489bb52ee790f7ce6dbf4c (diff) |
arm: tegra: power: add pcie dependency to xusb ops
Due to a HW bug 1320346 in t12x/t13x, PCIE needs to be unpowergated when XUSB
is to be accessed. Currently PCIE powergating ops need to be invoked from XUSB
driver since powergating module doesn't internally handle this dependency.
This patch implements this dependency within the powergating module so that
xhci-tegra driver can stay chip-agnostic.
Bug 1451279
Bug 1524744
Bug 200027067
Change-Id: I57da2645c9bde1c98b73a906f2ff5e407a3a8380
Reviewed-on: http://git-master/r/424035
(cherry picked from commit ff373b04f297ee653c58a86c6642325037f5d10e)
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Reviewed-on: http://git-master/r/498661
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/powergate-t12x.c | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/powergate-t12x.c b/arch/arm/mach-tegra/powergate-t12x.c index b54989269468..36deee3172c6 100644 --- a/arch/arm/mach-tegra/powergate-t12x.c +++ b/arch/arm/mach-tegra/powergate-t12x.c @@ -695,6 +695,39 @@ static int tegra12x_pcie_unpowergate(int id) return ret; } +/* + * Due to a HW bug 1320346 in t12x/t13x, PCIE needs to be unpowergated when + * XUSB is to be accessed. Since PCIE uses reference counter, we can attempt + * to powergated/unpowergate PCIE when XUSB is powergated/unpowergated. This + * will ensure that PCIE is unpowergated when (either XUSB or PCIE) needs it + * and will be powergated when (neither XUSB nor PCIE) needs it. + */ +static int tegra12x_xusbc_powergate(int id) +{ + int ret = 0; + + if (!TEGRA_IS_XUSBC_POWERGATE_ID(id)) + return -EINVAL; + + CHECK_RET(tegra12x_powergate(id)); + CHECK_RET(tegra12x_pcie_powergate(TEGRA_POWERGATE_PCIE)); + + return ret; +} + +static int tegra12x_xusbc_unpowergate(int id) +{ + int ret = 0; + + if (!TEGRA_IS_XUSBC_POWERGATE_ID(id)) + return -EINVAL; + + CHECK_RET(tegra12x_unpowergate(id)); + CHECK_RET(tegra12x_pcie_unpowergate(TEGRA_POWERGATE_PCIE)); + + return ret; +} + int tegra12x_powergate_partition(int id) { int ret; @@ -710,6 +743,8 @@ int tegra12x_powergate_partition(int id) ret = tegra12x_venc_powergate(id); else if (id == TEGRA_POWERGATE_PCIE) ret = tegra12x_pcie_powergate(id); + else if (id == TEGRA_POWERGATE_XUSBC) + ret = tegra12x_xusbc_powergate(id); else { /* call common power-gate API for t1xx */ ret = tegra1xx_powergate(id, @@ -734,6 +769,8 @@ int tegra12x_unpowergate_partition(int id) ret = tegra12x_venc_unpowergate(id); else if (id == TEGRA_POWERGATE_PCIE) ret = tegra12x_pcie_unpowergate(id); + else if (id == TEGRA_POWERGATE_XUSBC) + ret = tegra12x_xusbc_unpowergate(id); else { ret = tegra1xx_unpowergate(id, &tegra12x_powergate_partition_info[id]); @@ -828,11 +865,23 @@ static int tegra12x_powergate_init_refcount(void) * powergated only when both XUSB and PCIE are not active. */ + atomic_set(&ref_count_pcie, 0); + +#ifdef CONFIG_ARCH_TEGRA_HAS_PCIE + if (pcie_powered) + atomic_inc(&ref_count_pcie); + else { + tegra12x_unpowergate_partition(TEGRA_POWERGATE_PCIE); + pcie_powered = true; + } +#endif + +#ifdef CONFIG_TEGRA_XUSB_PLATFORM if (pcie_powered) - atomic_set(&ref_count_pcie, 1); + atomic_inc(&ref_count_pcie); else - atomic_set(&ref_count_pcie, 0); - + tegra12x_unpowergate_partition(TEGRA_POWERGATE_PCIE); +#endif return 0; } |