msm: ocmem: Ocmem staging while turning memory on

The HPG is updated to power up memories one cbc at a time
and stagger the core and peripheral power controls. Update
the ocmem driver to reflect this staggering.

CRs-Fixed: 478540
Change-Id: I4bfe06500af50f254e9efddb8f5c8b79059a1fc9
Signed-off-by: Neeti Desai <neetid@codeaurora.org>
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 4ea1de9..4ed4eda 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -97,9 +97,12 @@
 #define REGION_SLEEP_PERI_ON 0x00007777
 
 #define REGION_DEFAULT_OFF REGION_SLEEP_NO_RETENTION
-#define REGION_DEFAULT_ON REGION_NORMAL_PASSTHROUGH
+#define REGION_DEFAULT_ON REGION_FORCE_CORE_ON
 #define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
 
+#define REGION_STAGING_SET(x) (REGION_SLEEP_PERI_OFF & (0xF << (x * 0x4)))
+#define REGION_ON_SET(x) (REGION_DEFAULT_OFF & (0xF << (x * 0x4)))
+
 enum rpm_macro_state {
 	rpm_macro_off = 0x0,
 	rpm_macro_retain,
@@ -195,6 +198,51 @@
 
 	return state;
 }
+#ifndef CONFIG_MSM_OCMEM_POWER_DISABLE
+static int commit_region_staging(unsigned region_num, unsigned start_m,
+				unsigned new_state)
+{
+	int rc = -1;
+	unsigned state = 0x0;
+	unsigned read_state = 0x0;
+	unsigned curr_state = 0x0;
+
+	if (region_num >= num_regions)
+		return -EINVAL;
+
+	if (rpm_power_control)
+		return 0;
+	else {
+		if (new_state != REGION_DEFAULT_OFF) {
+			curr_state = read_region_state(region_num);
+			state = curr_state | REGION_STAGING_SET(start_m);
+			rc = ocmem_write(state,
+				ocmem_base + PSCGC_CTL_n(region_num));
+			/* Barrier to commit the region state */
+			mb();
+			read_state = read_region_state(region_num);
+			if (new_state == REGION_DEFAULT_ON) {
+				curr_state = read_region_state(region_num);
+				state = curr_state ^ REGION_ON_SET(start_m);
+				rc = ocmem_write(state,
+					ocmem_base + PSCGC_CTL_n(region_num));
+				/* Barrier to commit the region state */
+				mb();
+				read_state = read_region_state(region_num);
+			}
+		} else {
+			curr_state = read_region_state(region_num);
+			state = curr_state ^ REGION_STAGING_SET(start_m);
+			rc = ocmem_write(state,
+				ocmem_base + PSCGC_CTL_n(region_num));
+			/* Barrier to commit the region state */
+			mb();
+			read_state = read_region_state(region_num);
+		}
+	}
+	return 0;
+}
+#endif
 
 /* Returns the current state of a OCMEM macro that belongs to a region */
 static int read_macro_state(unsigned region_num, unsigned macro_num)
@@ -948,9 +996,11 @@
 			apply_macro_vote(id, i, j,
 				hw_macro_state(new_state));
 			aggregate_macro_state(i, j);
+			commit_region_staging(i, j, new_state);
 		}
 		aggregate_region_state(i);
-		commit_region_state(i);
+		if (rpm_power_control)
+			commit_region_state(i);
 		len -= region_size;
 
 		/* If we voted ON/retain the banks must never be OFF */
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 8afe695..a14b960 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1515,6 +1515,18 @@
 				pr_err("ocmem: Failed to unmap %p\n", req);
 				goto free_fail;
 			}
+			/* Turn off the memory */
+			if (req->req_sz != 0) {
+
+				offset = phys_to_offset(req->req_start);
+				rc = ocmem_memory_off(req->owner, offset,
+					req->req_sz);
+
+				if (rc < 0) {
+					pr_err("Failed to switch OFF memory macros\n");
+					goto free_fail;
+				}
+			}
 
 			rc = do_free(req);
 			if (rc < 0) {
@@ -1525,21 +1537,19 @@
 			pr_debug("request %p was already shrunk to 0\n", req);
 	}
 
-	/* Turn off the memory */
-	if (req->req_sz != 0) {
+	if (!TEST_STATE(req, R_FREE)) {
+		/* Turn off the memory */
+		if (req->req_sz != 0) {
 
-		offset = phys_to_offset(req->req_start);
+			offset = phys_to_offset(req->req_start);
+			rc = ocmem_memory_off(req->owner, offset, req->req_sz);
 
-		rc = ocmem_memory_off(req->owner, offset, req->req_sz);
-
-		if (rc < 0) {
-			pr_err("Failed to switch OFF memory macros\n");
-			goto free_fail;
+			if (rc < 0) {
+				pr_err("Failed to switch OFF memory macros\n");
+				goto free_fail;
+			}
 		}
 
-	}
-
-	if (!TEST_STATE(req, R_FREE)) {
 		/* free the allocation */
 		rc = do_free(req);
 		if (rc < 0)