From 4d7daf785c70f7250fb854a4d8458771c2130890 Mon Sep 17 00:00:00 2001 From: Haribabu Narayanan Date: Mon, 16 Jun 2014 17:57:46 -0700 Subject: 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 Reviewed-on: http://git-master/r/498661 Reviewed-by: Matthew Pedro --- arch/arm/mach-tegra/powergate-t12x.c | 55 ++++++++++++++++++++++++++++++++++-- include/linux/tegra-powergate.h | 1 + 2 files changed, 53 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; } diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h index b98c61ee04d0..b9017ec48356 100644 --- a/include/linux/tegra-powergate.h +++ b/include/linux/tegra-powergate.h @@ -90,6 +90,7 @@ ((id) == TEGRA_POWERGATE_DISB)) #define TEGRA_IS_VENC_POWERGATE_ID(id) ((id) == TEGRA_POWERGATE_VENC) #define TEGRA_IS_PCIE_POWERGATE_ID(id) ((id) == TEGRA_POWERGATE_PCIE) +#define TEGRA_IS_XUSBC_POWERGATE_ID(id) ((id) == TEGRA_POWERGATE_XUSBC) #endif int __init tegra_powergate_init(void); -- cgit v1.2.3