]> nv-tegra.nvidia Code Review - linux-3.10.git/commitdiff
platform: tegra210: add powergating driver
authorPrashant Gaikwad <pgaikwad@nvidia.com>
Thu, 13 Mar 2014 11:38:49 +0000 (04:38 -0700)
committerSachin Nikam <snikam@nvidia.com>
Fri, 2 May 2014 07:15:06 +0000 (00:15 -0700)
This change adds support to powergate and unpowergate
partitions on T210 SoC.

Bug 1482370

Change-Id: Id70318b0b4a4b9f2ba29c6cd26c48bccb8ccc85a
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-on: http://git-master/r/402459
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
arch/arm/mach-tegra/powergate-priv.h
arch/arm/mach-tegra/powergate.c
drivers/platform/tegra/Makefile
drivers/platform/tegra/powergate-t21x.c [new file with mode: 0644]
include/linux/tegra-powergate.h

index 946026ef56bab6ba8241f7c9205e10f3a937f118..edf283fe0c9cfc538ec1c13ddd639d0b5211ec9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2012-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -75,6 +75,7 @@ struct partition_clk_info {
 struct powergate_partition_info {
        const char *name;
        struct partition_clk_info clk_info[MAX_CLK_EN_NUM];
+       int refcount;
 };
 
 struct powergate_ops {
@@ -167,4 +168,12 @@ static inline struct powergate_ops *tegra14x_powergate_init_chip_support(void)
 }
 #endif
 
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+struct powergate_ops *tegra210_powergate_init_chip_support(void);
+#else
+static inline struct powergate_ops *tegra210_powergate_init_chip_support(void)
+{
+       return NULL;
+}
+#endif
 #endif /* __POWERGATE_PRIV_H__ */
index 1c41ae37ff64ce04d2da8ba3c13639d6ea07bd71..fd52080e165d74c9fbcc2e39e547cf632036dd83 100644 (file)
@@ -667,6 +667,10 @@ int __init tegra_powergate_init(void)
                        pg_ops = tegra12x_powergate_init_chip_support(); /* FIXME */
                        break;
 
+               case TEGRA_CHIPID_TEGRA21:
+                       pg_ops = tegra210_powergate_init_chip_support();
+                       break;
+
                default:
                        pg_ops = NULL;
                        pr_info("%s: Unknown Tegra variant. Disabling powergate\n", __func__);
index afc50edba5258736b6fc8436a99cef18fdc4a3c9..36909b130954c3bd8bc4c03d1aa9906a6230f7a2 100644 (file)
@@ -53,6 +53,7 @@ obj-y += powergate.o
 obj-y += powergate-ops-txx.o
 obj-y += powergate-ops-t1xx.o
 obj-$(CONFIG_ARCH_TEGRA_12x_SOC)        += powergate-t12x.o
+obj-$(CONFIG_ARCH_TEGRA_21x_SOC)        += powergate-t21x.o
 
 obj-y += dvfs.o
 obj-$(CONFIG_ARCH_TEGRA_13x_SOC) += tegra13_dvfs.o
diff --git a/drivers/platform/tegra/powergate-t21x.c b/drivers/platform/tegra/powergate-t21x.c
new file mode 100644 (file)
index 0000000..674b934
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/tegra-powergate.h>
+
+#include "../../../arch/arm/mach-tegra/powergate-priv.h"
+#include "../../../arch/arm/mach-tegra/powergate-ops-t1xx.h"
+#include "../../../arch/arm/mach-tegra/powergate-ops-txx.h"
+#include "../../../arch/arm/mach-tegra/dvfs.h"
+
+enum mc_client {
+       MC_CLIENT_AFI           = 0,
+       MC_CLIENT_AVPC          = 1,
+       MC_CLIENT_DC            = 2,
+       MC_CLIENT_DCB           = 3,
+       MC_CLIENT_HC            = 6,
+       MC_CLIENT_HDA           = 7,
+       MC_CLIENT_ISP2          = 8,
+       MC_CLIENT_NVENC         = 11,
+       MC_CLIENT_SATA          = 15,
+       MC_CLIENT_VI            = 17,
+       MC_CLIENT_VIC           = 18,
+       MC_CLIENT_XUSB_HOST     = 19,
+       MC_CLIENT_XUSB_DEV      = 20,
+       MC_CLIENT_BPMP          = 21,
+       MC_CLIENT_TSEC          = 22,
+       MC_CLIENT_SDMMC1        = 29,
+       MC_CLIENT_SDMMC2        = 30,
+       MC_CLIENT_SDMMC3        = 31,
+       MC_CLIENT_SDMMC4        = 32,
+       MC_CLIENT_ISP2B         = 33,
+       MC_CLIENT_GPU           = 34,
+       MC_CLIENT_NVDEC         = 37,
+       MC_CLIENT_APE           = 38,
+       MC_CLIENT_SE            = 39,
+       MC_CLIENT_NVJPG         = 40,
+       MC_CLIENT_TSECB         = 45,
+       MC_CLIENT_LAST          = -1,
+};
+
+struct tegra210_mc_client_info {
+       enum mc_client  hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
+};
+
+static struct tegra210_mc_client_info tegra210_pg_mc_info[] = {
+       [TEGRA_POWERGATE_CRAIL] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_VE] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_ISP2,
+                       [1] = MC_CLIENT_VI,
+                       [2] = MC_CLIENT_LAST,
+               },
+       },
+#ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
+       [TEGRA_POWERGATE_PCIE] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_AFI,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_HAS_SATA
+       [TEGRA_POWERGATE_SATA] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_SATA,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+#endif
+       [TEGRA_POWERGATE_NVENC] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_NVENC,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_SOR] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_DISA] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_DC,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_DISB] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_DCB,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_XUSBA] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_XUSBB] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_XUSB_DEV,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_XUSBC] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_XUSB_HOST,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+#ifdef CONFIG_ARCH_TEGRA_VIC
+       [TEGRA_POWERGATE_VIC] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_VIC,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+#endif
+       [TEGRA_POWERGATE_NVDEC] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_NVDEC,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_NVJPG] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_NVJPG,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_APE] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_APE,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_VE2] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_ISP2B,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+       [TEGRA_POWERGATE_GPU] = {
+               .hot_reset_clients = {
+                       [0] = MC_CLIENT_GPU,
+                       [1] = MC_CLIENT_LAST,
+               },
+       },
+};
+
+static struct powergate_partition_info tegra210_pg_partition_info[] = {
+       [TEGRA_POWERGATE_VE] = {
+               .name = "ve",
+               .clk_info = {
+                       [0] = { .clk_name = "ispa", .clk_type = CLK_AND_RST },
+                       [1] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
+                       [2] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
+                       [3] = { .clk_name = "vi_i2c", .clk_type = CLK_AND_RST },
+                       [4] = { .clk_name = "cilab", .clk_type = CLK_ONLY },
+                       [5] = { .clk_name = "cilcd", .clk_type = CLK_ONLY },
+                       [6] = { .clk_name = "cile", .clk_type = CLK_ONLY },
+               },
+       },
+#ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
+       [TEGRA_POWERGATE_PCIE] = {
+               .name = "pcie",
+               .clk_info = {
+                       [0] = { .clk_name = "afi", .clk_type = CLK_AND_RST },
+                       [1] = { .clk_name = "pcie", .clk_type = CLK_AND_RST },
+                       [2] = { .clk_name = "cml0", .clk_type = CLK_ONLY },
+                       [3] = { .clk_name = "pciex", .clk_type = RST_ONLY },
+               },
+       },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_HAS_SATA
+       [TEGRA_POWERGATE_SATA] = {
+               .name = "sata",
+               .clk_info = {
+                       [0] = { .clk_name = "sata", .clk_type = CLK_AND_RST },
+                       [1] = { .clk_name = "sata_oob", .clk_type = CLK_AND_RST },
+                       [2] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
+                       [3] = { .clk_name = "sata_cold", .clk_type = RST_ONLY },
+               },
+       },
+#endif
+       [TEGRA_POWERGATE_NVENC] = {
+               .name = "nvenc",
+               .clk_info = {
+                       [0] = { .clk_name = "msenc.cbus", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_SOR] = {
+               .name = "sor",
+               .clk_info = {
+                       [0] = { .clk_name = "sor0", .clk_type = CLK_AND_RST },
+                       [1] = { .clk_name = "dsia", .clk_type = CLK_AND_RST },
+                       [2] = { .clk_name = "dsib", .clk_type = CLK_AND_RST },
+                       [3] = { .clk_name = "hdmi", .clk_type = CLK_AND_RST },
+                       [4] = { .clk_name = "mipi-cal", .clk_type = CLK_AND_RST },
+                       [5] = { .clk_name = "dpaux", .clk_type = CLK_ONLY },
+               },
+       },
+       [TEGRA_POWERGATE_DISA] = {
+               .name = "disa",
+               .clk_info = {
+                       [0] = { .clk_name = "disp1", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_DISB] = {
+               .name = "disb",
+               .clk_info = {
+                       [0] = { .clk_name = "disp2", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_XUSBA] = {
+               .name = "xusba",
+               .clk_info = {
+                       [0] = { .clk_name = "xusb_ss", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_XUSBB] = {
+               .name = "xusbb",
+               .clk_info = {
+                       [0] = { .clk_name = "xusb_dev", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_XUSBC] = {
+               .name = "xusbc",
+               .clk_info = {
+                       [0] = { .clk_name = "xusb_host", .clk_type = CLK_AND_RST },
+               },
+       },
+#ifdef CONFIG_ARCH_TEGRA_VIC
+       [TEGRA_POWERGATE_VIC] = {
+               .name = "vic",
+               .clk_info = {
+                       [0] = { .clk_name = "vic03.cbus", .clk_type = CLK_AND_RST },
+               },
+       },
+#endif
+       [TEGRA_POWERGATE_NVDEC] = {
+               .name = "nvdec",
+               .clk_info = {
+                       [0] = { .clk_name = "nvdec", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_NVJPG] = {
+               .name = "nvjpg",
+               .clk_info = {
+                       [0] = { .clk_name = "nvjpg", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_APE] = {
+               .name = "ape",
+               .clk_info = {
+                       [0] = { .clk_name = "ape", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_VE2] = {
+               .name = "ve2",
+               .clk_info = {
+                       [0] = { .clk_name = "ispb", .clk_type = CLK_AND_RST },
+               },
+       },
+       [TEGRA_POWERGATE_GPU] = {
+               .name = "gpu",
+               .clk_info = {
+                       [0] = { .clk_name = "gpu_ref", .clk_type = CLK_AND_RST },
+                       [1] = { .clk_name = "pll_p_out5", .clk_type = CLK_ONLY },
+               },
+       },
+};
+
+struct mc_client_hotreset_reg {
+       u32 control_reg;
+       u32 status_reg;
+};
+
+static struct mc_client_hotreset_reg tegra210_mc_reg[] = {
+       [0] = { .control_reg = 0x200, .status_reg = 0x204 },
+       [1] = { .control_reg = 0x970, .status_reg = 0x974 },
+};
+
+#define PMC_GPU_RG_CONTROL             0x2d4
+
+static DEFINE_SPINLOCK(tegra210_pg_lock);
+
+static struct dvfs_rail *gpu_rail;
+
+#define HOTRESET_READ_COUNTS           5
+
+static bool tegra210_pg_hotreset_check(u32 status_reg, u32 *status)
+{
+       int i;
+       u32 curr_status;
+       u32 prev_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tegra210_pg_lock, flags);
+       prev_status = mc_read(status_reg);
+       for (i = 0; i < HOTRESET_READ_COUNTS; i++) {
+               curr_status = mc_read(status_reg);
+               if (curr_status != prev_status) {
+                       spin_unlock_irqrestore(&tegra210_pg_lock, flags);
+                       return false;
+               }
+       }
+       *status = curr_status;
+       spin_unlock_irqrestore(&tegra210_pg_lock, flags);
+
+       return 0;
+}
+
+static int tegra210_pg_mc_flush(int id)
+{
+       u32 idx, rst_control, rst_status;
+       u32 rst_control_reg, rst_status_reg;
+       enum mc_client mc_client_bit;
+       unsigned long flags;
+       bool ret;
+       int reg_idx;
+
+       for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
+               mc_client_bit = tegra210_pg_mc_info[id].hot_reset_clients[idx];
+               if (mc_client_bit == MC_CLIENT_LAST)
+                       break;
+
+               reg_idx = mc_client_bit / 32;
+               mc_client_bit %= 32;
+               rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
+               rst_status_reg = tegra210_mc_reg[reg_idx].status_reg;
+
+               spin_lock_irqsave(&tegra210_pg_lock, flags);
+               rst_control = mc_read(rst_control_reg);
+               rst_control |= (1 << mc_client_bit);
+               mc_write(rst_control, rst_control_reg);
+               spin_unlock_irqrestore(&tegra210_pg_lock, flags);
+
+               do {
+                       udelay(10);
+                       rst_status = 0;
+                       ret = tegra210_pg_hotreset_check(rst_status_reg,
+                                                               &rst_status);
+                       if (!ret)
+                               continue;
+               } while (!(rst_status & (1 << mc_client_bit)));
+       }
+
+       return 0;
+}
+
+static int tegra210_pg_mc_flush_done(int id)
+{
+       u32 idx, rst_control, rst_control_reg;
+       enum mc_client mc_client_bit;
+       unsigned long flags;
+       int reg_idx;
+
+       for (idx = 0; idx <= MAX_HOTRESET_CLIENT_NUM; idx++) {
+               mc_client_bit = tegra210_pg_mc_info[id].hot_reset_clients[idx];
+               if (mc_client_bit == MC_CLIENT_LAST)
+                       break;
+
+               reg_idx = mc_client_bit / 32;
+               rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
+
+               spin_lock_irqsave(&tegra210_pg_lock, flags);
+               rst_control = mc_read(rst_control_reg);
+               rst_control &= ~(1 << mc_client_bit);
+               mc_write(rst_control, rst_control_reg);
+               spin_unlock_irqrestore(&tegra210_pg_lock, flags);
+
+       }
+       wmb();
+
+       return 0;
+}
+
+static int tegra210_pg_powergate(int id)
+{
+       struct powergate_partition_info *partition =
+                               &tegra210_pg_partition_info[id];
+
+       if (partition->refcount-- <= 0)
+               return 0;
+
+       if (!tegra_powergate_is_powered(id)) {
+               WARN(1, "Partition %s already powergated, refcount \
+                               and status mismatch\n", partition->name);
+               return 0;
+       }
+
+       return tegra1xx_powergate(id, partition);
+}
+
+static int tegra210_pg_unpowergate(int id)
+{
+       struct powergate_partition_info *partition =
+                               &tegra210_pg_partition_info[id];
+
+       if (partition->refcount++ > 0)
+               return 0;
+
+       if (tegra_powergate_is_powered(id)) {
+               WARN(1, "Partition %s is already unpowergated, refcount \
+                               and status mismatch\n", partition->name);
+               return 0;
+       }
+
+       return tegra1xx_unpowergate(id, partition);
+}
+
+static int tegra210_pg_gpu_powergate(int id)
+{
+       int ret;
+       struct powergate_partition_info *partition =
+                               &tegra210_pg_partition_info[id];
+
+       if (partition->refcount-- <= 0)
+               return 0;
+
+       if (!tegra_powergate_is_powered(id)) {
+               WARN(1, "GPU rail is already off, \
+                                       refcount and status mismatch\n");
+               return 0;
+       }
+
+       if (!partition->clk_info[0].clk_ptr)
+               get_clk_info(partition);
+
+       tegra_powergate_mc_flush(id);
+
+       udelay(10);
+
+       powergate_partition_assert_reset(partition);
+
+       udelay(10);
+
+       pmc_write(0x1, PMC_GPU_RG_CONTROL);
+
+       udelay(10);
+
+       partition_clk_disable(partition);
+
+       udelay(10);
+
+       if (gpu_rail) {
+               ret = tegra_dvfs_rail_power_down(gpu_rail);
+               if (ret) {
+                       WARN(1, "Could not power down GPU rail\n");
+                       return ret;
+               }
+       } else {
+               pr_info("No GPU regulator?\n");
+       }
+
+       return 0;
+}
+
+static int tegra210_pg_gpu_unpowergate(int id)
+{
+       int ret = 0;
+       bool first = false;
+       struct powergate_partition_info *partition =
+                               &tegra210_pg_partition_info[id];
+
+       if (partition->refcount++ > 0)
+               return 0;
+
+       if (!gpu_rail) {
+               gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu");
+               if (IS_ERR_OR_NULL(gpu_rail)) {
+                       WARN(1, "No GPU regulator?\n");
+                       goto err_power;
+               }
+               first = true;
+       } else {
+               if (tegra_powergate_is_powered(id)) {
+                       WARN(1, "GPU rail is already on, \
+                                       refcount and status mismatch\n");
+                       return 0;
+               }
+
+               ret = tegra_dvfs_rail_power_up(gpu_rail);
+               if (ret)
+                       goto err_power;
+       }
+
+       if (!partition->clk_info[0].clk_ptr)
+               get_clk_info(partition);
+
+       if (!first) {
+               ret = partition_clk_enable(partition);
+               if (ret)
+                       goto err_clk_on;
+       }
+
+       udelay(10);
+
+       powergate_partition_assert_reset(partition);
+
+       pmc_write(0, PMC_GPU_RG_CONTROL);
+
+       udelay(10);
+
+       powergate_partition_deassert_reset(partition);
+
+       udelay(10);
+
+       tegra_powergate_mc_flush_done(id);
+
+       udelay(10);
+
+       return 0;
+
+err_clk_on:
+       powergate_module(id);
+err_power:
+       WARN(1, "Could not turn on GPU rail\n");
+       return ret;
+}
+
+static int tegra210_pg_powergate_sor(int id)
+{
+       int ret;
+
+       ret = tegra210_pg_powergate(id);
+       if (ret)
+               return ret;
+
+       ret = tegra_powergate_partition(TEGRA_POWERGATE_SOR);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int tegra210_pg_unpowergate_sor(int id)
+{
+       int ret;
+
+       ret = tegra_unpowergate_partition(TEGRA_POWERGATE_SOR);
+       if (ret)
+               return ret;
+
+       ret = tegra210_pg_unpowergate(id);
+       if (ret) {
+               tegra_powergate_partition(TEGRA_POWERGATE_SOR);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int tegra210_pg_nvdec_powergate(int id)
+{
+       tegra210_pg_powergate(TEGRA_POWERGATE_NVDEC);
+       tegra_powergate_partition(TEGRA_POWERGATE_NVJPG);
+
+       return 0;
+}
+
+static int tegra210_pg_nvdec_unpowergate(int id)
+{
+       tegra_unpowergate_partition(TEGRA_POWERGATE_NVJPG);
+       tegra210_pg_unpowergate(TEGRA_POWERGATE_NVDEC);
+
+       return 0;
+}
+
+static int tegra210_pg_powergate_partition(int id)
+{
+       int ret;
+
+       switch (id) {
+               case TEGRA_POWERGATE_GPU:
+                       ret = tegra210_pg_gpu_powergate(id);
+                       break;
+               case TEGRA_POWERGATE_DISA:
+               case TEGRA_POWERGATE_DISB:
+               case TEGRA_POWERGATE_VE:
+                       ret = tegra210_pg_powergate_sor(id);
+                       break;
+               case TEGRA_POWERGATE_NVDEC:
+                       ret = tegra210_pg_nvdec_powergate(id);
+                       break;
+               default:
+                       ret = tegra210_pg_powergate(id);
+       }
+
+       return ret;
+}
+
+static int tegra210_pg_unpowergate_partition(int id)
+{
+       int ret;
+
+       switch (id) {
+               case TEGRA_POWERGATE_GPU:
+                       ret = tegra210_pg_gpu_unpowergate(id);
+                       break;
+               case TEGRA_POWERGATE_DISA:
+               case TEGRA_POWERGATE_DISB:
+               case TEGRA_POWERGATE_VE:
+                       ret = tegra210_pg_unpowergate_sor(id);
+                       break;
+               case TEGRA_POWERGATE_NVDEC:
+                       ret = tegra210_pg_nvdec_unpowergate(id);
+                       break;
+               default:
+                       ret = tegra210_pg_unpowergate(id);
+       }
+
+       return ret;
+}
+
+static int tegra210_pg_powergate_clk_off(int id)
+{
+       BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
+
+       return tegraxx_powergate_partition_with_clk_off(id,
+                       &tegra210_pg_partition_info[id]);
+}
+
+static int tegra210_pg_unpowergate_clk_on(int id)
+{
+       BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
+
+       return tegraxx_unpowergate_partition_with_clk_on(id,
+                       &tegra210_pg_partition_info[id]);
+}
+
+static const char *tegra210_pg_get_name(int id)
+{
+       return tegra210_pg_partition_info[id].name;
+}
+
+static spinlock_t *tegra210_pg_get_lock(void)
+{
+       return &tegra210_pg_lock;
+}
+
+static bool tegra210_pg_skip(int id)
+{
+       switch (id) {
+#ifdef CONFIG_ARCH_TEGRA_HAS_SATA
+               case TEGRA_POWERGATE_SATA:
+                       return true;
+#endif
+               default:
+                       return false;
+       }
+}
+
+static bool tegra210_pg_is_powered(int id)
+{
+       u32 status = 0;
+
+       if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
+               if (gpu_rail)
+                       status = tegra_dvfs_is_rail_up(gpu_rail);
+       } else {
+               status = pmc_read(PWRGATE_STATUS) & (1 << id);
+       }
+
+       return !!status;
+}
+
+static int tegra210_pg_init_refcount(void)
+{
+       int i;
+
+       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
+               if (tegra_powergate_is_powered(i))
+                       tegra210_pg_partition_info[i].refcount = 1;
+
+       return 0;
+}
+
+static struct powergate_ops tegra210_pg_ops = {
+       .soc_name = "tegra210",
+
+       .num_powerdomains = TEGRA_NUM_POWERGATE,
+
+       .get_powergate_lock = tegra210_pg_get_lock,
+       .get_powergate_domain_name = tegra210_pg_get_name,
+
+       .powergate_partition = tegra210_pg_powergate_partition,
+       .unpowergate_partition = tegra210_pg_unpowergate_partition,
+
+       .powergate_partition_with_clk_off = tegra210_pg_powergate_clk_off,
+       .unpowergate_partition_with_clk_on = tegra210_pg_unpowergate_clk_on,
+
+       .powergate_mc_flush = tegra210_pg_mc_flush,
+       .powergate_mc_flush_done = tegra210_pg_mc_flush_done,
+
+       .powergate_skip = tegra210_pg_skip,
+
+       .powergate_is_powered = tegra210_pg_is_powered,
+
+       .powergate_init_refcount = tegra210_pg_init_refcount,
+};
+
+struct powergate_ops *tegra210_powergate_init_chip_support(void)
+{
+       return &tegra210_pg_ops;
+}
index 7c052c5183515b8b75f43cd2fed0125392d047e5..aa4c7dc58e498b9ceac36e0d4f51d5f63877bce1 100644 (file)
@@ -2,7 +2,7 @@
  * drivers/regulator/tegra-regulator.c
  *
  * Copyright (c) 2010 Google, Inc
- * Copyright (C) 2011-2014 NVIDIA Corporation.
+ * Copyright (C) 2011-2014 NVIDIA Corporation. All rights reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
 #define TEGRA_POWERGATE_3D0    TEGRA_POWERGATE_3D
 #define TEGRA_POWERGATE_GPU    TEGRA_POWERGATE_3D
 #define TEGRA_POWERGATE_VENC   2
+#define TEGRA_POWERGATE_VE     TEGRA_POWERGATE_VENC
 #define TEGRA_POWERGATE_PCIE   3
 #define TEGRA_POWERGATE_VDEC   4
+#define TEGRA_POWERGATE_NVDEC  TEGRA_POWERGATE_VDEC
 #if defined(CONFIG_ARCH_TEGRA_14x_SOC)
 #define TEGRA_POWERGATE_C0L2   5
 #else
 #define TEGRA_POWERGATE_L2     5
 #endif
 #define TEGRA_POWERGATE_MPE    6
+#define TEGRA_POWERGATE_NVENC  TEGRA_POWERGATE_MPE
 #define TEGRA_POWERGATE_HEG    7
 #define TEGRA_POWERGATE_SATA   8
 #define TEGRA_POWERGATE_CPU1   9
 #define TEGRA_POWERGATE_IRAM   24
 #endif
 
+#if defined(CONFIG_ARCH_TEGRA_21x_SOC)
+#define TEGRA_POWERGATE_VE2    24
+#define TEGRA_POWERGATE_NVJPG  25
+#define TEGRA_POWERGATE_APE    26
+#endif
+
 #define TEGRA_POWERGATE_CPU    TEGRA_POWERGATE_CPU0
 
 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
@@ -76,6 +85,8 @@
 #define TEGRA_NUM_POWERGATE    14
 #elif defined(CONFIG_ARCH_TEGRA_11x_SOC)
 #define TEGRA_NUM_POWERGATE    23
+#elif defined(CONFIG_ARCH_TGRA_21x_SOC)
+#define TEGRA_NUM_POWERGATE    27
 #else
 #define TEGRA_NUM_POWERGATE    24
 #endif