msm: pil-q6v5: Move bus port halting into pil-q6v5 library

Other drivers that use the pil-q6v5 library will also need bus port
halting functions. Generalize the LPASS-specific code for doing this
and move it into pil-q6v5.c.

Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
Change-Id: I4d6e5798dfc7692d17abcec05ac3bc818e3634ec
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 3b9d542..6a96990 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/of.h>
@@ -25,11 +26,18 @@
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
-/* Register Offsets */
+/* QDSP6SS Register Offsets */
 #define QDSP6SS_RESET			0x014
 #define QDSP6SS_GFMUX_CTL		0x020
 #define QDSP6SS_PWR_CTL			0x030
 
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ			0x0
+#define AXI_HALTACK			0x4
+#define AXI_IDLE			0x8
+
+#define HALT_ACK_TIMEOUT_US		100000
+
 /* QDSP6SS_RESET */
 #define Q6SS_CORE_ARES			BIT(1)
 #define Q6SS_ETM_ISDB_ARES		BIT(3)
@@ -68,6 +76,27 @@
 }
 EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
 
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base)
+{
+	int ret;
+	u32 status;
+
+	/* Assert halt request */
+	writel_relaxed(1, halt_base + AXI_HALTREQ);
+
+	/* Wait for halt */
+	ret = readl_poll_timeout(halt_base + AXI_HALTACK,
+		status, status != 0, 50, HALT_ACK_TIMEOUT_US);
+	if (ret)
+		dev_warn(pil->dev, "Port %p halt timeout\n", halt_base);
+	else if (!readl_relaxed(halt_base + AXI_IDLE))
+		dev_warn(pil->dev, "Port %p halt failed\n", halt_base);
+
+	/* Clear halt request (port will remain halted until reset) */
+	writel_relaxed(0, halt_base + AXI_HALTREQ);
+}
+EXPORT_SYMBOL(pil_q6v5_halt_axi_port);
+
 int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
 			       size_t size)
 {
@@ -210,6 +239,11 @@
 				     resource_size(res));
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
+					  resource_size(res));
+	if (!drv->axi_halt_base)
+		return ERR_PTR(-ENOMEM);
 
 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc)