diff options
author | Chris Johnson <cwj@nvidia.com> | 2011-08-12 08:58:17 +0300 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:17 -0800 |
commit | 0fcfd0857b199e8ab9ca2b86795e0dd7c61a96e4 (patch) | |
tree | 908c4c2999ccf3df8176d898e712d5574fdda681 /arch/arm/mach-tegra/powergate.c | |
parent | 9d6b71c8e8bf85c350951e4f8c3a1cb5ba54bac0 (diff) |
ARM: tegra: power: Support for resetting module
Add support for resetting a module.
Bug 625545
Original-Change-Id: Ibc5e57d73085e85f3d1184d0657d9bc650b28e4e
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/46870
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Daniel Willemsen <dwillemsen@nvidia.com>
Rebase-Id: Rcaa388b315159b1cc69dd29dd03176f4136bd285
Diffstat (limited to 'arch/arm/mach-tegra/powergate.c')
-rw-r--r-- | arch/arm/mach-tegra/powergate.c | 239 |
1 files changed, 216 insertions, 23 deletions
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index bdd3695d46ce..23b065c09e12 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -40,36 +40,55 @@ #define PWRGATE_STATUS 0x38 -#define MC_CLIENT_HOTRESET_CTRL 0x200 -#define MC_CLIENT_HOTRESET_STAT 0x204 - +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) enum mc_client { - MC_CLIENT_AFI = 0, - MC_CLIENT_AVPC = 1, - MC_CLIENT_DC = 2, - MC_CLIENT_DCB = 3, - MC_CLIENT_EPP = 4, - MC_CLIENT_G2 = 5, - MC_CLIENT_HC = 6, - MC_CLIENT_HDA = 7, - MC_CLIENT_ISP = 8, + MC_CLIENT_AFI = 0, + MC_CLIENT_AVPC = 1, + MC_CLIENT_DC = 2, + MC_CLIENT_DCB = 3, + MC_CLIENT_EPP = 4, + MC_CLIENT_G2 = 5, + MC_CLIENT_HC = 6, + MC_CLIENT_HDA = 7, + MC_CLIENT_ISP = 8, MC_CLIENT_MPCORE = 9, MC_CLIENT_MPCORELP = 10, - MC_CLIENT_MPE = 11, - MC_CLIENT_NV = 12, - MC_CLIENT_NV2 = 13, - MC_CLIENT_PPCS = 14, - MC_CLIENT_SATA = 15, - MC_CLIENT_VDE = 16, - MC_CLIENT_VI = 17, - MC_CLIENT_LAST = -1, + MC_CLIENT_MPE = 11, + MC_CLIENT_NV = 12, + MC_CLIENT_NV2 = 13, + MC_CLIENT_PPCS = 14, + MC_CLIENT_SATA = 15, + MC_CLIENT_VDE = 16, + MC_CLIENT_VI = 17, + MC_CLIENT_LAST = -1, }; +#else +enum mc_client { + MC_CLIENT_AVPC = 0, + MC_CLIENT_DC = 1, + MC_CLIENT_DCB = 2, + MC_CLIENT_EPP = 3, + MC_CLIENT_G2 = 4, + MC_CLIENT_HC = 5, + MC_CLIENT_ISP = 6, + MC_CLIENT_MPCORE = 7, + MC_CLIENT_MPEA = 8, + MC_CLIENT_MPEB = 9, + MC_CLIENT_MPEC = 10, + MC_CLIENT_NV = 11, + MC_CLIENT_PPCS = 12, + MC_CLIENT_VDE = 13, + MC_CLIENT_VI = 14, + MC_CLIENT_LAST = -1, + MC_CLIENT_AFI = MC_CLIENT_LAST, +}; +#endif #define MAX_CLK_EN_NUM 4 static DEFINE_SPINLOCK(tegra_powergate_lock); -#define MAX_HOTRESET_CLIENT_NUM 3 +#define MAX_HOTRESET_CLIENT_NUM 4 enum clk_type { CLK_AND_RST, @@ -105,7 +124,12 @@ static struct powergate_partition powergate_partition_info[TEGRA_NUM_POWERGATE] {MC_CLIENT_VDE, MC_CLIENT_LAST}, {{"vde", CLK_AND_RST} }, }, [TEGRA_POWERGATE_MPE] = { "mpe", - {MC_CLIENT_MPE, MC_CLIENT_LAST}, +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + {MC_CLIENT_MPE, MC_CLIENT_LAST}, +#else + {MC_CLIENT_MPEA, MC_CLIENT_MPEB, + MC_CLIENT_MPEC, MC_CLIENT_LAST}, +#endif {{"mpe", CLK_AND_RST} }, }, [TEGRA_POWERGATE_VENC] = { "ve", {MC_CLIENT_ISP, MC_CLIENT_VI, MC_CLIENT_LAST}, @@ -146,7 +170,6 @@ static void pmc_write(u32 val, unsigned long reg) writel(val, pmc + reg); } -#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE); static u32 mc_read(unsigned long reg) @@ -159,6 +182,11 @@ static void mc_write(u32 val, unsigned long reg) writel(val, mc + reg); } +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) + +#define MC_CLIENT_HOTRESET_CTRL 0x200 +#define MC_CLIENT_HOTRESET_STAT 0x204 + static void mc_flush(int id) { u32 idx, rst_ctrl, rst_stat; @@ -211,7 +239,172 @@ static void mc_flush_done(int id) wmb(); } + +int tegra_powergate_mc_flush(int id) +{ + if (id < 0 || id >= TEGRA_NUM_POWERGATE) + return -EINVAL; + mc_flush(id); + return 0; +} + +int tegra_powergate_mc_flush_done(int id) +{ + if (id < 0 || id >= TEGRA_NUM_POWERGATE) + return -EINVAL; + mc_flush_done(id); + return 0; +} + +int tegra_powergate_mc_disable(int id) +{ + return 0; +} + +int tegra_powergate_mc_enable(int id) +{ + return 0; +} + #else + +#define MC_CLIENT_CTRL 0x100 +#define MC_CLIENT_HOTRESETN 0x104 +#define MC_CLIENT_ORRC_BASE 0x140 + +int tegra_powergate_mc_disable(int id) +{ + u32 idx, clt_ctrl, orrc_reg; + enum mc_client mcClientBit; + unsigned long flags; + + if (id < 0 || id >= TEGRA_NUM_POWERGATE) { + WARN_ON(1); + return -EINVAL; + } + + for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) { + mcClientBit = + powergate_partition_info[id].hot_reset_clients[idx]; + if (mcClientBit == MC_CLIENT_LAST) + break; + + spin_lock_irqsave(&tegra_powergate_lock, flags); + + /* clear client enable bit */ + clt_ctrl = mc_read(MC_CLIENT_CTRL); + clt_ctrl &= ~(1 << mcClientBit); + mc_write(clt_ctrl, MC_CLIENT_CTRL); + + /* read back to flush write */ + clt_ctrl = mc_read(MC_CLIENT_CTRL); + + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + + /* wait for outstanding requests to reach 0 */ + orrc_reg = MC_CLIENT_ORRC_BASE + (mcClientBit * 4); + while (mc_read(orrc_reg) != 0) + udelay(10); + } + return 0; +} + +int tegra_powergate_mc_flush(int id) +{ + u32 idx, hot_rstn; + enum mc_client mcClientBit; + unsigned long flags; + + if (id < 0 || id >= TEGRA_NUM_POWERGATE) { + WARN_ON(1); + return -EINVAL; + } + + for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) { + mcClientBit = + powergate_partition_info[id].hot_reset_clients[idx]; + if (mcClientBit == MC_CLIENT_LAST) + break; + + spin_lock_irqsave(&tegra_powergate_lock, flags); + + /* assert hotreset (client module is currently in reset) */ + hot_rstn = mc_read(MC_CLIENT_HOTRESETN); + hot_rstn &= ~(1 << mcClientBit); + mc_write(hot_rstn, MC_CLIENT_HOTRESETN); + + /* read back to flush write */ + hot_rstn = mc_read(MC_CLIENT_HOTRESETN); + + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + } + return 0; +} + +int tegra_powergate_mc_flush_done(int id) +{ + u32 idx, hot_rstn; + enum mc_client mcClientBit; + unsigned long flags; + + if (id < 0 || id >= TEGRA_NUM_POWERGATE) { + WARN_ON(1); + return -EINVAL; + } + + for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) { + mcClientBit = + powergate_partition_info[id].hot_reset_clients[idx]; + if (mcClientBit == MC_CLIENT_LAST) + break; + + spin_lock_irqsave(&tegra_powergate_lock, flags); + + /* deassert hotreset */ + hot_rstn = mc_read(MC_CLIENT_HOTRESETN); + hot_rstn |= (1 << mcClientBit); + mc_write(hot_rstn, MC_CLIENT_HOTRESETN); + + /* read back to flush write */ + hot_rstn = mc_read(MC_CLIENT_HOTRESETN); + + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + } + return 0; +} + +int tegra_powergate_mc_enable(int id) +{ + u32 idx, clt_ctrl; + enum mc_client mcClientBit; + unsigned long flags; + + if (id < 0 || id >= TEGRA_NUM_POWERGATE) { + WARN_ON(1); + return -EINVAL; + } + + for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) { + mcClientBit = + powergate_partition_info[id].hot_reset_clients[idx]; + if (mcClientBit == MC_CLIENT_LAST) + break; + + spin_lock_irqsave(&tegra_powergate_lock, flags); + + /* enable client */ + clt_ctrl = mc_read(MC_CLIENT_CTRL); + clt_ctrl |= (1 << mcClientBit); + mc_write(clt_ctrl, MC_CLIENT_CTRL); + + /* read back to flush write */ + clt_ctrl = mc_read(MC_CLIENT_CTRL); + + spin_unlock_irqrestore(&tegra_powergate_lock, flags); + } + return 0; +} + static void mc_flush(int id) {} static void mc_flush_done(int id) {} #endif |