msm: pil-gss: Apply 8064v1.0 GSS QGIC bus workaround to secure PIL

On 8064v1.0 hardware, the secure PIL code will not release the A5
processor from reset as part of pas_auth_and_reset(). Instead,
Linux is expected to perform the GSS QGIC bus workaround after
pas_auth_and_reset() returns and then release the A5 reset itself
from non-secure context.

This is done to guarantee that the workaround is executed on Krait0,
while at the same time accommodating a secure-PIL implementation
under pas_auth_and_reset() that is shared with other high-level
operating systems.

Change-Id: Ibff9d85493cc190938ed829ed237982e8842e4c8
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 6ec9b5d..2b4dae1 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -25,6 +25,7 @@
 
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
+#include <mach/socinfo.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -142,13 +143,17 @@
 	writel_relaxed(A5_RESET, base + GSS_CSR_RESET);
 }
 
-static void setup_qgic2_bus_access(void *data)
+static void cfg_qgic2_bus_access(void *data)
 {
 	struct gss_data *drv = data;
-	void __iomem *base = drv->base;
 	int i;
 
-	writel_relaxed(0x2, base + GSS_CSR_CFG_HID);
+	/*
+	 * Apply a 8064 v1.0 workaround to configure QGIC bus access.
+	 * This must be done from Krait 0 to configure the Master ID
+	 * correctly.
+	 */
+	writel_relaxed(0x2, drv->base + GSS_CSR_CFG_HID);
 	for (i = 0; i <= 3; i++)
 		readl_relaxed(drv->qgic2_base);
 }
@@ -233,15 +238,15 @@
 	while (!(readl_relaxed(base + GSS_CSR_POWER_UP_DOWN) & A5_POWER_STATUS))
 		cpu_relax();
 
-	/*
-	 * Apply a 8064 v1.0 workaround to configure QGIC bus access. This must
-	 * be done from Krait 0 to configure the Master ID correctly.
-	 */
-	ret = smp_call_function_single(0, setup_qgic2_bus_access, drv, 1);
-	if (ret) {
-		pr_err("Failed to configure QGIC2 bus access\n");
-		pil_gss_shutdown(pil);
-		return ret;
+	if (cpu_is_apq8064() &&
+	    ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) &&
+	     (SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0))) {
+		ret = smp_call_function_single(0, cfg_qgic2_bus_access, drv, 1);
+		if (ret) {
+			pr_err("Failed to configure QGIC2 bus access\n");
+			pil_gss_shutdown(pil);
+			return ret;
+		}
 	}
 
 	/* Release A5 from reset. */
@@ -263,6 +268,20 @@
 	return pas_init_image(PAS_GSS, metadata, size);
 }
 
+static int pil_gss_shutdown_trusted(struct pil_desc *pil)
+{
+	struct gss_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = pas_shutdown(PAS_GSS);
+	if (ret)
+		return ret;
+
+	remove_gss_proxy_votes_now(drv);
+
+	return ret;
+}
+
 static int pil_gss_reset_trusted(struct pil_desc *pil)
 {
 	struct gss_data *drv = dev_get_drvdata(pil->dev);
@@ -276,23 +295,26 @@
 	if (err)
 		remove_gss_proxy_votes_now(drv);
 
+	if (cpu_is_apq8064() &&
+	    ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) &&
+	     (SOCINFO_VERSION_MINOR(socinfo_get_version()) == 0))) {
+		err = smp_call_function_single(0, cfg_qgic2_bus_access, drv, 1);
+		if (err) {
+			pr_err("Failed to configure QGIC2 bus access\n");
+			pil_gss_shutdown_trusted(pil);
+			return err;
+		}
+		/*
+		 * On 8064v1.0, pas_auth_and_reset() will not release the A5
+		 * from reset. Linux must do this after cfg_qgic2_bus_access()
+		 * is called on CPU0.
+		 */
+		writel_relaxed(0x0, drv->base + GSS_CSR_RESET);
+	}
+
 	return err;
 }
 
-static int pil_gss_shutdown_trusted(struct pil_desc *pil)
-{
-	struct gss_data *drv = dev_get_drvdata(pil->dev);
-	int ret;
-
-	ret = pas_shutdown(PAS_GSS);
-	if (ret)
-		return ret;
-
-	remove_gss_proxy_votes_now(drv);
-
-	return ret;
-}
-
 static struct pil_reset_ops pil_gss_ops_trusted = {
 	.init_image = pil_gss_init_image_trusted,
 	.verify_blob = nop_verify_blob,