summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/powergate.c
diff options
context:
space:
mode:
authorChris Johnson <cwj@nvidia.com>2011-08-12 08:58:17 +0300
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:17 -0800
commit0fcfd0857b199e8ab9ca2b86795e0dd7c61a96e4 (patch)
tree908c4c2999ccf3df8176d898e712d5574fdda681 /arch/arm/mach-tegra/powergate.c
parent9d6b71c8e8bf85c350951e4f8c3a1cb5ba54bac0 (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.c239
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