summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/powergate.c
diff options
context:
space:
mode:
authorJin Qian <jqian@nvidia.com>2011-04-21 12:55:47 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:42:35 -0800
commitb7bd555772b66ec17d0df4442d48c53575cbb6ad (patch)
tree2f7427414623f7f088dbda4feb6303492c219950 /arch/arm/mach-tegra/powergate.c
parent863101f343fa20b397146b90e1094c47b31e2a3c (diff)
ARM: tegra: powergate: Add hot reset sequence for powergate
Original-Change-Id: I0e37b788c666ae99f46e7e6995c3700b0b23d412 Reviewed-on: http://git-master/r/29901 Tested-by: Jin Qian <jqian@nvidia.com> Reviewed-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Rebase-Id: R24afa8e7f33265722cee139f37ad53774d1dcb96
Diffstat (limited to 'arch/arm/mach-tegra/powergate.c')
-rw-r--r--arch/arm/mach-tegra/powergate.c156
1 files changed, 135 insertions, 21 deletions
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index ba3b06806909..22bfbd3860e9 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -38,9 +38,70 @@
#define PWRGATE_STATUS 0x38
+#define MC_CLIENT_HOTRESET_CTRL 0x200
+#define MC_CLIENT_HOTRESET_STAT 0x204
+
+typedef enum {
+ MC_CLIENT_AFI = 0,
+ MC_CLIENT_AVPC = 1,
+ MC_CLIENT_DC = 2,
+ MC_CLIENT_DCB = 3,
+ MC_CLIENT_EPP = 4,
+ MC_CLIENT_G2 = 5,
+ MC_CLIENT_HC = 6,
+ MC_CLIENT_HDA = 7,
+ MC_CLIENT_ISP = 8,
+ MC_CLIENT_MPCORE = 9,
+ MC_CLIENT_MPCORELP = 10,
+ MC_CLIENT_MPE = 11,
+ MC_CLIENT_NV = 12,
+ MC_CLIENT_NV2 = 13,
+ MC_CLIENT_PPCS = 14,
+ MC_CLIENT_SATA = 15,
+ MC_CLIENT_VDE = 16,
+ MC_CLIENT_VI = 17,
+ MC_CLIENT_LAST = -1,
+} MC_CLIENT;
+
static DEFINE_SPINLOCK(tegra_powergate_lock);
+#define MAX_HOTRESET_CLIENT_NUM 3
+
+typedef struct {
+ const char * name;
+ MC_CLIENT hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
+ /* add clocks for each partition*/
+} powergate_partition;
+
+static powergate_partition powergate_partition_info[TEGRA_NUM_POWERGATE] = {
+ [TEGRA_POWERGATE_CPU] = { "cpu0", {MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_L2] = { "l2", {MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_3D] = { "3d0",
+ {MC_CLIENT_NV, MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_PCIE] = { "pcie",
+ {MC_CLIENT_AFI, MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_VDEC] = { "vde",
+ {MC_CLIENT_VDE, MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_MPE] = { "mpe",
+ {MC_CLIENT_MPE, MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_VENC] = { "ve",
+ {MC_CLIENT_ISP, MC_CLIENT_VI, MC_CLIENT_LAST} },
+#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_A9LP] = { "a9lp", {MC_CLIENT_LAST}},
+ [TEGRA_POWERGATE_SATA] = { "sata",
+ {MC_CLIENT_SATA, MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_3D1] = { "3d1",
+ {MC_CLIENT_NV2, MC_CLIENT_LAST} },
+ [TEGRA_POWERGATE_HEG] = { "heg",
+ {MC_CLIENT_G2, MC_CLIENT_EPP, MC_CLIENT_HC} },
+#endif
+};
+
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
static u32 pmc_read(unsigned long reg)
{
@@ -52,6 +113,74 @@ static void pmc_write(u32 val, unsigned long reg)
writel(val, pmc + reg);
}
+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)
+static void mc_flush(int id)
+{
+ u32 idx, rst_ctrl, rst_stat;
+ 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);
+
+ do {
+ udelay(10);
+ rst_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
+ } while (!(rst_stat & (1 << mcClientBit)));
+ }
+}
+
+static void mc_flush_done(int id)
+{
+ u32 idx, rst_ctrl;
+ 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();
+}
+#else
+static void mc_flush(int id) {}
+static void mc_flush_done(int id) {}
+#endif
+
static int tegra_powergate_set(int id, bool new_state)
{
bool status;
@@ -86,6 +215,8 @@ int tegra_powergate_power_off(int id)
if (id < 0 || id >= TEGRA_NUM_POWERGATE)
return -EINVAL;
+ mc_flush(id);
+
return tegra_powergate_set(id, false);
}
@@ -170,6 +301,8 @@ int tegra_powergate_sequence_power_up(int id, struct clk *clk)
udelay(10);
tegra_periph_reset_deassert(clk);
+ mc_flush_done(id);
+
return 0;
err_clamp:
@@ -180,31 +313,12 @@ err_power:
return ret;
}
-static const char * const powergate_name[] = {
- [TEGRA_POWERGATE_CPU] = "cpu0",
- [TEGRA_POWERGATE_3D] = "3d0",
- [TEGRA_POWERGATE_VENC] = "venc",
- [TEGRA_POWERGATE_VDEC] = "vdec",
- [TEGRA_POWERGATE_PCIE] = "pcie",
- [TEGRA_POWERGATE_L2] = "l2",
- [TEGRA_POWERGATE_MPE] = "mpe",
-#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
- [TEGRA_POWERGATE_HEG] = "heg",
- [TEGRA_POWERGATE_SATA] = "sata",
- [TEGRA_POWERGATE_CPU1] = "cpu1",
- [TEGRA_POWERGATE_CPU2] = "cpu2",
- [TEGRA_POWERGATE_CPU3] = "cpu3",
- [TEGRA_POWERGATE_A9LP] = "a9lp",
- [TEGRA_POWERGATE_3D1] = "3d1",
-#endif
-};
-
const char* tegra_powergate_get_name(int id)
{
if (id < 0 || id >= TEGRA_NUM_POWERGATE)
return "invalid";
- return powergate_name[id];
+ return powergate_partition_info[id].name;
}
#ifdef CONFIG_DEBUG_FS
@@ -217,7 +331,7 @@ static int powergate_show(struct seq_file *s, void *data)
seq_printf(s, "------------------\n");
for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
- seq_printf(s, " %9s %7s\n", powergate_name[i],
+ seq_printf(s, " %9s %7s\n", powergate_partition_info[i].name,
tegra_powergate_is_powered(i) ? "yes" : "no");
return 0;
}