Merge "coresight: resolve pcsave and etm tracing concurreny issue"
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 50bae55..c961713 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -195,6 +195,7 @@
 	struct wake_lock		wake_lock;
 	int				cpu;
 	uint8_t				arch;
+	bool				enable;
 	uint8_t				nr_addr_cmp;
 	uint8_t				nr_cntr;
 	uint8_t				nr_ext_inp;
@@ -203,7 +204,6 @@
 	uint8_t				reset;
 	uint32_t			mode;
 	uint32_t			ctrl;
-	uint8_t				ctrl_pwrdwn;
 	uint32_t			trigger_event;
 	uint32_t			startstop_ctrl;
 	uint32_t			enable_event;
@@ -230,7 +230,6 @@
 	uint32_t			ctxid_mask;
 	uint32_t			sync_freq;
 	uint32_t			timestamp_event;
-	uint8_t				pdcr_pwrup;
 	bool				pcsave_impl;
 	bool				pcsave_enable;
 };
@@ -339,48 +338,18 @@
 	     etm_readl(drvdata, ETMSR));
 }
 
-static void etm_save_pwrdwn(struct etm_drvdata *drvdata)
-{
-	drvdata->ctrl_pwrdwn = BVAL(etm_readl(drvdata, ETMCR), 0);
-}
-
-static void etm_restore_pwrdwn(struct etm_drvdata *drvdata)
-{
-	uint32_t etmcr;
-
-	etmcr = etm_readl(drvdata, ETMCR);
-	etmcr = (etmcr & ~BIT(0)) | drvdata->ctrl_pwrdwn;
-	etm_writel(drvdata, etmcr, ETMCR);
-}
-
-static void etm_save_pwrup(struct etm_drvdata *drvdata)
-{
-	drvdata->pdcr_pwrup = BVAL(etm_readl_mm(drvdata, ETMPDCR), 3);
-}
-
-static void etm_restore_pwrup(struct etm_drvdata *drvdata)
-{
-	uint32_t etmpdcr;
-
-	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
-	etmpdcr = (etmpdcr & ~BIT(3)) | (drvdata->pdcr_pwrup << 3);
-	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
-}
-
 static void etm_enable_pcsave(void *info)
 {
 	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
 
-	etm_save_pwrup(drvdata);
 	/*
 	 * ETMPDCR is only accessible via memory mapped interface and so use
 	 * it first to enable power/clock to allow subsequent cp14 accesses.
 	 */
 	etm_set_pwrup(drvdata);
 	etm_clr_pwrdwn(drvdata);
-	etm_restore_pwrup(drvdata);
 
 	ETM_LOCK(drvdata);
 }
@@ -391,14 +360,10 @@
 
 	ETM_UNLOCK(drvdata);
 
-	etm_save_pwrup(drvdata);
-	/*
-	 * ETMPDCR is only accessible via memory mapped interface and so use
-	 * it first to enable power/clock to allow subsequent cp14 accesses.
-	 */
-	etm_set_pwrup(drvdata);
-	etm_set_pwrdwn(drvdata);
-	etm_restore_pwrup(drvdata);
+	if (!drvdata->enable) {
+		etm_set_pwrdwn(drvdata);
+		etm_clr_pwrup(drvdata);
+	}
 
 	ETM_LOCK(drvdata);
 }
@@ -416,10 +381,10 @@
 	 * to allow subsequent cp14 accesses.
 	 */
 	etm_set_pwrup(drvdata);
-	etm_save_pwrdwn(drvdata);
 	/*
 	 * Clear power down bit since when this bit is set writes to
-	 * certain registers might be ignored.
+	 * certain registers might be ignored. This is also a pre-requisite
+	 * for trace enable.
 	 */
 	etm_clr_pwrdwn(drvdata);
 	etm_set_prog(drvdata);
@@ -463,7 +428,6 @@
 	etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
 
 	etm_clr_prog(drvdata);
-	etm_restore_pwrdwn(drvdata);
 	ETM_LOCK(drvdata);
 
 	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
@@ -481,10 +445,12 @@
 		goto err_clk;
 
 	mutex_lock(&drvdata->mutex);
-	/* executing __etm_enable on the cpu whose ETM is being enabled
+	/*
+	 * Executing __etm_enable on the cpu whose ETM is being enabled
 	 * ensures that register writes occur when cpu is powered.
 	 */
 	smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
+	drvdata->enable = true;
 	mutex_unlock(&drvdata->mutex);
 
 	wake_unlock(&drvdata->wake_lock);
@@ -501,20 +467,15 @@
 	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
-	etm_save_pwrdwn(drvdata);
-	/*
-	 * Clear power down bit since when this bit is set writes to
-	 * certain registers might be ignored.
-	 */
-	etm_clr_pwrdwn(drvdata);
 	etm_set_prog(drvdata);
 
 	/* program trace enable to low by using always false event */
 	etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
 
-	etm_restore_pwrdwn(drvdata);
-	/* Vote for ETM power/clock disable */
-	etm_clr_pwrup(drvdata);
+	if (!drvdata->pcsave_enable) {
+		etm_set_pwrdwn(drvdata);
+		etm_clr_pwrup(drvdata);
+	}
 	ETM_LOCK(drvdata);
 
 	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@@ -527,10 +488,12 @@
 	wake_lock(&drvdata->wake_lock);
 
 	mutex_lock(&drvdata->mutex);
-	/* executing __etm_disable on the cpu whose ETM is being disabled
+	/*
+	 * Executing __etm_disable on the cpu whose ETM is being disabled
 	 * ensures that register writes occur when cpu is powered.
 	 */
 	smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
+	drvdata->enable = false;
 	mutex_unlock(&drvdata->mutex);
 
 	clk_disable_unprepare(drvdata->clk);
@@ -1677,7 +1640,6 @@
 	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
 	etm_set_pwrdwn(drvdata);
-	/* Vote for ETM power/clock disable */
 	etm_clr_pwrup(drvdata);
 	ETM_LOCK(drvdata);
 }