ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / powergate.c
index 52bbb61..2778e8c 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * drivers/powergate/tegra-powergate.c
+ * arch/arm/mach-tegra/powergate.c
  *
  * Copyright (c) 2010 Google, Inc
- * Copyright (C) 2011-2012 NVIDIA Corporation.
+ * Copyright (c) 2011 - 2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/clk.h>
+#include <linux/clk/tegra.h>
 #include <linux/string.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/clk/tegra.h>
+#include <linux/tegra-powergate.h>
+#include <linux/tegra-soc.h>
 #include <trace/events/power.h>
-
-#include <mach/powergate.h>
+#include <asm/atomic.h>
 
 #include "clock.h"
-#include "fuse.h"
 #include "iomap.h"
+#include "powergate-priv.h"
+#include "common.h"
 
-#if defined(DEBUG_T11x_POWERGATE)
-static void test_powergate_parts(void);
-#endif
-#if defined(DEBUG_T11x_POWERUNGATE)
-static void test_powerungate_parts(void);
-#endif
-#if defined(DEBUG_T11x_POWERGATE_CLK_OFF)
-static void test_powergate_clk_off_parts(void);
-#endif
-#if defined(DEBUG_T11x_POWERUNGATE_CLK_OFF)
-static void test_unpowergate_clk_on_parts(void);
-#endif
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static int tegra11x_check_partition_pug_seq(int id);
-#endif
-
-#define PWRGATE_TOGGLE         0x30
-#define PWRGATE_TOGGLE_START   (1 << 8)
-
-#define REMOVE_CLAMPING                0x34
-
-#define PWRGATE_STATUS         0x38
-
-#if defined(CONFIG_ARCH_TEGRA_3x_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_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,
-};
-#elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
-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,
-};
-#else
-/* bit positions are specific to chip */
-enum mc_client {
-       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_MSENC         = 11,
-       MC_CLIENT_NV            = 12,
-       MC_CLIENT_PPCS          = 14,
-       MC_CLIENT_VDE           = 16,
-       MC_CLIENT_VI            = 17,
-       MC_CLIENT_XUSB_HOST     = 19,
-       MC_CLIENT_XUSB_DEV      = 20,
-       MC_CLIENT_EMUCIF        = 21,
-       MC_CLIENT_TSEC          = 22,
-       MC_CLIENT_LAST          = -1,
-       MC_CLIENT_AFI           = MC_CLIENT_LAST,
-       MC_CLIENT_MPE           = MC_CLIENT_LAST,
-       MC_CLIENT_NV2           = MC_CLIENT_LAST,
-       MC_CLIENT_SATA          = MC_CLIENT_LAST,
-};
-#endif
-
-#define MAX_CLK_EN_NUM                 9
-
-static int tegra_num_powerdomains;
-static int tegra_num_cpu_domains;
-static u8 *tegra_cpu_domains;
-static u8 tegra_quad_cpu_domains[] = {
-       TEGRA_POWERGATE_CPU0,
-       TEGRA_POWERGATE_CPU1,
-       TEGRA_POWERGATE_CPU2,
-       TEGRA_POWERGATE_CPU3,
-};
-
-static DEFINE_SPINLOCK(tegra_powergate_lock);
-
-#define MAX_HOTRESET_CLIENT_NUM                4
-
-enum clk_type {
-       CLK_AND_RST,
-       RST_ONLY,
-       CLK_ONLY,
-};
-
-struct partition_clk_info {
-       const char *clk_name;
-       enum clk_type clk_type;
-       /* true if clk is only used in assert/deassert reset and not while enable-den*/
-       struct clk *clk_ptr;
-};
-
-struct powergate_partition {
-       const char *name;
-       enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
-       struct partition_clk_info clk_info[MAX_CLK_EN_NUM];
-};
-
-static struct powergate_partition powergate_partition_info[TEGRA_NUM_POWERGATE] = {
-       [TEGRA_POWERGATE_CPU]   = { "cpu0",     {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_L2]    = { "l2",       {MC_CLIENT_LAST}, },
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       [TEGRA_POWERGATE_3D]    = { "3d0",
-#else
-       [TEGRA_POWERGATE_3D]    = { "3d",
-#endif
-                                               {MC_CLIENT_NV, MC_CLIENT_LAST},
-                                               {{"3d", CLK_AND_RST} }, },
-/* T11x does not have pcie */
-#if !defined(CONFIG_ARCH_TEGRA_11x_SOC)
-#ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
-       [TEGRA_POWERGATE_PCIE]  = { "pcie",
-                                               {MC_CLIENT_AFI, MC_CLIENT_LAST},
-                                               {{"afi", CLK_AND_RST},
-                                               {"pcie", CLK_AND_RST},
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
-                                               {"cml0", CLK_ONLY},
-#endif
-                                               {"pciex", RST_ONLY} }, },
-#endif
-#endif
-       [TEGRA_POWERGATE_VDEC]  = { "vde",
-                                               {MC_CLIENT_VDE, MC_CLIENT_LAST},
-                                               {{"vde", CLK_AND_RST} }, },
-       [TEGRA_POWERGATE_MPE]   = { "mpe",
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-                                       {
-                                               MC_CLIENT_MPE,
-                                               MC_CLIENT_LAST
-                                       },
-#elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
-                                               {MC_CLIENT_MPEA, MC_CLIENT_MPEB,
-                                                MC_CLIENT_MPEC, MC_CLIENT_LAST},
-#else
-                                       {
-                                               MC_CLIENT_MSENC,
-                                               MC_CLIENT_LAST
-                                       },
-#endif
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
-                                       {
-                                               {"mpe", CLK_AND_RST}
-                                       },
-#else
-                                       {
-                                               {"msenc.cbus", CLK_AND_RST}
-                                       },
-#endif
-                               },
-       [TEGRA_POWERGATE_VENC]  = { "ve",
-                                       {
-                                               MC_CLIENT_ISP,
-                                               MC_CLIENT_VI,
-                                               MC_CLIENT_LAST
-                                       },
-                                       {
-                                               {"isp", CLK_AND_RST},
-                                               {"vi", CLK_AND_RST},
-                                               {"csi", CLK_AND_RST}
-                                       },
-                               },
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
-       [TEGRA_POWERGATE_CPU1]  = { "cpu1",     {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_CPU2]  = { "cpu2",     {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_CPU3]  = { "cpu3",     {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_CELP]  = { "celp",     {MC_CLIENT_LAST}, },
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
-#ifdef CONFIG_ARCH_TEGRA_HAS_SATA
-       [TEGRA_POWERGATE_SATA]  = { "sata",     {MC_CLIENT_SATA, MC_CLIENT_LAST},
-                                               {{"sata", CLK_AND_RST},
-                                               {"sata_oob", CLK_AND_RST},
-                                               {"cml1", CLK_ONLY},
-                                               {"sata_cold", RST_ONLY} }, },
-#endif
-#ifdef CONFIG_ARCH_TEGRA_HAS_DUAL_3D
-       [TEGRA_POWERGATE_3D1]   = { "3d1",
-                                               {MC_CLIENT_NV2, MC_CLIENT_LAST},
-                                               {{"3d2", CLK_AND_RST} }, },
-#endif
-#endif
-       [TEGRA_POWERGATE_HEG]   = { "heg",
-                                       {
-                                               MC_CLIENT_G2,
-                                               MC_CLIENT_EPP,
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
-                                               MC_CLIENT_HC,
-#endif
-                                               MC_CLIENT_LAST
-                                       },
-                                       {
-                                               {"2d", CLK_AND_RST},
-                                               {"epp", CLK_AND_RST},
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
-                                               {"host1x", CLK_AND_RST},
-                                               {"3d", RST_ONLY}
-#endif
-                                       },
-                               },
-#endif
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       [TEGRA_POWERGATE_CRAIL] = { "crail",    {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_C0NC]  = { "c0nc",     {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_C1NC]  = { "c1nc",     {MC_CLIENT_LAST}, },
-       [TEGRA_POWERGATE_DISA]  = { "disa",
-                                       {
-                                               MC_CLIENT_DC,
-                                               MC_CLIENT_LAST
-                                       },
-                                       {
-                                               {"disp1", CLK_AND_RST},
-                                               {"dsia", CLK_AND_RST},
-                                               {"dsib", CLK_AND_RST},
-                                               {"csi", CLK_AND_RST},
-                                               {"mipi-cal", CLK_AND_RST}
-                                       },
-                               },
-       [TEGRA_POWERGATE_DISB]  = { "disb",
-                                       {
-                                               MC_CLIENT_DCB,
-                                               MC_CLIENT_LAST
-                                       },
-                                       {
-                                               {"disp2", CLK_AND_RST},
-                                               {"hdmi", CLK_AND_RST}
-                                       },
-                               },
-       [TEGRA_POWERGATE_XUSBA] = { "xusba",
-                                       { MC_CLIENT_LAST },
-                                       {
-                                               {"xusb_ss", CLK_AND_RST}
-                                       },
-                               },
-       [TEGRA_POWERGATE_XUSBB] = { "xusbb",
-                                       {
-                                               MC_CLIENT_XUSB_DEV,
-                                               MC_CLIENT_LAST
-                                       },
-                                       {
-                                               {"xusb_dev", CLK_AND_RST},
-                                       },
-                               },
-       [TEGRA_POWERGATE_XUSBC] = { "xusbc",
-                                       {
-                                               MC_CLIENT_XUSB_HOST,
-                                               MC_CLIENT_LAST
-                                       },
-                                       {
-                                               {"xusb_host", CLK_AND_RST},
-                                       },
-                               },
-#endif
-
-};
-
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static void __iomem *mipi_cal = IO_ADDRESS(TEGRA_MIPI_CAL_BASE);
-
-static u32 mipi_cal_read(unsigned long reg)
-{
-       return readl(mipi_cal + reg);
-}
-
-static void mipi_cal_write(u32 val, unsigned long reg)
-{
-       writel(val, mipi_cal + reg);
-}
-
-static void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-
-static u32 clk_rst_read(unsigned long reg)
-{
-       return readl(clk_rst + reg);
-}
-#endif
-
-static u32 pmc_read(unsigned long reg)
-{
-       return readl(pmc + reg);
-}
-
-static void pmc_write(u32 val, unsigned long reg)
-{
-       writel(val, pmc + reg);
-}
-
-static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
-
-static u32 mc_read(unsigned long reg)
-{
-       return readl(mc + reg);
-}
-
-static void mc_write(u32 val, unsigned long reg)
-{
-       writel(val, mc + reg);
-}
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
-       !defined(CONFIG_TEGRA_SIMULATION_PLATFORM)
-
-#define MC_CLIENT_HOTRESET_CTRL        0x200
-#define MC_CLIENT_HOTRESET_STAT        0x204
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
-       !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-/* FIXME: this is sw workaround for unstable hotreset status
- * for T11x.
- */
-#define HOTRESET_READ_COUNT 5
-static bool tegra11x_stable_hotreset_check(u32 *stat)
-{
-       int i;
-       u32 cur_stat;
-       u32 prv_stat;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tegra_powergate_lock, flags);
-       prv_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
-       for (i = 0; i < HOTRESET_READ_COUNT; i++) {
-               cur_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
-               if (cur_stat != prv_stat) {
-                       spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-                       return false;
-               }
-       }
-       *stat = cur_stat;
-       spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-       return true;
-}
-#endif
-
-static void mc_flush(int id)
-{
-       u32 idx, rst_ctrl, rst_stat;
-       enum mc_client mcClientBit;
-       unsigned long flags;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
-       !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool ret;
-#endif
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
-
-       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);
-               rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
-               rst_ctrl |= (1 << mcClientBit);
-               mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
-
-               spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-
-               do {
-                       udelay(10);
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
-                       rst_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
-#else
-                       rst_stat = 0;
-                       ret = tegra11x_stable_hotreset_check(&rst_stat);
-                       if (!ret)
-                               continue;
-#endif
-               } while (!(rst_stat & (1 << mcClientBit)));
-       }
-}
-
-static void mc_flush_done(int id)
-{
-       u32 idx, rst_ctrl;
-       enum mc_client mcClientBit;
-       unsigned long flags;
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
-
-       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);
-
-               rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
-               rst_ctrl &= ~(1 << mcClientBit);
-               mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
-
-               spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-       }
-
-       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;
-       }
+static struct powergate_ops *pg_ops;
 
-       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)
+static spinlock_t *tegra_get_powergate_lock(void)
 {
-       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);
+       if (pg_ops && pg_ops->get_powergate_lock)
+               return pg_ops->get_powergate_lock();
+       else
+               WARN_ON_ONCE("This SOC does not export powergate lock");
 
-               spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-       }
-       return 0;
+       return NULL;
 }
 
-static void mc_flush(int id) {}
-static void mc_flush_done(int id) {}
-#endif
-
-static int tegra_powergate_set(int id, bool new_state)
+int tegra_powergate_set(int id, bool new_state)
 {
-#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
        bool status;
        unsigned long flags;
+       spinlock_t *lock;
+       u32 reg;
+
        /* 10us timeout for toggle operation if it takes affect*/
        int toggle_timeout = 10;
+
        /* 100 * 10 = 1000us timeout for toggle command to take affect in case
           of contention with h/w initiated CPU power gating */
        int contention_timeout = 100;
 
-       spin_lock_irqsave(&tegra_powergate_lock, flags);
+       if (tegra_cpu_is_asim())
+               return 0;
+
+       lock = tegra_get_powergate_lock();
+
+       spin_lock_irqsave(lock, flags);
 
        status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
 
        if (status == new_state) {
-               spin_unlock_irqrestore(&tegra_powergate_lock, flags);
+               spin_unlock_irqrestore(lock, flags);
                return 0;
        }
 
@@ -662,12 +85,43 @@ static int tegra_powergate_set(int id, bool new_state)
                /* CPU ungated in s/w only during boot/resume with outer
                   waiting loop and no contention from other CPUs */
                pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
-               spin_unlock_irqrestore(&tegra_powergate_lock, flags);
+               spin_unlock_irqrestore(lock, flags);
                return 0;
        }
 
+#if !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       /* Wait if PMC is already processing some other power gating request */
+       do {
+               udelay(1);
+               reg = pmc_read(PWRGATE_TOGGLE);
+               contention_timeout--;
+       } while ((contention_timeout > 0) && (reg & PWRGATE_TOGGLE_START));
+
+       if (contention_timeout <= 0)
+               pr_err(" Timed out waiting for PMC to submit \
+                               new power gate request \n");
+       contention_timeout = 100;
+#endif
+
+       /* Submit power gate request */
+       pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
+
+#if !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       /* Wait while PMC accepts the request */
+       do {
+               udelay(1);
+               reg = pmc_read(PWRGATE_TOGGLE);
+               contention_timeout--;
+       } while ((contention_timeout > 0) && (reg & PWRGATE_TOGGLE_START));
+
+       if (contention_timeout <= 0)
+               pr_err(" Timed out waiting for PMC to accept \
+                               new power gate request \n");
+       contention_timeout = 100;
+#endif
+
+       /* Check power gate status */
        do {
-               pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
                do {
                        udelay(1);
                        status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
@@ -678,206 +132,87 @@ static int tegra_powergate_set(int id, bool new_state)
                contention_timeout--;
        } while ((status != new_state) && (contention_timeout > 0));
 
-       spin_unlock_irqrestore(&tegra_powergate_lock, flags);
+       spin_unlock_irqrestore(lock, flags);
 
        if (status != new_state) {
                WARN(1, "Could not set powergate %d to %d", id, new_state);
                return -EBUSY;
        }
 
-       trace_power_domain_target(powergate_partition_info[id].name, new_state,
-                       smp_processor_id());
-#endif
+       trace_power_domain_target(tegra_powergate_get_name(id), new_state,
+                       raw_smp_processor_id());
 
        return 0;
 }
 
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static bool tegra11x_check_plld_plld2_disable(void)
-{
-       /* FIXME:
-        * add check for plld and plld2 disable
-        */
-#define CLK_RST_CONTROLLER_PLLD_BASE_0 0xd0
-#define CLK_RST_CONTROLLER_PLLD_BASE_0_PLLD_ENABLE_LSB 30
-#define CLK_RST_CONTROLLER_PLLD2_BASE_0 0x4b8
-#define CLK_RST_CONTROLLER_PLLD2_BASE_0_PLLD2_ENABLE_LSB 30
-       u32 status;
-       status = clk_rst_read(CLK_RST_CONTROLLER_PLLD_BASE_0);
-       if (status & (1 << CLK_RST_CONTROLLER_PLLD_BASE_0_PLLD_ENABLE_LSB))
-               return false;
-       status = clk_rst_read(CLK_RST_CONTROLLER_PLLD2_BASE_0);
-       if (status & (1 << CLK_RST_CONTROLLER_PLLD2_BASE_0_PLLD2_ENABLE_LSB))
-               return false;
-       return true;
-}
-
-static bool tegra11x_pg_sw_war_missing(int id)
+int is_partition_clk_disabled(struct powergate_partition_info *pg_info)
 {
-       bool ret;
-
-       switch (id) {
-       case TEGRA_POWERGATE_DISA:
-               /* FIXME:
-                * [SW WAR bug 954988]:
-                * Disable PLLD and PLLD2 by clearing bits:
-a.     CLK_RST_CONTROLLER_PLLD_BASE_0_PLLD_ENABLE
-b.     CLK_RST_CONTROLLER_PLLD2_BASE_0_PLLD2_ENABLE
-                * We should not need to disable PLLD and PLLD2
-                * for linux/android implementation
-                * adding check in case PLLD or PLLD2 is/are ON
-                */
-               ret = tegra11x_check_plld_plld2_disable();
-               if (!ret)
-                       return true;
-
-               break;
-       }
-       return false;
-}
-#endif
+       u32 idx;
+       struct clk *clk;
+       struct partition_clk_info *clk_info;
+       int ret = 0;
 
-static int unpowergate_module(int id)
-{
-       if (id < 0 || id >= tegra_num_powerdomains)
-               return -EINVAL;
-       return tegra_powergate_set(id, true);
-}
+       for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
+               clk_info = &pg_info->clk_info[idx];
+               clk = clk_info->clk_ptr;
 
-static int powergate_module(int id)
-{
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool need_sw_war;
-#endif
-       if (id < 0 || id >= tegra_num_powerdomains)
-               return -EINVAL;
+               if (!clk)
+                       break;
 
-       mc_flush(id);
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       need_sw_war = tegra11x_pg_sw_war_missing(id);
-       if (need_sw_war) {
-               pr_err("Error: missing powergate sw war in file: %s, func: %s, line=%d\n",
-               __FILE__, __func__, __LINE__);
-               return -1;
+               if (clk_info->clk_type != RST_ONLY) {
+                       if (tegra_is_clk_enabled(clk)) {
+                               ret = -1;
+                               break;
+                       }
+               }
        }
-#endif
-       return tegra_powergate_set(id, false);
-}
-
-bool tegra_powergate_is_powered(int id)
-{
-       u32 status;
-
-       if (id < 0 || id >= tegra_num_powerdomains)
-               return -EINVAL;
 
-       status = pmc_read(PWRGATE_STATUS) & (1 << id);
-       return !!status;
+       return ret;
 }
-EXPORT_SYMBOL(tegra_powergate_is_powered);
 
-int tegra_powergate_remove_clamping(int id)
+int powergate_module(int id)
 {
-       u32 mask;
-       int contention_timeout = 100;
-
-       if (id < 0 || id >= tegra_num_powerdomains)
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
                return -EINVAL;
+       }
 
-       /*
-        * PCIE and VDE clamping masks are swapped with respect to their
-        * partition ids
-        */
-       if (id ==  TEGRA_POWERGATE_VDEC)
-               mask = (1 << TEGRA_POWERGATE_PCIE);
-       else if (id == TEGRA_POWERGATE_PCIE)
-               mask = (1 << TEGRA_POWERGATE_VDEC);
-       else
-               mask = (1 << id);
-
-       pmc_write(mask, REMOVE_CLAMPING);
-       /* Wait until clamp is removed */
-       do {
-               udelay(1);
-               contention_timeout--;
-       } while ((contention_timeout > 0)
-                       && (pmc_read(REMOVE_CLAMPING) & mask));
+       if (id < 0 || id >= pg_ops->num_powerdomains)
+               return -EINVAL;
 
-       WARN(contention_timeout <= 0, "Couldn't remove clamping");
+       tegra_powergate_mc_flush(id);
 
-       return 0;
+       return tegra_powergate_set(id, false);
 }
 
-static void get_clk_info(int id)
+int unpowergate_module(int id)
 {
-       int idx;
-
-       for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
-               if (!powergate_partition_info[id].clk_info[idx].clk_name)
-                       break;
-               powergate_partition_info[id].
-                               clk_info[idx].clk_ptr =
-                                       tegra_get_clock_by_name(
-                       powergate_partition_info[id].clk_info[idx].clk_name);
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
        }
-}
 
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static bool tegra11x_pug_clk_n_rst_skip(int id, u32 idx)
-{
-       switch (id) {
-       case TEGRA_POWERGATE_VENC:
-               if ((powergate_partition_info[id].clk_info[idx].clk_name) &&
-                       (!(strncmp("csi",
-                       powergate_partition_info[id].clk_info[idx].clk_name,
-                       3)))) {
-                               /* DIS powered ON then do clk enable CSI */
-                               if (!tegra_powergate_is_powered(
-                                               TEGRA_POWERGATE_DISA))
-                                       return true;
-               }
-               break;
-       case TEGRA_POWERGATE_DISA:
-               if ((powergate_partition_info[id].clk_info[idx].clk_name) &&
-                       (!(strncmp("csi",
-                       powergate_partition_info[id].clk_info[idx].clk_name,
-                       3)))) {
-                               /* DIS powered ON then do clk enable CSI */
-                               if (!tegra_powergate_is_powered(
-                                               TEGRA_POWERGATE_VENC))
-                                       return true;
-               }
-               break;
-       }
-       return false;
+       if (id < 0 || id >= pg_ops->num_powerdomains)
+               return -EINVAL;
+
+       return tegra_powergate_set(id, true);
 }
-#endif
 
-static int partition_clk_enable(int id)
+int partition_clk_enable(struct powergate_partition_info *pg_info)
 {
        int ret;
        u32 idx;
        struct clk *clk;
        struct partition_clk_info *clk_info;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool skip_enable;
-#endif
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
 
        for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-               skip_enable = tegra11x_pug_clk_n_rst_skip(id, idx);
-               if (skip_enable)
-                       continue;
-#endif
-               clk_info = &powergate_partition_info[id].clk_info[idx];
+               clk_info = &pg_info->clk_info[idx];
                clk = clk_info->clk_ptr;
                if (!clk)
                        break;
 
                if (clk_info->clk_type != RST_ONLY) {
-                       ret = clk_prepare_enable(clk);
+                       ret = tegra_clk_prepare_enable(clk);
                        if (ret)
                                goto err_clk_en;
                }
@@ -886,770 +221,453 @@ static int partition_clk_enable(int id)
        return 0;
 
 err_clk_en:
-       WARN(1, "Could not enable clk %s", clk->name);
+       WARN(1, "Could not enable clk %s, error %d", clk->name, ret);
        while (idx--) {
-               clk_info = &powergate_partition_info[id].clk_info[idx];
+               clk_info = &pg_info->clk_info[idx];
                if (clk_info->clk_type != RST_ONLY)
-                       clk_disable_unprepare(clk_info->clk_ptr);
+                       tegra_clk_disable_unprepare(clk_info->clk_ptr);
        }
 
        return ret;
 }
 
-static int is_partition_clk_disabled(int id)
+void partition_clk_disable(struct powergate_partition_info *pg_info)
 {
        u32 idx;
        struct clk *clk;
        struct partition_clk_info *clk_info;
-       int ret = 0;
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
 
        for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
-               clk_info = &powergate_partition_info[id].clk_info[idx];
+               clk_info = &pg_info->clk_info[idx];
                clk = clk_info->clk_ptr;
+
                if (!clk)
                        break;
 
-               if (clk_info->clk_type != RST_ONLY) {
-                       if (tegra_is_clk_enabled(clk)) {
-                               ret = -1;
-                               break;
-                       }
-               }
+               if (clk_info->clk_type != RST_ONLY)
+                       tegra_clk_disable_unprepare(clk);
        }
-
-       return ret;
 }
 
-static void partition_clk_disable(int id)
+void get_clk_info(struct powergate_partition_info *pg_info)
 {
-       u32 idx;
-       struct clk *clk;
-       struct partition_clk_info *clk_info;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool skip_disable;
-#endif
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
+       int idx;
 
        for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-               if (id == TEGRA_POWERGATE_DISA) {
-                       skip_disable = tegra11x_pug_clk_n_rst_skip(id, idx);
-                       if (skip_disable)
-                               continue;
-               }
-#endif
-               clk_info = &powergate_partition_info[id].clk_info[idx];
-               clk = clk_info->clk_ptr;
-               if (!clk)
+               if (!pg_info->clk_info[idx].clk_name)
                        break;
 
-               if (clk_info->clk_type != RST_ONLY)
-                       clk_disable_unprepare(clk);
+               pg_info->clk_info[idx].clk_ptr = tegra_get_clock_by_name(
+                       pg_info->clk_info[idx].clk_name);
        }
 }
 
-static void powergate_partition_assert_reset(int id)
+void powergate_partition_assert_reset(struct powergate_partition_info *pg_info)
 {
        u32 idx;
        struct clk *clk_ptr;
        struct partition_clk_info *clk_info;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool skip_reset;
-#endif
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
 
        for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-               if (id == TEGRA_POWERGATE_DISA) {
-                       skip_reset = tegra11x_pug_clk_n_rst_skip(id, idx);
-                       if (skip_reset)
-                               continue;
-               }
-#endif
-               clk_info = &powergate_partition_info[id].clk_info[idx];
+               clk_info = &pg_info->clk_info[idx];
                clk_ptr = clk_info->clk_ptr;
+
                if (!clk_ptr)
                        break;
+
                if (clk_info->clk_type != CLK_ONLY)
                        tegra_periph_reset_assert(clk_ptr);
        }
 }
 
-static void powergate_partition_deassert_reset(int id)
+void powergate_partition_deassert_reset(struct powergate_partition_info *pg_info)
 {
        u32 idx;
        struct clk *clk_ptr;
        struct partition_clk_info *clk_info;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool skip_reset;
-#endif
-
-       BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
 
        for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-               skip_reset = tegra11x_pug_clk_n_rst_skip(id, idx);
-               if (skip_reset)
-                       continue;
-#endif
-               clk_info = &powergate_partition_info[id].clk_info[idx];
+               clk_info = &pg_info->clk_info[idx];
                clk_ptr = clk_info->clk_ptr;
+
                if (!clk_ptr)
                        break;
+
                if (clk_info->clk_type != CLK_ONLY)
                        tegra_periph_reset_deassert(clk_ptr);
        }
 }
 
-/* Must be called with clk disabled, and returns with clk disabled */
-static int tegra_powergate_reset_module(int id)
+int tegra_powergate_reset_module(struct powergate_partition_info *pg_info)
 {
        int ret;
 
-       powergate_partition_assert_reset(id);
+       powergate_partition_assert_reset(pg_info);
 
        udelay(10);
 
-       ret = partition_clk_enable(id);
+       ret = partition_clk_enable(pg_info);
        if (ret)
                return ret;
 
        udelay(10);
 
-       powergate_partition_deassert_reset(id);
+       powergate_partition_deassert_reset(pg_info);
 
-       partition_clk_disable(id);
+       partition_clk_disable(pg_info);
 
        return 0;
 }
 
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-/*
- * FIXME: sw war for mipi-cal calibration when unpowergating DISA partition
- */
-static void tegra11x_mipical_calibrate(int id)
+bool tegra_powergate_check_clamping(int id)
 {
-       struct reg_offset_val {
-               u32 offset;
-               u32 por_value;
-       };
-       u32 status;
-       unsigned long flags;
-#define MIPI_CAL_MIPI_CAL_CTRL_0 0x0
-#define MIPI_CAL_CIL_MIPI_CAL_STATUS_0 0x8
-#define MIPI_CAL_CILA_MIPI_CAL_CONFIG_0 0x14
-#define MIPI_CAL_CILB_MIPI_CAL_CONFIG_0 0x18
-#define MIPI_CAL_CILC_MIPI_CAL_CONFIG_0 0x1c
-#define MIPI_CAL_CILD_MIPI_CAL_CONFIG_0 0x20
-#define MIPI_CAL_CILE_MIPI_CAL_CONFIG_0 0x24
-#define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0 0x38
-#define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0 0x3c
-#define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0 0x40
-#define MIPI_CAL_DSID_MIPI_CAL_CONFIG_0 0x44
-       static struct reg_offset_val mipi_cal_por_values[] = {
-               { MIPI_CAL_MIPI_CAL_CTRL_0, 0x2a000000 },
-               { MIPI_CAL_CILA_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_CILB_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_CILC_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_CILD_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_CILE_MIPI_CAL_CONFIG_0, 0x00000000 },
-               { MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0, 0x00200000 },
-               { MIPI_CAL_DSID_MIPI_CAL_CONFIG_0, 0x00200000 },
-       };
-       int i;
-
-       if (id != TEGRA_POWERGATE_DISA)
-               return;
-       spin_lock_irqsave(&tegra_powergate_lock, flags);
-       /* mipi cal por restore */
-       for (i = 0; i < ARRAY_SIZE(mipi_cal_por_values); i++) {
-               mipi_cal_write(mipi_cal_por_values[i].por_value,
-                       mipi_cal_por_values[i].offset);
+       if (!pg_ops || !pg_ops->powergate_check_clamping) {
+               pr_info("This SOC can't check clamping status\n");
+               return -EINVAL;
        }
-       /* mipi cal status clear */
-       status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
-       mipi_cal_write(status, MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
-       /* mipi cal status read - to flush writes */
-       status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
-       spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-       if (status)
-               pr_err("Error: mipi_cal calibration failed at file: %s, func: %s, line=%d\n",
-               __FILE__, __func__, __LINE__);
-}
-#endif
-
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static bool skip_pg_check(int id, bool is_unpowergate)
-{
-       /*
-        * FIXME: need to stress test partition power gating before
-        * enabling power gating for T11x
-        * List of T11x partition id which skip power gating
-        */
-       static int skip_pg_t11x_list[] = {
-               /*
-                * CPU power gate enable/disable done
-                * from cpu power management code
-                */
-               TEGRA_POWERGATE_CRAIL,
-               TEGRA_POWERGATE_VENC,
-               TEGRA_POWERGATE_PCIE,
-               TEGRA_POWERGATE_VDEC,
-               TEGRA_POWERGATE_L2,
-               TEGRA_POWERGATE_SATA,
-               TEGRA_POWERGATE_CELP,
-               TEGRA_POWERGATE_C0NC,
-               TEGRA_POWERGATE_C1NC,
-               TEGRA_POWERGATE_DISA,
-               TEGRA_POWERGATE_DISB,
-               TEGRA_POWERGATE_XUSBA,
-               TEGRA_POWERGATE_XUSBB,
-               TEGRA_POWERGATE_XUSBC,
-       };
-       int i;
 
-       /*
-        * skip unnecessary multiple calls e.g. powergate call when
-        * partition is already powered-off or vice-versa
-        */
-       if ((tegra_powergate_is_powered(id) &&
-               is_unpowergate) ||
-               (!(tegra_powergate_is_powered(id)) &&
-               (!is_unpowergate))) {
-               pr_err("Partition %s already powered-%s and %spowergate skipped\n",
-                       tegra_powergate_get_name(id),
-                       (tegra_powergate_is_powered(id)) ?
-                       "on" : "off",
-                       (is_unpowergate) ? "un" : "");
-               return true;
-       }
-       /* unpowergate is allowed for all partitions */
-       if (!tegra_powergate_is_powered(id) &&
-               is_unpowergate) {
-               pr_err("Partition %s already powered-%s unpowergating\n",
-                       tegra_powergate_get_name(id),
-                       (tegra_powergate_is_powered(id)) ?
-                       "on" : "off");
-               return false;
-       }
-       for (i = 0; i < tegra_num_powerdomains; i++) {
-               if (id == skip_pg_t11x_list[i]) {
-                       pr_err("Partition %s %spowergate skipped\n",
-                               tegra_powergate_get_name(id),
-                               (is_unpowergate) ? "un" : "");
-                       return true;
-               }
-       }
+       if (id < 0 || id >= pg_ops->num_powerdomains)
+               return -EINVAL;
 
-       return false;
+       return pg_ops->powergate_check_clamping(id);
 }
-#endif
 
-/*
- * Must be called with clk disabled, and returns with clk disabled
- * Drivers should enable clks for partition. Unpowergates only the
- * partition.
- */
-int tegra_unpowergate_partition(int id)
+int tegra_powergate_remove_clamping(int id)
 {
-       int ret;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool is_pg_skip;
-
-       is_pg_skip = skip_pg_check(id, true);
-       if (is_pg_skip)
-               return 0;
-       ret = tegra11x_check_partition_pug_seq(id);
-       if (ret)
-               return ret;
-#endif
-       /* If first clk_ptr is null, fill clk info for the partition */
-       if (!powergate_partition_info[id].clk_info[0].clk_ptr)
-               get_clk_info(id);
-
-       if (tegra_powergate_is_powered(id))
-               return tegra_powergate_reset_module(id);
-
-       ret = unpowergate_module(id);
-       if (ret)
-               goto err_power;
-
-       powergate_partition_assert_reset(id);
-
-       /* Un-Powergating fails if all clks are not enabled */
-       ret = partition_clk_enable(id);
-       if (ret)
-               goto err_clk_on;
-
-       udelay(10);
+       u32 mask;
+       int contention_timeout = 100;
 
-       ret = tegra_powergate_remove_clamping(id);
-       if (ret)
-               goto err_clamp;
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       udelay(10);
+       if (id < 0 || id >= pg_ops->num_powerdomains)
+               return -EINVAL;
 
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       tegra11x_mipical_calibrate(id);
-#endif
-       powergate_partition_deassert_reset(id);
+       /*
+        * PCIE and VDE clamping masks are swapped with respect to their
+        * partition ids
+        */
+       if (id ==  TEGRA_POWERGATE_VDEC)
+               mask = (1 << TEGRA_POWERGATE_PCIE);
+       else if (id == TEGRA_POWERGATE_PCIE)
+               mask = (1 << TEGRA_POWERGATE_VDEC);
+       else
+               mask = (1 << id);
 
-       mc_flush_done(id);
+       pmc_write(mask, REMOVE_CLAMPING);
+       /* Wait until clamp is removed */
+       do {
+               udelay(1);
+               contention_timeout--;
+       } while ((contention_timeout > 0)
+                       && (pmc_read(PWRGATE_CLAMP_STATUS) & BIT(id)));
 
-       /* Disable all clks enabled earlier. Drivers should enable clks */
-       partition_clk_disable(id);
+       WARN(contention_timeout <= 0, "Couldn't remove clamping");
 
        return 0;
-
-err_clamp:
-       partition_clk_disable(id);
-err_clk_on:
-       powergate_module(id);
-err_power:
-       WARN(1, "Could not Un-Powergate %d", id);
-       return ret;
 }
 
-int tegra_cpu_powergate_id(int cpuid)
+static inline bool tegra_powergate_check_skip_list(int id)
 {
-       if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
-               return tegra_cpu_domains[cpuid];
-
-       return -EINVAL;
+       return pg_ops->powergate_skip ?
+               pg_ops->powergate_skip(id) : false;
 }
 
-int __init tegra_powergate_init(void)
-{
-       switch (tegra_chip_id) {
-       case TEGRA20:
-               tegra_num_powerdomains = 7;
-               break;
-       case TEGRA30:
-               tegra_num_powerdomains = 14;
-               tegra_num_cpu_domains = 4;
-               tegra_cpu_domains = tegra_quad_cpu_domains;
-               break;
-       case TEGRA11X:
-               tegra_num_powerdomains = 23;
-               tegra_num_cpu_domains = 4;
-               tegra_cpu_domains = tegra_quad_cpu_domains;
-               break;
-       default:
-               /* Unknown Tegra variant. Disable powergating */
-               tegra_num_powerdomains = 0;
-               break;
-       }
-
-#if defined(DEBUG_T11x_POWERGATE)
-       test_powergate_parts();
-#endif
-#if defined(DEBUG_T11x_POWERUNGATE)
-       test_unpowergate_parts();
-#endif
-#if defined(DEBUG_T11x_POWERGATE_CLK_OFF)
-       test_powergate_clk_off_parts();
-#endif
-#if defined(DEBUG_T11x_POWERUNGATE_CLK_ON)
-       test_unpowergate_clk_on_parts();
-#endif
-       return 0;
-}
+/* EXTERNALY VISIBLE APIS */
 
-/*
- * Must be called with clk disabled, and returns with clk enabled
- * Unpowergates the partition and enables all required clks.
- */
-int tegra_unpowergate_partition_with_clk_on(int id)
+bool tegra_powergate_is_powered(int id)
 {
-       int ret = 0;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool is_pg_skip;
+       u32 status;
 
-       is_pg_skip = skip_pg_check(id, true);
-       if (is_pg_skip)
-               return 0;
-#endif
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       /* Restrict this functions use to few partitions */
-       BUG_ON(id != TEGRA_POWERGATE_SATA && id != TEGRA_POWERGATE_PCIE);
-#elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
-       /* Restrict this functions use to few partitions */
-       BUG_ON(id != TEGRA_POWERGATE_PCIE);
-#endif
+       if (!pg_ops) {
+               pr_debug("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       ret = tegra_unpowergate_partition(id);
-       if (ret)
-               goto err_unpowergating;
+       if (id < 0 || id >= pg_ops->num_powerdomains)
+               return -EINVAL;
 
-       /* Enable clks for the partition */
-       ret = partition_clk_enable(id);
-       if (ret)
-               goto err_unpowergate_clk;
+       if (pg_ops->powergate_is_powered)
+               return pg_ops->powergate_is_powered(id);
+       else
+               status = pmc_read(PWRGATE_STATUS) & (1 << id);
 
-       return ret;
+       status = pmc_read(PWRGATE_STATUS) & (1 << id);
 
-err_unpowergate_clk:
-       tegra_powergate_partition(id);
-       WARN(1, "Could not Un-Powergate %d, err in enabling clk", id);
-err_unpowergating:
-       WARN(1, "Could not Un-Powergate %d", id);
-       return ret;
+       return !!status;
 }
+EXPORT_SYMBOL(tegra_powergate_is_powered);
 
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-static int tegra11x_3d_powergate_set(int id, bool new_state)
+int tegra_cpu_powergate_id(int cpuid)
 {
-#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
-       bool status;
-       unsigned long flags;
-       /* 10us timeout for toggle operation if it takes affect*/
-       int toggle_timeout = 10;
-       /* 100 * 10 = 1000us timeout for toggle command to take affect in case
-          of contention with h/w initiated CPU power gating */
-       int contention_timeout = 100;
-
-       spin_lock_irqsave(&tegra_powergate_lock, flags);
-
-       status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
-
-       if (status == new_state) {
-               spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-               return 0;
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
        }
 
-       pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
-       do {
-               do {
-                       udelay(1);
-                       status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
-
-                       toggle_timeout--;
-               } while ((status != new_state) && (toggle_timeout > 0));
-
-               contention_timeout--;
-       } while ((status != new_state) && (contention_timeout > 0));
-
-       spin_unlock_irqrestore(&tegra_powergate_lock, flags);
-
-       if (status != new_state) {
-               WARN(1, "Could not set powergate %d to %d", id, new_state);
-               return -EBUSY;
+       if (cpuid < 0 || cpuid >= pg_ops->num_cpu_domains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
        }
 
-       trace_power_domain_target(powergate_partition_info[id].name, new_state,
-                       smp_processor_id());
-#endif
+       if (pg_ops->cpu_domains)
+               return pg_ops->cpu_domains[cpuid];
+       else
+               WARN_ON_ONCE("This SOC does not support CPU powergate\n");
 
-       return 0;
+       return -EINVAL;
 }
+EXPORT_SYMBOL(tegra_cpu_powergate_id);
 
-static int tegra11x_powergate_3d(int id)
+int tegra_powergate_partition(int id)
 {
-       int ret;
-
-       /* If first clk_ptr is null, fill clk info for the partition */
-       if (powergate_partition_info[id].clk_info[0].clk_ptr)
-               get_clk_info(id);
-
-       ret = partition_clk_enable(id);
-       if (ret)
-               WARN(1, "Couldn't enable clock");
-
-       udelay(10);
-
-       mc_flush(id);
-
-       udelay(10);
-
-       powergate_partition_assert_reset(id);
-
-       udelay(10);
-
-       /* Powergating is done only if refcnt of all clks is 0 */
-       partition_clk_disable(id);
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       udelay(10);
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
+       }
 
-       ret = tegra11x_3d_powergate_set(id, false);
-       if (ret)
-               goto err_power_off;
+       if (tegra_powergate_check_skip_list(id))
+               printk_once("%s: %s is in powergate skip list\n", __func__,
+                       tegra_powergate_get_name(id));
 
-       return 0;
+       if (pg_ops->powergate_partition)
+               return pg_ops->powergate_partition(id);
+       else
+               WARN_ON_ONCE("This SOC doesn't support powergating");
 
-err_power_off:
-       WARN(1, "Could not Powergate Partition %d", id);
-       return ret;
+       return -EINVAL;
 }
+EXPORT_SYMBOL(tegra_powergate_partition);
 
-static int tegra11x_unpowergate_3d(int id)
+int tegra_unpowergate_partition(int id)
 {
-       int ret;
-       /* If first clk_ptr is null, fill clk info for the partition */
-       if (!powergate_partition_info[id].clk_info[0].clk_ptr)
-               get_clk_info(id);
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       if (tegra_powergate_is_powered(id))
-               return tegra_powergate_reset_module(id);
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
+       }
 
-       ret = tegra11x_3d_powergate_set(id, true);
-       if (ret)
-               goto err_power;
+       if (tegra_powergate_check_skip_list(id))
+               printk_once("%s: %s is in powergate skip list\n", __func__,
+                       tegra_powergate_get_name(id));
 
-       udelay(10);
+       if (pg_ops->unpowergate_partition)
+               return pg_ops->unpowergate_partition(id);
+       else
+               WARN_ON_ONCE("This SOC doesn't support un-powergating");
 
-       /* Un-Powergating fails if all clks are not enabled */
-       ret = partition_clk_enable(id);
-       if (ret)
-               goto err_clk_on;
+       return -EINVAL;
+}
+EXPORT_SYMBOL(tegra_unpowergate_partition);
 
-       udelay(10);
+int tegra_powergate_partition_with_clk_off(int id)
+{
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       ret = tegra_powergate_remove_clamping(id);
-       if (ret)
-               goto err_clamp;
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
+       }
 
-       udelay(10);
+       if (tegra_powergate_check_skip_list(id))
+               printk_once("%s: %s is in powergate skip list\n", __func__,
+                       tegra_powergate_get_name(id));
 
-       powergate_partition_deassert_reset(id);
+       if (pg_ops->powergate_partition_with_clk_off)
+               return pg_ops->powergate_partition_with_clk_off(id);
+       else
+               WARN_ON_ONCE("This SOC doesn't support powergating with clk off");
 
-       udelay(10);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(tegra_powergate_partition_with_clk_off);
 
-       mc_flush_done(id);
+int tegra_unpowergate_partition_with_clk_on(int id)
+{
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       udelay(10);
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
+       }
 
-       /* Disable all clks enabled earlier. Drivers should enable clks */
-       partition_clk_disable(id);
+       if (tegra_powergate_check_skip_list(id))
+               printk_once("%s: %s is in powergate skip list\n", __func__,
+                       tegra_powergate_get_name(id));
 
-       return 0;
+       if (pg_ops->unpowergate_partition_with_clk_on)
+               return pg_ops->unpowergate_partition_with_clk_on(id);
+       else
+               WARN_ON_ONCE("This SOC doesn't support power un-gating with clk on");
 
-err_clamp:
-       partition_clk_disable(id);
-err_clk_on:
-       powergate_module(id);
-err_power:
-       WARN(1, "Could not Un-Powergate %d", id);
-       return ret;
+       return -EINVAL;
 }
+EXPORT_SYMBOL(tegra_unpowergate_partition_with_clk_on);
 
-static int tegra11x_powergate_partition(int id)
+int tegra_powergate_mc_enable(int id)
 {
-       int ret;
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       if (tegra_powergate_is_powered(id)) {
-               ret = is_partition_clk_disabled(id);
-               if (ret < 0) {
-                       /* clock enabled */
-                       ret = tegra_powergate_partition_with_clk_off(id);
-                       if (ret < 0)
-                               return ret;
-               } else {
-                       ret = tegra_powergate_partition(id);
-                       if (ret < 0)
-                               return ret;
-               }
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
        }
-       return 0;
-}
 
-static int tegra11x_unpowergate_partition(int id)
-{
-       int ret;
+       if (pg_ops->powergate_mc_enable)
+               return pg_ops->powergate_mc_enable(id);
+       else
+               WARN_ON_ONCE("This SOC does not support powergate mc enable");
 
-       if (!tegra_powergate_is_powered(id)) {
-               ret = is_partition_clk_disabled(id);
-               if (ret) {
-                       /* clock disabled */
-                       ret = tegra_unpowergate_partition_with_clk_on(id);
-                       if (ret < 0)
-                               return ret;
-               } else {
-                       ret = tegra_unpowergate_partition(id);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
-       return 0;
+       return -EINVAL;
 }
+EXPORT_SYMBOL(tegra_powergate_mc_enable);
 
-static int tegra11x_check_partition_pg_seq(int id)
+int tegra_powergate_mc_disable(int id)
 {
-       int ret;
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       switch (id) {
-       case TEGRA_POWERGATE_DISA:
-               ret = tegra11x_powergate_partition(TEGRA_POWERGATE_VENC);
-               if (ret < 0)
-                       return ret;
-               ret = tegra11x_powergate_partition(TEGRA_POWERGATE_DISB);
-               if (ret < 0)
-                       return ret;
-
-               break;
-       case TEGRA_POWERGATE_3D:
-       case TEGRA_POWERGATE_HEG:
-       case TEGRA_POWERGATE_MPE:
-               ret = tegra11x_powergate_3d(id);
-               if (ret < 0)
-                       return ret;
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
        }
-       return 0;
-}
 
-static int tegra11x_check_partition_pug_seq(int id)
-{
-       int ret;
+       if (pg_ops->powergate_mc_disable)
+               return pg_ops->powergate_mc_disable(id);
+       else
+               WARN_ON_ONCE("This SOC does not support powergate mc disable");
 
-       switch (id) {
-       case TEGRA_POWERGATE_DISB:
-       case TEGRA_POWERGATE_VENC:
-               ret = tegra11x_unpowergate_partition(TEGRA_POWERGATE_DISA);
-               if (ret < 0)
-                       return ret;
-
-               break;
-       case TEGRA_POWERGATE_3D:
-       case TEGRA_POWERGATE_HEG:
-       case TEGRA_POWERGATE_MPE:
-               ret = tegra11x_unpowergate_3d(id);
-               if (ret < 0)
-                       return ret;
-       }
-       return 0;
+       return -EINVAL;
 }
-#endif
+EXPORT_SYMBOL(tegra_powergate_mc_disable);
 
-/*
- * Must be called with clk disabled. Powergates the partition only
- */
-int tegra_powergate_partition(int id)
+int tegra_powergate_mc_flush(int id)
 {
-       int ret;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool is_pg_skip;
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       is_pg_skip = skip_pg_check(id, false);
-       if (is_pg_skip)
-               return 0;
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
+       }
 
-       ret = tegra11x_check_partition_pg_seq(id);
-       if (ret)
-               return ret;
-#endif
-       /* If first clk_ptr is null, fill clk info for the partition */
-       if (powergate_partition_info[id].clk_info[0].clk_ptr)
-               get_clk_info(id);
+       if (pg_ops->powergate_mc_flush)
+               return pg_ops->powergate_mc_flush(id);
+       else
+               WARN_ON_ONCE("This SOC does not support powergate mc flush");
 
-       powergate_partition_assert_reset(id);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(tegra_powergate_mc_flush);
 
-       /* Powergating is done only if refcnt of all clks is 0 */
-       ret = is_partition_clk_disabled(id);
-       if (ret)
-               goto err_clk_off;
+int tegra_powergate_mc_flush_done(int id)
+{
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
-       ret = powergate_module(id);
-       if (ret)
-               goto err_power_off;
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("%s: invalid powergate id\n", __func__);
+               return -EINVAL;
+       }
 
-       return 0;
+       if (pg_ops->powergate_mc_flush_done)
+               return pg_ops->powergate_mc_flush_done(id);
+       else
+               WARN_ON_ONCE("This SOC does not support powergate mc flush done");
 
-err_power_off:
-       WARN(1, "Could not Powergate Partition %d", id);
-err_clk_off:
-       WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
-       return ret;
+       return -EINVAL;
 }
+EXPORT_SYMBOL(tegra_powergate_mc_flush_done);
 
-int tegra_powergate_partition_with_clk_off(int id)
+const char *tegra_powergate_get_name(int id)
 {
-       int ret = 0;
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       bool is_pg_skip;
-
-       is_pg_skip = skip_pg_check(id, false);
-       if (is_pg_skip)
-               return 0;
-#endif
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
-       /* Restrict functions use to selected partitions */
-       BUG_ON(id != TEGRA_POWERGATE_PCIE && id != TEGRA_POWERGATE_SATA);
-#elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
-       /* Restrict functions use to selected partitions */
-       BUG_ON(id != TEGRA_POWERGATE_PCIE);
-#endif
-       /* Disable clks for the partition */
-       partition_clk_disable(id);
-
-       ret = is_partition_clk_disabled(id);
-       if (ret)
-               goto err_powergate_clk;
+       if (!pg_ops) {
+               pr_info("This SOC doesn't support powergating\n");
+               return NULL;
+       }
 
-       ret = tegra_powergate_partition(id);
-       if (ret)
-               goto err_powergating;
+       if (id < 0 || id >= pg_ops->num_powerdomains) {
+               pr_info("invalid powergate id\n");
+               return "invalid";
+       }
 
-       return ret;
+       if (pg_ops->get_powergate_domain_name)
+               return pg_ops->get_powergate_domain_name(id);
+       else
+               WARN_ON_ONCE("This SOC does not support CPU powergate");
 
-err_powergate_clk:
-       WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
-err_powergating:
-       partition_clk_enable(id);
-       WARN(1, "Could not Powergate Partition %d", id);
-       return ret;
+       return "invalid";
 }
+EXPORT_SYMBOL(tegra_powergate_get_name);
 
-#if defined(DEBUG_T11x_POWERGATE)
-static void test_powergate_parts(void)
+int tegra_powergate_init_refcount(void)
 {
-       int i;
+       if ((!pg_ops) || (!pg_ops->powergate_init_refcount))
+               return 0;
 
-       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
-               tegra_powergate_partition(i);
+       return pg_ops->powergate_init_refcount();
 }
-#endif
 
-#if defined(DEBUG_T11x_POWERUNGATE)
-static void test_powerungate_parts(void)
+int __init tegra_powergate_init(void)
 {
-       int i;
+       switch (tegra_get_chip_id()) {
+               case TEGRA_CHIPID_TEGRA2:
+                       pg_ops = tegra2_powergate_init_chip_support();
+                       break;
 
-       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
-               tegra_unpowergate_partition(i);
-}
-#endif
+               case TEGRA_CHIPID_TEGRA3:
+                       pg_ops = tegra3_powergate_init_chip_support();
+                       break;
 
-#if defined(DEBUG_T11x_POWERGATE_CLK_OFF)
-static void test_powergate_clk_off_parts(void)
-{
-       int i;
+               case TEGRA_CHIPID_TEGRA11:
+                       pg_ops = tegra11x_powergate_init_chip_support();
+                       break;
 
-       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
-               tegra_powergate_partition_with_clk_off(i);
-}
-#endif
+               case TEGRA_CHIPID_TEGRA14:
+                       pg_ops = tegra14x_powergate_init_chip_support();
+                       break;
 
-#if defined(DEBUG_T11x_POWERUNGATE_CLK_OFF)
-static void test_unpowergate_clk_on_parts(void)
-{
-       int i;
+               case TEGRA_CHIPID_TEGRA12:
+                       pg_ops = tegra12x_powergate_init_chip_support();
+                       break;
 
-       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
-               tegra_unpowergate_partition_with_clk_on(i);
-}
-#endif
+               default:
+                       pg_ops = NULL;
+                       pr_info("%s: Unknown Tegra variant. Disabling powergate\n", __func__);
+                       break;
+       }
 
-const char *tegra_powergate_get_name(int id)
-{
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
-               return "invalid";
+       tegra_powergate_init_refcount();
+
+       pr_info("%s: DONE\n", __func__);
 
-       return powergate_partition_info[id].name;
+       return (pg_ops ? 0 : -EINVAL);
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -1658,15 +676,25 @@ static int powergate_show(struct seq_file *s, void *data)
 {
        int i;
        const char *name;
+       bool is_pg_skip;
+
+       if (!pg_ops) {
+               seq_printf(s, "This SOC doesn't support powergating\n");
+               return -EINVAL;
+       }
 
        seq_printf(s, " powergate powered\n");
        seq_printf(s, "------------------\n");
 
-       for (i = 0; i < tegra_num_powerdomains; i++) {
+       for (i = 0; i < pg_ops->num_powerdomains; i++) {
                name = tegra_powergate_get_name(i);
-               if (name)
+               if (name) {
+                       is_pg_skip = tegra_powergate_check_skip_list(i);
                        seq_printf(s, " %9s %7s\n", name,
-                               tegra_powergate_is_powered(i) ? "yes" : "no");
+                               (is_pg_skip ? "skip" : \
+                               (tegra_powergate_is_powered(i) ? \
+                               "yes" : "no")));
+               }
        }
 
        return 0;
@@ -1688,12 +716,10 @@ int __init tegra_powergate_debugfs_init(void)
 {
        struct dentry *d;
 
-       if (powergate_name) {
-               d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
-                       &powergate_fops);
-               if (!d)
-                       return -ENOMEM;
-       }
+       d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
+               &powergate_fops);
+       if (!d)
+               return -ENOMEM;
 
        return 0;
 }