diff options
author | Jin Qian <jqian@nvidia.com> | 2011-04-21 12:55:47 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:42:35 -0800 |
commit | b7bd555772b66ec17d0df4442d48c53575cbb6ad (patch) | |
tree | 2f7427414623f7f088dbda4feb6303492c219950 /arch/arm/mach-tegra/powergate.c | |
parent | 863101f343fa20b397146b90e1094c47b31e2a3c (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.c | 156 |
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; } |