ARM: tegra: power: Support for resetting module
Chris Johnson [Fri, 12 Aug 2011 05:58:17 +0000 (08:58 +0300)]
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

arch/arm/mach-tegra/include/mach/powergate.h
arch/arm/mach-tegra/powergate.c

index 9238dd5..52377fb 100644 (file)
 struct clk;
 
 bool tegra_powergate_is_powered(int id);
+int tegra_powergate_mc_disable(int id);
+int tegra_powergate_mc_enable(int id);
+int tegra_powergate_mc_flush(int id);
+int tegra_powergate_mc_flush_done(int id);
 int tegra_powergate_remove_clamping(int id);
 const char *tegra_powergate_get_name(int id);
 
index bdd3695..23b065c 100644 (file)
 
 #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