summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/powergate-t12x.c
diff options
context:
space:
mode:
authorChao Xu <cxu@nvidia.com>2013-07-18 11:21:18 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:32:50 -0700
commit4f628c0db3cf0f8b489de09e0d5cb535c05cc619 (patch)
tree8020c9b37eb6d003123be1aec94a2d3d2049642c /arch/arm/mach-tegra/powergate-t12x.c
parentc0cced752383dd16652a84e65aff0e94ebd0a9e2 (diff)
ARM: tegra: powergate: Add t124 display powergate support
T124 display powergating was changed in the following way: 1. New SOR partition including all SOR units (hdmi, dsi, edp lvds etc). So this partition needs to be powered whenever one of DC enabled. 2. DISPA partition cannot be power down if DISPB is being used. bug 1324532. Change-Id: Ibcef6822cf75aface1f04377247d3d3d2d16c389 Signed-off-by: Chao Xu <cxu@nvidia.com> Reviewed-on: http://git-master/r/251428
Diffstat (limited to 'arch/arm/mach-tegra/powergate-t12x.c')
-rw-r--r--arch/arm/mach-tegra/powergate-t12x.c110
1 files changed, 80 insertions, 30 deletions
diff --git a/arch/arm/mach-tegra/powergate-t12x.c b/arch/arm/mach-tegra/powergate-t12x.c
index ad3632da7697..e8064461ffa1 100644
--- a/arch/arm/mach-tegra/powergate-t12x.c
+++ b/arch/arm/mach-tegra/powergate-t12x.c
@@ -162,17 +162,12 @@ static struct powergate_partition_info tegra12x_powergate_partition_info[] = {
.name = "disa",
.clk_info = {
[0] = { .clk_name = "disp1", .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 = "csi", .clk_type = CLK_AND_RST },
- [4] = { .clk_name = "mipi-cal", .clk_type = CLK_AND_RST },
},
},
[TEGRA_POWERGATE_DISB] = {
.name = "disb",
.clk_info = {
[0] = { .clk_name = "disp2", .clk_type = CLK_AND_RST },
- [1] = { .clk_name = "hdmi", .clk_type = CLK_AND_RST },
},
},
[TEGRA_POWERGATE_XUSBA] = {
@@ -219,6 +214,11 @@ static struct powergate_partition_info tegra12x_powergate_partition_info[] = {
.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 },
},
},
#ifdef CONFIG_ARCH_TEGRA_VIC
@@ -231,9 +231,6 @@ static struct powergate_partition_info tegra12x_powergate_partition_info[] = {
#endif
};
-static atomic_t ref_count_a = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISA */
-static atomic_t ref_count_b = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISB */
-
#define MC_CLIENT_HOTRESET_CTRL 0x200
#define MC_CLIENT_HOTRESET_STAT 0x204
#define MC_CLIENT_HOTRESET_CTRL_1 0x970
@@ -500,23 +497,86 @@ err_power:
return ret;
}
-int tegra12x_powergate_partition(int id)
+static atomic_t ref_count_disp = ATOMIC_INIT(0);
+
+#define CHECK_RET(x) \
+ do { \
+ ret = (x); \
+ if (ret != 0) \
+ return ret; \
+ } while (0)
+
+
+static inline int tegra12x_powergate(int id)
+{
+ if (tegra_powergate_is_powered(id))
+ return tegra1xx_powergate(id,
+ &tegra12x_powergate_partition_info[id]);
+ return 0;
+}
+
+static inline int tegra12x_unpowergate(int id)
+{
+ if (!tegra_powergate_is_powered(id))
+ return tegra1xx_unpowergate(id,
+ &tegra12x_powergate_partition_info[id]);
+ return 0;
+}
+
+
+static int tegra12x_disp_powergate(int id)
+{
+ int ret = 0;
+ int ref_count = atomic_read(&ref_count_disp);
+
+ if (!TEGRA_IS_DISP_POWERGATE_ID(id))
+ return -EINVAL;
+
+ if (id == TEGRA_POWERGATE_DISA) {
+ ref_count = atomic_dec_return(&ref_count_disp);
+ WARN(ref_count < 0, "DISP ref count underflow");
+ } else
+ CHECK_RET(tegra12x_powergate(TEGRA_POWERGATE_DISB));
+
+ if (ref_count <= 0 &&
+ !tegra_powergate_is_powered(TEGRA_POWERGATE_DISB)) {
+ CHECK_RET(tegra12x_powergate(TEGRA_POWERGATE_SOR));
+ CHECK_RET(tegra12x_powergate(TEGRA_POWERGATE_DISA));
+ }
+ return ret;
+}
+
+static int tegra12x_disp_unpowergate(int id)
{
int ret;
- WARN_ONCE(atomic_read(&ref_count_a) < 0, "ref count A underflow");
- WARN_ONCE(atomic_read(&ref_count_b) < 0, "ref count B underflow");
+ if (!TEGRA_IS_DISP_POWERGATE_ID(id))
+ return -EINVAL;
- if (id == TEGRA_POWERGATE_DISA && atomic_dec_return(&ref_count_a) != 0)
- return 0;
- else if (id == TEGRA_POWERGATE_DISB &&
- atomic_dec_return(&ref_count_b) != 0)
- return 0;
+ /* always unpowergate dispA and SOR partition */
+ CHECK_RET(tegra12x_unpowergate(TEGRA_POWERGATE_DISA));
+ CHECK_RET(tegra12x_unpowergate(TEGRA_POWERGATE_SOR));
+
+ if (id == TEGRA_POWERGATE_DISA)
+ WARN_ONCE(atomic_inc_return(&ref_count_disp) > 1,
+ "disp ref count overflow");
+ else
+ ret = tegra12x_unpowergate(TEGRA_POWERGATE_DISB);
+
+ return ret;
+}
+
+
+int tegra12x_powergate_partition(int id)
+{
+ int ret;
if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
ret = tegra12x_gpu_powergate(id,
&tegra12x_powergate_partition_info[id]);
- } else {
+ } else if (TEGRA_IS_DISP_POWERGATE_ID(id))
+ ret = tegra12x_disp_powergate(id);
+ else {
/* call common power-gate API for t1xx */
ret = tegra1xx_powergate(id,
&tegra12x_powergate_partition_info[id]);
@@ -529,19 +589,12 @@ int tegra12x_unpowergate_partition(int id)
{
int ret;
- WARN_ONCE(atomic_read(&ref_count_a) < 0, "ref count A underflow");
- WARN_ONCE(atomic_read(&ref_count_b) < 0, "ref count B underflow");
-
- if (id == TEGRA_POWERGATE_DISA && atomic_inc_return(&ref_count_a) != 1)
- return 0;
- else if (id == TEGRA_POWERGATE_DISB &&
- atomic_inc_return(&ref_count_b) != 1)
- return 0;
-
if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
ret = tegra12x_gpu_unpowergate(id,
&tegra12x_powergate_partition_info[id]);
- } else {
+ } else if (TEGRA_IS_DISP_POWERGATE_ID(id))
+ ret = tegra12x_disp_unpowergate(id);
+ else {
ret = tegra1xx_unpowergate(id,
&tegra12x_powergate_partition_info[id]);
}
@@ -580,15 +633,12 @@ bool tegra12x_powergate_skip(int id)
switch (id) {
case TEGRA_POWERGATE_VDEC:
case TEGRA_POWERGATE_VENC:
- case TEGRA_POWERGATE_DISA:
- case TEGRA_POWERGATE_DISB:
case TEGRA_POWERGATE_XUSBA:
case TEGRA_POWERGATE_XUSBB:
case TEGRA_POWERGATE_XUSBC:
#ifdef CONFIG_ARCH_TEGRA_HAS_SATA
case TEGRA_POWERGATE_SATA:
#endif
- case TEGRA_POWERGATE_SOR:
return true;
default: