msm: pil-8960: Break off Q6v4 pil code into platform driver

Create a platform driver to manage the Q6v4 instead of having
a module that exists for any 8960 target. This allows us to add
platform devices when the device really exists and simplifies how
we handle regulators as well.

Change-Id: I20956040662a8aaf331b415c2b6c6f283ec4feef
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 1b836c4..e9aa3c6 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1570,6 +1570,14 @@
 
 	  Say yes to support these devices.
 
+config MSM_PIL_QDSP6V4
+	tristate "QDSP6v4 (Hexagon) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down QDSP6v4 processors (hexagon).
+	  The QDSP6 is a low power DSP used in audio, modem firmware, and modem
+	  software applications.
+
 config MSM_SCM
 	bool "Secure Channel Manager (SCM) support"
 	default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e8430e0..fe270c5 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -68,6 +68,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += peripheral-reset.o
 obj-$(CONFIG_ARCH_MSM8960) += peripheral-reset-8960.o
 endif
+obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
 obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-msm8960-regulator.c
index 559312c..976534e 100644
--- a/arch/arm/mach-msm/board-msm8960-regulator.c
+++ b/arch/arm/mach-msm/board-msm8960-regulator.c
@@ -119,15 +119,15 @@
 };
 VREG_CONSUMERS(L26) = {
 	REGULATOR_SUPPLY("8921_l26",		NULL),
-	REGULATOR_SUPPLY("q6_lpass",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.0"),
 };
 VREG_CONSUMERS(L27) = {
 	REGULATOR_SUPPLY("8921_l27",		NULL),
-	REGULATOR_SUPPLY("q6_modem_sw",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.2"),
 };
 VREG_CONSUMERS(L28) = {
 	REGULATOR_SUPPLY("8921_l28",		NULL),
-	REGULATOR_SUPPLY("q6_modem_fw",		NULL),
+	REGULATOR_SUPPLY("core_vdd",		"pil_qdsp6v4.1"),
 };
 VREG_CONSUMERS(L29) = {
 	REGULATOR_SUPPLY("8921_l29",		NULL),
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 9e68257..7ffb9b2 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -2227,6 +2227,9 @@
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
+	&msm_8960_q6_lpass,
+	&msm_8960_q6_mss_fw,
+	&msm_8960_q6_mss_sw,
 	&msm8960_device_otg,
 	&msm8960_device_gadget_peripheral,
 	&msm_device_hsusb_host,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 2add8f9..8e1e63a 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -38,6 +38,8 @@
 #include "footswitch.h"
 #include "msm_watchdog.h"
 #include "rpm_stats.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
 
 #ifdef CONFIG_MSM_MPM
 #include "mpm.h"
@@ -815,6 +817,107 @@
 	},
 };
 
+#define MSM_LPASS_QDSP6SS_PHYS	0x28800000
+#define SFAB_LPASS_Q6_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x23A0)
+
+static struct resource msm_8960_q6_lpass_resources[] = {
+	{
+		.start  = MSM_LPASS_QDSP6SS_PHYS,
+		.end    = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_lpass_data = {
+	.strap_tcm_base  = 0x01460000,
+	.strap_ahb_upper = 0x00290000,
+	.strap_ahb_lower = 0x00000280,
+	.aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
+	.name = "q6",
+	.pas_id = PAS_Q6,
+};
+
+struct platform_device msm_8960_q6_lpass = {
+	.name = "pil_qdsp6v4",
+	.id = 0,
+	.num_resources  = ARRAY_SIZE(msm_8960_q6_lpass_resources),
+	.resource       = msm_8960_q6_lpass_resources,
+	.dev.platform_data = &msm_8960_q6_lpass_data,
+};
+
+#define MSM_MSS_ENABLE_PHYS	0x08B00000
+#define MSM_FW_QDSP6SS_PHYS	0x08800000
+#define MSS_Q6FW_JTAG_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C6C)
+#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
+
+static struct resource msm_8960_q6_mss_fw_resources[] = {
+	{
+		.start  = MSM_FW_QDSP6SS_PHYS,
+		.end    = MSM_FW_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM_MSS_ENABLE_PHYS,
+		.end    = MSM_MSS_ENABLE_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_mss_fw_data = {
+	.strap_tcm_base  = 0x00400000,
+	.strap_ahb_upper = 0x00090000,
+	.strap_ahb_lower = 0x00000080,
+	.aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
+	.jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
+	.name = "modem_fw",
+	.depends = "q6",
+	.pas_id = PAS_MODEM_FW,
+};
+
+struct platform_device msm_8960_q6_mss_fw = {
+	.name = "pil_qdsp6v4",
+	.id = 1,
+	.num_resources  = ARRAY_SIZE(msm_8960_q6_mss_fw_resources),
+	.resource       = msm_8960_q6_mss_fw_resources,
+	.dev.platform_data = &msm_8960_q6_mss_fw_data,
+};
+
+#define MSM_SW_QDSP6SS_PHYS	0x08900000
+#define SFAB_MSS_Q6_SW_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2040)
+#define MSS_Q6SW_JTAG_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C68)
+
+static struct resource msm_8960_q6_mss_sw_resources[] = {
+	{
+		.start  = MSM_SW_QDSP6SS_PHYS,
+		.end    = MSM_SW_QDSP6SS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM_MSS_ENABLE_PHYS,
+		.end    = MSM_MSS_ENABLE_PHYS + 4 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct pil_q6v4_pdata msm_8960_q6_mss_sw_data = {
+	.strap_tcm_base  = 0x00420000,
+	.strap_ahb_upper = 0x00090000,
+	.strap_ahb_lower = 0x00000080,
+	.aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
+	.jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
+	.name = "modem",
+	.depends = "modem_fw",
+	.pas_id = PAS_MODEM_SW,
+};
+
+struct platform_device msm_8960_q6_mss_sw = {
+	.name = "pil_qdsp6v4",
+	.id = 2,
+	.num_resources  = ARRAY_SIZE(msm_8960_q6_mss_sw_resources),
+	.resource       = msm_8960_q6_mss_sw_resources,
+	.dev.platform_data = &msm_8960_q6_mss_sw_data,
+};
+
 struct platform_device msm_device_smd = {
 	.name		= "msm_smd",
 	.id		= -1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index bf611f4..147f01d 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -172,6 +172,10 @@
 extern struct platform_device msm_cpudai_afe_02_tx;
 extern struct platform_device msm_pcm_afe;
 
+extern struct platform_device msm_8960_q6_lpass;
+extern struct platform_device msm_8960_q6_mss_fw;
+extern struct platform_device msm_8960_q6_mss_sw;
+
 extern struct platform_device *msm_footswitch_devices[];
 extern unsigned msm_num_footswitch_devices;
 
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
index b964417..54b103a 100644
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ b/arch/arm/mach-msm/peripheral-reset-8960.c
@@ -28,49 +28,6 @@
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
-#define MSM_FW_QDSP6SS_PHYS	0x08800000
-#define MSM_SW_QDSP6SS_PHYS	0x08900000
-#define MSM_LPASS_QDSP6SS_PHYS	0x28800000
-#define MSM_MSS_ENABLE_PHYS	0x08B00000
-
-#define QDSP6SS_RST_EVB		0x0
-#define QDSP6SS_RESET		0x04
-#define QDSP6SS_CGC_OVERRIDE	0x18
-#define QDSP6SS_STRAP_TCM	0x1C
-#define QDSP6SS_STRAP_AHB	0x20
-#define QDSP6SS_GFMUX_CTL	0x30
-#define QDSP6SS_PWR_CTL		0x38
-
-#define MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C70)
-#define MSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
-#define SFAB_MSS_M_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2340)
-#define SFAB_MSS_S_HCLK_CTL	(MSM_CLK_CTL_BASE + 0x2C00)
-#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
-#define SFAB_MSS_Q6_SW_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2040)
-#define SFAB_LPASS_Q6_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x23A0)
-#define MSS_Q6FW_JTAG_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C6C)
-#define MSS_Q6SW_JTAG_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C68)
-#define MSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
-
-#define Q6SS_SS_ARES		BIT(0)
-#define Q6SS_CORE_ARES		BIT(1)
-#define Q6SS_ISDB_ARES		BIT(2)
-#define Q6SS_ETM_ARES		BIT(3)
-#define Q6SS_STOP_CORE_ARES	BIT(4)
-#define Q6SS_PRIV_ARES		BIT(5)
-
-#define Q6SS_L2DATA_SLP_NRET_N	BIT(0)
-#define Q6SS_SLP_RET_N		BIT(1)
-#define Q6SS_L1TCM_SLP_NRET_N	BIT(2)
-#define Q6SS_L2TAG_SLP_NRET_N	BIT(3)
-#define Q6SS_ETB_SLEEP_NRET_N	BIT(4)
-#define Q6SS_ARR_STBY_N		BIT(5)
-#define Q6SS_CLAMP_IO		BIT(6)
-
-#define Q6SS_CLK_ENA		BIT(1)
-#define Q6SS_SRC_SWITCH_CLK_OVR	BIT(8)
-#define Q6SS_AXIS_ACLK_EN	BIT(9)
-
 #define MSM_RIVA_PHYS			0x03204000
 #define RIVA_PMU_A2XB_CFG		(msm_riva_base + 0xB8)
 #define RIVA_PMU_A2XB_CFG_EN		BIT(0)
@@ -121,339 +78,14 @@
 #define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
 #define PPSS_HCLK_CTL			(MSM_CLK_CTL_BASE + 0x2580)
 
-struct q6_data {
-	const unsigned strap_tcm_base;
-	const unsigned strap_ahb_upper;
-	const unsigned strap_ahb_lower;
-	const unsigned reg_base_phys;
-	void __iomem *reg_base;
-	void __iomem *aclk_reg;
-	void __iomem *jtag_clk_reg;
-	int start_addr;
-	struct regulator *vreg;
-	bool vreg_enabled;
-	const char *name;
-};
-
-static struct q6_data q6_lpass = {
-	.strap_tcm_base  = (0x146 << 16),
-	.strap_ahb_upper = (0x029 << 16),
-	.strap_ahb_lower = (0x028 << 4),
-	.reg_base_phys = MSM_LPASS_QDSP6SS_PHYS,
-	.aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
-	.name = "q6_lpass",
-};
-
-static struct q6_data q6_modem_fw = {
-	.strap_tcm_base  = (0x40 << 16),
-	.strap_ahb_upper = (0x09 << 16),
-	.strap_ahb_lower = (0x08 << 4),
-	.reg_base_phys = MSM_FW_QDSP6SS_PHYS,
-	.aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
-	.jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
-	.name = "q6_modem_fw",
-};
-
-static struct q6_data q6_modem_sw = {
-	.strap_tcm_base  = (0x42 << 16),
-	.strap_ahb_upper = (0x09 << 16),
-	.strap_ahb_lower = (0x08 << 4),
-	.reg_base_phys = MSM_SW_QDSP6SS_PHYS,
-	.aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
-	.jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
-	.name = "q6_modem_sw",
-};
-
-static void __iomem *mss_enable_reg;
 static void __iomem *msm_riva_base;
 static unsigned long riva_start;
 
-static int init_image_lpass_q6_trusted(struct pil_desc *pil,
-				       const u8 *metadata, size_t size)
-{
-	return pas_init_image(PAS_Q6, metadata, size);
-}
-
-static int init_image_modem_fw_q6_trusted(struct pil_desc *pil,
-					  const u8 *metadata, size_t size)
-{
-	return pas_init_image(PAS_MODEM_FW, metadata, size);
-}
-
-static int init_image_modem_sw_q6_trusted(struct pil_desc *pil,
-					  const u8 *metadata, size_t size)
-{
-	return pas_init_image(PAS_MODEM_SW, metadata, size);
-}
-
-static int init_image_lpass_q6_untrusted(struct pil_desc *pil,
-					 const u8 *metadata, size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	q6_lpass.start_addr = ehdr->e_entry;
-	return 0;
-}
-
-static int init_image_modem_fw_q6_untrusted(struct pil_desc *pil,
-					    const u8 *metadata, size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	q6_modem_fw.start_addr = ehdr->e_entry;
-	return 0;
-}
-
-static int init_image_modem_sw_q6_untrusted(struct pil_desc *pil,
-					    const u8 *metadata, size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	q6_modem_sw.start_addr = ehdr->e_entry;
-	return 0;
-}
-
 static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
 {
 	return 0;
 }
 
-static int power_up_q6(struct q6_data *q6)
-{
-	int err;
-
-	err = regulator_set_voltage(q6->vreg, 1050000, 1050000);
-	if (err) {
-		pr_err("Failed to set %s regulator's voltage.\n", q6->name);
-		return err;
-	}
-	err = regulator_set_optimum_mode(q6->vreg, 100000);
-	if (err < 0) {
-		pr_err("Failed to set %s regulator's mode.\n", q6->name);
-		return err;
-	}
-	err = regulator_enable(q6->vreg);
-	if (err) {
-		pr_err("Failed to enable %s's regulator.\n", q6->name);
-		return err;
-	}
-	q6->vreg_enabled = true;
-	return 0;
-}
-
-static int reset_q6_trusted(int id, struct q6_data *q6)
-{
-	int err = power_up_q6(q6);
-	if (err)
-		return err;
-	return pas_auth_and_reset(id);
-}
-
-static int reset_lpass_q6_trusted(struct pil_desc *pil)
-{
-	return reset_q6_trusted(PAS_Q6, &q6_lpass);
-}
-
-static int reset_modem_fw_q6_trusted(struct pil_desc *pil)
-{
-	return reset_q6_trusted(PAS_MODEM_FW, &q6_modem_fw);
-}
-
-static int reset_modem_sw_q6_trusted(struct pil_desc *pil)
-{
-	return reset_q6_trusted(PAS_MODEM_SW, &q6_modem_sw);
-}
-
-static int reset_q6_untrusted(struct q6_data *q6)
-{
-	u32 reg, err = 0;
-
-	err = power_up_q6(q6);
-	if (err)
-		return err;
-	/* Enable Q6 ACLK */
-	writel_relaxed(0x10, q6->aclk_reg);
-
-	if (q6 == &q6_modem_fw || q6 == &q6_modem_sw) {
-		/* Enable MSS clocks */
-		writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
-		writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
-		writel_relaxed(0x10, MSS_S_HCLK_CTL);
-		writel_relaxed(0x10, MSS_SLP_CLK_CTL);
-		/* Wait for clocks to enable */
-		mb();
-		udelay(10);
-
-		/* Enable JTAG clocks */
-		/* TODO: Remove if/when Q6 software enables them? */
-		writel_relaxed(0x10, q6->jtag_clk_reg);
-
-		/* De-assert MSS reset */
-		writel_relaxed(0x0,  MSS_RESET);
-		mb();
-		udelay(10);
-
-		/* Enable MSS */
-		writel_relaxed(0x7,  mss_enable_reg);
-	}
-
-	/*
-	 * Assert AXIS_ACLK_EN override to allow for correct updating of the
-	 * QDSP6_CORE_STATE status bit. This is mandatory only for the SW Q6
-	 * in 8960v1 and optional elsewhere.
-	 */
-	reg = readl_relaxed(q6->reg_base + QDSP6SS_CGC_OVERRIDE);
-	reg |= Q6SS_AXIS_ACLK_EN;
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_CGC_OVERRIDE);
-
-	/* Deassert Q6SS_SS_ARES */
-	reg = readl_relaxed(q6->reg_base + QDSP6SS_RESET);
-	reg &= ~(Q6SS_SS_ARES);
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_RESET);
-
-	/* Program boot address */
-	writel_relaxed((q6->start_addr >> 8) & 0xFFFFFF,
-			q6->reg_base + QDSP6SS_RST_EVB);
-
-	/* Program TCM and AHB address ranges */
-	writel_relaxed(q6->strap_tcm_base, q6->reg_base + QDSP6SS_STRAP_TCM);
-	writel_relaxed(q6->strap_ahb_upper | q6->strap_ahb_lower,
-		       q6->reg_base + QDSP6SS_STRAP_AHB);
-
-	/* Turn off Q6 core clock */
-	writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
-		       q6->reg_base + QDSP6SS_GFMUX_CTL);
-
-	/* Put memories to sleep */
-	writel_relaxed(Q6SS_CLAMP_IO, q6->reg_base + QDSP6SS_PWR_CTL);
-
-	/* Assert resets */
-	reg = readl_relaxed(q6->reg_base + QDSP6SS_RESET);
-	reg |= (Q6SS_CORE_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES
-	    | Q6SS_STOP_CORE_ARES);
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_RESET);
-
-	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
-	mb();
-	usleep_range(20, 30);
-
-	/* Turn on Q6 memories */
-	reg = Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N | Q6SS_L1TCM_SLP_NRET_N
-	    | Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLEEP_NRET_N | Q6SS_ARR_STBY_N
-	    | Q6SS_CLAMP_IO;
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_PWR_CTL);
-
-	/* Turn on Q6 core clock */
-	reg = Q6SS_CLK_ENA | Q6SS_SRC_SWITCH_CLK_OVR;
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_GFMUX_CTL);
-
-	/* Remove Q6SS_CLAMP_IO */
-	reg = readl_relaxed(q6->reg_base + QDSP6SS_PWR_CTL);
-	reg &= ~Q6SS_CLAMP_IO;
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_PWR_CTL);
-
-	/* Bring Q6 core out of reset and start execution. */
-	writel_relaxed(0x0, q6->reg_base + QDSP6SS_RESET);
-
-	/*
-	 * Re-enable auto-gating of AXIS_ACLK at lease one AXI clock cycle
-	 * after resets are de-asserted.
-	 */
-	mb();
-	usleep_range(1, 10);
-	reg = readl_relaxed(q6->reg_base + QDSP6SS_CGC_OVERRIDE);
-	reg &= ~Q6SS_AXIS_ACLK_EN;
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_CGC_OVERRIDE);
-
-	return 0;
-}
-
-static int reset_lpass_q6_untrusted(struct pil_desc *pil)
-{
-	return reset_q6_untrusted(&q6_lpass);
-}
-
-static int reset_modem_fw_q6_untrusted(struct pil_desc *pil)
-{
-	return reset_q6_untrusted(&q6_modem_fw);
-}
-
-static int reset_modem_sw_q6_untrusted(struct pil_desc *pil)
-{
-	return reset_q6_untrusted(&q6_modem_sw);
-}
-
-static int shutdown_q6_trusted(int id, struct q6_data *q6)
-{
-	int ret;
-
-	ret = pas_shutdown(id);
-	if (ret)
-		return ret;
-
-	if (q6->vreg_enabled) {
-		regulator_disable(q6->vreg);
-		q6->vreg_enabled = false;
-	}
-
-	return ret;
-}
-
-static int shutdown_lpass_q6_trusted(struct pil_desc *pil)
-{
-	return shutdown_q6_trusted(PAS_Q6, &q6_lpass);
-}
-
-static int shutdown_modem_fw_q6_trusted(struct pil_desc *pil)
-{
-	return shutdown_q6_trusted(PAS_MODEM_FW, &q6_modem_fw);
-}
-
-static int shutdown_modem_sw_q6_trusted(struct pil_desc *pil)
-{
-	return shutdown_q6_trusted(PAS_MODEM_SW, &q6_modem_sw);
-}
-
-static int shutdown_q6_untrusted(struct q6_data *q6)
-{
-	u32 reg;
-
-	/* Turn off Q6 core clock */
-	writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
-		       q6->reg_base + QDSP6SS_GFMUX_CTL);
-
-	/* Assert resets */
-	reg = (Q6SS_SS_ARES | Q6SS_CORE_ARES | Q6SS_ISDB_ARES
-	     | Q6SS_ETM_ARES | Q6SS_STOP_CORE_ARES | Q6SS_PRIV_ARES);
-	writel_relaxed(reg, q6->reg_base + QDSP6SS_RESET);
-
-	/* Turn off Q6 memories */
-	writel_relaxed(Q6SS_CLAMP_IO, q6->reg_base + QDSP6SS_PWR_CTL);
-
-	/* Put Modem Subsystem back into reset when shutting down FWQ6 */
-	if (q6 == &q6_modem_fw)
-		writel_relaxed(0x1, MSS_RESET);
-
-	if (q6->vreg_enabled) {
-		regulator_disable(q6->vreg);
-		q6->vreg_enabled = false;
-	}
-
-	return 0;
-}
-
-static int shutdown_lpass_q6_untrusted(struct pil_desc *pil)
-{
-	return shutdown_q6_untrusted(&q6_lpass);
-}
-
-static int shutdown_modem_fw_q6_untrusted(struct pil_desc *pil)
-{
-	return shutdown_q6_untrusted(&q6_modem_fw);
-}
-
-static int shutdown_modem_sw_q6_untrusted(struct pil_desc *pil)
-{
-	return shutdown_q6_untrusted(&q6_modem_sw);
-}
-
 static int init_image_riva_untrusted(struct pil_desc *pil, const u8 *metadata,
 				     size_t size)
 {
@@ -635,27 +267,6 @@
 	return pas_shutdown(PAS_TZAPPS);
 }
 
-static struct pil_reset_ops pil_modem_fw_q6_ops = {
-	.init_image = init_image_modem_fw_q6_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_modem_fw_q6_untrusted,
-	.shutdown = shutdown_modem_fw_q6_untrusted,
-};
-
-static struct pil_reset_ops pil_modem_sw_q6_ops = {
-	.init_image = init_image_modem_sw_q6_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_modem_sw_q6_untrusted,
-	.shutdown = shutdown_modem_sw_q6_untrusted,
-};
-
-static struct pil_reset_ops pil_lpass_q6_ops = {
-	.init_image = init_image_lpass_q6_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_lpass_q6_untrusted,
-	.shutdown = shutdown_lpass_q6_untrusted,
-};
-
 static struct pil_reset_ops pil_riva_ops = {
 	.init_image = init_image_riva_untrusted,
 	.verify_blob = verify_blob,
@@ -677,38 +288,6 @@
 	.shutdown = shutdown_tzapps,
 };
 
-static struct platform_device pil_lpass_q6 = {
-	.name = "pil_lpass_q6",
-};
-
-static struct pil_desc pil_lpass_q6_desc = {
-	.name = "q6",
-	.dev = &pil_lpass_q6.dev,
-	.ops = &pil_lpass_q6_ops,
-};
-
-static struct platform_device pil_modem_fw_q6 = {
-	.name = "pil_modem_fw_q6",
-};
-
-static struct pil_desc pil_modem_fw_q6_desc = {
-	.name = "modem_fw",
-	.depends_on = "q6",
-	.dev = &pil_modem_fw_q6.dev,
-	.ops = &pil_modem_fw_q6_ops,
-};
-
-static struct platform_device pil_modem_sw_q6 = {
-	.name = "pil_modem_sw_q6",
-};
-
-static struct pil_desc pil_modem_sw_q6_desc = {
-	.name = "modem",
-	.depends_on = "modem_fw",
-	.dev = &pil_modem_sw_q6.dev,
-	.ops = &pil_modem_sw_q6_ops,
-};
-
 static struct platform_device pil_riva = {
 	.name = "pil_riva",
 };
@@ -739,51 +318,8 @@
 	.ops = &pil_tzapps_ops,
 };
 
-static int __init q6_reset_init(struct q6_data *q6)
-{
-	int err;
-
-	q6->reg_base = ioremap(q6->reg_base_phys, SZ_256);
-	if (!q6->reg_base) {
-		err = -ENOMEM;
-		goto err_map;
-	}
-
-	q6->vreg = regulator_get(NULL, q6->name);
-	if (IS_ERR(q6->vreg)) {
-		err = PTR_ERR(q6->vreg);
-		goto err_vreg;
-	}
-
-	return 0;
-
-err_vreg:
-	iounmap(q6->reg_base);
-err_map:
-	return err;
-}
-
 static void __init use_secure_pil(void)
 {
-
-	if (pas_supported(PAS_Q6) > 0) {
-		pil_lpass_q6_ops.init_image = init_image_lpass_q6_trusted;
-		pil_lpass_q6_ops.auth_and_reset = reset_lpass_q6_trusted;
-		pil_lpass_q6_ops.shutdown = shutdown_lpass_q6_trusted;
-	}
-
-	if (pas_supported(PAS_MODEM_FW) > 0) {
-		pil_modem_fw_q6_ops.init_image = init_image_modem_fw_q6_trusted;
-		pil_modem_fw_q6_ops.auth_and_reset = reset_modem_fw_q6_trusted;
-		pil_modem_fw_q6_ops.shutdown = shutdown_modem_fw_q6_trusted;
-	}
-
-	if (pas_supported(PAS_MODEM_SW) > 0) {
-		pil_modem_sw_q6_ops.init_image = init_image_modem_sw_q6_trusted;
-		pil_modem_sw_q6_ops.auth_and_reset = reset_modem_sw_q6_trusted;
-		pil_modem_sw_q6_ops.shutdown = shutdown_modem_sw_q6_trusted;
-	}
-
 	if (pas_supported(PAS_DSPS) > 0) {
 		pil_dsps_ops.init_image = init_image_dsps_trusted;
 		pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
@@ -797,11 +333,8 @@
 	}
 }
 
-
 static int __init msm_peripheral_reset_init(void)
 {
-	int err;
-
 	/*
 	 * Don't initialize PIL on simulated targets, as some
 	 * subsystems may not be emulated on them.
@@ -811,34 +344,6 @@
 
 	use_secure_pil();
 
-	err = q6_reset_init(&q6_lpass);
-	if (err)
-		return err;
-	BUG_ON(platform_device_register(&pil_lpass_q6));
-	BUG_ON(msm_pil_register(&pil_lpass_q6_desc));
-
-	mss_enable_reg = ioremap(MSM_MSS_ENABLE_PHYS, 4);
-	if (!mss_enable_reg)
-		return -ENOMEM;
-
-	err = q6_reset_init(&q6_modem_fw);
-	if (err) {
-		iounmap(mss_enable_reg);
-		return err;
-	}
-	BUG_ON(platform_device_register(&pil_modem_fw_q6));
-	if (err) {
-		iounmap(mss_enable_reg);
-		return err;
-	}
-	BUG_ON(msm_pil_register(&pil_modem_fw_q6_desc));
-
-	err = q6_reset_init(&q6_modem_sw);
-	if (err)
-		return err;
-	BUG_ON(platform_device_register(&pil_modem_sw_q6));
-	BUG_ON(msm_pil_register(&pil_modem_sw_q6_desc));
-
 	BUG_ON(platform_device_register(&pil_dsps));
 	BUG_ON(msm_pil_register(&pil_dsps_desc));
 	BUG_ON(platform_device_register(&pil_tzapps));
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
new file mode 100644
index 0000000..fd7753c
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -0,0 +1,400 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/regulator/consumer.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+#define QDSP6SS_RST_EVB		0x0
+#define QDSP6SS_RESET		0x04
+#define QDSP6SS_CGC_OVERRIDE	0x18
+#define QDSP6SS_STRAP_TCM	0x1C
+#define QDSP6SS_STRAP_AHB	0x20
+#define QDSP6SS_GFMUX_CTL	0x30
+#define QDSP6SS_PWR_CTL		0x38
+
+#define MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C70)
+#define MSS_SLP_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C60)
+#define SFAB_MSS_M_ACLK_CTL	(MSM_CLK_CTL_BASE + 0x2340)
+#define SFAB_MSS_S_HCLK_CTL	(MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_RESET		(MSM_CLK_CTL_BASE + 0x2C64)
+
+#define Q6SS_SS_ARES		BIT(0)
+#define Q6SS_CORE_ARES		BIT(1)
+#define Q6SS_ISDB_ARES		BIT(2)
+#define Q6SS_ETM_ARES		BIT(3)
+#define Q6SS_STOP_CORE_ARES	BIT(4)
+#define Q6SS_PRIV_ARES		BIT(5)
+
+#define Q6SS_L2DATA_SLP_NRET_N	BIT(0)
+#define Q6SS_SLP_RET_N		BIT(1)
+#define Q6SS_L1TCM_SLP_NRET_N	BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N	BIT(3)
+#define Q6SS_ETB_SLEEP_NRET_N	BIT(4)
+#define Q6SS_ARR_STBY_N		BIT(5)
+#define Q6SS_CLAMP_IO		BIT(6)
+
+#define Q6SS_CLK_ENA		BIT(1)
+#define Q6SS_SRC_SWITCH_CLK_OVR	BIT(8)
+#define Q6SS_AXIS_ACLK_EN	BIT(9)
+
+struct q6v4_data {
+	void __iomem *base;
+	void __iomem *modem_base;
+	unsigned long start_addr;
+	struct regulator *vreg;
+	bool vreg_enabled;
+};
+
+static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+	return 0;
+}
+
+static int pil_q6v4_power_up(struct device *dev)
+{
+	int err;
+	struct q6v4_data *drv = dev_get_drvdata(dev);
+
+	err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+	if (err) {
+		dev_err(dev, "Failed to set regulator's voltage.\n");
+		return err;
+	}
+	err = regulator_set_optimum_mode(drv->vreg, 100000);
+	if (err < 0) {
+		dev_err(dev, "Failed to set regulator's mode.\n");
+		return err;
+	}
+	err = regulator_enable(drv->vreg);
+	if (err) {
+		dev_err(dev, "Failed to enable regulator.\n");
+		return err;
+	}
+	drv->vreg_enabled = true;
+	return 0;
+}
+
+static DEFINE_MUTEX(pil_q6v4_modem_lock);
+static unsigned pil_q6v4_modem_count;
+
+/* Bring modem subsystem out of reset */
+static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+{
+	mutex_lock(&pil_q6v4_modem_lock);
+	if (!pil_q6v4_modem_count) {
+		/* Enable MSS clocks */
+		writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
+		writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+		writel_relaxed(0x10, MSS_S_HCLK_CTL);
+		writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+		/* Wait for clocks to enable */
+		mb();
+		udelay(10);
+
+		/* De-assert MSS reset */
+		writel_relaxed(0x0, MSS_RESET);
+		mb();
+		udelay(10);
+		/* Enable MSS */
+		writel_relaxed(0x7, base);
+	}
+
+	/* Enable JTAG clocks */
+	/* TODO: Remove if/when Q6 software enables them? */
+	writel_relaxed(0x10, jtag_clk);
+
+	pil_q6v4_modem_count++;
+	mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+/* Put modem subsystem back into reset */
+static void pil_q6v4_shutdown_modem(void)
+{
+	mutex_lock(&pil_q6v4_modem_lock);
+	if (pil_q6v4_modem_count)
+		pil_q6v4_modem_count--;
+	if (pil_q6v4_modem_count == 0)
+		writel_relaxed(0x1, MSS_RESET);
+	mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+static int pil_q6v4_reset(struct pil_desc *pil)
+{
+	u32 reg, err = 0;
+	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+	err = pil_q6v4_power_up(pil->dev);
+	if (err)
+		return err;
+	/* Enable Q6 ACLK */
+	writel_relaxed(0x10, pdata->aclk_reg);
+
+	if (drv->modem_base)
+		pil_q6v4_init_modem(drv->modem_base, pdata->jtag_clk_reg);
+
+	/*
+	 * Assert AXIS_ACLK_EN override to allow for correct updating of the
+	 * QDSP6_CORE_STATE status bit. This is mandatory only for the SW Q6
+	 * in 8960v1 and optional elsewhere.
+	 */
+	reg = readl_relaxed(drv->base + QDSP6SS_CGC_OVERRIDE);
+	reg |= Q6SS_AXIS_ACLK_EN;
+	writel_relaxed(reg, drv->base + QDSP6SS_CGC_OVERRIDE);
+
+	/* Deassert Q6SS_SS_ARES */
+	reg = readl_relaxed(drv->base + QDSP6SS_RESET);
+	reg &= ~(Q6SS_SS_ARES);
+	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+	/* Program boot address */
+	writel_relaxed((drv->start_addr >> 8) & 0xFFFFFF,
+			drv->base + QDSP6SS_RST_EVB);
+
+	/* Program TCM and AHB address ranges */
+	writel_relaxed(pdata->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
+	writel_relaxed(pdata->strap_ahb_upper | pdata->strap_ahb_lower,
+		       drv->base + QDSP6SS_STRAP_AHB);
+
+	/* Turn off Q6 core clock */
+	writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
+		       drv->base + QDSP6SS_GFMUX_CTL);
+
+	/* Put memories to sleep */
+	writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
+
+	/* Assert resets */
+	reg = readl_relaxed(drv->base + QDSP6SS_RESET);
+	reg |= (Q6SS_CORE_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES
+	    | Q6SS_STOP_CORE_ARES);
+	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+	/* Wait 8 AHB cycles for Q6 to be fully reset (AHB = 1.5Mhz) */
+	mb();
+	usleep_range(20, 30);
+
+	/* Turn on Q6 memories */
+	reg = Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N | Q6SS_L1TCM_SLP_NRET_N
+	    | Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLEEP_NRET_N | Q6SS_ARR_STBY_N
+	    | Q6SS_CLAMP_IO;
+	writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
+
+	/* Turn on Q6 core clock */
+	reg = Q6SS_CLK_ENA | Q6SS_SRC_SWITCH_CLK_OVR;
+	writel_relaxed(reg, drv->base + QDSP6SS_GFMUX_CTL);
+
+	/* Remove Q6SS_CLAMP_IO */
+	reg = readl_relaxed(drv->base + QDSP6SS_PWR_CTL);
+	reg &= ~Q6SS_CLAMP_IO;
+	writel_relaxed(reg, drv->base + QDSP6SS_PWR_CTL);
+
+	/* Bring Q6 core out of reset and start execution. */
+	writel_relaxed(0x0, drv->base + QDSP6SS_RESET);
+
+	/*
+	 * Re-enable auto-gating of AXIS_ACLK at lease one AXI clock cycle
+	 * after resets are de-asserted.
+	 */
+	mb();
+	usleep_range(1, 10);
+	reg = readl_relaxed(drv->base + QDSP6SS_CGC_OVERRIDE);
+	reg &= ~Q6SS_AXIS_ACLK_EN;
+	writel_relaxed(reg, drv->base + QDSP6SS_CGC_OVERRIDE);
+
+	return 0;
+}
+
+static int pil_q6v4_shutdown(struct pil_desc *pil)
+{
+	u32 reg;
+	struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Turn off Q6 core clock */
+	writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
+		       drv->base + QDSP6SS_GFMUX_CTL);
+
+	/* Assert resets */
+	reg = (Q6SS_SS_ARES | Q6SS_CORE_ARES | Q6SS_ISDB_ARES
+	     | Q6SS_ETM_ARES | Q6SS_STOP_CORE_ARES | Q6SS_PRIV_ARES);
+	writel_relaxed(reg, drv->base + QDSP6SS_RESET);
+
+	/* Turn off Q6 memories */
+	writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
+
+	if (drv->modem_base)
+		pil_q6v4_shutdown_modem();
+
+	if (drv->vreg_enabled) {
+		regulator_disable(drv->vreg);
+		drv->vreg_enabled = false;
+	}
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_ops = {
+	.init_image = pil_q6v4_init_image,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_q6v4_reset,
+	.shutdown = pil_q6v4_shutdown,
+};
+
+static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+	return pas_init_image(pdata->pas_id, metadata, size);
+}
+
+static int pil_q6v4_reset_trusted(struct pil_desc *pil)
+{
+	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+	int err;
+
+	err = pil_q6v4_power_up(pil->dev);
+	if (err)
+		return err;
+	return pas_auth_and_reset(pdata->pas_id);
+}
+
+static int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+	struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+
+	ret = pas_shutdown(pdata->pas_id);
+	if (ret)
+		return ret;
+
+	if (drv->vreg_enabled) {
+		regulator_disable(drv->vreg);
+		drv->vreg_enabled = false;
+	}
+
+	return ret;
+}
+
+static struct pil_reset_ops pil_q6v4_ops_trusted = {
+	.init_image = pil_q6v4_init_image_trusted,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_q6v4_reset_trusted,
+	.shutdown = pil_q6v4_shutdown_trusted,
+};
+
+static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
+{
+	const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
+	struct q6v4_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		drv->modem_base = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+		if (!drv->modem_base)
+			return -ENOMEM;
+	}
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	desc->name = pdata->name;
+	desc->depends_on = pdata->depends;
+	desc->dev = &pdev->dev;
+
+	if (pas_supported(pdata->pas_id) > 0) {
+		desc->ops = &pil_q6v4_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_q6v4_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	drv->vreg = regulator_get(&pdev->dev, "core_vdd");
+	if (IS_ERR(drv->vreg))
+		return PTR_ERR(drv->vreg);
+
+	if (msm_pil_register(desc)) {
+		regulator_put(drv->vreg);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
+{
+	struct q6v4_data *drv = platform_get_drvdata(pdev);
+	regulator_put(drv->vreg);
+	return 0;
+}
+
+static struct platform_driver pil_q6v4_driver = {
+	.probe = pil_q6v4_driver_probe,
+	.remove = __devexit_p(pil_q6v4_driver_exit),
+	.driver = {
+		.name = "pil_qdsp6v4",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_q6v4_init(void)
+{
+	return platform_driver_register(&pil_q6v4_driver);
+}
+module_init(pil_q6v4_init);
+
+static void __exit pil_q6v4_exit(void)
+{
+	platform_driver_unregister(&pil_q6v4_driver);
+}
+module_exit(pil_q6v4_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.h b/arch/arm/mach-msm/pil-q6v4.h
new file mode 100644
index 0000000..6aba9a5
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_PIL_Q6V4_H
+#define __MSM_PIL_Q6V4_H
+
+struct pil_q6v4_pdata {
+	const unsigned long strap_tcm_base;
+	const unsigned long strap_ahb_upper;
+	const unsigned long strap_ahb_lower;
+	void __iomem *aclk_reg;
+	void __iomem *jtag_clk_reg;
+	const char *name;
+	const char *depends;
+	const unsigned pas_id;
+};
+#endif